"use client"; import { ShieldAlert, ShieldCheck } from "lucide-react"; import { useTranslations } from "next-intl"; import { useCallback, useEffect, useState } from "react"; import { v4 } from "uuid"; import { errorToast } from "../../../../components"; import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Separator } from "../../../../shadcnui"; import { showToast } from "../../../../utils/toast"; import { PasskeyInterface } from "../../data/passkey.interface"; import { TotpAuthenticatorInterface } from "../../data/totp-authenticator.interface"; import { TwoFactorStatusInterface } from "../../data/two-factor-status.interface"; import { TwoFactorService } from "../../data/two-factor.service"; import { BackupCodesDialog } from "./BackupCodesDialog"; import { DisableTwoFactorDialog } from "./DisableTwoFactorDialog"; import { PasskeyList } from "./PasskeyList"; import { PasskeySetupDialog } from "./PasskeySetupDialog"; import { TotpAuthenticatorList } from "./TotpAuthenticatorList"; import { TotpSetupDialog } from "./TotpSetupDialog"; export function TwoFactorSettings() { const t = useTranslations(); const [status, setStatus] = useState(null); const [authenticators, setAuthenticators] = useState([]); const [passkeys, setPasskeys] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isEnabling, setIsEnabling] = useState(false); const [passkeyDialogOpen, setPasskeyDialogOpen] = useState(false); const loadStatus = useCallback(async () => { try { // Load status and lists in parallel const [statusData, authenticatorsList, passkeysList] = await Promise.all([ TwoFactorService.getStatus(), TwoFactorService.listTotpAuthenticators(), TwoFactorService.listPasskeys(), ]); setStatus(statusData); setAuthenticators(authenticatorsList); setPasskeys(passkeysList); } catch (error) { errorToast({ title: t("common.errors.error"), error }); } finally { setIsLoading(false); } }, [t]); useEffect(() => { loadStatus(); }, [loadStatus]); const handleRefresh = () => { loadStatus(); }; const handleEnable2FA = async () => { setIsEnabling(true); try { const preferredMethod = authenticators.length > 0 ? "totp" : "passkey"; await TwoFactorService.enable({ id: v4(), preferredMethod }); showToast(t("common.success"), { description: t("auth.two_factor.enabled_success") }); await loadStatus(); } catch (error) { errorToast({ title: t("common.errors.error"), error }); } finally { setIsEnabling(false); } }; if (isLoading) { return (

{t("common.loading")}

); } const isEnabled = status?.isEnabled ?? false; return (
{isEnabled ? ( ) : ( )}
{t("auth.two_factor.title")} {isEnabled ? t("auth.two_factor.enabled_description") : t("auth.two_factor.disabled_description")}
{/* Authenticator Apps Section */}

{t("auth.two_factor.authenticator_apps")}

{t("auth.two_factor.authenticator_apps_description")}

{/* Passkeys Section */}

{t("auth.two_factor.passkeys")}

{t("auth.two_factor.passkeys_description")}

{/* Backup Codes Section */}

{t("auth.two_factor.backup_codes")}

{t("auth.two_factor.backup_codes_description")}

{/* Enable 2FA - shown when not enabled but methods exist */} {!isEnabled && (authenticators.length > 0 || passkeys.length > 0) && ( <>

{t("auth.two_factor.enable_2fa")}

{t("auth.two_factor.enable_description")}

)} {/* Disable 2FA */} {isEnabled && ( <>

{t("auth.two_factor.disable_2fa")}

{t("auth.two_factor.disable_warning")}

)}
); }