// Events / Calendar Module function Events({ onNavigate }) { const [view, setView] = React.useState('month'); const [events, setEvents] = React.useState([]); const [appUsers, setAppUsers] = React.useState([]); const [reportModal, setReportModal] = React.useState(null); // { event, type } const [loading, setLoading] = React.useState(true); const [selectedEvent, setSelectedEvent] = React.useState(null); const [addModal, setAddModal] = React.useState(false); const [editEventModal, setEditEventModal] = React.useState(false); const [editEventForm, setEditEventForm] = React.useState({ name: '', client: '', type: 'Inauguração', location: '', date: '', date_end: '', time: '09:00', vendedor_id: '', responsavel_producao_id: '' }); const [savingEvent, setSavingEvent] = React.useState(false); const [form, setForm] = React.useState({ name: '', client: '', type: 'Inauguração', date: '2026-04-22', date_end: '', time: '09:00', location: '', vendedor_id: '', responsavel_producao_id: '' }); const [toast, setToast] = React.useState(null); const showToast = (msg, type = 'success') => { setToast({ msg, type }); setTimeout(() => setToast(null), 3000); }; const mapRow = (row) => { const d = row.event_date ? new Date(row.event_date + 'T00:00:00') : null; return { id: row.id, name: row.name, client: row.client_name, type: row.type, day: d ? d.getDate() : 1, month: d ? d.getMonth() + 1 : 1, year: d ? d.getFullYear() : new Date().getFullYear(), date_iso: row.event_date || '', date_end_iso: row.event_end_date || '', time: row.event_time || '', duration: row.duration || '', color: row.color || '#3B82F6', status: row.status || 'Planejamento', team: row.team || [], budget: row.budget || 0, location: row.location || '', vendedor_id: row.vendedor_id || '', responsavel_producao_id: row.responsavel_producao_id || '', }; }; React.useEffect(() => { sb.from('events').select('*').order('event_date').then(({ data, error }) => { if (data) setEvents(data.map(mapRow)); setLoading(false); }); Promise.all([ sb.from('app_users').select('id, name, email, role').order('name'), sb.auth.getUser(), ]).then(([listRes, authRes]) => { const list = listRes.data || []; const cu = authRes.data?.user; if (cu && !list.some(u => u.id === cu.id)) { list.unshift({ id: cu.id, name: cu.user_metadata?.name || (cu.email ? cu.email.split('@')[0] : 'Eu'), email: cu.email || '', role: 'admin', }); } setAppUsers(list); }); }, []); const userName = (id) => { const u = appUsers.find(x => x.id === id); return u ? (u.name || u.email) : '—'; }; const userOptions = [{ value: '', label: '— Selecionar —' }, ...appUsers.map(u => ({ value: u.id, label: u.name || u.email }))]; const addEvent = async () => { if (!form.name.trim()) return; const { data, error } = await sb.from('events').insert({ name: form.name, client_name: form.client, type: form.type, event_date: form.date, event_end_date: form.date_end || null, event_time: form.time, duration: '1 dia', color: '#3B82F6', status: 'Planejamento', team: [], location: form.location, vendedor_id: form.vendedor_id || null, responsavel_producao_id: form.responsavel_producao_id || null, }).select().single(); if (data) { setEvents(prev => [...prev, mapRow(data)]); showToast('Evento criado com sucesso!'); } else { showToast('Erro ao criar evento', 'danger'); } setAddModal(false); setForm({ name: '', client: '', type: 'Inauguração', date: '2026-04-22', date_end: '', time: '09:00', location: '', vendedor_id: '', responsavel_producao_id: '' }); }; const openEditEvent = () => { if (!selectedEvent) return; setEditEventForm({ name: selectedEvent.name || '', client: selectedEvent.client || '', type: selectedEvent.type || 'Inauguração', location: selectedEvent.location || '', date: selectedEvent.date_iso || '', date_end: selectedEvent.date_end_iso || '', time: selectedEvent.time || '09:00', vendedor_id: selectedEvent.vendedor_id || '', responsavel_producao_id: selectedEvent.responsavel_producao_id || '', }); setEditEventModal(true); }; const handleEditEvent = async () => { if (!editEventForm.name.trim()) { showToast('Preencha o nome do evento.', 'danger'); return; } setSavingEvent(true); const { data, error } = await sb.from('events').update({ name: editEventForm.name, client_name: editEventForm.client, type: editEventForm.type, location: editEventForm.location, event_date: editEventForm.date || selectedEvent.date_iso, event_end_date: editEventForm.date_end || null, event_time: editEventForm.time || selectedEvent.time, vendedor_id: editEventForm.vendedor_id || null, responsavel_producao_id: editEventForm.responsavel_producao_id || null, }).eq('id', selectedEvent.id).select().single(); setSavingEvent(false); if (error) { showToast('Erro ao salvar evento.', 'danger'); return; } const updated = mapRow(data); setEvents(prev => prev.map(e => e.id === updated.id ? updated : e)); setSelectedEvent(updated); setEditEventModal(false); showToast('Evento atualizado!'); }; const handleCancelEvent = async () => { if (!selectedEvent) return; const isCancelled = selectedEvent.status === 'Cancelado'; const newStatus = isCancelled ? 'Planejamento' : 'Cancelado'; const msg = isCancelled ? 'Reativar este evento? Ele voltará para o status "Planejamento".' : 'Cancelar este evento? O registro será mantido no histórico.'; if (!window.confirm(msg)) return; setSavingEvent(true); const { data, error } = await sb.from('events').update({ status: newStatus }).eq('id', selectedEvent.id).select().single(); setSavingEvent(false); if (error) { showToast('Erro ao atualizar evento.', 'danger'); return; } const updated = mapRow(data); setEvents(prev => prev.map(e => e.id === updated.id ? updated : e)); setSelectedEvent(updated); showToast(isCancelled ? 'Evento reativado!' : 'Evento cancelado.'); }; const checklist = [ { label: 'Aprovação de Orçamento', done: false }, { label: 'Conferir Produção', done: false }, { label: 'Ação Definida', done: false }, { label: 'Equipe Contratada', done: false }, { label: 'Equip. Separados e Revisados', done: false }, { label: 'Montagem Agendada', done: false }, ]; const [checks, setChecks] = React.useState(checklist); const EVENT_TYPES = [ { value: 'Inauguração', label: 'Inauguração' }, { value: 'Ativação de Marca', label: 'Ativação de Marca' }, { value: 'Ação Promocional', label: 'Ação Promocional' }, { value: 'Panfletagem', label: 'Panfletagem' }, { value: 'Sampling', label: 'Sampling' }, { value: 'Confraternização', label: 'Confraternização' }, { value: 'Corporativo', label: 'Corporativo' }, { value: 'Outro', label: 'Outro' }, ]; const typeColor = { 'Inauguração': '#3B82F6', 'Ativação de Marca': '#8B5CF6', 'Ação Promocional': '#10B981', 'Panfletagem': '#F59E0B', 'Sampling': '#EF4444', 'Confraternização': '#EC4899', 'Corporativo': '#3B82F6', 'Outro': '#64748B' }; const statusVariant = { 'Confirmado': 'success', 'Planejamento': 'warning', 'Orçamento': 'default', 'Em andamento': 'primary', 'Cancelado': 'danger' }; const MONTH_NAMES = ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro']; const MONTH_SHORT = ['JAN', 'FEV', 'MAR', 'ABR', 'MAI', 'JUN', 'JUL', 'AGO', 'SET', 'OUT', 'NOV', 'DEZ']; const [currentDate, setCurrentDate] = React.useState(() => { const d = new Date(); d.setDate(1); return d; }); const year = currentDate.getFullYear(); const month = currentDate.getMonth(); // 0-indexed const daysInMonth = new Date(year, month + 1, 0).getDate(); const startDay = new Date(year, month, 1).getDay(); const realToday = new Date(); const isCurrentMonth = realToday.getFullYear() === year && realToday.getMonth() === month; const today = isCurrentMonth ? realToday.getDate() : -1; const goToPrevMonth = () => setCurrentDate(new Date(year, month - 1, 1)); const goToNextMonth = () => setCurrentDate(new Date(year, month + 1, 1)); const goToToday = () => { const d = new Date(); d.setDate(1); setCurrentDate(d); }; const eventsThisMonth = events.filter(e => e.month === month + 1 && e.year === year); const getEventsForDay = (day) => eventsThisMonth.filter(e => e.day === day); const MonthView = () => (
{MONTH_NAMES[month]} {year} · {eventsThisMonth.length} eventos programados