Back to comparisons

Auth Flow

Login and forgot-password forms. AI output missed error state resets, hardcoded messages, and accessibility attributes. The production version fixes all six issues found in review.

AI Generated
1export function LoginForm() {
2 const dispatch = useAppDispatch();
3 const { status } = useAppSelector((s) => s.auth);
4
5 const {
6 register,
7 handleSubmit,
8 formState: { errors },
9 } = useForm<LoginValues>({
10 resolver: zodResolver(loginSchema),
11 mode: "onBlur",
12 });
13
14 function onSubmit(data: LoginValues) {
15 dispatch(loginUser(data));
16 }
17
18 const isLoading = status === "loading";
19
20 return (
21 <form onSubmit={handleSubmit(onSubmit)} className="grid gap-4">
22 {status === "failed" && (
23 <div role="alert" className="text-sm text-destructive">
24 Login failed. Please try again.
25 </div>
26 )}
27
28 <div className="grid gap-2">
29 <Label htmlFor="password">Password</Label>
30 <Input
31 id="password"
32 type="password"
33 autoComplete="current-password"
34 aria-invalid={!!errors.password}
35 {...register("password")}
36 />
37 {errors.password && (
38 <p className="text-sm text-destructive">
39 {errors.password.message}
40 </p>
41 )}
42 </div>
43
44 <Button type="submit" disabled={isLoading}>
45 {isLoading ? "Signing in..." : "Sign in"}
46 </Button>
47 </form>
48 );
49}
fixNo error state reset on mountL1–3

Navigating from /signup back to /login keeps a stale error banner because the Redux error state is never cleared. The AI did not add a useEffect to dispatch clearError().

fixHardcoded error messageL24–27

The AI used a static "Login failed. Please try again." string instead of rendering the actual error from the API response stored in Redux state.

fixMissing aria-describedby on password inputL33

The password input has no aria-describedby linking it to the error message. Screen readers cannot associate the validation error with the field.

fixError state cleared on mountL14–16

A useEffect dispatches clearError() when the component mounts, preventing stale errors from a previous screen from persisting.

fixDynamic error from API responseL26–29

The error message comes from the Redux store, which is populated from the server response via rejectWithValue. Users see the actual reason their login failed.

fixaria-describedby connects input to errorL37

The password input links to "password-error" via aria-describedby, and the error paragraph has a matching id. Screen readers now announce the error when the field is focused.