import { Button, Copy, FocusModal, Heading, Hint, OtpInput, Text, } from "@medusajs/ui" import type { AuthMfaSetupResponse } from "@medusajs/js-sdk" import { useState } from "react" import { useTranslation } from "react-i18next" import { useGenerateAuthMfaRecoveryCodes, useVerifyAuthMfa, } from "../../../../../hooks/api" import { MfaQrCode } from "./mfa-qr-code" type MfaSetupModalProps = { setup: AuthMfaSetupResponse onClose: () => void } export const MfaSetupModal = ({ setup, onClose }: MfaSetupModalProps) => { const { t } = useTranslation() const [step, setStep] = useState<"verify" | "recovery-codes">("verify") const [code, setCode] = useState("") const [error, setError] = useState(null) const [isVerified, setIsVerified] = useState(false) const [recoveryCodes, setRecoveryCodes] = useState([]) const secret = setup.secret const otpauthUrl = setup.otpauth_url const { mutateAsync: verify, isPending: isVerifying } = useVerifyAuthMfa( setup.mfa_factor.id ) const { mutateAsync: generateRecoveryCodes, isPending: isGenerating } = useGenerateAuthMfaRecoveryCodes() const generateAndShowRecoveryCodes = async () => { setError(null) try { const { recovery_codes } = await generateRecoveryCodes() setRecoveryCodes(recovery_codes) setStep("recovery-codes") } catch (e) { setError( e instanceof Error ? e.message : t("profile.mfa.recoveryCodesError") ) } } const handleVerify = async (nextCode = code) => { if (isVerified) { await generateAndShowRecoveryCodes() return } if (nextCode.length !== 6) { return } setError(null) try { await verify({ code: nextCode }) setIsVerified(true) } catch (e) { setError(e instanceof Error ? e.message : t("profile.mfa.verifyError")) setCode("") return } await generateAndShowRecoveryCodes() } const handleOtpChange = (value: string) => { setCode(value) } const handleDownloadRecoveryCodes = () => { const blob = new Blob([recoveryCodes.join("\n")], { type: "text/plain;charset=utf-8", }) const url = URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = "medusa-recovery-codes.txt" link.click() URL.revokeObjectURL(url) } return ( !open && onClose()}> {step === "verify" ? t("profile.mfa.setupTitle") : t("profile.mfa.recoveryCodesTitle")} {step === "verify" ? (
{t("profile.mfa.setupAuthenticatorApp")} {t("profile.mfa.setupDescription")}
{secret && otpauthUrl ? (
{secret}
) : ( {t("profile.mfa.setupError")} )}
{error && ( {error} )}
) : (
{t("profile.mfa.recoveryCodesTitle")} {t("profile.mfa.recoveryCodesDescription")}
{recoveryCodes.map((recoveryCode) => { return ( {recoveryCode} ) })}
)}
{step === "verify" ? ( <> ) : ( <> )}
) }