'use client' import * as React from 'react' import { formatDistanceToNow } from 'date-fns' import { Loader2, Mail, Trash2 } from 'lucide-react' import { useT } from '@open-mercato/shared/lib/i18n/context' import { flash } from '@open-mercato/ui/backend/FlashMessages' import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall' import { Badge } from '@open-mercato/ui/primitives/badge' import { Button } from '@open-mercato/ui/primitives/button' import { IconButton } from '@open-mercato/ui/primitives/icon-button' import type { MfaMethod } from '../types' import MfaConfiguredBadge from './mfa-provider-list-items/MfaConfiguredBadge' type OtpEmailProviderDetailsProps = { methods?: MfaMethod[] saving?: boolean onRemoveMethod?: (method: MfaMethod) => Promise onMethodsChanged?: () => Promise } type OtpSetupResponse = { setupId?: string clientData?: Record } type OtpConfirmResponse = { ok?: boolean recoveryCodes?: string[] } function formatRelative(value: string | null, fallback: string): string { if (!value) return fallback const parsed = new Date(value) if (Number.isNaN(parsed.getTime())) return fallback return formatDistanceToNow(parsed, { addSuffix: true }) } function readMetadataEmail(method: MfaMethod): string | null { const emailValue = method.providerMetadata?.email if (typeof emailValue !== 'string' || emailValue.length === 0) return null return emailValue } export default function OtpEmailProviderDetails({ methods = [], saving = false, onRemoveMethod, onMethodsChanged, }: OtpEmailProviderDetailsProps) { const t = useT() const [loading, setLoading] = React.useState(false) const configuredMethod = methods[0] ?? null const configuredEmail = configuredMethod ? readMetadataEmail(configuredMethod) : null const handleEnable = React.useCallback(async () => { if (loading || configuredMethod) return setLoading(true) try { const setup = await readApiResultOrThrow( '/api/security/mfa/provider/otp_email', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({}), }, ) if (!setup.setupId) { throw new Error('Missing setupId') } await readApiResultOrThrow( '/api/security/mfa/provider/otp_email', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ setupId: setup.setupId, payload: {}, }), }, ) await onMethodsChanged?.() flash(t('security.profile.mfa.providers.otpEmail.enabled', 'Email OTP enabled.'), 'success') } finally { setLoading(false) } }, [configuredMethod, loading, onMethodsChanged, t]) return (

{t( 'security.profile.mfa.providers.otpEmail.description', 'Receive one-time verification codes by email when signing in.', )}

{configuredMethod ? (

{configuredMethod.label ?? t('security.profile.mfa.providers.otpEmail.title', 'Email OTP')}

{configuredEmail ? (

{configuredEmail}

) : null}

{t('security.profile.mfa.method.lastUsed', 'Last used')}:{' '} {formatRelative(configuredMethod.lastUsedAt, t('security.profile.mfa.method.neverUsed', 'Never used'))}

{onRemoveMethod ? ( { void onRemoveMethod(configuredMethod) }} > ) : null}
) : (
)}
) }