fix: address CodeRabbit review feedback

- Remove overly broad 'invalid' check (can match PKCE errors, not just expired tokens)
- Rename handleSendNewLink → handleShowEmailForm (more accurate)
- Remove unused isLoading/linkSent props from ExpiredLinkMessage
- Simplify ExpiredLinkMessage component (single prop)
- Encode catch block error parameter for consistency
This commit is contained in:
Bentlybro
2026-02-16 12:13:35 +00:00
parent 6b6d3fec11
commit 7366a51d92
3 changed files with 11 additions and 29 deletions

View File

@@ -23,7 +23,6 @@ function ResetPasswordContent() {
const [isLoading, setIsLoading] = useState(false);
const [disabled, setDisabled] = useState(false);
const [showExpiredMessage, setShowExpiredMessage] = useState(false);
const [linkSent, setLinkSent] = useState(false);
useEffect(() => {
const error = searchParams.get("error");
@@ -32,14 +31,14 @@ function ResetPasswordContent() {
if (error || errorCode) {
// Check if this is an expired/used link error
// Avoid broad checks like "invalid" which can match unrelated errors (e.g., PKCE errors)
const descLower = errorDescription?.toLowerCase() || "";
const isExpiredOrUsed =
error === "link_expired" ||
errorCode === "otp_expired" ||
descLower.includes("expired") ||
descLower.includes("invalid") ||
// access_denied alone is too broad - only treat as expired when combined with otp indicators
(error === "access_denied" && errorCode === "otp_expired");
descLower.includes("already") ||
descLower.includes("used");
if (isExpiredOrUsed) {
setShowExpiredMessage(true);
@@ -98,7 +97,6 @@ function ResetPasswordContent() {
return;
}
setDisabled(true);
setLinkSent(true);
toast({
title: "Email Sent",
description:
@@ -109,7 +107,7 @@ function ResetPasswordContent() {
[sendEmailForm, toast],
);
function handleSendNewLink() {
function handleShowEmailForm() {
setShowExpiredMessage(false);
}
@@ -158,11 +156,7 @@ function ResetPasswordContent() {
return (
<div className="flex h-full min-h-[85vh] w-full flex-col items-center justify-center">
<AuthCard title="Reset Password">
<ExpiredLinkMessage
onSendNewLink={handleSendNewLink}
isLoading={isLoading}
linkSent={linkSent}
/>
<ExpiredLinkMessage onRequestNewLink={handleShowEmailForm} />
</AuthCard>
</div>
);

View File

@@ -27,10 +27,10 @@ export async function GET(request: NextRequest) {
if (!result.success) {
// Check for expired or used link errors
// Avoid broad checks like "invalid" which can match unrelated errors (e.g., PKCE errors)
const errorMessage = result.error?.toLowerCase() || "";
const isExpiredOrUsed =
errorMessage.includes("expired") ||
errorMessage.includes("invalid") ||
errorMessage.includes("otp_expired") ||
errorMessage.includes("already") ||
errorMessage.includes("used");
@@ -48,7 +48,7 @@ export async function GET(request: NextRequest) {
} catch (error) {
console.error("Password reset callback error:", error);
return NextResponse.redirect(
`${origin}/reset-password?error=Password reset failed`,
`${origin}/reset-password?error=${encodeURIComponent("Password reset failed")}`,
);
}
}

View File

@@ -3,16 +3,10 @@ import { Link } from "../atoms/Link/Link";
import { Text } from "../atoms/Text/Text";
interface Props {
onSendNewLink: () => void;
isLoading?: boolean;
linkSent?: boolean;
onRequestNewLink: () => void;
}
export function ExpiredLinkMessage({
onSendNewLink,
isLoading = false,
linkSent = false,
}: Props) {
export function ExpiredLinkMessage({ onRequestNewLink }: Props) {
return (
<div className="flex flex-col items-center gap-6">
<Text variant="h3" className="text-center">
@@ -21,14 +15,8 @@ export function ExpiredLinkMessage({
<Text variant="body-medium" className="text-center text-muted-foreground">
Enter your email below to request a new password reset link.
</Text>
<Button
variant="primary"
onClick={onSendNewLink}
loading={isLoading}
disabled={linkSent}
className="w-full"
>
{linkSent ? "Check Your Email" : "Request a New Link"}
<Button variant="primary" onClick={onRequestNewLink} className="w-full">
Request a New Link
</Button>
<div className="flex items-center gap-1">
<Text variant="body-small" className="text-muted-foreground">