import { ArrowLeft, BarChart3, Boxes, FolderKanban, LayoutDashboard, LockKeyhole, LogOut, Power, ShieldAlert, Users2, } from "lucide-react"; import { revalidatePath } from "next/cache"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import Link from "next/link"; import { MotionFade } from "@/components/motion-fade"; import { routing } from "@/i18n/routing"; import { clearAdminSessionCookie, getAdminLockState, isAdminAuthConfigured, isAdminAuthenticated, isPasswordValid, registerFailedAdminAttempt, resetAdminFailedAttempts, setAdminSessionCookie, } from "@/lib/admin-auth"; import { getMaintenanceMode, setMaintenanceMode } from "@/lib/app-config"; import { resolveLocale } from "@/lib/site-data"; import { AppHeader } from "@/src/components/layout/app-header"; import { AppShell } from "@/src/components/layout/app-shell"; import { AppSidebar } from "@/src/components/layout/app-sidebar"; import { Badge } from "@/src/components/ui/badge"; import { Button } from "@/src/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/src/components/ui/card"; import { Input } from "@/src/components/ui/input"; import { Label } from "@/src/components/ui/label"; type RootPageProps = { searchParams?: { error?: string; }; }; export const dynamic = "force-dynamic"; export default async function RootPage({ searchParams }: RootPageProps) { const requestLocale = cookies().get("NEXT_LOCALE")?.value; const localeKey = resolveLocale(requestLocale ?? "de"); const authConfigured = isAdminAuthConfigured(); const basicConfigured = Boolean( process.env.ROOT_BASIC_AUTH_USER && process.env.ROOT_BASIC_AUTH_PASS, ); const authenticated = isAdminAuthenticated(); const lockState = getAdminLockState(); const maintenanceEnabled = authenticated ? await getMaintenanceMode() : false; async function loginAction(formData: FormData) { "use server"; const password = String(formData.get("password") ?? ""); const currentLockState = getAdminLockState(); if (currentLockState.locked) { redirect("/root?error=locked"); } if (!isAdminAuthConfigured() || !isPasswordValid(password)) { const failState = registerFailedAdminAttempt(); if (failState.locked) { redirect("/root?error=locked"); } redirect("/root?error=invalid"); } resetAdminFailedAttempts(); setAdminSessionCookie(); redirect("/root"); } async function logoutAction() { "use server"; clearAdminSessionCookie(); redirect("/root"); } async function updateMaintenanceMode(formData: FormData) { "use server"; if (!isAdminAuthenticated()) { redirect("/root"); } const nextValue = formData.get("enabled") === "true"; await setMaintenanceMode(nextValue); revalidatePath("/", "layout"); revalidatePath("/root"); for (const appLocale of routing.locales) { revalidatePath(`/${appLocale}`, "layout"); revalidatePath(`/${appLocale}/coming-soon`); } redirect("/root"); } const copy = resolveLocale(requestLocale ?? localeKey) === "de" ? { title: "Root", subtitle: "Interner Bereich fuer Kennzahlen und Wartungssteuerung.", activeUsers: "Aktive Nutzer", projects: "Laufende Projekte", products: "Aktive Produkte", conversion: "Conversion", updates: "Letzte Updates", updateOne: "Kontaktformular wurde ueberarbeitet.", updateTwo: "Neue Produktseite fuer Growth Kit vorbereitet.", updateThree: "Portfolio-Daten fuer Q2 aktualisiert.", maintenanceTitle: "Wartungsmodus", maintenanceText: "Wenn aktiv, werden alle Seiten auf die Coming Soon Seite weitergeleitet.", maintenanceOn: "Aktiv", maintenanceOff: "Inaktiv", enableMaintenance: "Wartungsmodus aktivieren", disableMaintenance: "Wartungsmodus deaktivieren", loginTitle: "Root Login", loginText: "Nur autorisierte Nutzer duerfen diesen Bereich verwenden.", passwordLabel: "Passwort", loginButton: "Einloggen", invalidLogin: "Falsches Passwort.", lockedLogin: "Zu viele Fehlversuche. Bitte spaeter erneut versuchen.", configMissing: "ADMIN_PASSWORD und ADMIN_AUTH_SECRET fehlen in env.", basicAuthMissing: "ROOT_BASIC_AUTH_USER und ROOT_BASIC_AUTH_PASS fehlen in env.", logout: "Ausloggen", backToSite: "Zur Website", } : { title: "Root", subtitle: "Internal area for metrics and maintenance controls.", activeUsers: "Active users", projects: "Running projects", products: "Active products", conversion: "Conversion", updates: "Latest updates", updateOne: "Contact form layout updated.", updateTwo: "New Growth Kit product page prepared.", updateThree: "Portfolio data updated for Q2.", maintenanceTitle: "Maintenance mode", maintenanceText: "When enabled, all site routes are redirected to the coming soon page.", maintenanceOn: "Enabled", maintenanceOff: "Disabled", enableMaintenance: "Enable maintenance mode", disableMaintenance: "Disable maintenance mode", loginTitle: "Root login", loginText: "Only authorized users can access this area.", passwordLabel: "Password", loginButton: "Sign in", invalidLogin: "Invalid password.", lockedLogin: "Too many failed attempts. Please try again later.", configMissing: "ADMIN_PASSWORD and ADMIN_AUTH_SECRET are missing in env.", basicAuthMissing: "ROOT_BASIC_AUTH_USER and ROOT_BASIC_AUTH_PASS are missing in env.", logout: "Sign out", backToSite: "Back to site", }; if (!authenticated) { return (

{copy.loginTitle}

{copy.loginText}
{!authConfigured ? (

{copy.configMissing}

) : null} {!basicConfigured ? (

{copy.basicAuthMissing}

) : null} {searchParams?.error === "invalid" ? (

{copy.invalidLogin}

) : null} {searchParams?.error === "locked" || lockState.locked ? (

{copy.lockedLogin}

) : null}
); } const stats = [ { label: copy.activeUsers, value: "1,280", icon: Users2 }, { label: copy.projects, value: "24", icon: FolderKanban }, { label: copy.products, value: "8", icon: Boxes }, { label: copy.conversion, value: "4.8%", icon: BarChart3 }, ]; const sidebarItems = [ { label: copy.title, href: "/root", icon: LayoutDashboard, active: true }, { label: copy.maintenanceTitle, href: "#maintenance", icon: ShieldAlert }, { label: copy.updates, href: "#updates", icon: FolderKanban }, ]; return ( } /> } header={ {maintenanceEnabled ? copy.maintenanceOn : copy.maintenanceOff} } /> } >
{copy.maintenanceTitle} {copy.maintenanceText}
{stats.map((item, index) => { const Icon = item.icon; return (

{item.label}

{item.value}

); })}
{copy.updates}
    {[copy.updateOne, copy.updateTwo, copy.updateThree].map((item) => (
  • {item}
  • ))}
); }