import React, { useEffect, useState, useCallback } from "react"; import { api } from "../api/client"; import { PageHeader } from "../components/PageHeader"; import { Table } from "../components/Table"; import { Modal } from "../components/Modal"; import { FormField, Btn } from "../components/FormField"; // ─── Types ────────────────────────────────────────────────────────────────── interface Vendor { id: string; name: string; } interface EventTaxOverride { id: string; taxId: string; rate: number; tax: { name: string; rate: number }; } interface EventProductItem { id: string; productId: string; product: { id: string; name: string; price: number; sku?: string }; } interface Event { id: string; name: string; description?: string; startsAt: string; endsAt: string; isActive: boolean; vendorId: string; vendor?: Vendor; taxOverrides?: EventTaxOverride[]; products?: EventProductItem[]; _count?: { products: number; taxOverrides: number; transactions: number }; } interface Tax { id: string; name: string; rate: number; } interface Product { id: string; name: string; price: number; sku?: string; } interface ApiList { data: T[]; pagination: { total: number } } interface EventSummary { event: { id: string; name: string; startsAt: string; endsAt: string }; totals: { revenue: number; tax: number; discounts: number; transactionCount: number; averageTransaction: number }; byPaymentMethod: { method: string; revenue: number; count: number }[]; topProducts: { productId: string; productName: string; revenue: number; unitsSold: number }[]; } // ─── Main Page ────────────────────────────────────────────────────────────── export default function EventsPage() { const [events, setEvents] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [editing, setEditing] = useState(null); const [detail, setDetail] = useState(null); const [detailView, setDetailView] = useState<"config" | "report">("config"); const load = useCallback(async () => { setLoading(true); try { const res = await api.get>("/events?limit=50"); setEvents(res.data); setTotal(res.pagination.total); } catch (err) { console.error(err); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, [load]); const openDetail = async (ev: Event) => { try { const full = await api.get(`/events/${ev.id}`); setDetail(full); setDetailView("config"); } catch (err) { console.error(err); } }; const handleDelete = async (id: string) => { if (!confirm("Delete this event? This cannot be undone.")) return; await api.delete(`/events/${id}`); load(); }; const columns = [ { key: "name", header: "Name", render: (ev: Event) => ev.name }, { key: "dates", header: "Dates", render: (ev: Event) => `${fmtDate(ev.startsAt)} → ${fmtDate(ev.endsAt)}` }, { key: "vendor", header: "Vendor", render: (ev: Event) => ev.vendor?.name ?? ev.vendorId }, { key: "status", header: "Status", render: (ev: Event) => ( {ev.isActive ? "Active" : "Inactive"} ) }, { key: "counts", header: "Products / Taxes / Txns", render: (ev: Event) => `${ev._count?.products ?? 0} / ${ev._count?.taxOverrides ?? 0} / ${ev._count?.transactions ?? 0}` }, { key: "actions", header: "", render: (ev: Event) => (
openDetail(ev)}>View { setEditing(ev); setShowForm(true); }}>Edit handleDelete(ev.id)}>Delete
) }, ]; return (
{ setEditing(null); setShowForm(true); }}>+ New Event} /> {showForm && ( setShowForm(false)} onSaved={() => { setShowForm(false); load(); }} /> )} {detail && ( setDetail(null)} onRefresh={() => openDetail(detail)} /> )} ); } // ─── Event Form Modal ──────────────────────────────────────────────────────── function EventFormModal({ event, onClose, onSaved }: { event: Event | null; onClose: () => void; onSaved: () => void; }) { const [name, setName] = useState(event?.name ?? ""); const [description, setDescription] = useState(event?.description ?? ""); const [startsAt, setStartsAt] = useState(event ? toDatetimeLocal(event.startsAt) : ""); const [endsAt, setEndsAt] = useState(event ? toDatetimeLocal(event.endsAt) : ""); const [isActive, setIsActive] = useState(event?.isActive ?? true); const [error, setError] = useState(""); const [saving, setSaving] = useState(false); const save = async () => { setSaving(true); setError(""); try { const body = { name, description: description || undefined, startsAt: new Date(startsAt).toISOString(), endsAt: new Date(endsAt).toISOString(), isActive, }; if (event) { await api.put(`/events/${event.id}`, body); } else { await api.post("/events", body); } onSaved(); } catch (err) { setError(err instanceof Error ? err.message : "Save failed"); } finally { setSaving(false); } }; return ( setName(e.target.value)} />