diff --git a/app/page.tsx b/app/page.tsx
index 51881f6..0f4642e 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -5,7 +5,7 @@ import { DashboardAnalysisCard } from "@/components/dashboard-analysis-card";
import { EmptyState } from "@/components/empty-state";
import { StatCard } from "@/components/stat-card";
import { formatDateShort, formatDistance, formatDuration, formatPace } from "@/lib/format";
-import { getDashboardAnalysis } from "@/lib/models/analysis";
+import { getDashboardAnalysis, serializeAnalysis } from "@/lib/models/analysis";
import { listRunningActivities } from "@/lib/models/running";
import { listStrengthWorkouts } from "@/lib/models/strength";
@@ -84,7 +84,7 @@ export default async function Home() {
-
+
);
}
diff --git a/app/running/[id]/page.tsx b/app/running/[id]/page.tsx
index 43d9396..016c4f4 100644
--- a/app/running/[id]/page.tsx
+++ b/app/running/[id]/page.tsx
@@ -5,7 +5,7 @@ import { RouteMapSection } from "@/components/route-map-section";
import { StatCard } from "@/components/stat-card";
import { formatDate, formatDistance, formatDuration, formatPace } from "@/lib/format";
import { fetchActivityRoutePoints, getAuthorizedClient } from "@/lib/garmin/client";
-import { getLatestAnalysisForTarget } from "@/lib/models/analysis";
+import { getLatestAnalysisForTarget, serializeAnalysis } from "@/lib/models/analysis";
import { getRunningActivity, setRunningActivityRoutePoints, type RunningActivity } from "@/lib/models/running";
export const dynamic = "force-dynamic";
@@ -117,7 +117,7 @@ export default async function RunningActivityPage({
) : null}
-
+
);
}
diff --git a/app/strength/[id]/page.tsx b/app/strength/[id]/page.tsx
index 7152615..5ed5124 100644
--- a/app/strength/[id]/page.tsx
+++ b/app/strength/[id]/page.tsx
@@ -3,7 +3,7 @@ import { AiAnalysisCard } from "@/components/ai-analysis-card";
import { ExerciseProgressChart } from "@/components/exercise-progress-chart";
import { InfoTooltip } from "@/components/info-tooltip";
import { formatDate, formatDateShort } from "@/lib/format";
-import { getLatestAnalysisForTarget } from "@/lib/models/analysis";
+import { getLatestAnalysisForTarget, serializeAnalysis } from "@/lib/models/analysis";
import { getStrengthWorkout, listStrengthWorkouts } from "@/lib/models/strength";
import { exerciseE1rm, getExerciseHistory } from "@/lib/strength/stats";
@@ -40,7 +40,7 @@ export default async function StrengthWorkoutPage({
{workout.notes ?
{exercisesWithHistory.map(({ exercise }, index) => {
diff --git a/components/ai-analysis-card.tsx b/components/ai-analysis-card.tsx
index 6aca758..123c085 100644
--- a/components/ai-analysis-card.tsx
+++ b/components/ai-analysis-card.tsx
@@ -4,12 +4,12 @@ import { useActionState } from "react";
import { Sparkles } from "lucide-react";
import { generateAnalysisAction } from "@/app/ai/actions";
import { formatDate } from "@/lib/format";
-import type { AiAnalysis, AiAnalysisTargetType } from "@/lib/models/analysis";
+import type { AiAnalysisTargetType, SerializedAiAnalysis } from "@/lib/models/analysis";
type AiAnalysisCardProps = {
targetType: AiAnalysisTargetType;
targetId: string;
- analysis: AiAnalysis | null;
+ analysis: SerializedAiAnalysis | null;
};
export function AiAnalysisCard({ targetType, targetId, analysis }: AiAnalysisCardProps) {
diff --git a/components/dashboard-analysis-card.tsx b/components/dashboard-analysis-card.tsx
index 7ae9f1a..f1e1037 100644
--- a/components/dashboard-analysis-card.tsx
+++ b/components/dashboard-analysis-card.tsx
@@ -4,10 +4,10 @@ import { useActionState } from "react";
import { Sparkles } from "lucide-react";
import { generateDashboardAnalysisAction } from "@/app/ai/actions";
import { formatDate } from "@/lib/format";
-import type { AiAnalysis } from "@/lib/models/analysis";
+import type { SerializedAiAnalysis } from "@/lib/models/analysis";
type Props = {
- analysis: AiAnalysis | null;
+ analysis: SerializedAiAnalysis | null;
};
export function DashboardAnalysisCard({ analysis }: Props) {
diff --git a/components/exercise-progress-chart.tsx b/components/exercise-progress-chart.tsx
index 6becc27..890b365 100644
--- a/components/exercise-progress-chart.tsx
+++ b/components/exercise-progress-chart.tsx
@@ -1,5 +1,6 @@
"use client";
+import { useEffect, useState } from "react";
import { CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
type ExerciseProgressChartProps = {
@@ -26,8 +27,18 @@ function E1rmDelta({ data }: { data: ExerciseProgressChartProps["data"] }) {
}
export function ExerciseProgressChart({ name, data }: ExerciseProgressChartProps) {
- if (data.length < 2) {
- return null;
+ const [mounted, setMounted] = useState(false);
+ useEffect(() => setMounted(true), []);
+
+ if (data.length < 2) return null;
+
+ if (!mounted) {
+ return (
+
+ );
}
return (
diff --git a/components/volume-chart.tsx b/components/volume-chart.tsx
index b8631fa..95aa4b4 100644
--- a/components/volume-chart.tsx
+++ b/components/volume-chart.tsx
@@ -1,5 +1,6 @@
"use client";
+import { useEffect, useState } from "react";
import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
type VolumeChartProps = {
@@ -7,6 +8,18 @@ type VolumeChartProps = {
};
export function VolumeChart({ data }: VolumeChartProps) {
+ const [mounted, setMounted] = useState(false);
+ useEffect(() => setMounted(true), []);
+
+ if (!mounted) {
+ return (
+
+ );
+ }
+
return (
Wolumen treningowy (ciężar × powtórzenia)
diff --git a/lib/format.ts b/lib/format.ts
index 02636ba..0a86317 100644
--- a/lib/format.ts
+++ b/lib/format.ts
@@ -1,12 +1,12 @@
import { format } from "date-fns";
import { pl } from "date-fns/locale";
-export function formatDate(date: Date): string {
- return format(date, "d MMMM yyyy, HH:mm", { locale: pl });
+export function formatDate(date: Date | string): string {
+ return format(new Date(date), "d MMMM yyyy, HH:mm", { locale: pl });
}
-export function formatDateShort(date: Date): string {
- return format(date, "d MMM yyyy", { locale: pl });
+export function formatDateShort(date: Date | string): string {
+ return format(new Date(date), "d MMM yyyy", { locale: pl });
}
export function formatDuration(seconds: number): string {
diff --git a/lib/models/analysis.ts b/lib/models/analysis.ts
index d12e23f..6b1eace 100644
--- a/lib/models/analysis.ts
+++ b/lib/models/analysis.ts
@@ -16,6 +16,28 @@ export type AiAnalysis = AiAnalysisInput & {
createdAt: Date;
};
+export type SerializedAiAnalysis = {
+ _id: string;
+ targetType: AiAnalysisTargetType;
+ targetId: string;
+ summary: string;
+ tips: string[];
+ model: string;
+ createdAt: string;
+};
+
+export function serializeAnalysis(analysis: AiAnalysis): SerializedAiAnalysis {
+ return {
+ _id: analysis._id.toString(),
+ targetType: analysis.targetType,
+ targetId: analysis.targetId.toString(),
+ summary: analysis.summary,
+ tips: analysis.tips,
+ model: analysis.model,
+ createdAt: analysis.createdAt.toISOString(),
+ };
+}
+
const COLLECTION = "ai_analyses";
async function getCollection() {