import { useState } from "react";
import { beginTotpSetup, confirmTotpSetup, disableTwoFactor, newRecoveryCodes } from "~/fns/account-security";
import { useAction } from "~/hooks/use-action";
import { Button } from "~/ui/Button";
import { TextField } from "~/ui/Field";
import { ErrorBanner } from "~/ui/Callout";
import { Badge } from "~/ui/Badge";
import { Panel } from "~/ui/Panel";
import { RecoveryCodes } from "./RecoveryCodes";
import { ExternalLink } from "~/ui/TextLink";
import { QrCode } from "~/ui/QrCode";
type Props = { enabled: boolean; recoveryCodesLeft: number; hasPassword: boolean };
function field(form: HTMLFormElement, name: string): string {
return String(new FormData(form).get(name) ?? "");
}
export function TwoFactorPanel({ enabled, recoveryCodesLeft, hasPassword }: Props) {
const [setup, setSetup] = useState<{ secret: string; uri: string } | null>(null);
const [codes, setCodes] = useState<string[] | null>(null);
const begin = useAction(beginTotpSetup, { invalidate: false });
const confirm = useAction(confirmTotpSetup);
const disable = useAction(disableTwoFactor);
const regenerate = useAction(newRecoveryCodes);
const error = begin.error ?? confirm.error ?? disable.error ?? regenerate.error;
const passwordField = hasPassword ? (
<TextField label="Current password" name="password" type="password" autoComplete="current-password" required />
) : null;
return (
<Panel
title={
<span className="flex items-center gap-2">
Authenticator app {enabled && <Badge tone="success">Enabled</Badge>}
</span>
}
>
<div className="space-y-4 p-4 text-sm">
<ErrorBanner message={error} />