import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import Layout from '../../components/Layout'; import { supabase } from '../../lib/supabase'; import { generateSubcontractorPOPDF } from '../../lib/invoice'; import { blobToEmailAttachment, sendEmail } from '../../lib/email'; const statusColor = { draft: 'not_started', submitted: 'in_progress', paid: 'client_approved' }; export default function SubInvoiceDetail() { const { id } = useParams(); const navigate = useNavigate(); const [invoice, setInvoice] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [generating, setGenerating] = useState(false); useEffect(() => { supabase .from('subcontractor_invoices') .select('*, profile:profiles!subcontractor_invoices_profile_id_fkey(id, name, email), items:subcontractor_invoice_items(*)') .eq('id', id) .single() .then(({ data }) => { setInvoice(data); setLoading(false); }); }, [id]); const total = (invoice?.items || []).reduce((s, i) => s + Number(i.unit_price || 0) * Number(i.quantity || 1), 0); const buildPDFArgs = (inv) => ({ po_number: inv.invoice_number, status: 'paid', profile: inv.profile, project: { name: 'Subcontractor Invoice', company: { name: 'Fourge Branding' } }, date: inv.created_at?.split('T')[0], due_date: (inv.paid_at || new Date().toISOString()).split('T')[0], amount: total, description: 'Payment for completed subcontractor work.', notes: inv.notes, items: (inv.items || []).map((item, idx) => ({ description: item.description, amount: Number(item.unit_price) * Number(item.quantity || 1), sort_order: item.sort_order ?? idx, })), }); const handleMarkPaid = async () => { setSaving(true); try { const paidAt = new Date().toISOString(); const { error } = await supabase.from('subcontractor_invoices').update({ status: 'paid', paid_at: paidAt }).eq('id', id); if (error) throw error; const updated = { ...invoice, status: 'paid', paid_at: paidAt }; setInvoice(updated); let pdfBlob = null; try { pdfBlob = await generateSubcontractorPOPDF(buildPDFArgs(updated), { output: 'blob' }); } catch {} if (invoice.profile?.email) { try { const attachments = pdfBlob ? [await blobToEmailAttachment(pdfBlob, `${invoice.invoice_number}-receipt.pdf`)] : []; await sendEmail('receipt_sent', invoice.profile.email, { invoiceNumber: invoice.invoice_number, billTo: invoice.profile.name || invoice.profile.email, total: total.toFixed(2), paidDate: new Date(paidAt).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }), }, attachments); } catch (emailErr) { alert(`Marked paid, but email failed: ${emailErr.message || 'unknown error'}`); } } } catch (err) { alert(`Failed to mark as paid: ${err.message}`); } setSaving(false); }; const handleReceipt = async () => { setGenerating(true); try { await generateSubcontractorPOPDF(buildPDFArgs(invoice)); } catch (err) { alert(err.message); } setGenerating(false); }; const handleDelete = async () => { if (!window.confirm(`Delete invoice ${invoice.invoice_number}? This cannot be undone.`)) return; setSaving(true); const { error } = await supabase.from('subcontractor_invoices').delete().eq('id', id); if (error) { alert('Failed to delete: ' + error.message); setSaving(false); return; } navigate('/invoices', { state: { tab: 'sub-invoices' } }); }; if (loading) return

Loading...

; if (!invoice) return

Invoice not found.

; const sortedItems = [...(invoice.items || [])].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0)); return (
{invoice.invoice_number}
{invoice.profile?.name || 'External'} · {invoice.profile?.email || '—'}
{invoice.status}
Invoice Info

{invoice.invoice_number}

{invoice.status}

{invoice.submitted_at ? new Date(invoice.submitted_at).toLocaleDateString() : '—'}

{invoice.paid_at && (

{new Date(invoice.paid_at).toLocaleDateString()}

)}
Summary

{sortedItems.length}

${total.toFixed(2)}

Line Items
{sortedItems.length === 0 ? (

No line items.

) : (
{sortedItems.map(item => ( ))}
Description Qty Unit Price Amount
{item.description} {item.quantity} ${Number(item.unit_price).toFixed(2)} ${(Number(item.unit_price) * Number(item.quantity || 1)).toFixed(2)}
Total ${total.toFixed(2)}
)} {invoice.notes && (
Notes

{invoice.notes}

)}
Actions
{invoice.status === 'submitted' && ( )} {invoice.status === 'paid' && ( )}
); }