diff --git a/contexts/DataContext.tsx b/contexts/DataContext.tsx index 7a4cb4c..9eede62 100644 --- a/contexts/DataContext.tsx +++ b/contexts/DataContext.tsx @@ -2,6 +2,40 @@ import React, { createContext, useContext, useState, ReactNode } from 'react'; import { EventData, EventStatus, EventType, Institution } from '../types'; +interface Photographer { + id: string; + name: string; + email: string; + phone: string; + avatar: string; + specialties: string[]; + rating: number; + eventsCompleted: number; +} + +const MOCK_PHOTOGRAPHERS: Photographer[] = [ + { + id: 'photographer-1', + name: 'Ana Paula Silva', + email: 'ana.silva@photum.com', + phone: '(51) 99999-1234', + avatar: 'https://i.pravatar.cc/150?img=5', + specialties: ['Formaturas', 'Eventos Universitários', 'Colações de Grau'], + rating: 4.9, + eventsCompleted: 87 + }, + { + id: 'photographer-2', + name: 'Carlos Mendes', + email: 'carlos.mendes@photum.com', + phone: '(51) 99888-5678', + avatar: 'https://i.pravatar.cc/150?img=12', + specialties: ['Formaturas', 'Eventos Corporativos'], + rating: 4.8, + eventsCompleted: 65 + } +]; + // Initial Mock Data const INITIAL_INSTITUTIONS: Institution[] = [ { @@ -25,10 +59,10 @@ const INITIAL_INSTITUTIONS: Institution[] = [ const INITIAL_EVENTS: EventData[] = [ { id: '1', - name: 'Casamento Juliana & Marcos', + name: 'Formatura Medicina UFRGS', date: '2024-10-15', - time: '16:00', - type: EventType.WEDDING, + time: '19:00', + type: EventType.GRADUATION, status: EventStatus.CONFIRMED, address: { street: 'Av. das Hortênsias', @@ -37,8 +71,8 @@ const INITIAL_EVENTS: EventData[] = [ state: 'RS', zip: '95670-000' }, - briefing: 'Cerimônia ao pôr do sol. Foco em fotos espontâneas dos noivos e pais.', - coverImage: 'https://picsum.photos/id/1059/800/400', + briefing: 'Cerimônia de formatura no Teatro Guaíra. Foco em fotos da colação de grau, formandos e familiares.', + coverImage: 'https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=800&h=400&fit=crop', contacts: [{ id: 'c1', name: 'Cerimonial Silva', role: 'Cerimonialista', phone: '9999-9999', email: 'c@teste.com'}], checklist: [], ownerId: 'client-1', @@ -71,6 +105,7 @@ const INITIAL_EVENTS: EventData[] = [ interface DataContextType { events: EventData[]; institutions: Institution[]; + photographers: Photographer[]; addEvent: (event: EventData) => void; updateEventStatus: (id: string, status: EventStatus) => void; assignPhotographer: (eventId: string, photographerId: string) => void; @@ -79,6 +114,7 @@ interface DataContextType { updateInstitution: (id: string, institution: Partial) => void; getInstitutionsByUserId: (userId: string) => Institution[]; getInstitutionById: (id: string) => Institution | undefined; + getPhotographerById: (id: string) => Photographer | undefined; } const DataContext = createContext(undefined); @@ -86,6 +122,7 @@ const DataContext = createContext(undefined); export const DataProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [events, setEvents] = useState(INITIAL_EVENTS); const [institutions, setInstitutions] = useState(INITIAL_INSTITUTIONS); + const [photographers] = useState(MOCK_PHOTOGRAPHERS); const addEvent = (event: EventData) => { setEvents(prev => [event, ...prev]); @@ -138,10 +175,15 @@ export const DataProvider: React.FC<{ children: ReactNode }> = ({ children }) => return institutions.find(inst => inst.id === id); }; + const getPhotographerById = (id: string) => { + return photographers.find(p => p.id === id); + }; + return ( = ({ children }) => addInstitution, updateInstitution, getInstitutionsByUserId, - getInstitutionById + getInstitutionById, + getPhotographerById }}> {children} diff --git a/pages/Calendar.tsx b/pages/Calendar.tsx index 31e2bbb..8b30743 100644 --- a/pages/Calendar.tsx +++ b/pages/Calendar.tsx @@ -78,6 +78,7 @@ const MOCK_EVENTS: Event[] = [ export const CalendarPage: React.FC = () => { const [selectedMonth, setSelectedMonth] = useState(new Date()); const [selectedEvent, setSelectedEvent] = useState(null); + const [selectedDate, setSelectedDate] = useState(null); const getStatusColor = (status: Event['status']) => { switch (status) { @@ -145,6 +146,50 @@ export const CalendarPage: React.FC = () => { year: 'numeric' }); + // Generate calendar days + const generateCalendarDays = () => { + const year = selectedMonth.getFullYear(); + const month = selectedMonth.getMonth(); + + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + + const firstDayOfWeek = firstDay.getDay(); + const daysInMonth = lastDay.getDate(); + + const days: (Date | null)[] = []; + + // Add empty cells for days before month starts + for (let i = 0; i < firstDayOfWeek; i++) { + days.push(null); + } + + // Add all days of the month + for (let day = 1; day <= daysInMonth; day++) { + days.push(new Date(year, month, day)); + } + + return days; + }; + + const getEventsForDate = (date: Date) => { + return MOCK_EVENTS.filter(event => { + const eventDate = new Date(event.date + 'T00:00:00'); + return eventDate.getDate() === date.getDate() && + eventDate.getMonth() === date.getMonth() && + eventDate.getFullYear() === date.getFullYear(); + }); + }; + + const isToday = (date: Date) => { + const today = new Date(); + return date.getDate() === today.getDate() && + date.getMonth() === today.getMonth() && + date.getFullYear() === today.getFullYear(); + }; + + const calendarDays = generateCalendarDays(); + // Filter events for selected month const monthEvents = MOCK_EVENTS.filter(event => { const eventDate = new Date(event.date + 'T00:00:00'); @@ -158,121 +203,242 @@ export const CalendarPage: React.FC = () => { ); return ( -
-
+
+
{/* Header */} -
-

