photum/contexts/DataContext.tsx
João Vitor d087cefb1b feat: Integração completa Mapbox + Upload de avatares
- 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
2025-12-02 13:55:56 -03:00

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;
};