diff --git a/apps/web/src/components/forms/forgot-password.tsx b/apps/web/src/components/forms/forgot-password.tsx index 240f1ece1..1dcd0f2b1 100644 --- a/apps/web/src/components/forms/forgot-password.tsx +++ b/apps/web/src/components/forms/forgot-password.tsx @@ -7,6 +7,7 @@ import { Loader } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; +import { TRPCClientError } from '@documenso/trpc/client'; import { trpc } from '@documenso/trpc/react'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; @@ -43,23 +44,33 @@ export const ForgotPasswordForm = ({ className }: ForgotPasswordFormProps) => { const { mutateAsync: forgotPassword } = trpc.profile.forgotPassword.useMutation(); const onFormSubmit = async ({ email }: TForgotPasswordFormSchema) => { - // TODO: Handle error with try/catch - await forgotPassword({ - email, - }); + try { + await forgotPassword({ email }); - toast({ - title: 'Password updated', - description: 'Your password has been updated successfully.', - duration: 5000, - }); + toast({ + title: 'Reset email sent', + description: 'Your password reset mail has been sent successfully.', + duration: 5000, + }); - await new Promise((resolve) => { - setTimeout(resolve, 2000); - }); - - reset(); - router.push('/check-email'); + reset(); + router.push('/check-email'); + } catch (err) { + if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') { + toast({ + title: 'An error occurred', + description: err.message, + variant: 'destructive', + }); + } else { + toast({ + title: 'An unknown error occurred', + variant: 'destructive', + description: + 'We encountered an unknown error while attempting to send your email. Please try again later.', + }); + } + } }; return ( diff --git a/apps/web/src/components/forms/reset-password.tsx b/apps/web/src/components/forms/reset-password.tsx index f4e83d203..af6944ef4 100644 --- a/apps/web/src/components/forms/reset-password.tsx +++ b/apps/web/src/components/forms/reset-password.tsx @@ -7,6 +7,7 @@ import { Loader } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; +import { TRPCClientError } from '@documenso/trpc/client'; import { trpc } from '@documenso/trpc/react'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; @@ -51,24 +52,38 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps) const { mutateAsync: resetPassword } = trpc.profile.resetPassword.useMutation(); - const onFormSubmit = async ({ password, repeatedPassword }: TResetPasswordFormSchema) => { - // TODO: Handle error with try/catch - console.log(password, repeatedPassword, token); + const onFormSubmit = async ({ password }: Omit) => { + try { + await resetPassword({ + password, + token, + }); - await resetPassword({ - password, - token, - }); + reset(); - reset(); + toast({ + title: 'Password updated', + description: 'Your password has been updated successfully.', + duration: 5000, + }); - toast({ - title: 'Password updated', - description: 'Your password has been updated successfully.', - duration: 5000, - }); - - router.push('/signin'); + router.push('/signin'); + } catch (err) { + if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') { + toast({ + title: 'An error occurred', + description: err.message, + variant: 'destructive', + }); + } else { + toast({ + title: 'An unknown error occurred', + variant: 'destructive', + description: + 'We encountered an unknown error while attempting to reset your password. Please try again later.', + }); + } + } }; return ( diff --git a/packages/lib/server-only/auth/send-reset-password.ts b/packages/lib/server-only/auth/send-reset-password.ts index 9cd09fe5a..95e49914d 100644 --- a/packages/lib/server-only/auth/send-reset-password.ts +++ b/packages/lib/server-only/auth/send-reset-password.ts @@ -10,6 +10,8 @@ export interface SendResetPasswordOptions { } export const sendResetPassword = async ({ userId }: SendResetPasswordOptions) => { + // TODO: Better Error Handling + const user = await prisma.user.findFirstOrThrow({ where: { id: userId, diff --git a/packages/lib/server-only/user/forgot-password.ts b/packages/lib/server-only/user/forgot-password.ts index e309c9006..fcf6b7766 100644 --- a/packages/lib/server-only/user/forgot-password.ts +++ b/packages/lib/server-only/user/forgot-password.ts @@ -6,14 +6,19 @@ import { TForgotPasswordFormSchema } from '@documenso/trpc/server/profile-router import { sendForgotPassword } from '../auth/send-forgot-password'; export const forgotPassword = async ({ email }: TForgotPasswordFormSchema) => { - const user = await prisma.user.findFirstOrThrow({ - where: { - email: email.toLowerCase(), - }, - }); + let user; + try { + user = await prisma.user.findFirstOrThrow({ + where: { + email: email.toLowerCase(), + }, + }); + } catch (error) { + throw new Error('No account found with that email address.'); + } if (!user) { - throw new Error('A password reset email has been sent.'); + throw new Error('No account found with that email address.'); } const existingToken = await prisma.passwordResetToken.findFirst({ @@ -42,7 +47,7 @@ export const forgotPassword = async ({ email }: TForgotPasswordFormSchema) => { }, }); } catch (error) { - throw new Error('Something went wrong'); + throw new Error('We were unable to send your email. Please try again.'); } return await sendForgotPassword({ diff --git a/packages/lib/server-only/user/reset-password.ts b/packages/lib/server-only/user/reset-password.ts index 58a93749c..f539115e9 100644 --- a/packages/lib/server-only/user/reset-password.ts +++ b/packages/lib/server-only/user/reset-password.ts @@ -12,7 +12,7 @@ export type ResetPasswordOptions = { export const resetPassword = async ({ token, password }: ResetPasswordOptions) => { if (!token) { - throw new Error('Invalid Token'); + throw new Error('Invalid token provided. Please try again.'); } const foundToken = await prisma.passwordResetToken.findFirstOrThrow({ @@ -25,13 +25,13 @@ export const resetPassword = async ({ token, password }: ResetPasswordOptions) = }); if (!foundToken) { - throw new Error('Invalid Token'); + throw new Error('Invalid token provided. Please try again.'); } const now = new Date(); if (now > foundToken.expiry) { - throw new Error('Token has expired'); + throw new Error('Token has expired. Please try again.'); } const isSamePassword = await compare(password, foundToken.User.password!); @@ -59,7 +59,7 @@ export const resetPassword = async ({ token, password }: ResetPasswordOptions) = ]); if (!transactions) { - throw new Error('Unable to update password'); + throw new Error('We were unable to reset your password. Please try again.'); } await sendResetPassword({ userId: foundToken.userId }); diff --git a/packages/trpc/server/profile-router/router.ts b/packages/trpc/server/profile-router/router.ts index adbb93a80..74920c0e6 100644 --- a/packages/trpc/server/profile-router/router.ts +++ b/packages/trpc/server/profile-router/router.ts @@ -69,8 +69,7 @@ export const profileRouter = router({ email, }); } catch (err) { - let message = - 'We were unable to update your profile. Please review the information you provided and try again.'; + let message = 'We were unable to send your email. Please try again.'; if (err instanceof Error) { message = err.message; @@ -92,8 +91,7 @@ export const profileRouter = router({ password, }); } catch (err) { - let message = - 'We were unable to update your profile. Please review the information you provided and try again.'; + let message = 'We were unable to reset your password. Please try again.'; if (err instanceof Error) { message = err.message;