"use client";
import { useQuery, useMutation } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { Users, Wifi, FileText, DollarSign, Ticket, TrendingUp, Database, RefreshCw, AlertCircle } 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 { useAuthStore } from "@/lib/auth-store";
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 && →
}
);
}
function KpiSkeleton() {
return (
);
}
function ErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {
return (
);
}
const priorityVariant: Record = {
URGENT: "danger", urgent: "danger",
HIGH: "warning", high: "warning",
NORMAL: "default", normal: "default",
MEDIUM: "default", medium: "default",
LOW: "muted", low: "muted",
};
function buildChartData(stats: DashboardSummary | undefined) {
if (!stats) return [];
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 },
{ month: thisMonth, revenue: stats.revenue.thisMonth },
];
}
export default function DashboardPage() {
const router = useRouter();
const user = useAuthStore((s) => s.user);
const isAdmin = user?.roles?.some(r => r.toLowerCase() === "admin" || r.toLowerCase() === "super_admin");
const {
data: stats,
isLoading: statsLoading,
isError: statsError,
refetch: refetchStats,
} = useQuery({
queryKey: ["dashboard-summary"],
queryFn: async () => {
const res = await api.get("/api/v1/dashboard/summary");
return res.data;
},
});
const {
data: ticketsData,
isLoading: ticketsLoading,
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: any) => {
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 (
{/* Header */}
Dashboard
Overview of your ISP operations
{isAdmin && (
)}
{/* KPI Cards */}
{statsLoading ? (
{[1,2,3,4].map(i => )}
) : statsError ? (
) : (
{isAdmin && (
0 ? "+" : ""}${stats.revenue.growth.toFixed(1)}% vs last month`
: "vs last month"} href="/payments" />
)}
)}
{/* Secondary stats */}
router.push("/tickets")}>
Open Tickets
{stats?.support.openTickets ?? 0}
router.push("/tickets")}>
In-Progress Tickets
{stats?.support.inProgressTickets ?? 0}
{/* Revenue Chart — admin only */}
{isAdmin && !statsLoading && (
Revenue Overview
{hasChartData ? (
`₱${(v/1000).toFixed(0)}k`} />
formatCurrency(Number(v))} />
) : (
Revenue data will appear once payments are recorded.
)}
)}
{/* Recent Tickets */}
Recent Tickets
{ticketsLoading ? (
) : 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}
))}
)}
);
}