diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx index 5f3accd726d..2b18106f3ed 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx @@ -1,5 +1,6 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useQueryClient } from '@tanstack/react-query' +import { useFlag } from 'common' import { useEffect, useState } from 'react' import { useForm, type SubmitHandler } from 'react-hook-form' import { toast } from 'sonner' @@ -10,11 +11,14 @@ import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { z } from 'zod' +import { RecoveryCodesModal } from './RecoveryCodesModal' import InformationBox from '@/components/ui/InformationBox' import { organizationKeys } from '@/data/organizations/keys' import { useMfaChallengeAndVerifyMutation } from '@/data/profile/mfa-challenge-and-verify-mutation' import { useMfaEnrollMutation } from '@/data/profile/mfa-enroll-mutation' import { useMfaUnenrollMutation } from '@/data/profile/mfa-unenroll-mutation' +import { useRecoveryCodesGenerateMutation } from '@/data/recovery-codes/recovery-codes-generate-mutation' +import { useRecoveryCodesStatusQuery } from '@/data/recovery-codes/recovery-codes-status-query' import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' type TOTP = { qr_code: string; secret: string; uri: string } @@ -26,6 +30,15 @@ interface AddNewFactorModalProps { export const AddNewFactorModal = ({ visible, onClose }: AddNewFactorModalProps) => { const { data, mutate: enroll, isPending: isEnrolling, reset } = useMfaEnrollMutation() + const enableAuthRecoveryCodes = useFlag('enableAuthRecoveryCodes') + const { isPending: isRecoveryCodesStatusPending, refetch: refetchRecoveryCodesStatus } = + useRecoveryCodesStatusQuery({ + enabled: enableAuthRecoveryCodes, + }) + + const recoveryCodesGenerateMutation = useRecoveryCodesGenerateMutation() + + const [isRecoveryCodesModalOpen, setIsRecoveryCodesModalOpen] = useState(false) useEffect(() => { if (!visible) reset() @@ -35,7 +48,7 @@ export const AddNewFactorModal = ({ visible, onClose }: AddNewFactorModalProps) <> } - isLoading={isEnrolling} - onClose={onClose} + isLoading={isEnrolling || (enableAuthRecoveryCodes && isRecoveryCodesStatusPending)} + onClose={async () => { + if (enableAuthRecoveryCodes) { + const { data: currentRecoveryCodesStatus } = await refetchRecoveryCodesStatus() + const shouldGenerateRecoveryCodes = currentRecoveryCodesStatus?.status === 'unenrolled' + + if (shouldGenerateRecoveryCodes) { + recoveryCodesGenerateMutation.mutate({}) + setIsRecoveryCodesModalOpen(true) + } + } + onClose() + }} + /> + setIsRecoveryCodesModalOpen(open)} + mutation={recoveryCodesGenerateMutation} /> ) diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/RecoveryCodesModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/RecoveryCodesModal.tsx index ddfc9ee1ed8..4efec68cf56 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/RecoveryCodesModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/RecoveryCodesModal.tsx @@ -132,7 +132,10 @@ const GenerateRecoveryCodesModalContent = ({ if (status === 'success') { return (
-

Save your recovery codes somewhere safe.

+

+ Recovery codes allow you to recover your account in case you lost access to your MFA apps. + Save them somewhere safe. +

           
             {codes?.map((code) => (