Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/routeModules/admin/mfa-challenge.component.tsx
T

63 lines
3.1 KiB
TypeScript

import { Form, Link, useActionData, useLoaderData, useNavigation } from "react-router";
import { useTranslation } from "react-i18next";
import { ADMIN_MFA_ENROLLMENT_PATH } from "~/utils/auth/mfa/paths";
import { useRootData } from "~/utils/data/useRootData";
import type { ActionData, LoaderData } from "~/routeModules/admin/mfa-challenge.impl";
export default function AdminMfaChallengeRoute() {
const { t } = useTranslation();
const data = useLoaderData<LoaderData>();
const actionData = useActionData<ActionData>();
const navigation = useNavigation();
const rootData = useRootData();
const isSubmitting = navigation.state === "submitting";
return (
<main className="mx-auto flex min-h-screen max-w-md flex-col justify-center px-6 py-12">
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<h1 className="text-xl font-semibold text-gray-900">{t("admin.mfaChallenge.title")}</h1>
<p className="mt-2 text-sm text-gray-600">{t("admin.mfaChallenge.description")}</p>
{actionData?.error ? <p className="mt-4 rounded-md bg-red-50 p-3 text-sm text-red-700">{actionData.error}</p> : null}
<Form method="post" className="mt-6 space-y-4">
{rootData.csrf && <input type="hidden" name="csrf" value={rootData.csrf} />}
<input type="hidden" name="redirectTo" value={actionData?.redirectTo ?? data.redirectTo} />
<div>
<label htmlFor="code" className="block text-sm font-medium text-gray-700">
{t("admin.mfaChallenge.fields.authenticatorCode")}
</label>
<input
id="code"
name="code"
inputMode="numeric"
autoComplete="one-time-code"
pattern="[0-9]{6}"
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-gray-900 shadow-sm focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900"
/>
</div>
<div>
<label htmlFor="recoveryCode" className="block text-sm font-medium text-gray-700">
{t("admin.mfaChallenge.fields.recoveryCode")}
</label>
<input
id="recoveryCode"
name="recoveryCode"
autoComplete="off"
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 uppercase text-gray-900 shadow-sm focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900"
/>
</div>
<button
type="submit"
disabled={isSubmitting || !data.totpEnabled}
className="w-full rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-60"
>
{isSubmitting ? t("admin.mfaChallenge.actions.verifying") : t("admin.mfaChallenge.actions.verifyAndContinue")}
</button>
</Form>
<Link to={data.enrollmentPath || ADMIN_MFA_ENROLLMENT_PATH} className="mt-4 inline-block text-sm text-gray-600 hover:text-gray-900">
{t("admin.mfaChallenge.actions.manageSettings")}
</Link>
</div>
</main>
);
}