From f7165bab09b41905d992769407b0b00eb2a68587 Mon Sep 17 00:00:00 2001 From: Aayan Date: Tue, 7 Jan 2025 18:44:58 +0530 Subject: [PATCH] forgotPasswordForm added and forget password feature enabled on login page --- app/(root)/auth/page.tsx | 68 +++++++------ components/auth/ForgotPasswordForm.tsx | 131 +++++++++++++++++++++++++ components/auth/loginForm.tsx | 36 ++++--- components/ui/alert.tsx | 59 +++++++++++ 4 files changed, 248 insertions(+), 46 deletions(-) create mode 100644 components/auth/ForgotPasswordForm.tsx create mode 100644 components/ui/alert.tsx diff --git a/app/(root)/auth/page.tsx b/app/(root)/auth/page.tsx index 03da36a..fb29dfc 100644 --- a/app/(root)/auth/page.tsx +++ b/app/(root)/auth/page.tsx @@ -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 ( -
-
-
-

- Get started -

- {!isLogin && ( -

- Already have an account?{' '} - -

- )} - {isLogin && ( -

- Don't have an account?{' '} - -

- )} -
- - {isLogin ? : } +
+
+
+

Get started

+ {!isLogin && ( +

+ Already have an account?{" "} + +

+ )} + {isLogin && ( +

+ Don't have an account?{" "} + +

+ )}
+ + {isLogin ? : }
+
); -} \ No newline at end of file +} diff --git a/components/auth/ForgotPasswordForm.tsx b/components/auth/ForgotPasswordForm.tsx new file mode 100644 index 0000000..4e99936 --- /dev/null +++ b/components/auth/ForgotPasswordForm.tsx @@ -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>({ + resolver: zodResolver(formSchema), + defaultValues: { email: "" }, + }); + + async function onSubmit(values: z.infer) { + 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 ( +
+ + + + Password reset instructions have been sent to your email address. + + + +
+ ); + } + + return ( +
+
+ + ( + + Email + + + + + + )} + /> + +
+

+ Enter your email address and we'll send you a link to reset your + password. +

+
+
+ + +
+ + +
+ ); +} diff --git a/components/auth/loginForm.tsx b/components/auth/loginForm.tsx index 024f8fb..c9059df 100644 --- a/components/auth/loginForm.tsx +++ b/components/auth/loginForm.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useState } from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; @@ -16,9 +14,10 @@ import { } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { createClient } from "@/lib/supabase/client"; -import { useToast } from "@/hooks/use-toast" -import { ToastAction } from "@/components/ui/toast" +import { useToast } from "@/hooks/use-toast"; +import { ToastAction } from "@/components/ui/toast"; import { OAuthButtons } from "./oAuthButton"; +import { ForgotPasswordForm } from "./ForgotPasswordForm"; const formSchema = z.object({ email: z.string().email("Invalid email address"), @@ -27,6 +26,7 @@ const formSchema = z.object({ export function LoginForm() { const [isLoading, setIsLoading] = useState(false); + const [showForgotPassword, setShowForgotPassword] = useState(false); const supabase = createClient(); const { toast } = useToast(); @@ -72,11 +72,8 @@ export function LoginForm() { if (data?.user) { toast({ description: "Successfully signed in! Redirecting...", - }) + }); window.location.href = "/dashboard"; - // setTimeout(() => { - // window.location.reload() - // }, 1000); } } catch (error) { console.error("Login error:", error); @@ -91,9 +88,12 @@ export function LoginForm() { } } + if (showForgotPassword) { + return setShowForgotPassword(false)} />; + } + return (
-
( - Password +
+ Password + +
@@ -122,7 +132,11 @@ export function LoginForm() {
)} /> - diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx new file mode 100644 index 0000000..5afd41d --- /dev/null +++ b/components/ui/alert.tsx @@ -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 & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)) +Alert.displayName = "Alert" + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertTitle.displayName = "AlertTitle" + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertDescription.displayName = "AlertDescription" + +export { Alert, AlertTitle, AlertDescription }