import React, { useState, useEffect } from "react"; import { EventType, EventStatus, Address } from "../types"; import { Input, Select } from "./Input"; import { Button } from "./Button"; import { MapPin, Upload, Plus, X, Check, FileText, ExternalLink, Search, CheckCircle, Building2, AlertCircle, } from "lucide-react"; import { searchMapboxLocation, MapboxResult, reverseGeocode, } from "../services/mapboxService"; import { useAuth } from "../contexts/AuthContext"; import { useData } from "../contexts/DataContext"; import { UserRole } from "../types"; import { InstitutionForm } from "./InstitutionForm"; import { MapboxMap } from "./MapboxMap"; interface EventFormProps { onCancel: () => void; onSubmit: (data: any) => void; initialData?: any; } export const EventForm: React.FC = ({ onCancel, onSubmit, initialData, }) => { const { user } = useAuth(); const { institutions, getInstitutionsByUserId, addInstitution, getActiveCoursesByInstitutionId, } = useData(); const [activeTab, setActiveTab] = useState< "details" | "location" | "briefing" | "files" >("details"); const [addressQuery, setAddressQuery] = useState(""); const [addressResults, setAddressResults] = useState([]); const [isSearching, setIsSearching] = useState(false); const [isGeocoding, setIsGeocoding] = useState(false); const [showToast, setShowToast] = useState(false); const [showInstitutionForm, setShowInstitutionForm] = useState(false); const [availableCourses, setAvailableCourses] = useState([]); // Get institutions based on user role // Business owners and admins see all institutions, clients see only their own const userInstitutions = user ? user.role === UserRole.BUSINESS_OWNER || user.role === UserRole.SUPERADMIN ? institutions : getInstitutionsByUserId(user.id) : []; // Default State or Initial Data const [formData, setFormData] = useState( initialData || { name: "", date: "", time: "", startTime: "", endTime: "", type: "", status: EventStatus.PLANNING, address: { street: "", number: "", city: "", state: "", zip: "", lat: -22.7394, lng: -47.3314, mapLink: "", } as Address, briefing: "", contacts: [{ name: "", role: "", phone: "" }], files: [] as File[], institutionId: "", attendees: "", courseId: "", } ); const isClientRequest = user?.role === UserRole.EVENT_OWNER; const formTitle = initialData ? "Editar Evento" : isClientRequest ? "Solicitar Orçamento/Evento" : "Cadastrar Novo Evento"; const submitLabel = initialData ? "Salvar Alterações" : isClientRequest ? "Enviar Solicitação" : "Criar Evento"; // Carregar cursos disponíveis quando instituição for selecionada useEffect(() => { if (formData.institutionId) { const courses = getActiveCoursesByInstitutionId(formData.institutionId); setAvailableCourses(courses); } else { setAvailableCourses([]); // Limpa o curso selecionado se a instituição mudar if (formData.courseId) { setFormData((prev: any) => ({ ...prev, courseId: "" })); } } }, [formData.institutionId, getActiveCoursesByInstitutionId]); // Address Autocomplete Logic using Mapbox useEffect(() => { const timer = setTimeout(async () => { if (addressQuery.length > 3) { setIsSearching(true); const results = await searchMapboxLocation(addressQuery); setAddressResults(results); setIsSearching(false); } else { setAddressResults([]); } }, 500); return () => clearTimeout(timer); }, [addressQuery]); const handleAddressSelect = (addr: MapboxResult) => { setFormData((prev: any) => ({ ...prev, address: { street: addr.street, number: addr.number, city: addr.city, state: addr.state, zip: addr.zip, lat: addr.lat, lng: addr.lng, mapLink: addr.mapLink, }, })); setAddressQuery(""); setAddressResults([]); }; const handleMapLocationChange = async (lat: number, lng: number) => { // Buscar endereço baseado nas coordenadas const addressData = await reverseGeocode(lat, lng); if (addressData) { setFormData((prev: any) => ({ ...prev, address: { street: addressData.street, number: addressData.number, city: addressData.city, state: addressData.state, zip: addressData.zip, lat: addressData.lat, lng: addressData.lng, mapLink: addressData.mapLink, }, })); } else { // Se não conseguir o endereço, atualiza apenas as coordenadas setFormData((prev: any) => ({ ...prev, address: { ...prev.address, lat, lng, mapLink: `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`, }, })); } }; // Geocoding quando o usuário digita o endereço manualmente const handleManualAddressChange = async () => { const { street, number, city, state } = formData.address; // Montar query de busca const query = `${street} ${number}, ${city}, ${state}`.trim(); if (query.length < 5) return; // Endereço muito curto setIsGeocoding(true); try { const results = await searchMapboxLocation(query); if (results.length > 0) { const firstResult = results[0]; setFormData((prev: any) => ({ ...prev, address: { ...prev.address, lat: firstResult.lat, lng: firstResult.lng, mapLink: firstResult.mapLink, }, })); } } catch (error) { console.error("Erro ao geocodificar endereço manual:", error); } finally { setIsGeocoding(false); } }; const addContact = () => { setFormData((prev: any) => ({ ...prev, contacts: [...prev.contacts, { name: "", role: "", phone: "" }], })); }; const removeContact = (index: number) => { const newContacts = [...formData.contacts]; newContacts.splice(index, 1); setFormData((prev: any) => ({ ...prev, contacts: newContacts })); }; const handleFileUpload = (e: React.ChangeEvent) => { if (e.target.files) { setFormData((prev: any) => ({ ...prev, files: [...prev.files, ...Array.from(e.target.files || [])], })); } }; const handleSubmit = () => { // Validate institution selection if (!formData.institutionId) { alert("Por favor, selecione uma instituição antes de continuar."); return; } // Validate course selection if (!formData.courseId) { alert("Por favor, selecione um curso/turma antes de continuar."); return; } // Show toast setShowToast(true); // Call original submit after small delay for visual effect or immediately setTimeout(() => { onSubmit(formData); }, 1000); }; const handleInstitutionSubmit = (institutionData: any) => { const newInstitution = { ...institutionData, id: `inst-${Date.now()}`, ownerId: user?.id || "", }; addInstitution(newInstitution); setFormData((prev) => ({ ...prev, institutionId: newInstitution.id })); setShowInstitutionForm(false); }; // Show institution form modal if (showInstitutionForm) { return (
setShowInstitutionForm(false)} onSubmit={handleInstitutionSubmit} userId={user?.id || ""} />
); } return (
{/* Success Toast */} {showToast && (

Sucesso!

As informações foram salvas.

)} {/* Form Header */}

{formTitle}

{isClientRequest ? "Preencha os detalhes do seu sonho. Nossa equipe analisará em breve." : "Preencha as informações técnicas do evento."}

{/* Step indicators - Hidden on mobile, shown on tablet+ */}
{["details", "location", "briefing", "files"].map((tab, idx) => (
{idx + 1}
))}
{/* Mobile Tabs - Horizontal */}
{[ { id: "details", label: "Detalhes", icon: "1" }, { id: "location", label: "Localização", icon: "2" }, { id: "briefing", label: isClientRequest ? "Desejos" : "Briefing", icon: "3", }, { id: "files", label: "Arquivos", icon: "4" }, ].map((item) => ( ))}
{/* Desktop Sidebar Navigation */}
{[ { id: "details", label: "Detalhes & Data" }, { id: "location", label: "Localização" }, { id: "briefing", label: isClientRequest ? "Seus Desejos" : "Briefing & Equipe", }, { id: "files", label: "Inspirações" }, ].map((item) => ( ))}
{/* Form Content */}
{activeTab === "details" && (
setFormData({ ...formData, name: e.target.value }) } /> setFormData({ ...formData, date: e.target.value }) } />
setFormData({ ...formData, startTime: e.target.value }) } required /> setFormData({ ...formData, endTime: e.target.value }) } required />
{ const value = e.target.value; // Permite apenas números if (value === "" || /^\d+$/.test(value)) { setFormData({ ...formData, attendees: value }); } }} type="text" inputMode="numeric" /> {/* Institution Selection - OBRIGATÓRIO */}
{userInstitutions.length === 0 ? (

Nenhuma universidade cadastrada

Você precisa cadastrar uma universidade antes de criar um evento. Trabalhamos exclusivamente com eventos fotográficos em universidades.

) : (
{formData.institutionId && (
Universidade selecionada com sucesso
)}
)}
{/* Course Selection - Condicional baseado na instituição */} {formData.institutionId && (
{availableCourses.length === 0 ? (

Nenhum curso cadastrado

Entre em contato com a administração para cadastrar os cursos/turmas disponíveis nesta universidade.

) : ( )}
)}
)} {activeTab === "location" && (
setAddressQuery(e.target.value)} />
{isSearching ? (
) : ( )}
{addressResults.length > 0 && (
    {addressResults.map((addr, idx) => (
  • handleAddressSelect(addr)} >

    {addr.description}

    {addr.city}, {addr.state}

    {addr.mapLink && ( Maps Maps )}
  • ))}
)}
{ setFormData({ ...formData, address: { ...formData.address, street: e.target.value, }, }); }} onBlur={handleManualAddressChange} placeholder="Digite o nome da rua" />
{ const value = e.target.value; setFormData({ ...formData, address: { ...formData.address, number: value }, }); }} onBlur={handleManualAddressChange} type="text" inputMode="numeric" />
{ setFormData({ ...formData, address: { ...formData.address, city: e.target.value }, }); }} onBlur={handleManualAddressChange} placeholder="Digite a cidade" /> { const value = e.target.value.toUpperCase().slice(0, 2); setFormData({ ...formData, address: { ...formData.address, state: value }, }); }} onBlur={handleManualAddressChange} placeholder="SP" maxLength={2} />
{/* Mapa Interativo */}
{formData.address.mapLink && (
Localização verificada via Mapbox Ver no mapa
)}
)} {activeTab === "briefing" && (
{formData.contacts.map((contact: any, idx: number) => (
{ const newContacts = [...formData.contacts]; newContacts[idx].name = e.target.value; setFormData({ ...formData, contacts: newContacts }); }} /> { const newContacts = [...formData.contacts]; newContacts[idx].role = e.target.value; setFormData({ ...formData, contacts: newContacts }); }} />
))}
)} {activeTab === "files" && (

{isClientRequest ? "Anexe referências visuais (Moodboard)" : "Anexe contratos e cronogramas"}

PDF, JPG, PNG (Max 10MB)

{formData.files.length > 0 && (

Arquivos Selecionados:

{formData.files.map((file: any, idx: number) => (

{file.name}

{(file.size / 1024).toFixed(1)} KB

))}
)}
)}
); };