diff --git a/src/app/admin/analytics/page.tsx b/src/app/admin/analytics/page.tsx deleted file mode 100644 index 28ae351..0000000 --- a/src/app/admin/analytics/page.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { - getAnalyticsByYear, - getMonthlyCollected, - getAvailableYears, - getTimeByClient, - getTotalTrackedHours, -} from "@/lib/analytics-queries"; -import { YearSelector, MonthlyChart } from "@/components/admin/YearSelector"; - -export const revalidate = 0; - -function fmtEur(n: number) { - return n.toLocaleString("it-IT", { style: "currency", currency: "EUR", minimumFractionDigits: 2 }); -} - -function fmtSeconds(s: number): string { - const h = Math.floor(s / 3600); - const m = Math.floor((s % 3600) / 60); - if (h > 0) return `${h}h ${m}m`; - return `${m}m`; -} - -function MetricCard({ - label, value, sub, accent, -}: { - label: string; value: string; sub?: string; accent?: boolean; -}) { - return ( -
-

- {label} -

-

- {value} -

- {sub && ( -

{sub}

- )} -
- ); -} - -export default async function AnalyticsPage({ - searchParams, -}: { - searchParams: Promise<{ year?: string }>; -}) { - const { year: yearParam } = await searchParams; - const year = parseInt(yearParam ?? "") || new Date().getFullYear(); - - const [data, monthly, availableYears, timeByClient, totalHours] = await Promise.all([ - getAnalyticsByYear(year), - getMonthlyCollected(year), - getAvailableYears(), - getTimeByClient(year), - getTotalTrackedHours(year), - ]); - - const collectedPct = - data.contracted > 0 ? Math.round((data.collected / data.contracted) * 100) : 0; - - const maxClientSeconds = timeByClient[0]?.totalSeconds ?? 1; - - return ( -
- {/* Header */} -
-
-

Statistiche

-

Panoramica per anno

-
- -
- - {/* ── SEZIONE ECONOMICA ── */} -
-

Fatturato

- -
- - - - -
- - - - {data.contracted === 0 && ( -

- Nessun cliente registrato nel {year}. -

- )} -
- - {/* ── SEZIONE TIME TRACKING ── */} -
-

- Tempo tracciato -

- -
- -
- - {timeByClient.length === 0 ? ( -
-

- Nessuna sessione registrata nel {year}. - Usa il timer ▶ nella lista clienti per iniziare. -

-
- ) : ( -
-

Ore per cliente — {year}

-
- {timeByClient.map((row) => { - const pct = Math.round((row.totalSeconds / maxClientSeconds) * 100); - return ( -
-
- {row.clientName} - - {fmtSeconds(row.totalSeconds)} - -
-
-
-
-
- ); - })} -
-
- )} -
-
- ); -} \ No newline at end of file diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 93db251..dfe4b41 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,6 +1,14 @@ import { Suspense } from "react"; import { getDashboardStats } from "@/lib/dashboard-queries"; import { FollowUpWidget } from "@/components/admin/dashboard/FollowUpWidget"; +import { + getAnalyticsByYear, + getMonthlyCollected, + getAvailableYears, + getTimeByClient, + getTotalTrackedHours, +} from "@/lib/analytics-queries"; +import { YearSelector, MonthlyChart } from "@/components/admin/YearSelector"; import { Users, FolderOpen, Euro, Clock } from "lucide-react"; export const revalidate = 0; @@ -32,6 +40,44 @@ function KpiCard({ ); } +function MetricCard({ + label, + value, + sub, + accent, +}: { + label: string; + value: string; + sub?: string; + accent?: boolean; +}) { + return ( +
+

+ {label} +

+

+ {value} +

+ {sub && ( +

{sub}

+ )} +
+ ); +} + const ACTIVITY_ICONS: Record = { nuovo_cliente: "👤", nuovo_progetto: "📁", @@ -48,15 +94,44 @@ function fmt(ts: Date) { }).format(new Date(ts)); } -function fmtEur(val: string) { - return new Intl.NumberFormat("it-IT", { style: "currency", currency: "EUR" }).format( - parseFloat(val) || 0 - ); +function fmtEur(n: number) { + return n.toLocaleString("it-IT", { + style: "currency", + currency: "EUR", + minimumFractionDigits: 2, + }); } -export default async function AdminDashboard() { +function fmtSeconds(s: number): string { + const h = Math.floor(s / 3600); + const m = Math.floor((s % 3600) / 60); + if (h > 0) return `${h}h ${m}m`; + return `${m}m`; +} + +export default async function AdminDashboard({ + searchParams, +}: { + searchParams: Promise<{ year?: string }>; +}) { + const { year: yearParam } = await searchParams; + const year = parseInt(yearParam ?? "") || new Date().getFullYear(); + const { kpi, activity } = await getDashboardStats(); + const [data, monthly, availableYears, timeByClient, totalHours] = await Promise.all([ + getAnalyticsByYear(year), + getMonthlyCollected(year), + getAvailableYears(), + getTimeByClient(year), + getTotalTrackedHours(year), + ]); + + const collectedPct = + data.contracted > 0 ? Math.round((data.collected / data.contracted) * 100) : 0; + + const maxClientSeconds = timeByClient[0]?.totalSeconds ?? 1; + return (

Dashboard

@@ -78,7 +153,7 @@ export default async function AdminDashboard() { /> )}
+ + {/* ── SEZIONE STATISTICHE ANNUALI ── */} +
+
+
+

Statistiche

+

Panoramica per anno

+
+ +
+ + {/* Sezione economica */} +
+

Fatturato

+
+ + + + +
+ + {data.contracted === 0 && ( +

+ Nessun cliente registrato nel {year}. +

+ )} +
+ + {/* Sezione time tracking */} +
+

+ Tempo tracciato +

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

+ Nessuna sessione registrata nel {year}. Usa il timer ▶ nella lista clienti per + iniziare. +

+
+ ) : ( +
+

Ore per cliente — {year}

+
+ {timeByClient.map((row) => { + const pct = Math.round((row.totalSeconds / maxClientSeconds) * 100); + return ( +
+
+ + {row.clientName} + + + {fmtSeconds(row.totalSeconds)} + +
+
+
+
+
+ ); + })} +
+
+ )} +
+
); } diff --git a/src/components/admin/YearSelector.tsx b/src/components/admin/YearSelector.tsx index fad3c66..82bd276 100644 --- a/src/components/admin/YearSelector.tsx +++ b/src/components/admin/YearSelector.tsx @@ -15,7 +15,7 @@ export function YearSelector({ const thisYear = new Date().getFullYear(); function go(y: number) { - router.push(`/admin/analytics?year=${y}`); + router.push(`/admin?year=${y}`); } return (