From b09a7e2e56c4027bada2dd77a8102afddc6dbd5e Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 6 Sep 2026 17:00:19 +0200 Subject: [PATCH] fix(visits): pin tool page 500s without the "use client" directive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `GET /visits/pin-tool` returned 500 on every request: x `ssr: false` is not allowed with `next/dynamic` in Server Components. Please move it into a Client Component. The page uses `dynamic(..., { ssr: false })` to keep Leaflet off the server (it touches `window` on import) but was missing the `"use client"` directive that `supplier-map/page.tsx` carries for exactly the same reason. Worth noting how this got through: it fails at request time, not build time, so `tsc --noEmit` was clean and all 32 unit tests passed. Nothing renders the page, so only loading it in a browser surfaces it. Verified by hand — 500 before, 200 after. Co-Authored-By: Claude Opus 5 --- src/app/(app)/visits/pin-tool/page.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/app/(app)/visits/pin-tool/page.tsx b/src/app/(app)/visits/pin-tool/page.tsx index 0eb72a0..e0c6435 100644 --- a/src/app/(app)/visits/pin-tool/page.tsx +++ b/src/app/(app)/visits/pin-tool/page.tsx @@ -1,3 +1,5 @@ +"use client"; + import dynamic from "next/dynamic"; import { MapPinned } from "lucide-react"; @@ -5,6 +7,13 @@ import { MapPinned } from "lucide-react"; * Office pin tool — wraps the Leaflet-heavy view in `dynamic({ ssr: false })` * so the map never runs during SSR (Leaflet touches `window` on import). * Mirrors the supplier-map page pattern. + * + * The `"use client"` directive above is load-bearing, not decoration: + * Next refuses `ssr: false` on `next/dynamic` inside a Server Component + * ("not allowed with next/dynamic in Server Components"), and the page + * 500s at request time rather than failing the build — so neither + * `tsc` nor the unit tests catch its absence. `supplier-map/page.tsx` + * carries the same directive for the same reason. */ const PinToolView = dynamic( () => import("./pin-tool-view").then((module) => module.PinToolView),