- Integração Mapbox GL JS para seleção interativa de localização - Mapa arrastável com pin para localização exata - Geocoding e reverse geocoding automático - Busca de endereços com autocomplete - Campos editáveis que atualizam mapa automaticamente - Token configurado via variável de ambiente (.env.local) - Sistema de upload de fotos de fotógrafos - Upload via input de arquivo (substituiu URL) - Preview automático com FileReader API - Botão para remover foto selecionada - Placeholder com ícone de câmera - Remoção de funcionalidades de uploads/álbuns - Removida página Albums.tsx - Removido sistema de attachments - Removida aba Inspiração para empresas - Criada página Inspiração com galeria de exemplo - Melhorias de responsividade - Cards do mapa adaptados para mobile - Texto e padding reduzidos em telas pequenas - Arquivos de configuração - .env.example criado - vite-env.d.ts para tipagem - MAPBOX_SETUP.md com instruções - Footer atualizado com serviços universitários
163 lines
No EOL
4.8 KiB
TypeScript
163 lines
No EOL
4.8 KiB
TypeScript
|
|
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
import { EventData, EventStatus, EventType, Institution } from '../types';
|
|
|
|
// Initial Mock Data
|
|
const INITIAL_INSTITUTIONS: Institution[] = [
|
|
{
|
|
id: 'inst-1',
|
|
name: 'Universidade Federal do Rio Grande do Sul',
|
|
type: 'Universidade Pública',
|
|
phone: '(51) 3308-3333',
|
|
email: 'eventos@ufrgs.br',
|
|
address: {
|
|
street: 'Av. Paulo Gama',
|
|
number: '110',
|
|
city: 'Porto Alegre',
|
|
state: 'RS',
|
|
zip: '90040-060'
|
|
},
|
|
description: 'Campus Central - Principais eventos realizados no Salão de Atos',
|
|
ownerId: 'client-1'
|
|
}
|
|
];
|
|
|
|
const INITIAL_EVENTS: EventData[] = [
|
|
{
|
|
id: '1',
|
|
name: 'Casamento Juliana & Marcos',
|
|
date: '2024-10-15',
|
|
time: '16:00',
|
|
type: EventType.WEDDING,
|
|
status: EventStatus.CONFIRMED,
|
|
address: {
|
|
street: 'Av. das Hortênsias',
|
|
number: '1200',
|
|
city: 'Gramado',
|
|
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',
|
|
contacts: [{ id: 'c1', name: 'Cerimonial Silva', role: 'Cerimonialista', phone: '9999-9999', email: 'c@teste.com'}],
|
|
checklist: [],
|
|
ownerId: 'client-1',
|
|
photographerIds: ['photographer-1'],
|
|
institutionId: 'inst-1'
|
|
},
|
|
{
|
|
id: '2',
|
|
name: 'Conferência Tech Innovators',
|
|
date: '2024-11-05',
|
|
time: '08:00',
|
|
type: EventType.CORPORATE,
|
|
status: EventStatus.PENDING_APPROVAL,
|
|
address: {
|
|
street: 'Rua Olimpíadas',
|
|
number: '205',
|
|
city: 'São Paulo',
|
|
state: 'SP',
|
|
zip: '04551-000'
|
|
},
|
|
briefing: 'Cobrir palestras principais e networking no coffee break.',
|
|
coverImage: 'https://picsum.photos/id/3/800/400',
|
|
contacts: [],
|
|
checklist: [],
|
|
ownerId: 'client-2', // Other client
|
|
photographerIds: []
|
|
}
|
|
];
|
|
|
|
interface DataContextType {
|
|
events: EventData[];
|
|
institutions: Institution[];
|
|
addEvent: (event: EventData) => void;
|
|
updateEventStatus: (id: string, status: EventStatus) => void;
|
|
assignPhotographer: (eventId: string, photographerId: string) => void;
|
|
getEventsByRole: (userId: string, role: string) => EventData[];
|
|
addInstitution: (institution: Institution) => void;
|
|
updateInstitution: (id: string, institution: Partial<Institution>) => void;
|
|
getInstitutionsByUserId: (userId: string) => Institution[];
|
|
getInstitutionById: (id: string) => Institution | undefined;
|
|
}
|
|
|
|
const DataContext = createContext<DataContextType | undefined>(undefined);
|
|
|
|
export const DataProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
const [events, setEvents] = useState<EventData[]>(INITIAL_EVENTS);
|
|
const [institutions, setInstitutions] = useState<Institution[]>(INITIAL_INSTITUTIONS);
|
|
|
|
const addEvent = (event: EventData) => {
|
|
setEvents(prev => [event, ...prev]);
|
|
};
|
|
|
|
const updateEventStatus = (id: string, status: EventStatus) => {
|
|
setEvents(prev => prev.map(e => e.id === id ? { ...e, status } : e));
|
|
};
|
|
|
|
const assignPhotographer = (eventId: string, photographerId: string) => {
|
|
setEvents(prev => prev.map(e => {
|
|
if (e.id === eventId) {
|
|
const current = e.photographerIds || [];
|
|
if (!current.includes(photographerId)) {
|
|
return { ...e, photographerIds: [...current, photographerId] };
|
|
}
|
|
}
|
|
return e;
|
|
}));
|
|
};
|
|
|
|
const getEventsByRole = (userId: string, role: string) => {
|
|
if (role === 'SUPERADMIN' || role === 'BUSINESS_OWNER') {
|
|
return events;
|
|
}
|
|
if (role === 'EVENT_OWNER') {
|
|
return events.filter(e => e.ownerId === userId);
|
|
}
|
|
if (role === 'PHOTOGRAPHER') {
|
|
return events.filter(e => e.photographerIds.includes(userId));
|
|
}
|
|
return [];
|
|
};
|
|
|
|
const addInstitution = (institution: Institution) => {
|
|
setInstitutions(prev => [...prev, institution]);
|
|
};
|
|
|
|
const updateInstitution = (id: string, updatedData: Partial<Institution>) => {
|
|
setInstitutions(prev => prev.map(inst =>
|
|
inst.id === id ? { ...inst, ...updatedData } : inst
|
|
));
|
|
};
|
|
|
|
const getInstitutionsByUserId = (userId: string) => {
|
|
return institutions.filter(inst => inst.ownerId === userId);
|
|
};
|
|
|
|
const getInstitutionById = (id: string) => {
|
|
return institutions.find(inst => inst.id === id);
|
|
};
|
|
|
|
return (
|
|
<DataContext.Provider value={{
|
|
events,
|
|
institutions,
|
|
addEvent,
|
|
updateEventStatus,
|
|
assignPhotographer,
|
|
getEventsByRole,
|
|
addInstitution,
|
|
updateInstitution,
|
|
getInstitutionsByUserId,
|
|
getInstitutionById
|
|
}}>
|
|
{children}
|
|
</DataContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useData = () => {
|
|
const context = useContext(DataContext);
|
|
if (!context) throw new Error('useData must be used within a DataProvider');
|
|
return context;
|
|
}; |