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 (