Fix Next.js 16 build: wrap /change-password useSearchParams in Suspense

The static prerender step bails on a CSR-only component that reads
useSearchParams() outside a Suspense boundary. Caught by the first real
production build (Turbopack/standalone output).

Split ChangePasswordPage into an outer Suspense shell (default export)
and an inner ChangePasswordForm that owns the useSearchParams() call.
Fallback is null — the shell renders for ~1ms before the client hydrates
the form, invisible.

No behavior change. No other auth pages use useSearchParams.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
DJP 2026-04-20 20:25:04 -04:00
parent 7e7ef7b7c1
commit be46089569

View file

@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { Suspense, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -8,7 +8,18 @@ import { Label } from "@/components/ui/label";
const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
// Next.js 16 requires useSearchParams() consumers to live under a Suspense
// boundary so the static prerender has something to bail out into. Split the
// inner form out; the default export is just the Suspense shell.
export default function ChangePasswordPage() {
return (
<Suspense fallback={null}>
<ChangePasswordForm />
</Suspense>
);
}
function ChangePasswordForm() {
const router = useRouter();
const search = useSearchParams();
const isFirstLogin = search.get("first") === "1";