import { Suspense } from "react"; import { notFound } from "next/navigation"; import { AiAnalysisCard } from "@/components/ai-analysis-card"; import { ElevationChart } from "@/components/elevation-chart"; import { RouteMapSection } from "@/components/route-map-section"; import { GcbChart } from "@/components/gcb-chart"; import { RunMetricChart } from "@/components/run-metric-chart"; import { StatCard } from "@/components/stat-card"; import { formatDate, formatDistance, formatDuration, formatPace } from "@/lib/format"; import { getLatestAnalysisForTarget, serializeAnalysis } from "@/lib/models/analysis"; import { getRunningActivity, type RunMetrics, type RunningActivity, } from "@/lib/models/running"; import { getCurrentUserId } from "@/lib/session"; export const dynamic = "force-dynamic"; function RouteMap({ activity }: { activity: RunningActivity }) { const routePoints = activity.routePoints; return (
{routePoints && routePoints.length > 0 ? ( ) : (
Brak danych GPS — zsynchronizuj ponownie
)}
); } function ElevationSection({ activity }: { activity: RunningActivity }) { const elevationProfile = activity.elevationProfile; if (!elevationProfile || elevationProfile.length < 2) return null; const elevData = elevationProfile .map((altM, i) => ({ distanceKm: Math.round((i / elevationProfile.length) * activity.distanceM / 10) / 100, altM, })) .filter((p) => p.altM > 0); if (elevData.length < 2) return null; const paceSrc = activity.runMetrics?.paceSec; const data = elevData.map((ep, i) => { if (!paceSrc || paceSrc.length === 0) return ep; const pi = Math.min(Math.round((i / elevData.length) * paceSrc.length), paceSrc.length - 1); const v = paceSrc[pi]; return { ...ep, paceSec: v > 0 && v < 1800 ? v : undefined }; }); return ; } function toChartData( values: number[] | undefined, distances: number[] ): { distanceKm: number; value: number }[] { if (!values) return []; return distances .map((distanceKm, i) => ({ distanceKm, value: values[i] ?? 0 })) .filter((p) => p.value > 0); } function RunMetricsSection({ activity }: { activity: RunningActivity }) { const metrics: RunMetrics | undefined = activity.runMetrics; if (!metrics || metrics.distanceKm.length === 0) return null; const { hrBpm, gcbLeftPct } = metrics; const maxDist = Math.max(...metrics.distanceKm); const distanceKm = maxDist > 0 ? metrics.distanceKm : Array.from({ length: metrics.distanceKm.length }, (_, i) => Math.round(((i / (metrics.distanceKm.length - 1)) * activity.distanceM) / 10) / 100 ); const hrData = toChartData(hrBpm, distanceKm); const gcbData = gcbLeftPct ? distanceKm .map((d, i) => { const left = gcbLeftPct[i] ?? 0; return left > 0 ? { distanceKm: d, left, right: Math.round((100 - left) * 10) / 10 } : null; }) .filter((p): p is NonNullable => p !== null) : []; if (!hrData.length && !gcbData.length) return null; return (
{hrData.length > 1 && ( )} {gcbData.length > 1 && }
); } export default async function RunningActivityPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const userId = await getCurrentUserId(); const activity = await getRunningActivity(userId, id); if (!activity) { notFound(); } const analysis = await getLatestAnalysisForTarget(userId, "running", activity._id); return (

{activity.name}

{formatDate(activity.startTime)}

{activity.maxHr ? : null} {activity.elevationGainM ? : null} {activity.vo2Max ? : null} {activity.avgGroundContactTimeMs ? ( ) : null} {activity.avgVerticalOscillationCm ? ( ) : null} {activity.avgVerticalRatioPct ? ( ) : null} {activity.avgStrideLengthCm ? ( ) : null} {activity.avgGroundContactBalanceLeftPct ? ( ) : null} {activity.avgPowerW ? : null} {activity.maxPowerW ? : null} {activity.avgRespirationRate ? ( ) : null} {activity.aerobicTrainingEffect ? ( ) : null} {activity.anaerobicTrainingEffect ? ( ) : null}
); }