+
+

Minha Agenda

-

+

Gerencie seus eventos e compromissos fotográficos

-
- {/* Calendar Navigation */} -
-
-
+
+ {/* Full Calendar Grid */} +
+
+
-

+

{currentMonthName}

-
-
- Eventos este mês: - {monthEvents.length} + {/* Calendar Grid */} +
+ {/* Week Days Header */} +
+ {['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'].map((day) => ( +
+ {day} +
+ ))}
-
- Total de eventos: - {MOCK_EVENTS.length} + + {/* Calendar Days */} +
+ {calendarDays.map((date, index) => { + if (!date) { + return ( +
+ ); + } + + const dayEvents = getEventsForDate(date); + const hasEvents = dayEvents.length > 0; + const today = isToday(date); + + return ( + + ); + })}
-
-

Legenda

-
-
-
- Confirmado +
+
+
+ Eventos este mês: + {monthEvents.length}
-
-
- Pendente -
-
-
- Concluído +
+ Total: + {MOCK_EVENTS.length}
+ {/* Legend and Info Sidebar */} +
+
+

Legenda

+
+
+
+ Confirmado +
+
+
+ Pendente +
+
+
+ Concluído +
+
+
+ Hoje +
+
+
+ Com eventos +
+
+ + {selectedDate && ( +
+

+ {selectedDate.toLocaleDateString('pt-BR', { + day: '2-digit', + month: 'long', + year: 'numeric' + })} +

+ {getEventsForDate(selectedDate).length > 0 ? ( +
+ {getEventsForDate(selectedDate).map(event => ( +
setSelectedEvent(event)} + > +
+ {event.title} +
+
+ + {event.time} +
+
+ ))} +
+ ) : ( +

Nenhum evento neste dia

+ )} +
+ )} +
+
+ {/* Events List */} -
+
-
-

