import React, { useEffect, useState } from "react"; import { Button } from "@/components/button.tsx"; import { Input } from "@/components/input.tsx"; import { Shield, Loader2 } from "lucide-react"; import { useTranslation } from "react-i18next"; import type { MFAPromptMode } from "@termix/plugin-sdk/frontend"; export type { MFAPromptMode }; interface TOTPDialogProps { isOpen: boolean; prompt: string; mode?: MFAPromptMode; waiting?: boolean; onSubmit: (code: string) => void; onCancel: () => void; backgroundColor?: string; } export function TOTPDialog({ isOpen, prompt, mode, waiting = false, onSubmit, onCancel, backgroundColor, }: TOTPDialogProps) { const { t } = useTranslation(); const [pushSubmitted, setPushSubmitted] = useState(false); useEffect(() => { if (isOpen && !waiting) { setPushSubmitted(false); } }, [isOpen, waiting]); if (!isOpen) return null; const isPush = mode === "push"; const isMenu = mode === "menu"; const isTotp = !isPush && !isMenu && mode !== "password"; const showWaiting = waiting || (isPush && pushSubmitted); // FortiToken-style prompts ask for a numeric code or the literal word // "push", so the field can't be restricted to digits only. const allowsPushKeyword = isTotp && /push/i.test(prompt); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (isPush) { setPushSubmitted(true); onSubmit(""); return; } const input = e.currentTarget.elements.namedItem( "totpCode", ) as HTMLInputElement; if (input?.value.trim()) { onSubmit(input.value.trim()); } }; const title = isPush ? t("terminal.mfaPushRequired") : isMenu ? t("terminal.mfaPromptRequired") : t("terminal.totpRequired"); const label = prompt || (isTotp ? t("terminal.totpCodeLabel") : undefined); return (

{title}

{label && (

{label}

)}
{showWaiting ? (

{t("terminal.mfaWaitingApproval")}

) : (
{isPush ? null : isMenu ? ( ) : allowsPushKeyword ? ( ) : ( )}
)}
); }