"use client"; import { useActionState, useEffect, useMemo, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Select } from "@/components/ui/select"; import { Combobox } from "@/components/ui/combobox"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { Eye, Send, FileCheck2 } from "lucide-react"; import { bulkUpdateStatus, type ActionResult as DNActionResult } from "@/actions/delivery-notes"; import { sendStatement, type ActionResult } from "@/actions/statements"; import { toast } from "sonner"; import type { Customer, DeliveryNote } from "@/lib/types"; import { formatCurrency, formatDate, formatNumber } from "@/lib/utils"; const initial: ActionResult = { ok: false, error: "" }; interface Props { customers: Customer[]; preselectedCustomerId?: string; preselectedEmail?: string; fromEmail: string; ccEmail: string; } function rangeDates(range: string, customStart?: string, customEnd?: string) { const now = new Date(); if (range === "this-month") { return { start: new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10), end: new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString().slice(0, 10), }; } if (range === "last-month") { return { start: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString().slice(0, 10), end: new Date(now.getFullYear(), now.getMonth(), 0).toISOString().slice(0, 10), }; } if (customStart && customEnd) return { start: customStart, end: customEnd }; return { start: "", end: "" }; } export function SendStatementForm({ customers, preselectedCustomerId, preselectedEmail, fromEmail, ccEmail }: Props) { const router = useRouter(); const [customerId, setCustomerId] = useState(preselectedCustomerId || ""); const [range, setRange] = useState("this-month"); const [customStart, setCustomStart] = useState(""); const [customEnd, setCustomEnd] = useState(""); const [recipientEmail, setRecipientEmail] = useState(preselectedEmail || ""); const [includePricing, setIncludePricing] = useState(true); const [notes, setNotes] = useState([]); const [notesLoading, setNotesLoading] = useState(false); const [state, action, pending] = useActionState(sendStatement, initial); const [, startMarkTransition] = useTransition(); const customerMap = useMemo(() => new Map(customers.map((c) => [c.id, c])), [customers]); const customer = customerId ? customerMap.get(customerId) : null; // Auto-fill recipient from customer email useEffect(() => { if (customer?.email && !recipientEmail) { setRecipientEmail(customer.email); } }, [customer, recipientEmail]); // Fetch pending notes for the current selection useEffect(() => { if (!customerId) { setNotes([]); return; } const { start, end } = rangeDates(range, customStart, customEnd); if (!start || !end) return; setNotesLoading(true); fetch(`/api/notes-for-statement?customer=${customerId}&start=${start}&end=${end}`) .then((r) => r.json()) .then((d) => setNotes(d.notes || [])) .catch(() => setNotes([])) .finally(() => setNotesLoading(false)); }, [customerId, range, customStart, customEnd]); useEffect(() => { if (state.ok) { if (state.data === undefined) { toast.success("Statement sent"); router.refresh(); } } else if (state.error) { toast.error(state.error); } }, [state, router]); const previewUrl = customerId ? `/api/statements/preview?customer=${customerId}&range=${range}${range === "custom" ? `&start=${customStart}&end=${customEnd}` : ""}&include_pricing=${includePricing}` : ""; function onMarkInvoiced() { if (notes.length === 0) { toast.error("No notes to mark"); return; } startMarkTransition(async () => { const res = await bulkUpdateStatus(notes.map((n) => n.id), "Invoiced"); if (res.ok) { toast.success("Marked as Invoiced"); router.refresh(); } else { toast.error(res.error); } }); } const totalQty = notes.reduce((a, n) => a + (n.qty_litres_supplied || 0), 0); const totalValue = notes.reduce((a, n) => a + (n.total_value || 0), 0); return (
Statement details Choose a customer and date range, then preview or send.
({ value: c.id, label: c.name }))} placeholder="Search customers…" required />
setCustomStart(e.target.value)} />
setCustomEnd(e.target.value)} />
)}
setRecipientEmail(e.target.value)} required /> {ccEmail && (

CC: {ccEmail}

)}

If off, the statement will only list quantities (no prices).

From: {fromEmail || "(not configured)"}
Pending delivery notes {notesLoading ? "Loading…" : notes.length === 0 ? "No notes in this range" : `${notes.length} note${notes.length !== 1 ? "s" : ""} • ${formatNumber(totalQty)} L • ${formatCurrency(totalValue)}`} Note # Date Vehicle Qty (L) Total Status {notes.length === 0 && !notesLoading && ( No notes to include. )} {notes.map((n) => ( {n.number} {formatDate(n.date)} {n.vehicle_registration || "—"} {formatNumber(n.qty_litres_supplied)} {formatCurrency(n.total_value)} {n.status ? {n.status} : Pending} ))}
); }