Próximos Eventos

+
+

Próximos Eventos

{sortedEvents.length === 0 ? ( -
- -

Nenhum evento agendado

+
+ +

Nenhum evento agendado

) : ( sortedEvents.map((event) => (
setSelectedEvent(event)} > -
-
-
-

+
+
+
+

{event.title}

- + {getTypeLabel(event.type)}
-
-
- - {formatDate(event.date)} +
+
+ + {formatDate(event.date)}
-
- - {event.time} +
+ + {event.time}
-
- - {event.location} +
+ + {event.location}
-
- - {event.client} +
+ + {event.client}
- + {getStatusLabel(event.status)}
@@ -285,23 +451,31 @@ export const CalendarPage: React.FC = () => {
- {/* Event Detail Modal */} + {/* Event Detail Modal - Improved & Centered */} {selectedEvent && (
setSelectedEvent(null)} >
e.stopPropagation()} > -
-
-

+ {/* Header with gradient */} +
+ + +
+

{selectedEvent.title}

-
- +
+ {getTypeLabel(selectedEvent.type)} @@ -309,49 +483,101 @@ export const CalendarPage: React.FC = () => {
-
-
-
- - {formatDate(selectedEvent.date)} + {/* Content */} +
+ {/* Date */} +
+
+ +
+
+

Data

+

{formatDate(selectedEvent.date)}

+
-
- - {selectedEvent.time} + + {/* Time */} +
+
+ +
+
+

Horário

+

{selectedEvent.time}

+
-
- - {selectedEvent.location} + + {/* Location */} +
+
+ +
+
+

Local

+

{selectedEvent.location}

+
-
- - {selectedEvent.client} + + {/* Client */} +
+
+ +
+
+

Cliente

+

{selectedEvent.client}

+
-
+ {/* Actions */} +
)} + +
); }; diff --git a/pages/Dashboard.tsx b/pages/Dashboard.tsx index b77c320..51d6db7 100644 --- a/pages/Dashboard.tsx +++ b/pages/Dashboard.tsx @@ -4,7 +4,7 @@ import { UserRole, EventData, EventStatus, EventType } from '../types'; import { EventCard } from '../components/EventCard'; import { EventForm } from '../components/EventForm'; import { Button } from '../components/Button'; -import { PlusCircle, Search, CheckCircle, Clock, Edit, Users, Map, Building2 } from 'lucide-react'; +import { PlusCircle, Search, CheckCircle, Clock, Edit, Users, Map, Building2, Phone, Mail, MapPin, FileText, Camera, Star } from 'lucide-react'; import { useAuth } from '../contexts/AuthContext'; import { useData } from '../contexts/DataContext'; import { STATUS_COLORS } from '../constants'; @@ -15,7 +15,7 @@ interface DashboardProps { export const Dashboard: React.FC = ({ initialView = 'list' }) => { const { user } = useAuth(); - const { events, getEventsByRole, addEvent, updateEventStatus, assignPhotographer, getInstitutionById } = useData(); + const { events, getEventsByRole, addEvent, updateEventStatus, assignPhotographer, addAttachment, getPhotographerById, getInstitutionById } = useData(); const [view, setView] = useState<'list' | 'create' | 'edit' | 'details'>(initialView); const [searchTerm, setSearchTerm] = useState(''); const [selectedEvent, setSelectedEvent] = useState(null); @@ -244,11 +244,21 @@ export const Dashboard: React.FC = ({ initialView = 'list' }) =>
)} -
-
- Cover -
-

{selectedEvent.name}

+
+
+ Cover +
+
+

{selectedEvent.name}

+
+ + {selectedEvent.type} + + + {new Date(selectedEvent.date).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })} + +
+
@@ -279,35 +289,62 @@ export const Dashboard: React.FC = ({ initialView = 'list' }) => const institution = getInstitutionById(selectedEvent.institutionId); if (institution) { return ( -
-
-
- +
+
+
+
+
+ +
-

{institution.name}

-

{institution.type}

+

{institution.name}

+ + {institution.type} + -
-
-

Contato

-

{institution.phone}

-

{institution.email}

+
+
+
+
+ +
+
+

Contato

+

{institution.phone}

+
+
+
+
+ +
+
+

Email

+

{institution.email}

+
+
{institution.address && ( -
-

Endereço

-

{institution.address.street}, {institution.address.number}

-

{institution.address.city} - {institution.address.state}

+
+
+ +
+
+

Endereço

+

{institution.address.street}, {institution.address.number}

+

{institution.address.city} - {institution.address.state}

+
)}
{institution.description && ( -

- {institution.description} -

+
+

+ {institution.description} +

+
)}
@@ -317,20 +354,40 @@ export const Dashboard: React.FC = ({ initialView = 'list' }) => return null; })()} -
-

