diff options
Diffstat (limited to 'src/app/login/page.tsx')
| -rw-r--r-- | src/app/login/page.tsx | 176 |
1 files changed, 114 insertions, 62 deletions
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index ae89e63..c8a80f1 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -22,11 +22,14 @@ export default function SignInPage() { const [error, setError] = useState("") const router = useRouter() + const [showTwoFactor, setShowTwoFactor] = useState(false) + const form = useForm<LoginInput>({ resolver: zodResolver(loginSchema), defaultValues: { email: "", password: "", + twoFactorCode: "", }, }) @@ -38,11 +41,17 @@ export default function SignInPage() { const result = await signIn("credentials", { email: data.email, password: data.password, + twoFactorCode: data.twoFactorCode, redirect: false, }) if (result?.error) { - setError("Invalid email or password") + if (result.error === "2FA_REQUIRED") { + setShowTwoFactor(true) + // Don't clear password here so user can just enter code + } else { + setError(result.error) + } } else if (result?.ok) { router.push("/") router.refresh() @@ -62,7 +71,9 @@ export default function SignInPage() { <CardHeader className="space-y-1"> <CardTitle className="text-2xl text-center">Sign In</CardTitle> <CardDescription className="text-center"> - Enter your email and password to access your account + {showTwoFactor + ? "Enter the code from your authenticator app" + : "Enter your email and password to access your account"} </CardDescription> </CardHeader> <CardContent className="space-y-4"> @@ -74,76 +85,117 @@ export default function SignInPage() { <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> - <FormField - control={form.control} - name="email" - render={({ field }) => ( - <FormItem> - <FormLabel>Email</FormLabel> - <FormControl> - <Input - type="email" - placeholder="john@example.com" - autoComplete="email" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - <FormField - control={form.control} - name="password" - render={({ field }) => ( - <FormItem> - <FormLabel>Password</FormLabel> - <FormControl> - <div className="relative"> + {!showTwoFactor ? ( + <> + <FormField + control={form.control} + name="email" + render={({ field }) => ( + <FormItem> + <FormLabel>Email</FormLabel> + <FormControl> + <Input + type="email" + placeholder="john@example.com" + autoComplete="email" + {...field} + /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + <FormField + control={form.control} + name="password" + render={({ field }) => ( + <FormItem> + <FormLabel>Password</FormLabel> + <FormControl> + <div className="relative"> + <Input + type={showPassword ? "text" : "password"} + placeholder="Enter your password" + autoComplete="current-password" + {...field} + /> + <Button + type="button" + variant="ghost" + size="sm" + className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent" + onClick={() => setShowPassword(!showPassword)} + > + {showPassword ? ( + <EyeOff className="h-4 w-4" /> + ) : ( + <Eye className="h-4 w-4" /> + )} + </Button> + </div> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + </> + ) : ( + <FormField + control={form.control} + name="twoFactorCode" + render={({ field }) => ( + <FormItem> + <FormLabel>Two-Factor Code</FormLabel> + <FormControl> <Input - type={showPassword ? "text" : "password"} - placeholder="Enter your password" - autoComplete="current-password" + placeholder="000000" + autoComplete="one-time-code" + maxLength={6} {...field} + autoFocus /> - <Button - type="button" - variant="ghost" - size="sm" - className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent" - onClick={() => setShowPassword(!showPassword)} - > - {showPassword ? ( - <EyeOff className="h-4 w-4" /> - ) : ( - <Eye className="h-4 w-4" /> - )} - </Button> - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + )} + <Button type="submit" className="w-full" disabled={isLoading}> {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} - Sign In + {showTwoFactor ? "Verify" : "Sign In"} </Button> </form> </Form> - <div className="text-center text-sm"> - <span className="text-muted-foreground">Don't have an account? </span> - <Link href="/signup" className="text-primary hover:underline font-medium"> - Sign up - </Link> - </div> + {!showTwoFactor && ( + <> + <div className="text-center text-sm"> + <span className="text-muted-foreground">Don't have an account? </span> + <Link href="/signup" className="text-primary hover:underline font-medium"> + Sign up + </Link> + </div> - <div className="text-center"> - <Button variant="link" className="text-sm text-muted-foreground"> - Forgot your password? - </Button> - </div> + <div className="text-center"> + <Button variant="link" className="text-sm text-muted-foreground"> + Forgot your password? + </Button> + </div> + </> + )} + + {showTwoFactor && ( + <div className="text-center"> + <Button + variant="link" + className="text-sm text-muted-foreground" + onClick={() => setShowTwoFactor(false)} + > + Back to login + </Button> + </div> + )} </CardContent> </Card> </div> |
