'use client'; import { useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { signIn } from 'next-auth/react'; import { useForm } from 'react-hook-form'; import { FcGoogle } from 'react-icons/fc'; import { z } from 'zod'; import { ErrorCode, isErrorCode } from '@documenso/lib/next-auth/error-codes'; import { ZCurrentPasswordSchema } from '@documenso/trpc/server/auth-router/schema'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@documenso/ui/primitives/dialog'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; import { PasswordInput } from '@documenso/ui/primitives/password-input'; import { useToast } from '@documenso/ui/primitives/use-toast'; const ERROR_MESSAGES: Partial> = { [ErrorCode.CREDENTIALS_NOT_FOUND]: 'The email or password provided is incorrect', [ErrorCode.INCORRECT_EMAIL_PASSWORD]: 'The email or password provided is incorrect', [ErrorCode.USER_MISSING_PASSWORD]: 'This account appears to be using a social login method, please sign in using that method', [ErrorCode.INCORRECT_TWO_FACTOR_CODE]: 'The two-factor authentication code provided is incorrect', [ErrorCode.INCORRECT_TWO_FACTOR_BACKUP_CODE]: 'The backup code provided is incorrect', }; const TwoFactorEnabledErrorCode = ErrorCode.TWO_FACTOR_MISSING_CREDENTIALS; const LOGIN_REDIRECT_PATH = '/documents'; export const ZSignInFormSchema = z.object({ email: z.string().email().min(1), password: ZCurrentPasswordSchema, totpCode: z.string().trim().optional(), backupCode: z.string().trim().optional(), }); export type TSignInFormSchema = z.infer; export type SignInFormProps = { className?: string; initialEmail?: string; isGoogleSSOEnabled?: boolean; }; export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: SignInFormProps) => { const { toast } = useToast(); const [isTwoFactorAuthenticationDialogOpen, setIsTwoFactorAuthenticationDialogOpen] = useState(false); const [twoFactorAuthenticationMethod, setTwoFactorAuthenticationMethod] = useState< 'totp' | 'backup' >('totp'); const form = useForm({ values: { email: initialEmail ?? '', password: '', totpCode: '', backupCode: '', }, resolver: zodResolver(ZSignInFormSchema), }); const isSubmitting = form.formState.isSubmitting; const onCloseTwoFactorAuthenticationDialog = () => { form.setValue('totpCode', ''); form.setValue('backupCode', ''); setIsTwoFactorAuthenticationDialogOpen(false); }; const onToggleTwoFactorAuthenticationMethodClick = () => { const method = twoFactorAuthenticationMethod === 'totp' ? 'backup' : 'totp'; if (method === 'totp') { form.setValue('backupCode', ''); } if (method === 'backup') { form.setValue('totpCode', ''); } setTwoFactorAuthenticationMethod(method); }; const onFormSubmit = async ({ email, password, totpCode, backupCode }: TSignInFormSchema) => { try { const credentials: Record = { email, password, }; if (totpCode) { credentials.totpCode = totpCode; } if (backupCode) { credentials.backupCode = backupCode; } const result = await signIn('credentials', { ...credentials, callbackUrl: LOGIN_REDIRECT_PATH, redirect: false, }); if (result?.error && isErrorCode(result.error)) { if (result.error === TwoFactorEnabledErrorCode) { setIsTwoFactorAuthenticationDialogOpen(true); return; } const errorMessage = ERROR_MESSAGES[result.error]; toast({ variant: 'destructive', title: 'Unable to sign in', description: errorMessage ?? 'An unknown error occurred', }); return; } if (!result?.url) { throw new Error('An unknown error occurred'); } window.location.href = result.url; } catch (err) { toast({ title: 'An unknown error occurred', description: 'We encountered an unknown error while attempting to sign you In. Please try again later.', }); } }; const onSignInWithGoogleClick = async () => { try { await signIn('google', { callbackUrl: LOGIN_REDIRECT_PATH }); } catch (err) { toast({ title: 'An unknown error occurred', description: 'We encountered an unknown error while attempting to sign you In. Please try again later.', variant: 'destructive', }); } }; return (
( Email )} /> ( Password )} />
{isGoogleSSOEnabled && ( <>
Or continue with
)} Two-Factor Authentication
{twoFactorAuthenticationMethod === 'totp' && ( ( Authentication Token )} /> )} {twoFactorAuthenticationMethod === 'backup' && ( ( Backup Code )} /> )}
); };