-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
forgotPasswordForm added and forget password feature enabled on login…
… page
- Loading branch information
Showing
4 changed files
with
248 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,43 @@ | ||
"use client"; | ||
|
||
import { useState } from 'react'; | ||
import { LoginForm } from '@/components/auth/loginForm'; | ||
import { SignupForm } from '@/components/auth/signupForm'; | ||
import { useState } from "react"; | ||
import { LoginForm } from "@/components/auth/loginForm"; | ||
import { SignupForm } from "@/components/auth/signupForm"; | ||
|
||
export default function AuthPage() { | ||
const [isLogin, setIsLogin] = useState(true); | ||
|
||
return ( | ||
<div className="min-h-screen w-full flex items-center justify-center p-8"> | ||
<div className="w-full max-w-md space-y-6"> | ||
<div className="space-y-2"> | ||
<h1 className="text-5xl font-bold tracking-tight"> | ||
Get started | ||
</h1> | ||
{!isLogin && ( | ||
<p className="text-muted-foreground"> | ||
Already have an account?{' '} | ||
<button | ||
onClick={() => setIsLogin(true)} | ||
className="text-primary hover:underline font-medium" | ||
> | ||
Sign in | ||
</button> | ||
</p> | ||
)} | ||
{isLogin && ( | ||
<p className="text-muted-foreground"> | ||
Don't have an account?{' '} | ||
<button | ||
onClick={() => setIsLogin(false)} | ||
className="text-primary hover:underline font-medium" | ||
> | ||
Sign up | ||
</button> | ||
</p> | ||
)} | ||
</div> | ||
|
||
{isLogin ? <LoginForm /> : <SignupForm />} | ||
<div className="min-h-screen w-full flex items-center justify-center p-8"> | ||
<div className="w-full max-w-md space-y-6"> | ||
<div className="space-y-2"> | ||
<h1 className="text-5xl font-bold tracking-tight">Get started</h1> | ||
{!isLogin && ( | ||
<p className="text-muted-foreground"> | ||
Already have an account?{" "} | ||
<button | ||
onClick={() => setIsLogin(true)} | ||
className="text-primary text-indigo-600 hover:underline font-bold" | ||
> | ||
Sign in | ||
</button> | ||
</p> | ||
)} | ||
{isLogin && ( | ||
<p className="text-muted-foreground"> | ||
Don't have an account?{" "} | ||
<button | ||
onClick={() => setIsLogin(false)} | ||
className="text-primary text-indigo-600 hover:underline font-bold" | ||
> | ||
Sign up | ||
</button> | ||
</p> | ||
)} | ||
</div> | ||
|
||
{isLogin ? <LoginForm /> : <SignupForm />} | ||
</div> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { useState } from "react"; | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { useForm } from "react-hook-form"; | ||
import * as z from "zod"; | ||
import { Loader2, ArrowLeft, CheckCircle2 } from "lucide-react"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form"; | ||
import { Input } from "@/components/ui/input"; | ||
import { createClient } from "@/lib/supabase/client"; | ||
import { useToast } from "@/hooks/use-toast"; | ||
import { Alert, AlertDescription } from "@/components/ui/alert"; | ||
|
||
const formSchema = z.object({ | ||
email: z.string().email("Invalid email address"), | ||
}); | ||
|
||
export function ForgotPasswordForm({ onBack }: { onBack: () => void }) { | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [isSuccess, setIsSuccess] = useState(false); | ||
const supabase = createClient(); | ||
const { toast } = useToast(); | ||
|
||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
defaultValues: { email: "" }, | ||
}); | ||
|
||
async function onSubmit(values: z.infer<typeof formSchema>) { | ||
setIsLoading(true); | ||
try { | ||
const { error } = await supabase.auth.resetPasswordForEmail( | ||
values.email, | ||
{ | ||
redirectTo: `${window.location.origin}/reset-password`, | ||
} | ||
); | ||
|
||
if (error) { | ||
toast({ | ||
variant: "destructive", | ||
title: "Error", | ||
description: error.message, | ||
}); | ||
return; | ||
} | ||
|
||
setIsSuccess(true); | ||
} catch (error) { | ||
console.error("Password reset error:", error); | ||
toast({ | ||
variant: "destructive", | ||
title: "Error", | ||
description: (error as Error).message, | ||
}); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
} | ||
|
||
if (isSuccess) { | ||
return ( | ||
<div className="space-y-6"> | ||
<Alert> | ||
<CheckCircle2 className="h-4 w-4" /> | ||
<AlertDescription> | ||
Password reset instructions have been sent to your email address. | ||
</AlertDescription> | ||
</Alert> | ||
<Button variant="outline" className="w-full" onClick={onBack}> | ||
<ArrowLeft className="mr-2 h-4 w-4" /> | ||
Back to Login | ||
</Button> | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div> | ||
<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 placeholder="[email protected]" {...field} /> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
|
||
<div className="text-center"> | ||
<p className="text-sm text-muted-foreground"> | ||
Enter your email address and we'll send you a link to reset your | ||
password. | ||
</p> | ||
</div> | ||
<div className="space-y-2"> | ||
<Button | ||
type="submit" | ||
className="w-full bg-indigo-600 hover:bg-indigo-800" | ||
disabled={isLoading} | ||
> | ||
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} | ||
Send Reset Instructions | ||
</Button> | ||
<Button | ||
type="button" | ||
variant="outline" | ||
className="w-full" | ||
onClick={onBack} | ||
> | ||
<ArrowLeft className="mr-2 h-4 w-4" /> | ||
Back to Login | ||
</Button> | ||
</div> | ||
</form> | ||
</Form> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import * as React from "react" | ||
import { cva, type VariantProps } from "class-variance-authority" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const alertVariants = cva( | ||
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", | ||
{ | ||
variants: { | ||
variant: { | ||
default: "bg-background text-foreground", | ||
destructive: | ||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: "default", | ||
}, | ||
} | ||
) | ||
|
||
const Alert = React.forwardRef< | ||
HTMLDivElement, | ||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants> | ||
>(({ className, variant, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
role="alert" | ||
className={cn(alertVariants({ variant }), className)} | ||
{...props} | ||
/> | ||
)) | ||
Alert.displayName = "Alert" | ||
|
||
const AlertTitle = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLHeadingElement> | ||
>(({ className, ...props }, ref) => ( | ||
<h5 | ||
ref={ref} | ||
className={cn("mb-1 font-medium leading-none tracking-tight", className)} | ||
{...props} | ||
/> | ||
)) | ||
AlertTitle.displayName = "AlertTitle" | ||
|
||
const AlertDescription = React.forwardRef< | ||
HTMLParagraphElement, | ||
React.HTMLAttributes<HTMLParagraphElement> | ||
>(({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn("text-sm [&_p]:leading-relaxed", className)} | ||
{...props} | ||
/> | ||
)) | ||
AlertDescription.displayName = "AlertDescription" | ||
|
||
export { Alert, AlertTitle, AlertDescription } |