"use client"; import { useState, useCallback } from "react"; import { formatDate } from "@/lib/date-utils"; import { exportTaxReport, exportTaxByState, type TaxOrderRow, type TaxByStateRow, } from "@/lib/reports-export"; import { AdminButton, AdminFilterTabs } from "@/components/admin/design-system"; type DatePreset = "month" | "quarter" | "this_year" | "custom"; type DateRange = { start: string; end: string }; function buildRange(preset: DatePreset, customStart?: string, customEnd?: string): DateRange { const now = new Date(); const toDateStr = (d: Date) => d.toISOString().slice(0, 10); const today = toDateStr(now); switch (preset) { case "month": { const start = new Date(now.getFullYear(), now.getMonth(), 1); return { start: toDateStr(start), end: today }; } case "quarter": { const q = Math.floor(now.getMonth() / 3); const start = new Date(now.getFullYear(), q * 3, 1); return { start: toDateStr(start), end: today }; } case "this_year": { const start = new Date(now.getFullYear(), 0, 1); return { start: toDateStr(start), end: today }; } case "custom": return { start: customStart ?? today, end: customEnd ?? today }; } } function quarterLabel(start: string, end: string): string { const s = new Date(start + "T00:00:00"); const q = Math.floor(s.getMonth() / 3) + 1; return `Q${q} ${s.getFullYear()}`; } type TaxSummaryData = { total_tax_collected: number; total_gross_sales: number; order_count: number; tax_by_state: Array<{ state: string; total_tax: number; gross_sales: number; order_count: number; }>; }; function SummaryCard({ label, value, prefix, suffix, highlight, }: { label: string; value: number; prefix?: string; suffix?: string; highlight?: boolean; }) { return (

{label}

{prefix ?? ""}{typeof value === "number" ? value.toLocaleString(undefined, { maximumFractionDigits: 2 }) : value}{suffix ?? ""}

); } function ExportBtn({ label, onClick }: { label: string; onClick: () => void }) { return ( Export CSV ); } function ReportTable({ headers, rows, renderRow }: { headers: string[]; rows: unknown[]; renderRow: (row: unknown, i: number) => React.ReactNode; }) { return (
{headers.map((h) => ( ))} {rows.length === 0 ? ( ) : ( rows.map((_, i) => renderRow(_, i)) )}
{h}
No data
); } const TABS = [ { value: "summary", label: "Tax Summary" }, { value: "orders", label: "Taxable Orders" }, ]; export default function TaxDashboard({ brands, initialBrandId, isPlatformAdmin, }: { brands: { id: string; name: string }[]; initialBrandId: string | null; isPlatformAdmin: boolean; }) { const [preset, setPreset] = useState("quarter"); const [customStart, setCustomStart] = useState(""); const [customEnd, setCustomEnd] = useState(""); const [selectedBrandId, setSelectedBrandId] = useState(initialBrandId ?? ""); const [activeTab, setActiveTab] = useState("summary"); const [summary, setSummary] = useState(null); const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const range: DateRange = buildRange(preset, customStart, customEnd); const fetchTaxSummary = useCallback(async () => { if (!selectedBrandId) return; setLoading(true); setError(null); try { const res = await fetch( `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/rpc/get_tax_summary`, { method: "POST", headers: { "Content-Type": "application/json", apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, }, body: JSON.stringify({ p_brand_id: selectedBrandId, p_start_date: range.start, p_end_date: range.end, }), } ); if (!res.ok) throw new Error(await res.text()); const data = await res.json(); setSummary({ total_tax_collected: Number(data?.total_tax_collected ?? 0), total_gross_sales: Number(data?.total_gross_sales ?? 0), order_count: Number(data?.order_count ?? 0), tax_by_state: data?.tax_by_state ?? [], }); } catch (err) { setError(err instanceof Error ? err.message : "Failed to load tax summary"); } finally { setLoading(false); } }, [selectedBrandId, range]); const fetchTaxableOrders = useCallback(async () => { if (!selectedBrandId) return; setLoading(true); setError(null); try { const res = await fetch( `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/rpc/get_taxable_orders`, { method: "POST", headers: { "Content-Type": "application/json", apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, }, body: JSON.stringify({ p_brand_id: selectedBrandId, p_start_date: range.start, p_end_date: range.end, }), } ); if (!res.ok) throw new Error(await res.text()); const data = await res.json(); setOrders( (data ?? []).map((row: Record) => ({ order_id: String(row.order_id ?? ""), date: String(row.date ?? ""), customer_name: String(row.customer_name ?? ""), city: String(row.city ?? ""), state: String(row.state ?? ""), taxable_amount: Number(row.taxable_amount ?? 0), tax_amount: Number(row.tax_amount ?? 0), tax_rate: Number(row.tax_rate ?? 0), tax_location: String(row.tax_location ?? ""), })) ); } catch (err) { setError(err instanceof Error ? err.message : "Failed to load orders"); } finally { setLoading(false); } }, [selectedBrandId, range]); function handleFetch() { if (activeTab === "summary") fetchTaxSummary(); else fetchTaxableOrders(); } // Auto-fetch when tab/brand/range changes if (summary === null && activeTab === "summary" && selectedBrandId && !loading) { fetchTaxSummary(); } if (orders.length === 0 && activeTab === "orders" && selectedBrandId && !loading) { fetchTaxableOrders(); } function handleExportCSV() { if (activeTab === "summary" && summary) { const rows: TaxByStateRow[] = summary.tax_by_state.map((s) => ({ state: s.state, total_tax: s.total_tax, gross_sales: s.gross_sales, order_count: s.order_count, })); const csv = exportTaxByState(rows); downloadCSV(csv, `tax-by-state-${range.start}.csv`); } else if (activeTab === "orders" && orders.length > 0) { const csv = exportTaxReport(orders); downloadCSV(csv, `taxable-orders-${range.start}.csv`); } } function downloadCSV(csv: string, filename: string) { const blob = new Blob([csv], { type: "text/csv" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } const effectiveRate = summary && summary.total_gross_sales > 0 ? (summary.total_tax_collected / summary.total_gross_sales) * 100 : 0; return (
{error && (
{error}
)} {/* ── Filters ── */}
{(["month", "quarter", "this_year", "custom"] as DatePreset[]).map((p) => ( setPreset(p)} variant={preset === p ? "primary" : "secondary"} size="sm" > {p === "month" ? "This Month" : p === "quarter" ? "This Quarter" : p === "this_year" ? "This Year" : "Custom"} ))}
{preset === "custom" && (
setCustomStart(e.target.value)} className="rounded-lg border border-zinc-600 px-3 py-1.5 text-xs" /> to setCustomEnd(e.target.value)} className="rounded-lg border border-zinc-600 px-3 py-1.5 text-xs" />
)} {isPlatformAdmin && ( )} Refresh {preset === "quarter" ? quarterLabel(range.start, range.end) : preset === "this_year" ? `${new Date().getFullYear()} YTD` : `${range.start} → ${range.end}`}
{/* ── Tab bar ── */} {/* ── TAX SUMMARY TAB ── */} {activeTab === "summary" && (
{summary && ( <>

Tax by State

{summary.tax_by_state.length > 0 && ( )}
{ const r = row as { state: string; total_tax: number; gross_sales: number; order_count: number }; const rate = r.gross_sales > 0 ? (r.total_tax / r.gross_sales) * 100 : 0; return ( {r.state} ${r.total_tax.toFixed(2)} ${r.gross_sales.toFixed(2)} {r.order_count} {rate.toFixed(2)}% ); }} /> )} {!summary && !loading && (
Click Refresh to load tax summary
)}
)} {/* ── TAXABLE ORDERS TAB ── */} {activeTab === "orders" && (

Taxable Orders

{orders.length > 0 && ( )}
{ const r = row as TaxOrderRow; return ( {r.order_id.slice(0, 8)} {r.date} {r.customer_name} {r.city} {r.state} ${Number(r.taxable_amount).toFixed(2)} ${Number(r.tax_amount).toFixed(2)} {Number(r.tax_rate).toFixed(4)} {r.tax_location} ); }} />
)}
); }