import type { Metadata } from "next"; import Link from "next/link"; import { Container, SectionHeading, Button, LinkButton } from "@/components/ui"; import { AccountNavCard, OrderIcon, AddressIcon, HeartIcon, ShieldIcon } from "@/components/account-ui"; import { TurnstileField } from "@/components/turnstile-widget"; import { PasswordField } from "@/components/password-field"; import { ConfirmForm } from "@/components/confirm-form"; import { getLocale } from "@/i18n/locale"; import { getDictionary } from "@/i18n/get-dictionary"; import { getCurrentCustomer } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; import { registerAction, loginAction, logoutAction, toggleNewsletterAction, logoutAllDevicesAction, resendVerificationEmailAction, deleteOwnAccountAction, } from "./actions"; export const metadata: Metadata = { title: "Mein Konto" }; export const dynamic = "force-dynamic"; export default async function KontoPage() { const t = getDictionary(await getLocale()); const customer = await getCurrentCustomer(); if (!customer) { return (

{t.account.login}

{/* Das Turnstile-Widget ist ein iframe mit FESTER Breite (rund 300 px) und kann nicht mitschrumpfen. In einer Zeile mit Knopf und Link — noch dazu in einer der beiden Spalten dieser Seite — reichte der Platz nie: die Elemente schoben sich uebereinander. Deshalb steht es auf einer eigenen Zeile, und Knopf und Link duerfen darunter umbrechen. Das Registrierungsformular daneben macht es schon immer so. */} {process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ? ( ) : null}
{t.account.forgotPassword}

{t.account.register}

{process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ? ( ) : null}
{t.account.ssoDivider}
{/* Bewusst ein einfaches statt LinkButton/next/link: der Klick muss eine ECHTE Browser-Top-Level-Navigation ausloesen, die dem 302-Redirect dieser Route bis zu login.microsoftonline.com folgt. Next.js' navigiert clientseitig per fetch() — dieser Cross-Origin-Redirect-Sprung wuerde dann von der connect-src-CSP in proxy.ts blockiert (die nur "self" u.ae. erlaubt), waehrend eine echte Top-Level-Navigation von CSP connect-src gar nicht erst betroffen ist. Bewusst immer sichtbar, auch ohne konfiguriertes SSO (siehe .env.example, ENTRA_*) — der Link fuehrt in dem Fall zu einer klaren Fehlermeldung auf dieser Seite statt eines defekten Buttons (src/app/api/auth/entra/login/route.ts prueft die Konfiguration server-seitig, bevor irgendetwas passiert). */} {t.account.ssoButton}
); } const newsletter = await prisma.newsletterSubscriber.findUnique({ where: { customerId: customer.id }, }); const isSubscribed = Boolean(newsletter && newsletter.unsubscribedAt === null); return (
{!customer.emailVerifiedAt ? (

{t.account.verifyEmailPrompt}

) : null}
} title={t.account.navOrders.title} description={t.account.navOrders.description} /> } title={t.account.navAddresses.title} description={t.account.navAddresses.description} /> } title={t.account.navWishlist.title} description={t.account.navWishlist.description} /> } title={t.account.navSecurity.title} description={`${t.account.navSecurity.twoFactorLabel}: ${customer.twoFactorEnabled ? t.account.navSecurity.twoFactorActive : t.account.navSecurity.twoFactorInactive}`} /> {customer.role === "ADMIN" ? ( } title={t.account.navAdmin.title} description={t.account.navAdmin.description} accent className="sm:col-span-2" /> ) : null}

{t.account.newsletterHeading}

{isSubscribed ? t.account.newsletterSubscribed : t.account.newsletterNotSubscribed}

{t.account.logoutAllDevicesHeading}

{t.account.logoutAllDevicesDescription}

{t.account.privacy.heading}

{t.account.privacy.downloadDataHeading}

{t.account.privacy.downloadDataDescription}

{t.account.privacy.downloadDataButton}

{t.account.privacy.deleteAccountHeading}

{t.account.privacy.deleteAccountDescription}

); } function Field({ name, label, type = "text", required = false, autoComplete, }: { name: string; label: string; type?: string; required?: boolean; autoComplete?: string; }) { return ( ); }