import React, { useState } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Input } from "@/components/ui/input.tsx"; import { Label } from "@/components/ui/label.tsx"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; import { Shield, Copy, Download, AlertCircle, CheckCircle2 } from "lucide-react"; import { setupTOTP, enableTOTP, disableTOTP, generateBackupCodes } from "@/ui/main-axios.ts"; import { toast } from "sonner"; interface TOTPSetupProps { isEnabled: boolean; onStatusChange?: (enabled: boolean) => void; } export function TOTPSetup({ isEnabled: initialEnabled, onStatusChange }: TOTPSetupProps) { const [isEnabled, setIsEnabled] = useState(initialEnabled); const [isSettingUp, setIsSettingUp] = useState(false); const [setupStep, setSetupStep] = useState<"init" | "qr" | "verify" | "backup">("init"); const [qrCode, setQrCode] = useState(""); const [secret, setSecret] = useState(""); const [verificationCode, setVerificationCode] = useState(""); const [backupCodes, setBackupCodes] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [password, setPassword] = useState(""); const [disableCode, setDisableCode] = useState(""); const handleSetupStart = async () => { setError(null); setLoading(true); try { const response = await setupTOTP(); setQrCode(response.qr_code); setSecret(response.secret); setSetupStep("qr"); setIsSettingUp(true); } catch (err: any) { setError(err?.response?.data?.error || "Failed to start TOTP setup"); } finally { setLoading(false); } }; const handleVerifyCode = async () => { if (verificationCode.length !== 6) { setError("Please enter a 6-digit code"); return; } setError(null); setLoading(true); try { const response = await enableTOTP(verificationCode); setBackupCodes(response.backup_codes); setSetupStep("backup"); toast.success("Two-factor authentication enabled successfully!"); } catch (err: any) { setError(err?.response?.data?.error || "Invalid verification code"); } finally { setLoading(false); } }; const handleDisable = async () => { setError(null); setLoading(true); try { await disableTOTP(password || undefined, disableCode || undefined); setIsEnabled(false); setIsSettingUp(false); setSetupStep("init"); setPassword(""); setDisableCode(""); onStatusChange?.(false); toast.success("Two-factor authentication disabled"); } catch (err: any) { setError(err?.response?.data?.error || "Failed to disable TOTP"); } finally { setLoading(false); } }; const handleGenerateNewBackupCodes = async () => { setError(null); setLoading(true); try { const response = await generateBackupCodes(password || undefined, disableCode || undefined); setBackupCodes(response.backup_codes); toast.success("New backup codes generated"); } catch (err: any) { setError(err?.response?.data?.error || "Failed to generate backup codes"); } finally { setLoading(false); } }; const copyToClipboard = (text: string, label: string) => { navigator.clipboard.writeText(text); toast.success(`${label} copied to clipboard`); }; const downloadBackupCodes = () => { const content = `Termix Two-Factor Authentication Backup Codes\n` + `Generated: ${new Date().toISOString()}\n\n` + `Keep these codes in a safe place. Each code can only be used once.\n\n` + backupCodes.map((code, i) => `${i + 1}. ${code}`).join('\n'); const blob = new Blob([content], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'termix-backup-codes.txt'; a.click(); URL.revokeObjectURL(url); toast.success("Backup codes downloaded"); }; const handleComplete = () => { setIsEnabled(true); setIsSettingUp(false); setSetupStep("init"); setVerificationCode(""); onStatusChange?.(true); }; if (isEnabled && !isSettingUp) { return ( Two-Factor Authentication Your account is protected with two-factor authentication Enabled Two-factor authentication is currently active on your account Disable 2FA Backup Codes Warning Disabling two-factor authentication will make your account less secure
setPassword(e.target.value)} />

Or

setDisableCode(e.target.value.replace(/\D/g, ''))} />

Generate new backup codes if you've lost your existing ones

setPassword(e.target.value)} />

Or

setDisableCode(e.target.value.replace(/\D/g, ''))} />
{backupCodes.length > 0 && (
{backupCodes.map((code, i) => (
{code}
))}
)}
{error && ( Error {error} )}
); } if (setupStep === "qr") { return ( Set Up Two-Factor Authentication Step 1: Scan the QR code with your authenticator app
TOTP QR Code

If you can't scan the QR code, enter this code manually in your authenticator app

); } if (setupStep === "verify") { return ( Verify Your Authenticator Step 2: Enter the 6-digit code from your authenticator app
setVerificationCode(e.target.value.replace(/\D/g, ''))} className="text-center text-2xl tracking-widest font-mono" />
{error && ( Error {error} )}
); } if (setupStep === "backup") { return ( Save Your Backup Codes Step 3: Store these codes in a safe place Important Save these backup codes in a secure location. You can use them to access your account if you lose your authenticator device.
{backupCodes.map((code, i) => (
{i + 1}. {code}
))}
); } return ( Two-Factor Authentication Add an extra layer of security to your account Not Enabled Two-factor authentication adds an extra layer of security by requiring a code from your authenticator app when signing in. {error && ( Error {error} )} ); }