/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useState } from 'react' import { RefreshCw, Loader2 } from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { regenerate2FABackupCodes } from '@/lib/api' import { Alert, AlertDescription } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { CopyButton } from '@/components/copy-button' import { Dialog } from '@/components/dialog' // ============================================================================ // Two-FA Backup Codes Dialog Component // ============================================================================ interface TwoFABackupDialogProps { open: boolean onOpenChange: (open: boolean) => void onSuccess: () => void } export function TwoFABackupDialog({ open, onOpenChange, onSuccess, }: TwoFABackupDialogProps) { const { t } = useTranslation() const [loading, setLoading] = useState(false) const [code, setCode] = useState('') const [backupCodes, setBackupCodes] = useState([]) const handleRegenerate = async () => { if (!code) { toast.error(t('Please enter your verification code')) return } try { setLoading(true) const response = await regenerate2FABackupCodes(code) if (response.success && response.data?.backup_codes) { setBackupCodes(response.data.backup_codes) toast.success(t('Backup codes regenerated successfully')) } else { toast.error(response.message || t('Failed to regenerate backup codes')) } } catch (_error) { toast.error(t('Failed to regenerate backup codes')) } finally { setLoading(false) } } const handleDone = () => { handleOpenChange(false) onSuccess() } const handleOpenChange = (open: boolean) => { if (!loading) { if (!open) { setCode('') setBackupCodes([]) } onOpenChange(open) } } return ( {t('Regenerate Backup Codes')} } description={ backupCodes.length > 0 ? t('Your new backup codes are ready') : t('Generate new backup codes for account recovery') } contentClassName='sm:max-w-md' titleClassName='flex items-center gap-2' contentHeight='auto' bodyClassName='space-y-4' footer={ <> {backupCodes.length === 0 ? ( <> ) : ( )} } >
{backupCodes.length === 0 ? ( <> {t( 'Generating new codes will invalidate all existing backup codes.' )}
setCode(e.target.value)} placeholder={t('Enter authenticator code')} maxLength={6} disabled={loading} />
) : ( <> {t( 'Save these codes in a safe place. Each code can only be used once.' )}
{backupCodes.map((code, index) => (
{code}
))}
{t('Copy All Codes')} )}
) }