Adds /konto/einstellungen, which gathers two-factor authentication, "sign out on all devices", the Erntepost consent, the data export (Art. 15 GDPR) and account deletion (Art. 17 GDPR) in one place. The account overview now links there through a "Settings" card instead of listing these blocks inline. Server actions are unchanged apart from redirecting failures and revalidating the new page. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
69 lines
2.5 KiB
TypeScript
69 lines
2.5 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 { ShieldIcon } from "@/components/account-ui";
|
|
import { PasswordField } from "@/components/password-field";
|
|
import { getCurrentCustomer } from "@/lib/auth";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { startTwoFactorSetupAction, disableTwoFactorAction } from "../actions";
|
|
import { getLocale } from "@/i18n/locale";
|
|
import { getDictionary } from "@/i18n/get-dictionary";
|
|
|
|
export const metadata: Metadata = { title: "Zwei-Faktor-Authentifizierung" };
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function ZweiFaktorPage() {
|
|
const t = getDictionary(await getLocale());
|
|
|
|
const customer = await getCurrentCustomer();
|
|
if (!customer) redirect("/konto");
|
|
|
|
const remainingBackupCodes = customer.twoFactorEnabled
|
|
? await prisma.twoFactorBackupCode.count({ where: { customerId: customer.id, usedAt: null } })
|
|
: 0;
|
|
|
|
return (
|
|
<div className="py-20">
|
|
<Container className="max-w-lg">
|
|
<FormPanel>
|
|
<BackLink href="/konto/einstellungen" label={t.twoFactorPage.backLabel} />
|
|
<SectionHeading
|
|
title={t.twoFactorPage.title}
|
|
subtitle={t.twoFactorPage.subtitle}
|
|
/>
|
|
|
|
|
|
{customer.twoFactorEnabled ? (
|
|
<div className="mt-8 space-y-6">
|
|
<p className="flex items-center gap-3 text-sm text-heading bg-forest/5 border border-heading/20 px-4 py-3">
|
|
<ShieldIcon />
|
|
<span>
|
|
{t.twoFactorPage.activeStatus(remainingBackupCodes)}
|
|
</span>
|
|
</p>
|
|
|
|
<form action={disableTwoFactorAction} className="space-y-4 border border-ink/10 p-6">
|
|
<h2 className="text-heading">{t.twoFactorPage.disableHeading}</h2>
|
|
<PasswordField
|
|
name="password"
|
|
label={t.twoFactorPage.passwordConfirmLabel}
|
|
autoComplete="current-password"
|
|
required
|
|
/>
|
|
<Button type="submit" variant="ghost">
|
|
{t.twoFactorPage.disableButton}
|
|
</Button>
|
|
</form>
|
|
</div>
|
|
) : (
|
|
<form action={startTwoFactorSetupAction} className="mt-8">
|
|
<Button type="submit">{t.twoFactorPage.setupButton}</Button>
|
|
</form>
|
|
)}
|
|
</FormPanel>
|
|
</Container>
|
|
</div>
|
|
);
|
|
}
|