"use client"; import { useEffect, useMemo, useState } from "react"; import { DashboardActivity } from "@/components/dashboard-activity"; import { DashboardSkeleton } from "@/components/dashboard-skeleton"; import { HouseholdsTrendChart } from "@/components/households-trend-chart"; import { PriorityBreakdown } from "@/components/priority-breakdown"; import { PriorityScoreChart } from "@/components/priority-score-chart"; import { RecentHouseholds } from "@/components/recent-households"; import { DashboardStats } from "@/components/stats"; import type { ActivityItem, GasStationStats } from "@/lib/dashboard-types"; import type { HouseholdRow, PovertyOverview } from "@/lib/poverty-types"; const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL ?? "http://localhost:4000"; type NamedRow = { id: number; name: string; created_at?: string }; export function Dashboard() { const [loading, setLoading] = useState(true); const [overview, setOverview] = useState(null); const [households, setHouseholds] = useState([]); const [gasStats, setGasStats] = useState(null); const [landMarkers, setLandMarkers] = useState([]); const [landShapes, setLandShapes] = useState([]); const [gasMarkers, setGasMarkers] = useState([]); // Aggregates everything the overview widgets need, straight from the DB. useEffect(() => { const token = localStorage.getItem("auth_token"); const headers: Record = token ? { Authorization: `Bearer ${token}` } : {}; const get = (path: string) => fetch(`${BACKEND_URL}${path}`, { headers }).then((r) => r.json()); const asRows = (r: PromiseSettledResult) => r.status === "fulfilled" && Array.isArray(r.value) ? (r.value as NamedRow[]) : []; Promise.allSettled([ get("/households/stats-overview"), get("/households"), get("/gas-station/stats"), get("/land/markers"), get("/land/shapes"), get("/gas-station/markers"), ]).then(([overviewR, hhR, gasStatsR, landMarkersR, landShapesR, gasMarkersR]) => { if (overviewR.status === "fulfilled" && overviewR.value?.totals) { setOverview(overviewR.value as PovertyOverview); } if (hhR.status === "fulfilled" && Array.isArray(hhR.value)) { setHouseholds(hhR.value as HouseholdRow[]); } if (gasStatsR.status === "fulfilled" && typeof gasStatsR.value?.total === "number") { setGasStats(gasStatsR.value as GasStationStats); } setLandMarkers(asRows(landMarkersR)); setLandShapes(asRows(landShapesR)); setGasMarkers(asRows(gasMarkersR)); setLoading(false); }); }, []); const activity = useMemo(() => { const items: ActivityItem[] = [ ...households.map((h) => ({ id: `hh-${h.id}`, kind: "household" as const, title: `Warga "${h.head_name}" terdata`, created_at: h.created_at, })), ...landMarkers.map((m) => ({ id: `lm-${m.id}`, kind: "land" as const, title: `Penanda lahan "${m.name}" ditambahkan`, created_at: m.created_at ?? "", })), ...landShapes.map((s) => ({ id: `ls-${s.id}`, kind: "land" as const, title: `Bidang lahan "${s.name}" digambar`, created_at: s.created_at ?? "", })), ...gasMarkers.map((g) => ({ id: `gs-${g.id}`, kind: "gas" as const, title: `Fasilitas "${g.name}" dipetakan`, created_at: g.created_at ?? "", })), ]; return items .filter((i) => i.created_at) .sort((a, b) => b.created_at.localeCompare(a.created_at)) .slice(0, 4); }, [households, landMarkers, landShapes, gasMarkers]); if (loading) return ; return (
); }