"use client"; import { useQuery, useMutation } from "@tanstack/react-query"; import { useRouter } from "next/navigation"; import { Users, Wifi, FileText, DollarSign, Ticket, CheckSquare, TrendingUp, Database, RefreshCw } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card"; import { Button } from "@/components/ui/Button"; import { Badge } from "@/components/ui/Badge"; import { formatCurrency, formatDateTime } from "@/lib/utils"; import { toast } from "sonner"; import api from "@/lib/api"; import type { DashboardSummary, PaginatedResponse, Ticket as TicketType } from "@/types"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, } from "recharts"; interface KpiCardProps { title: string; value: string | number; icon: React.ComponentType<{ className?: string }>; color: string; subtitle?: string; href?: string; } function KpiCard({ title, value, icon: Icon, color, subtitle, href }: KpiCardProps) { const router = useRouter(); return ( router.push(href) : undefined} >

{title}

{value}

{subtitle &&

{subtitle}

}
{href && (
)}
); } const priorityVariant: Record = { URGENT: "danger", urgent: "danger", HIGH: "warning", high: "warning", NORMAL: "default", normal: "default", MEDIUM: "default", medium: "default", LOW: "muted", low: "muted", }; // Build mock time-series data from revenue for the chart function buildChartData(stats: DashboardSummary | undefined) { if (!stats) return []; // Create a simple 2-month comparison from revenue data const now = new Date(); const thisMonth = now.toLocaleString("default", { month: "short" }); const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1).toLocaleString("default", { month: "short" }); return [ { month: lastMonth, revenue: stats.revenue.lastMonth, clients: stats.subscribers.total }, { month: thisMonth, revenue: stats.revenue.thisMonth, clients: stats.subscribers.active }, ]; } export default function DashboardPage() { const router = useRouter(); const { data: stats, isLoading: statsLoading, refetch: refetchStats } = useQuery({ queryKey: ["dashboard-summary"], queryFn: async () => { const res = await api.get("/api/v1/dashboard/summary"); return res.data; }, }); const { data: ticketsData, refetch: refetchTickets } = useQuery>({ queryKey: ["recent-tickets"], queryFn: async () => { const res = await api.get>("/api/v1/tickets?page=1&limit=5"); return res.data; }, }); const seedMutation = useMutation({ mutationFn: () => api.post<{ message: string }>("/api/v1/_seed", {}), onSuccess: (res) => { toast.success(res.data?.message || "Demo data seeded!"); refetchStats(); refetchTickets(); }, onError: (err: { response?: { data?: { message?: string } } }) => { toast.error(err?.response?.data?.message || "Seed failed"); }, }); const recentTickets = ticketsData?.data ?? []; const chartData = buildChartData(stats); const hasChartData = chartData.some((d) => d.revenue > 0); return (

Dashboard

Overview of your ISP operations

{/* KPI Cards */} {statsLoading ? (
{[1, 2, 3, 4].map((i) => (
))}
) : (
0 ? "+" : ""}${stats.revenue.growth.toFixed(1)}% vs last month` : "vs last month" } href="/payments" />
)} {/* Secondary stats */}
router.push("/tickets?status=OPEN")} >

Open Tickets

{stats?.support.openTickets ?? 0}

router.push("/tickets?status=IN_PROGRESS")} >

In-Progress Tickets

{stats?.support.inProgressTickets ?? 0}

router.push("/tasks")} >

Pending Tasks

{stats?.tasks.pending ?? 0}

{/* Revenue Chart */} {!statsLoading && ( Revenue Overview {hasChartData ? ( `₱${(v / 1000).toFixed(0)}k`} /> formatCurrency(Number(v))} /> ) : (

Revenue data will appear once payments are recorded.

)}
)} {/* Recent Tickets */} Recent Tickets {recentTickets.length === 0 ? (
No tickets yet
) : (
{recentTickets.map((ticket) => (
router.push("/tickets")} >

{ticket.subject}

{ticket.client ? `${ticket.client.firstName} ${ticket.client.lastName}` : "No client"}{" "} • {formatDateTime(ticket.createdAt)}

{ticket.priority} {ticket.status}
))}
)}
); }