- Gemeinsame FormPanel-Karte fuer Passwort- und Zwei-Faktor-Seiten - Zwei-Faktor-Code: grosses, zentriertes Ziffernfeld - Backup-Codes als nummerierte Kacheln statt langer Liste - Newsletter-Bestaetigung: Willkommensrabatt als Gutschein mit gestricheltem Rand und Kopier-Knopf (bestaetigt "Kopiert") Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { redirect } from "next/navigation";
|
|
import { Container, SectionHeading, Button, FormPanel } from "@/components/ui";
|
|
import { BackLink } from "@/components/back-link";
|
|
import { TurnstileField } from "@/components/turnstile-widget";
|
|
import { getTwoFactorChallengeCustomerId } from "@/lib/auth";
|
|
import { verifyTwoFactorAction } from "../actions";
|
|
import { getLocale } from "@/i18n/locale";
|
|
import { getDictionary } from "@/i18n/get-dictionary";
|
|
|
|
export const metadata: Metadata = { title: "Anmeldung bestätigen" };
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function ZweiFaktorCodePage() {
|
|
const t = getDictionary(await getLocale());
|
|
|
|
const customerId = await getTwoFactorChallengeCustomerId();
|
|
if (!customerId) redirect("/konto");
|
|
|
|
return (
|
|
<div className="py-20">
|
|
<Container className="max-w-lg">
|
|
<FormPanel>
|
|
<BackLink href="/konto" label={t.twoFactorCodePage.cancelLabel} />
|
|
<SectionHeading
|
|
eyebrow={t.twoFactorCodePage.eyebrow}
|
|
title={t.twoFactorCodePage.title}
|
|
subtitle={t.twoFactorCodePage.subtitle}
|
|
/>
|
|
|
|
|
|
<form action={verifyTwoFactorAction} className="mt-6 space-y-4">
|
|
<label className="block text-sm">
|
|
<span className="text-ink/70">{t.twoFactorCodePage.codeLabel}</span>
|
|
<input
|
|
name="code"
|
|
type="text"
|
|
inputMode="numeric"
|
|
autoComplete="one-time-code"
|
|
autoFocus
|
|
required
|
|
className="mt-2 w-full border border-ink/20 bg-background px-4 py-4 text-center font-serif text-3xl tracking-[0.4em] tabular-nums focus:outline-none focus:border-forest"
|
|
/>
|
|
</label>
|
|
{process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ? (
|
|
<TurnstileField siteKey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY} />
|
|
) : null}
|
|
<Button type="submit">{t.twoFactorCodePage.confirm}</Button>
|
|
</form>
|
|
</FormPanel>
|
|
</Container>
|
|
</div>
|
|
);
|
|
}
|