From 40162e03ca8fc60493fe18812b8ea5c746186876 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sun, 31 May 2026 20:11:56 +0200 Subject: [PATCH] feat(06-02): replace redirect with real dashboard RSC at /admin - 4 KPI cards: clienti attivi, revenue totale, progetti in corso, pagamenti in sospeso - Activity feed: last 10 events with icon, label, detail, timestamp - Page is RSC (async server component, no use client) - revalidate = 0 for fresh data on each request --- src/app/admin/page.tsx | 120 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 4222666..cf98a62 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,6 +1,118 @@ -import { redirect } from "next/navigation"; +import { getDashboardStats } from "@/lib/dashboard-queries"; +import { Users, FolderOpen, Euro, Clock } from "lucide-react"; -// Dashboard page — content added in Phase 6 Plan 02 -export default function AdminRoot() { - redirect("/admin/clients"); +export const revalidate = 0; + +function KpiCard({ + label, + value, + sub, + icon: Icon, + color, +}: { + label: string; + value: string | number; + sub?: string; + icon: React.ElementType; + color: string; +}) { + return ( +
+
+ +
+
+

{label}

+

{value}

+ {sub &&

{sub}

} +
+
+ ); +} + +const ACTIVITY_ICONS: Record = { + nuovo_cliente: "👤", + nuovo_progetto: "📁", + deliverable_approvato: "✅", + timer_stoppato: "⏱", +}; + +function fmt(ts: Date) { + return new Intl.DateTimeFormat("it-IT", { + day: "2-digit", + month: "short", + hour: "2-digit", + minute: "2-digit", + }).format(new Date(ts)); +} + +function fmtEur(val: string) { + return new Intl.NumberFormat("it-IT", { style: "currency", currency: "EUR" }).format( + parseFloat(val) || 0 + ); +} + +export default async function AdminDashboard() { + const { kpi, activity } = await getDashboardStats(); + + return ( +
+

Dashboard

+ + {/* KPI cards */} +
+ + + + +
+ + {/* Activity feed */} +
+
+

Attività recente

+
+ {activity.length === 0 ? ( +

Nessuna attività recente

+ ) : ( +
    + {activity.map((item, i) => ( +
  • +
    + {ACTIVITY_ICONS[item.type]} +
    +

    {item.label}

    +

    {item.detail}

    +
    +
    + {fmt(item.timestamp)} +
  • + ))} +
+ )} +
+
+ ); }