83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { createSignal } from "solid-js";
|
|
import { throwIfFatal } from "../../lib/error";
|
|
import { t } from "../../lib/i18n";
|
|
import { loginApi } from "../../lib/login";
|
|
import { AppError } from "../../types/api";
|
|
|
|
export default function TotpComponent({
|
|
loginChallenge,
|
|
}: {
|
|
loginChallenge: string;
|
|
}) {
|
|
const [code, setCode] = createSignal("");
|
|
const [rememberMe, setRememberMe] = createSignal(false);
|
|
const [error, setError] = createSignal<string | null>(null);
|
|
const [fatalError, setFatalError] = createSignal<Error | null>(null);
|
|
|
|
async function submit() {
|
|
let redirectUrl;
|
|
try {
|
|
redirectUrl = await loginApi.totp(code(), rememberMe(), loginChallenge);
|
|
} catch (err) {
|
|
if (!(err instanceof AppError)) {
|
|
setFatalError(err as Error);
|
|
return;
|
|
}
|
|
if (err.kind === "fatal") {
|
|
setFatalError(err);
|
|
return;
|
|
}
|
|
setError(err.message);
|
|
return;
|
|
}
|
|
window.location.href = redirectUrl!;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{throwIfFatal(fatalError, () => setFatalError(null))()}
|
|
|
|
<div class="flex flex-col items-center">
|
|
<h1 class="text-2xl text-center font-bold">{t("totp.title")}</h1>
|
|
<form
|
|
class="w-full"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
submit();
|
|
}}
|
|
>
|
|
<fieldset class="fieldset">
|
|
<label class="label">{t("totp.code")}</label>
|
|
<input
|
|
type="text"
|
|
class="input validator w-full"
|
|
placeholder={t("totp.code")}
|
|
value={code()}
|
|
onInput={(e) => setCode(e.target.value)}
|
|
required
|
|
pattern="\d{6}"
|
|
title={t("totp.error.enterValidCode")}
|
|
/>
|
|
<div class="validator-hint hidden">
|
|
{t("totp.error.enterValidCode")}
|
|
</div>
|
|
<label class="label">
|
|
<input
|
|
type="checkbox"
|
|
checked={rememberMe()}
|
|
onChange={(e) => setRememberMe(e.target.checked)}
|
|
class="toggle"
|
|
/>
|
|
{t("login.rememberMe")}
|
|
</label>
|
|
{error() && <p class="text-error mt-2">{error()}</p>}
|
|
<button type="submit" class="btn btn-primary mt-4">
|
|
{t("login.continue")}
|
|
</button>
|
|
</fieldset>
|
|
</form>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|