import { zodResolver } from '@hookform/resolvers/zod' import { SupportCategories } from '@supabase/shared-types/out/constants' import type { Factor } from '@supabase/supabase-js' import { useQueryClient } from '@tanstack/react-query' import { useAuthError } from 'common' import { Lock } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { SubmitHandler, useForm } from 'react-hook-form' import { Button, Form, FormControl, FormField, Input } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import z from 'zod' import { SupportLink } from '../Support/SupportLink' import AlertError from '@/components/ui/AlertError' import { useMfaChallengeAndVerifyMutation } from '@/data/profile/mfa-challenge-and-verify-mutation' import { useMfaListFactorsQuery } from '@/data/profile/mfa-list-factors-query' import { useSignOut } from '@/lib/auth' import { getReturnToPath } from '@/lib/gotrue' const schema = z.object({ code: z.string().min(1, 'MFA Code is required'), }) const formId = 'sign-in-mfa-form' interface SignInMfaFormProps { context?: 'forgot-password' | 'sign-in' } export const SignInMfaForm = ({ context = 'sign-in' }: SignInMfaFormProps) => { const router = useRouter() const signOut = useSignOut() const queryClient = useQueryClient() const [selectedFactor, setSelectedFactor] = useState(null) const form = useForm>({ resolver: zodResolver(schema as any), defaultValues: { code: '' }, }) const { code } = form.watch() const { data: factors, error: factorsError, isError: isErrorFactors, isSuccess: isSuccessFactors, isPending: isLoadingFactors, } = useMfaListFactorsQuery() const { mutate: mfaChallengeAndVerify, isPending: isVerifying, isSuccess, } = useMfaChallengeAndVerifyMutation({ onSuccess: async () => { await queryClient.resetQueries() if (context === 'forgot-password') { router.push({ pathname: '/reset-password', query: router.query, }) } else { router.push(getReturnToPath()) } }, }) const onClickLogout = async () => { await signOut() await router.replace('/sign-in') } const onSubmit: SubmitHandler> = async ({ code }) => { if (selectedFactor) { mfaChallengeAndVerify({ factorId: selectedFactor.id, code, refreshFactors: false }) } } useEffect(() => { if (isSuccessFactors) { // if the user wanders into this page and he has no MFA setup, send the user to the next screen if (factors.totp.length === 0) { queryClient.resetQueries().then(() => router.push(getReturnToPath())) } if (factors.totp.length > 0) { setSelectedFactor(factors.totp[0]) } } }, [factors?.totp, isSuccessFactors, router, queryClient]) useEffect(() => { if (code.length === 6) form.handleSubmit(onSubmit)() }, [code]) const error = useAuthError() if (error) { return ( Back to sign in } /> ) } return ( <> {isLoadingFactors && } {isErrorFactors && } {isSuccessFactors && (
(
)} />
)}
Unable to sign in?{' '}
) }