Skip to content

Commit 292f014

Browse files
author
Boopathi
committed
Fix: Move all hooks and handlers to top level, ensure React rules-of-hooks compliance, build passes
1 parent 3188301 commit 292f014

File tree

1 file changed

+38
-61
lines changed

1 file changed

+38
-61
lines changed

src/app/auth/action/page.tsx

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ const ResendVerificationForm = () => {
102102

103103

104104
const ActionHandlerContent: React.FC = () => {
105+
// All hooks at the very top
105106
const router = useRouter();
106107
const searchParams = useSearchParams();
107108
const { toast } = useToast();
108109
const { auth } = useFirebaseAuth();
109-
110110
const [mode, setMode] = React.useState<Action>(null);
111111
const [actionCode, setActionCode] = React.useState<string | null>(null);
112112
const [loading, setLoading] = React.useState(true);
@@ -115,24 +115,29 @@ const ActionHandlerContent: React.FC = () => {
115115
const [info, setInfo] = React.useState<{ email: string; from: 'verifyEmail' | 'resetPassword' } | null>(null);
116116
const [success, setSuccess] = React.useState(false);
117117
const [redirecting, setRedirecting] = React.useState(false);
118-
// Moved up: fallback email verification check states
119-
const [showCheckVerification, setShowCheckVerification] = React.useState(false);
118+
const [showVerifiedSuccess, setShowVerifiedSuccess] = React.useState(false);
120119
const [checkEmail, setCheckEmail] = React.useState("");
121120
const [checking, setChecking] = React.useState(false);
122121
const [checkResult, setCheckResult] = React.useState<null | "verified" | "not_verified" | "error">(null);
123122
const [checkError, setCheckError] = React.useState("");
124-
125123
const form = useForm<PasswordResetValues>({
126124
resolver: zodResolver(passwordResetSchema),
127125
});
128-
126+
// Move handlePasswordResetSubmit to the top level
127+
const handlePasswordResetSubmit = async (data: PasswordResetValues) => {
128+
if (!auth || !actionCode) return;
129+
try {
130+
await confirmPasswordReset(auth, actionCode, data.password);
131+
setSuccess(true);
132+
} catch (err) {
133+
setError("Failed to reset password. The link may have expired. Please try again.");
134+
}
135+
};
129136
React.useEffect(() => {
130137
const modeParam = searchParams.getAll('mode')[0] as Action; // Always get the first mode param
131138
const codeParam = searchParams.get('oobCode');
132-
133139
setMode(modeParam);
134140
setActionCode(codeParam);
135-
136141
if (!auth || !modeParam || !codeParam) {
137142
if(!auth) setLoading(false);
138143
if (!modeParam || !codeParam) {
@@ -141,17 +146,14 @@ const ActionHandlerContent: React.FC = () => {
141146
}
142147
return;
143148
}
144-
145149
const handleAction = async () => {
146150
try {
147151
const actionInfo = await checkActionCode(auth, codeParam);
148152
const { operation } = actionInfo;
149153
const { email } = actionInfo.data;
150-
151154
if (!email) {
152155
throw new Error("Invalid action code: email is missing.");
153156
}
154-
155157
if (operation === 'VERIFY_EMAIL') {
156158
await applyActionCode(auth, codeParam);
157159
setSuccess(true);
@@ -172,54 +174,8 @@ const ActionHandlerContent: React.FC = () => {
172174
setLoading(false);
173175
}
174176
};
175-
176177
handleAction();
177-
178178
}, [searchParams, auth]);
179-
180-
const handlePasswordResetSubmit = async (data: PasswordResetValues) => {
181-
if (!auth || !actionCode) return;
182-
183-
try {
184-
await confirmPasswordReset(auth, actionCode, data.password);
185-
setSuccess(true);
186-
} catch (err) {
187-
setError("Failed to reset password. The link may have expired. Please try again.");
188-
}
189-
}
190-
191-
if (loading) {
192-
return (
193-
<div className="text-center">
194-
<Loader2 className="h-12 w-12 animate-spin text-primary mx-auto mb-4" />
195-
<p className="text-muted-foreground">Verifying link...</p>
196-
</div>
197-
);
198-
}
199-
200-
if (showResendForm) {
201-
return <ResendVerificationForm />;
202-
}
203-
204-
if (error) {
205-
return (
206-
<div className="text-center">
207-
<XCircle className="h-12 w-12 text-destructive mx-auto mb-4" />
208-
<h2 className="text-2xl font-bold mb-2">Action Failed</h2>
209-
<p className="text-muted-foreground mb-6">{error}</p>
210-
<div className="flex flex-col gap-2 items-center">
211-
<Button onClick={() => router.push('/')} variant="secondary">Go to Homepage</Button>
212-
<Button onClick={() => router.push('/?action=login')} variant="default">Go to Login</Button>
213-
<Button onClick={() => setShowResendForm(true)} variant="outline">Resend Verification Email</Button>
214-
</div>
215-
</div>
216-
);
217-
}
218-
219-
// Add a new state to track if we should show the verified success UI
220-
const [showVerifiedSuccess, setShowVerifiedSuccess] = React.useState(false);
221-
222-
// Move the async redirect logic into useEffect
223179
React.useEffect(() => {
224180
if (success && info?.from === 'verifyEmail') {
225181
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
@@ -262,13 +218,36 @@ const ActionHandlerContent: React.FC = () => {
262218
}
263219
})();
264220
} else {
265-
// No token, just show the verified success UI
266221
setShowVerifiedSuccess(true);
267222
}
268223
}
269224
}, [success, info, router, toast]);
270-
271-
// In render, show the verified success UI if set
225+
// All hooks above, now logic and returns below
226+
if (loading) {
227+
return (
228+
<div className="text-center">
229+
<Loader2 className="h-12 w-12 animate-spin text-primary mx-auto mb-4" />
230+
<p className="text-muted-foreground">Verifying link...</p>
231+
</div>
232+
);
233+
}
234+
if (showResendForm) {
235+
return <ResendVerificationForm />;
236+
}
237+
if (error) {
238+
return (
239+
<div className="text-center">
240+
<XCircle className="h-12 w-12 text-destructive mx-auto mb-4" />
241+
<h2 className="text-2xl font-bold mb-2">Action Failed</h2>
242+
<p className="text-muted-foreground mb-6">{error}</p>
243+
<div className="flex flex-col gap-2 items-center">
244+
<Button onClick={() => router.push('/')} variant="secondary">Go to Homepage</Button>
245+
<Button onClick={() => router.push('/?action=login')} variant="default">Go to Login</Button>
246+
<Button onClick={() => setShowResendForm(true)} variant="outline">Resend Verification Email</Button>
247+
</div>
248+
</div>
249+
);
250+
}
272251
if (showVerifiedSuccess) {
273252
return (
274253
<div className="text-center">
@@ -279,7 +258,6 @@ const ActionHandlerContent: React.FC = () => {
279258
</div>
280259
);
281260
}
282-
283261
if (mode === 'resetPassword' && info) {
284262
return (
285263
<div>
@@ -322,7 +300,6 @@ const ActionHandlerContent: React.FC = () => {
322300
</div>
323301
);
324302
}
325-
326303
// Fallback for any other state
327304
return (
328305
<div className="text-center">

0 commit comments

Comments
 (0)