'use client'; import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { api } from '@/lib/api'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell } from 'recharts'; const peso = (v: number) => '₱' + (v ?? 0).toLocaleString('en-PH', { minimumFractionDigits: 2 }); export default function ReportsPage() { const [from, setFrom] = useState(() => { const d = new Date(); d.setDate(1); return d.toISOString().split('T')[0]; }); const [to, setTo] = useState(() => new Date().toISOString().split('T')[0]); const { data: collection, isLoading: collLoading } = useQuery({ queryKey: ['reports', 'collection', from, to], queryFn: async () => { const res = await api.get(`/api/v1/reports/collection?from=${from}&to=${to}`); return res.data as Array<{ collector: string; totalAmount: number; paymentCount: number }>; }, }); const { data: aging, isLoading: agingLoading } = useQuery({ queryKey: ['reports', 'aging'], queryFn: async () => { const res = await api.get('/api/v1/reports/aging'); return res.data as Array<{ bucket: string; invoiceCount: number; totalAmount: number }>; }, }); const { data: subscribers, isLoading: subLoading } = useQuery({ queryKey: ['reports', 'subscribers'], queryFn: async () => { const res = await api.get('/api/v1/reports/subscribers'); return res.data as Array<{ plan: string; count: number; revenue: number }>; }, }); const { data: revenue, isLoading: revLoading } = useQuery({ queryKey: ['reports', 'revenue'], queryFn: async () => { const res = await api.get('/api/v1/reports/revenue'); return res.data as Array<{ month: string; total: number }>; }, }); return (

Reports

Financial and operational analytics

{/* Collection Report */} Collection Report
setFrom(e.target.value)} className="border rounded-md px-2 py-1 text-sm text-slate-700" /> to setTo(e.target.value)} className="border rounded-md px-2 py-1 text-sm text-slate-700" />
{collLoading ? ( ) : !collection?.length ? (

No collections in this period

) : ( {collection?.map((row, i) => ( ))}
Collector Payments Total
{row.collector} {row.paymentCount} {peso(row.totalAmount)}
Total {collection?.reduce((s, r) => s + r.paymentCount, 0)} {peso(collection?.reduce((s, r) => s + r.totalAmount, 0) ?? 0)}
)}
{/* Revenue Trend */} Revenue Trend (12 months) {revLoading ? : ( `₱${(v/1000).toFixed(0)}k`} /> peso(v)} /> )} {/* Aging */} Accounts Receivable Aging {agingLoading ? : (
{aging?.map((bucket) => (
{bucket.bucket}d
b.totalAmount) ?? [1])) || 1)) * 100)}%`, backgroundColor: bucket.bucket === '90+' ? '#DC2626' : bucket.bucket === '61-90' ? '#D97706' : '#0891B2', }} />
{peso(bucket.totalAmount)} {bucket.invoiceCount} inv
))} {!aging?.some(b => b.totalAmount > 0) && (

No overdue invoices 🎉

)}
)}
{/* Subscribers by Plan */} Subscribers by Plan {subLoading ? : ( {(subscribers as any[])?.map((row: any, i: number) => ( ))}
Plan Subscribers Monthly Revenue
{row.plan ?? row.name ?? '—'} {row.count ?? row.subscribers ?? 0} {peso(row.revenue ?? row.monthlyRevenue ?? 0)}
)}
); }