diff --git a/apps/web/src/app/(unauthenticated)/check-email/page.tsx b/apps/web/src/app/(unauthenticated)/check-email/page.tsx new file mode 100644 index 000000000..26039f4ae --- /dev/null +++ b/apps/web/src/app/(unauthenticated)/check-email/page.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +import backgroundPattern from '~/assets/background-pattern.png'; + +export default function ForgotPasswordPage() { + return ( +
+
+
+ background pattern +
+ +
+

Reset Pasword

+ +

+ Please check your email for reset instructions +

+ +

+ + Sign in + +

+
+
+
+ ); +} diff --git a/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx b/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx new file mode 100644 index 000000000..73cfd01ca --- /dev/null +++ b/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx @@ -0,0 +1,38 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +import backgroundPattern from '~/assets/background-pattern.png'; +import { ForgotPasswordForm } from '~/components/forms/forgot-password'; + +export default function ForgotPasswordPage() { + return ( +
+
+
+ background pattern +
+ +
+

Forgot Password?

+ +

+ No worries, we'll send you reset instructions. +

+ + + +

+ Don't have an account?{' '} + + Sign up + +

+
+
+
+ ); +} diff --git a/apps/web/src/components/forms/forgot-password.tsx b/apps/web/src/components/forms/forgot-password.tsx new file mode 100644 index 000000000..94b5ea0cd --- /dev/null +++ b/apps/web/src/components/forms/forgot-password.tsx @@ -0,0 +1,104 @@ +'use client'; + +import { useEffect } from 'react'; + +import { useRouter, useSearchParams } from 'next/navigation'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { Loader } from 'lucide-react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import { ErrorCode, isErrorCode } from '@documenso/lib/next-auth/error-codes'; +import { cn } from '@documenso/ui/lib/utils'; +import { Button } from '@documenso/ui/primitives/button'; +import { Input } from '@documenso/ui/primitives/input'; +import { Label } from '@documenso/ui/primitives/label'; +import { useToast } from '@documenso/ui/primitives/use-toast'; + +const ERROR_MESSAGES = { + [ErrorCode.CREDENTIALS_NOT_FOUND]: 'No account found with that email address.', + [ErrorCode.INCORRECT_EMAIL_PASSWORD]: 'No account found with that email address.', + [ErrorCode.USER_MISSING_PASSWORD]: + 'This account appears to be using a social login method, please sign in using that method', +}; + +export const ZForgotPasswordFormSchema = z.object({ + email: z.string().email().min(1), +}); + +export type TForgotPasswordFormSchema = z.infer; + +export type ForgotPasswordFormProps = { + className?: string; +}; + +export const ForgotPasswordForm = ({ className }: ForgotPasswordFormProps) => { + const searchParams = useSearchParams(); + const router = useRouter(); + + const { toast } = useToast(); + + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm({ + values: { + email: '', + }, + resolver: zodResolver(ZForgotPasswordFormSchema), + }); + + const errorCode = searchParams?.get('error'); + + useEffect(() => { + let timeout: NodeJS.Timeout | null = null; + + if (isErrorCode(errorCode)) { + timeout = setTimeout(() => { + toast({ + variant: 'destructive', + description: ERROR_MESSAGES[errorCode] ?? 'An unknown error occurred', + }); + }, 0); + } + + return () => { + if (timeout) { + clearTimeout(timeout); + } + }; + }, [errorCode, toast]); + + const onFormSubmit = ({ email }: TForgotPasswordFormSchema) => { + // check if the email is available + // if not, throw an error + // if the email is available, create a password reset token and send an email + + console.log(email); + router.push('/check-email'); + }; + + return ( +
+
+ + + + + {errors.email && {errors.email.message}} +
+ + +
+ ); +}; diff --git a/apps/web/src/components/forms/signin.tsx b/apps/web/src/components/forms/signin.tsx index d9d727afc..a06c04c72 100644 --- a/apps/web/src/components/forms/signin.tsx +++ b/apps/web/src/components/forms/signin.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; +import Link from 'next/link'; import { useSearchParams } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -123,8 +124,11 @@ export const SignInForm = ({ className }: SignInFormProps) => {
-