diff --git a/.phase2-state.json b/.phase2-state.json index 24136f7..b094cc5 100644 --- a/.phase2-state.json +++ b/.phase2-state.json @@ -1,10 +1,11 @@ { "completed_features": [], - "current_feature": "router-with-new-pages", + "current_feature": "dashboard-stats", "started_at": "2026-05-23T04:42:59.289476", "attempted_features": [ "customers-crud", "projects-crud", - "api-client-extensions" + "api-client-extensions", + "router-with-new-pages" ] } \ No newline at end of file diff --git a/GENERATION_LOG.md b/GENERATION_LOG.md index 9aa5acf..e9e189c 100644 --- a/GENERATION_LOG.md +++ b/GENERATION_LOG.md @@ -284,3 +284,31 @@ src/routes/customers.ts(14,49): error TS7006: Parameter 'reply' implicitly has a src/routes/customers.ts(22,11): error TS2339: Property 'get' does not exist on type 'FastifyPluginAsync'. src/routes/customers.ts(22,27): error TS7006: Parameter 'request' implicitly has an 'any' type. src/routes/customers.ts(22,36): error TS7006: Parameter +- `04:46:07` **INFO** Committed feature router-with-new-pages +- `04:46:07` **INFO** Pushed: rc=0 +- `04:46:07` **WARN** ⚠️ Feature router-with-new-pages partial — moving on + +## Feature: dashboard-stats (2026-05-23 04:46:07) + +- `04:46:07` **INFO** Description: Dashboard mit echten Statistiken statt Placeholder +- `04:46:07` **INFO** Files: 1 +- `04:46:07` **INFO** Generating apps/web/src/pages/Dashboard.tsx (ÜBERARBEITETER Dashboard. Drei Karten oben: (1) 'Heute' — Gesamtstunde…) +- `04:47:03` **INFO** wrote 6545 chars in 55.9s (attempt 1) +- `04:47:03` **INFO** Running tsc --noEmit on api… +- `04:47:04` **WARN** tsc errors: +src/routes/auth.ts(9,11): error TS2339: Property 'post' does not exist on type 'FastifyPluginAsync'. +src/routes/auth.ts(9,33): error TS7006: Parameter 'request' implicitly has an 'any' type. +src/routes/auth.ts(9,42): error TS7006: Parameter 'reply' implicitly has an 'any' type. +src/routes/auth.ts(22,27): error TS2339: Property 'jwt' does not exist on type 'FastifyPluginAsync'. +src/routes/auth.ts(44,11): error TS2339: Property 'get' does not exist on type 'FastifyPluginAsync'. +src/routes/auth.ts(44,29): error TS7006: Parameter 'request' implicitly has an 'any' type. +src/routes/auth.ts(44,38): error TS7006: Parameter 'reply' implicitly has an 'any' type. +src/routes/auth.ts(70,11): error TS2339: Property 'post' does not exist on type 'FastifyPluginAsync'. +src/routes/auth.ts(70,34): error TS7006: Parameter 'request' implicitly has an 'any' type. +src/routes/auth.ts(70,43): error TS7006: Parameter 'reply' implicitly has an 'any' type. +src/routes/customers.ts(14,11): error TS2339: Property 'addHook' does not exist on type 'FastifyPluginAsync'. +src/routes/customers.ts(14,40): error TS7006: Parameter 'request' implicitly has an 'any' type. +src/routes/customers.ts(14,49): error TS7006: Parameter 'reply' implicitly has an 'any' type. +src/routes/customers.ts(22,11): error TS2339: Property 'get' does not exist on type 'FastifyPluginAsync'. +src/routes/customers.ts(22,27): error TS7006: Parameter 'request' implicitly has an 'any' type. +src/routes/customers.ts(22,36): error TS7006: Parameter diff --git a/apps/web/src/pages/Dashboard.tsx b/apps/web/src/pages/Dashboard.tsx index 4c6119e..6f87ba7 100644 --- a/apps/web/src/pages/Dashboard.tsx +++ b/apps/web/src/pages/Dashboard.tsx @@ -1,18 +1,36 @@ import { useQuery } from "@tanstack/react-query" import { useNavigate } from "@tanstack/react-router" import { api } from "../lib/api" +import { Clock, Calendar, FolderKanban, LogOut } from "lucide-react" export default function Dashboard() { const navigate = useNavigate() + const today = new Date().toISOString().split("T")[0] + + const getStartOfWeek = () => { + const d = new Date() + const day = d.getDay() + const diff = d.getDate() - day + (day === 0 ? -6 : 1) + const start = new Date(d.setDate(diff)) + return start.toISOString().split("T")[0] + } + + const weekStart = getStartOfWeek() + const { data: user, isLoading: userLoading } = useQuery({ queryKey: ["me"], queryFn: () => api.getMe() }) - const { data: entries, isLoading: entriesLoading } = useQuery({ + const { data: todayEntries, isLoading: todayLoading } = useQuery({ queryKey: ["timeEntries", "today"], - queryFn: () => api.listTimeEntries({ date: new Date().toISOString().split("T")[0] }) + queryFn: () => api.listTimeEntries({ date: today }) + }) + + const { data: weekEntries, isLoading: weekLoading } = useQuery({ + queryKey: ["timeEntries", "week"], + queryFn: () => api.listTimeEntries({ from: weekStart }) }) const handleLogout = () => { @@ -20,43 +38,119 @@ export default function Dashboard() { navigate({ to: "/login" }) } - if (userLoading || entriesLoading) { + if (userLoading || todayLoading || weekLoading) { return (
-
+
) } + const calcHours = (entries: any[]) => + entries?.reduce((acc, curr) => acc + (parseFloat(curr.duration) || 0), 0) || 0 + + const todayHours = calcHours(todayEntries || []) + const weekHours = calcHours(weekEntries || []) + const activeProjects = new Set((weekEntries || []).map(e => e.projectId)).size + const avgDailyHours = (weekHours / 5).toFixed(1) + + const lastFiveEntries = (weekEntries || []).slice(-5).reverse() + return (
-

Dashboard

+
+

Dashboard

+

Willkommen zurück, {user?.name}!

+
-
-
-

- Hallo, {user?.name || "Benutzer"}! -

-

- Willkommen zurück in deinem EmberClone. Hier ist die Übersicht deiner heutigen Aktivitäten. -

+
+
+ {/* Card 1: Heute */} +
+
+

Heute

+
+ {todayHours.toFixed(2)}h + {todayEntries?.length || 0} Einträge +
+
+
+ +
+
+ + {/* Card 2: Diese Woche */} +
+
+

Diese Woche

+
+ {weekHours.toFixed(2)}h + Ø {avgDailyHours}h / Tag +
+
+
+ +
+
+ + {/* Card 3: Aktive Projekte */} +
+
+

Aktive Projekte

+
+ {activeProjects} + diese Woche +
+
+
+ +
+
-
- - Heutige Einträge - - - {entries?.length || 0} - +
+
+

Letzte 5 Einträge

+
+
+ + + + + + + + + + + {lastFiveEntries.length > 0 ? ( + lastFiveEntries.map((entry) => ( + + + + + + + )) + ) : ( + + + + )} + +
DatumProjektBeschreibungDauer
{entry.date}{entry.projectName || "Unbekannt"}{entry.description}{entry.duration}h
+ Keine aktuellen Einträge gefunden. +
+