// Events / Calendar Module
function Events() {
const [view, setView] = React.useState('month');
const [events, setEvents] = React.useState([]);
const [loading, setLoading] = React.useState(true);
const [selectedEvent, setSelectedEvent] = React.useState(null);
const [addModal, setAddModal] = React.useState(false);
const [form, setForm] = React.useState({ name: '', client: '', type: 'Corporativo', date: '2026-04-22', time: '09:00', location: '', budget: '' });
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,
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 || '',
};
};
React.useEffect(() => {
sb.from('events').select('*').order('event_date').then(({ data, error }) => {
if (data) setEvents(data.map(mapRow));
setLoading(false);
});
}, []);
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_time: form.time,
duration: '1 dia',
color: '#3B82F6',
status: 'Planejamento',
team: [],
budget: parseFloat(form.budget) || 0,
location: form.location,
}).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: 'Corporativo', date: '2026-04-22', time: '09:00', location: '', budget: '' });
};
const checklist = [
{ label: 'Confirmação do espaço', done: true },
{ label: 'Contratação de equipe técnica', done: true },
{ label: 'Briefing aprovado pelo cliente', done: true },
{ label: 'Decoração definida', done: false },
{ label: 'Sonorização contratada', done: false },
{ label: 'Transporte da equipe confirmado', done: false },
{ label: 'Montagem agendada', done: false },
];
const [checks, setChecks] = React.useState(checklist);
const typeColor = { 'Corporativo': '#3B82F6', 'Casamento': '#8B5CF6', 'Social': '#10B981', 'Institucional': '#F59E0B' };
const statusVariant = { 'Confirmado': 'success', 'Planejamento': 'warning', 'Orçamento': 'default', 'Em andamento': 'primary' };
const daysInMonth = 30;
const startDay = 3;
const today = 22;
const getEventsForDay = (day) => events.filter(e => e.day === day && e.month === 4);
const MonthView = () => (
{['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'].map(d => (
{d}
))}
{Array.from({ length: startDay }).map((_, i) => (
))}
{Array.from({ length: daysInMonth }).map((_, i) => {
const day = i + 1;
const dayEvents = getEventsForDay(day);
const isToday = day === today;
return (
{day}
{dayEvents.map(ev => (
setSelectedEvent(ev)}
style={{ background: ev.color, color: '#fff', borderRadius: 4, padding: '2px 6px', fontSize: 10, fontWeight: 600, marginBottom: 2, cursor: 'pointer', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>
{ev.time} {ev.name}
))}
);
})}
);
const ListView = () => (
{events.sort((a, b) => a.day - b.day).map(ev => (
setSelectedEvent(ev)} style={{ padding: '16px 20px' }}>
{ev.name}
{ev.client} · {ev.location}
{ev.type}
{ev.status}
R$ {ev.budget.toLocaleString('pt-BR')}
))}
);
return (
Agenda de Eventos
Abril 2026 · {events.length} eventos programados
{[['month', 'Mensal'], ['week', 'Semanal'], ['list', 'Lista']].map(([v, l]) => (
))}
setAddModal(true)}>Novo evento
{loading ? : (
<>
{(view === 'month' || view === 'week') && }
{view === 'list' &&
}
>
)}
{/* Event detail modal */}
setSelectedEvent(null)} title={selectedEvent?.name || ''} width={600}>
{selectedEvent && (
{[
{ label: 'Cliente', value: selectedEvent.client },
{ label: 'Data e hora', value: `${selectedEvent.day} Abr · ${selectedEvent.time}` },
{ label: 'Tipo', value: selectedEvent.type },
{ label: 'Local', value: selectedEvent.location },
{ label: 'Duração', value: selectedEvent.duration },
{ label: 'Status', value: selectedEvent.status },
].map(({ label, value }) => (
))}
Equipe vinculada
{selectedEvent.team.length > 0 ? (
{selectedEvent.team.map(name => (
))}
) :
Nenhuma equipe vinculada ainda}
Checklist
{checks.map((c, i) => (
setChecks(ch => ch.map((item, idx) => idx === i ? { ...item, done: !item.done } : item))}
style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', borderRadius: DS.radius.sm, cursor: 'pointer', background: c.done ? DS.colors.successLight : '#F8FAFC', transition: 'background 0.15s' }}>
{c.done && }
{c.label}
))}
showToast('Indo para tarefas...')}>Ver tarefas
Editar evento
)}
{/* Add event modal */}
setAddModal(false)} title="Novo Evento">
setForm(f => ({ ...f, name: v }))} placeholder="Ex: Congresso Tech 2027" />
setForm(f => ({ ...f, client: v }))} placeholder="Ex: TechCorp Brasil" />
setForm(f => ({ ...f, date: v }))} type="date" />
setForm(f => ({ ...f, budget: v }))} placeholder="Ex: 50000" type="number" />
setForm(f => ({ ...f, location: v }))} placeholder="Ex: Centro de Convenções SP" />
setAddModal(false)}>Cancelar
Criar evento
{toast &&
setToast(null)} />}
);
}
Object.assign(window, { Events });