fix: wrap useSearchParams in Suspense on reset-password page

Next.js static rendering requires useSearchParams() to be inside a
Suspense boundary. Splits page into ResetPasswordContent (inner) +
ResetPasswordPage (Suspense wrapper). Caught by npm run build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Sonnet 4.6 committed 2026-06-13 12:21:07 +02:00
1 parent 847ac97bde
commit 01b4f18a97
1 file changed
+17 -40
+17 -40
View File
@@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { Suspense, useState } from "react";
import { useSignIn } from "@clerk/nextjs";
import { useRouter, useSearchParams } from "next/navigation";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -11,26 +11,11 @@ import { Label } from "@/components/ui/label";
/**
* Reset password page — /reset-password
*
* Completes Clerk's password reset flow using the Clerk 7 SignInFutureResource API:
* 1. signIn.resetPasswordEmailCode.verifyCode({ code }) — verify the emailed code
* 2. signIn.resetPasswordEmailCode.submitPassword({ password }) — set new password
* 3. signIn.finalize() — create the session and redirect
*
* The reset code comes from the Clerk-generated email link URL params.
*
* UI-SPEC: Auth Screens — Reset Password
* Heading: "Set a new password"
* CTA: "Reset password"
* Error states:
* - "Password must be at least 8 characters."
* - "Passwords don't match."
*
* Deviation note: Clerk 7 uses the new SignInFutureResource API. The old
* useSignIn().attemptFirstFactor() is replaced by resetPasswordEmailCode.verifyCode()
* + resetPasswordEmailCode.submitPassword() + finalize().
* useSearchParams() must be inside a Suspense boundary for static rendering.
* ResetPasswordContent is the real component; default export wraps it in Suspense.
*/
export default function ResetPasswordPage() {
// Clerk 7: useSignIn returns { errors, fetchStatus, signIn: SignInFutureResource }
function ResetPasswordContent() {
const { signIn, fetchStatus } = useSignIn();
const router = useRouter();
const searchParams = useSearchParams();
@@ -43,10 +28,8 @@ export default function ResetPasswordPage() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
// Client-side validation per UI-SPEC Error States
if (password.length < 8) {
setError("Password must be at least 8 characters.");
return;
@@ -57,13 +40,11 @@ export default function ResetPasswordPage() {
}
try {
// Clerk appends the code to the URL when the user clicks the email reset link
const code =
searchParams.get("__clerk_ticket") ??
searchParams.get("code") ??
"";
// Step 1: verify the reset code from the email
const verifyResult = await signIn.resetPasswordEmailCode.verifyCode({ code });
if (verifyResult.error) {
setError(
@@ -73,19 +54,12 @@ export default function ResetPasswordPage() {
return;
}
// Step 2: submit the new password
const submitResult = await signIn.resetPasswordEmailCode.submitPassword({
password,
});
const submitResult = await signIn.resetPasswordEmailCode.submitPassword({ password });
if (submitResult.error) {
setError(
submitResult.error.message ??
"Could not set new password. Please try again."
);
setError(submitResult.error.message ?? "Could not set new password. Please try again.");
return;
}
// Step 3: finalize the session
const finalizeResult = await signIn.finalize();
if (finalizeResult.error) {
setError(
@@ -98,19 +72,14 @@ export default function ResetPasswordPage() {
router.push("/pets");
} catch (err: unknown) {
const clerkError = err as { errors?: Array<{ message: string }> };
setError(
clerkError.errors?.[0]?.message ??
"Something went wrong. Please try again."
);
setError(clerkError.errors?.[0]?.message ?? "Something went wrong. Please try again.");
}
};
return (
<Card>
<CardHeader>
<CardTitle className="text-xl font-semibold">
Set a new password
</CardTitle>
<CardTitle className="text-xl font-semibold">Set a new password</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
@@ -157,3 +126,11 @@ export default function ResetPasswordPage() {
</Card>
);
}
export default function ResetPasswordPage() {
return (
<Suspense>
<ResetPasswordContent />
</Suspense>
);
}