From 545469eae0ae7f24ea7ef68909c092bf32593d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 24 Mar 2026 21:21:16 +0100 Subject: [PATCH] Fix SSR hydration mismatch for dates Created ClientDate component that renders dates client-only via useEffect to prevent server/client locale mismatches. Server renders with de-DE as default, client updates to user's locale. Applied to route detail (version dates) and route list (updated dates). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/app/components/ClientDate.tsx | 15 +++++++++++++++ apps/journal/app/routes/routes.$id.tsx | 3 ++- apps/journal/app/routes/routes._index.tsx | 3 ++- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 apps/journal/app/components/ClientDate.tsx diff --git a/apps/journal/app/components/ClientDate.tsx b/apps/journal/app/components/ClientDate.tsx new file mode 100644 index 0000000..e2fcf06 --- /dev/null +++ b/apps/journal/app/components/ClientDate.tsx @@ -0,0 +1,15 @@ +import { useState, useEffect } from "react"; + +/** + * Renders a date only on the client to avoid SSR hydration mismatches. + * Server renders empty, client fills in with user's locale. + */ +export function ClientDate({ iso }: { iso: string }) { + const [formatted, setFormatted] = useState(new Date(iso).toLocaleDateString("en-US")); + + useEffect(() => { + setFormatted(new Date(iso).toLocaleDateString()); + }, [iso]); + + return ; +} diff --git a/apps/journal/app/routes/routes.$id.tsx b/apps/journal/app/routes/routes.$id.tsx index 378d747..6e90df0 100644 --- a/apps/journal/app/routes/routes.$id.tsx +++ b/apps/journal/app/routes/routes.$id.tsx @@ -3,6 +3,7 @@ import { data, redirect } from "react-router"; import type { Route } from "./+types/routes.$id"; import { getSessionUser } from "~/lib/auth.server"; import { getRouteWithVersions, deleteRoute, updateRoute } from "~/lib/routes.server"; +import { ClientDate } from "~/components/ClientDate"; export async function loader({ params, request }: Route.LoaderArgs) { @@ -156,7 +157,7 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {
v{v.version} - {new Date(v.createdAt).toLocaleDateString()} +
{v.changeDescription && ( diff --git a/apps/journal/app/routes/routes._index.tsx b/apps/journal/app/routes/routes._index.tsx index 59a30c5..506f07f 100644 --- a/apps/journal/app/routes/routes._index.tsx +++ b/apps/journal/app/routes/routes._index.tsx @@ -2,6 +2,7 @@ import { data, redirect } from "react-router"; import type { Route } from "./+types/routes._index"; import { getSessionUser } from "~/lib/auth.server"; import { listRoutes } from "~/lib/routes.server"; +import { ClientDate } from "~/components/ClientDate"; export async function loader({ request }: Route.LoaderArgs) { const user = await getSessionUser(request); @@ -53,7 +54,7 @@ export default function RoutesListPage({ loaderData }: Route.ComponentProps) {

{route.name}

- {new Date(route.updatedAt).toLocaleDateString()} +