Sobre o Evento

-

{selectedEvent.briefing || "Sem briefing detalhado."}

+
+
+
+ +
+

Sobre o Evento

+
+

{selectedEvent.briefing || "Sem briefing detalhado."}

{selectedEvent.contacts.length > 0 && (
-

Contatos & Responsáveis

+
+
+ +
+

Contatos & Responsáveis

+
{selectedEvent.contacts.map((c, i) => ( -
-

{c.name}

-

{c.role}

-

{c.phone}

+
+
+
+ {c.name.charAt(0).toUpperCase()} +
+
+

{c.name}

+ {c.role} +
+ +

{c.phone}

+
+
+
))}
@@ -339,48 +396,96 @@ export const Dashboard: React.FC = ({ initialView = 'list' }) =>
-
-

Status Atual

-

{selectedEvent.status}

+
+
+
+
+
+ +
+

Status Atual

+
+ + {selectedEvent.status} + +
-
-

Localização

-

{selectedEvent.address.street}, {selectedEvent.address.number}

-

{selectedEvent.address.city} - {selectedEvent.address.state}

+
+
+
+ +
+

Localização

+
+

{selectedEvent.address.street}, {selectedEvent.address.number}

+

{selectedEvent.address.city} - {selectedEvent.address.state}

{selectedEvent.address.mapLink ? ( - + ) : ( - + )} -
{(selectedEvent.photographerIds.length > 0 || user.role === UserRole.BUSINESS_OWNER) && ( -
-
-

Equipe Designada

+
+
+
+
+ +
+

Equipe Designada

+
{(user.role === UserRole.BUSINESS_OWNER || user.role === UserRole.SUPERADMIN) && ( - + )}
{selectedEvent.photographerIds.length > 0 ? ( -
- {selectedEvent.photographerIds.map((id, idx) => ( -
- ))} +
+ {selectedEvent.photographerIds.map((id) => { + const photographer = getPhotographerById(id); + return ( +
+
+ {photographer?.name +
+
+
+

+ {photographer?.name || 'Fotógrafo'} +

+

Fotógrafo

+
+
+ ); + })}
) : ( -

Nenhum profissional atribuído.

+

Nenhum profissional atribuído

)}
)} @@ -391,6 +496,32 @@ export const Dashboard: React.FC = ({ initialView = 'list' }) =>
)}
+ +
); }; diff --git a/pages/Home.tsx b/pages/Home.tsx index 3d18556..a24321e 100644 --- a/pages/Home.tsx +++ b/pages/Home.tsx @@ -156,20 +156,20 @@ export const Home: React.FC = ({ onEnter }) => {

Envie sua mensagem, ligue ou faça uma visita em nossa empresa!

-
- {/* Left side - Contact Info */} -
+
+ {/* Left side - Location Info */} +
-
-
- +
+
+
-

Rua Bom Recreio, 305

-

Jd. Boer II • Americana SP

-

CEP 13477-720

+

Rua Bom Recreio, 305

+

Jd. Boer II • Americana SP

+

CEP 13477-720

= ({ onEnter }) => {
{/* Mini Map */} -
+