'use client'; import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Search } from 'lucide-react'; import { api } from '@/lib/api'; import { useDebounce } from '@/lib/hooks'; import { format } from 'date-fns'; interface Invoice { id: string; invoiceNumber: string; status: string; subtotal: number; lateFee: number; total: number; amountPaid: number; balance: number; dueDate: string; createdAt: string; client?: { firstName: string; lastName: string; accountNumber: string }; } const STATUS_COLORS: Record = { DRAFT: 'bg-gray-100 text-gray-600', SENT: 'bg-blue-100 text-blue-700', PARTIAL: 'bg-yellow-100 text-yellow-700', PAID: 'bg-emerald-100 text-emerald-700', OVERDUE: 'bg-red-100 text-red-700', VOID: 'bg-gray-100 text-gray-400', }; export default function InvoicesPage() { const [search, setSearch] = useState(''); const [status, setStatus] = useState(''); const [page, setPage] = useState(1); const debouncedSearch = useDebounce(search, 400); const limit = 20; const { data, isLoading } = useQuery({ queryKey: ['invoices', debouncedSearch, status, page], queryFn: async () => { const params = new URLSearchParams({ page: String(page), limit: String(limit) }); if (status) params.set('status', status); if (debouncedSearch) params.set('search', debouncedSearch); const res = await api.get(`/api/v1/invoices?${params}`); return res.data; }, }); const invoices: Invoice[] = Array.isArray(data) ? data : (data?.data ?? data?.items ?? []); const total = (data as any)?.meta?.total ?? (data as any)?.total ?? invoices.length; const STATUSES = ['', 'SENT', 'PARTIAL', 'PAID', 'OVERDUE', 'DRAFT', 'VOID']; return (

Invoices

Track billing and payment status

{/* Filters */}
{ setSearch(e.target.value); setPage(1); }} />
{STATUSES.map(s => ( ))}
Invoice # Client Status Total Balance Due Date {isLoading ? ( Array.from({ length: 8 }).map((_, i) => ( {Array.from({ length: 6 }).map((_, j) => ( ))} )) ) : invoices.length === 0 ? ( No invoices found ) : ( invoices.map((inv) => ( {inv.invoiceNumber} {inv.client ? `${inv.client.firstName} ${inv.client.lastName}` : '—'} {inv.client && #{inv.client.accountNumber}} {inv.status} ₱{Number(inv.total).toLocaleString()} 0 ? 'text-red-600 font-medium' : 'text-slate-400'}`}> {Number(inv.balance) > 0 ? `₱${Number(inv.balance).toLocaleString()}` : '—'} {format(new Date(inv.dueDate), 'MMM d, yyyy')} )) )}
); }