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:
1 parent
847ac97bde
commit
01b4f18a97
1 file changed
+17
-40
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user