"use client"; import Link from "next/link"; import { useActionState, useMemo, useState } from "react"; import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays, addMonths, subMonths, isSameMonth, isSameDay, isToday, isAfter, startOfDay, } from "date-fns"; import { pl } from "date-fns/locale"; import { Activity, ChevronLeft, ChevronRight, Dumbbell, Sparkles } from "lucide-react"; import { generateDashboardAnalysisAction } from "@/app/ai/actions"; import { formatDate, formatDistance, formatDuration, formatPace } from "@/lib/format"; import type { SerializedAiAnalysis } from "@/lib/models/analysis"; export type DayRun = { id: string; name: string; startTime: string; distanceM: number; durationSec: number; avgPaceSecPerKm: number; }; export type DayWorkout = { id: string; name: string; date: string; exerciseCount: number; }; type Props = { analyses: SerializedAiAnalysis[]; runs: DayRun[]; workouts: DayWorkout[]; }; function dayKey(date: Date): string { return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; } export function DashboardAnalysisCard({ analyses, runs, workouts }: Props) { const [state, formAction, pending] = useActionState(generateDashboardAnalysisAction, null); // Map each calendar day to its (latest) analysis. Selecting a day is a pure // local lookup, no server round-trip. const byDay = useMemo(() => { const map = new Map(); for (const a of analyses) { const key = dayKey(new Date(a.createdAt)); if (!map.has(key)) map.set(key, a); // analyses are newest-first } return map; }, [analyses]); const [currentMonth, setCurrentMonth] = useState(() => new Date()); const [selectedDate, setSelectedDate] = useState(() => new Date()); const runDays = useMemo( () => new Set(runs.map((r) => dayKey(new Date(r.startTime)))), [runs] ); const workoutDays = useMemo( () => new Set(workouts.map((w) => dayKey(new Date(w.date)))), [workouts] ); const todayStart = startOfDay(new Date()); const monthStart = startOfMonth(currentMonth); const monthEnd = endOfMonth(monthStart); const calendarStart = startOfWeek(monthStart, { weekStartsOn: 1 }); const calendarEnd = endOfWeek(monthEnd, { weekStartsOn: 1 }); const days: Date[] = []; let cursor = calendarStart; while (cursor <= calendarEnd) { days.push(cursor); cursor = addDays(cursor, 1); } const weekDays = ["Pn", "Wt", "Śr", "Cz", "Pt", "Sb", "Nd"]; const selectedAnalysis = byDay.get(dayKey(selectedDate)) ?? null; const viewingToday = isToday(selectedDate); const dayRuns = runs.filter((r) => isSameDay(new Date(r.startTime), selectedDate)); const dayWorkouts = workouts.filter((w) => isSameDay(new Date(w.date), selectedDate)); return (

Kondycja treningowa

{viewingToday && (
)}
{state && "error" in state ?

{state.error}

: null}
{format(currentMonth, "LLLL yyyy", { locale: pl })}
{weekDays.map((d) => (
{d}
))}
{days.map((d, i) => { const key = dayKey(d); const inMonth = isSameMonth(d, monthStart); const today = isToday(d); const future = isAfter(startOfDay(d), todayStart); const selectable = !future; const selected = isSameDay(d, selectedDate); const hasRun = runDays.has(key); const hasWorkout = workoutDays.has(key); const hasAnalysis = byDay.has(key); return ( ); })}
Bieg Siłownia Analiza

Treningi · {format(selectedDate, "d MMM yyyy", { locale: pl })}

{dayRuns.length === 0 && dayWorkouts.length === 0 ? (

Brak treningów tego dnia.

) : (
    {dayRuns.map((run) => (
  • {run.name} {formatDistance(run.distanceM)} · {formatDuration(run.durationSec)} ·{" "} {formatPace(run.avgPaceSecPerKm)}
  • ))} {dayWorkouts.map((workout) => (
  • {workout.name} {workout.exerciseCount}{" "} {workout.exerciseCount === 1 ? "ćwiczenie" : "ćwiczeń"}
  • ))}
)}
{selectedAnalysis ? (

{format(selectedDate, "d MMMM yyyy", { locale: pl })}

{selectedAnalysis.summary}

{selectedAnalysis.tips.length > 0 && (
    {selectedAnalysis.tips.map((tip, index) => (
  • {tip}
  • ))}
)}

{formatDate(selectedAnalysis.createdAt)} · {selectedAnalysis.model}

) : viewingToday ? (

Brak analizy na dziś. Wygeneruj kompleksową analizę kondycji łączącą dane biegowe, siłowe, HRV i sen.

) : (

Brak analizy AI dla {format(selectedDate, "d MMMM yyyy", { locale: pl })}.

)}
); }