153 lines
6.0 KiB
TypeScript
153 lines
6.0 KiB
TypeScript
import Link from "next/link";
|
|
import { isAdminIdentity } from "@/lib/auth/admin";
|
|
import { KontiaMark } from "@/components/app/kontia-mark";
|
|
import { getCurrentUser } from "@/lib/auth/user";
|
|
import { cn } from "@/lib/utils";
|
|
import { getHeaderVisibility, type HeaderModeRequest } from "@/lib/layout/header";
|
|
|
|
type PageShellProps = {
|
|
children: React.ReactNode;
|
|
title: string;
|
|
description?: string;
|
|
action?: React.ReactNode;
|
|
className?: string;
|
|
showPageHeading?: boolean;
|
|
headerMode?: HeaderModeRequest;
|
|
headerBackHref?: string;
|
|
headerBackLabel?: string;
|
|
headerNextHref?: string;
|
|
headerNextLabel?: string;
|
|
headerShowManual?: boolean;
|
|
headerPlanBadgeLabel?: string;
|
|
headerAction?: React.ReactNode;
|
|
headerShowLogout?: boolean;
|
|
contentWidth?: "default" | "wide";
|
|
};
|
|
|
|
function HeaderBadge({ label }: { label: string }) {
|
|
return <span className="rounded-full bg-[#0f2a5f] px-4 py-1.5 text-sm font-semibold text-white">{label}</span>;
|
|
}
|
|
|
|
export async function PageShell({
|
|
children,
|
|
title,
|
|
description,
|
|
action,
|
|
className,
|
|
showPageHeading = true,
|
|
headerMode = "auto",
|
|
headerBackHref = "/dashboard",
|
|
headerBackLabel = "Volver al Dashboard",
|
|
headerNextHref,
|
|
headerNextLabel,
|
|
headerShowManual = false,
|
|
headerPlanBadgeLabel,
|
|
headerAction,
|
|
headerShowLogout = true,
|
|
contentWidth = "default",
|
|
}: PageShellProps) {
|
|
const currentUser = await getCurrentUser();
|
|
const isAdmin = currentUser ? isAdminIdentity(currentUser.email, currentUser.role) : false;
|
|
const visibility = getHeaderVisibility(Boolean(currentUser), headerMode);
|
|
const containerClassName = contentWidth === "wide" ? "max-w-[1560px]" : "max-w-[1200px]";
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#eff2f7]">
|
|
<header className="border-b border-[#d8dde7] bg-[#eff2f7]">
|
|
<div className={cn("mx-auto flex w-full items-center justify-between gap-3 px-4 py-4 sm:px-6 lg:px-8", containerClassName)}>
|
|
{visibility.showBackLink ? (
|
|
<Link href={headerBackHref} className="inline-flex items-center gap-3 text-3xl font-semibold text-[#1a2c4f] [font-family:var(--font-display)]">
|
|
<span className="text-2xl" aria-hidden>
|
|
←
|
|
</span>
|
|
<span className="text-base font-semibold [font-family:var(--font-sans)]">{headerBackLabel}</span>
|
|
</Link>
|
|
) : (
|
|
<Link href="/">
|
|
<KontiaMark />
|
|
</Link>
|
|
)}
|
|
|
|
{visibility.showMarketingNav ? (
|
|
<nav className="hidden items-center gap-10 text-base font-medium text-[#4f5f7d] lg:flex">
|
|
<Link href="/#metodologia" className="transition-colors hover:text-[#223f7c]">
|
|
Metodologia
|
|
</Link>
|
|
<Link href="/#modulos" className="transition-colors hover:text-[#223f7c]">
|
|
Modulos
|
|
</Link>
|
|
<Link href="/#beneficios" className="transition-colors hover:text-[#223f7c]">
|
|
Beneficios
|
|
</Link>
|
|
<Link href="/#contacto" className="transition-colors hover:text-[#223f7c]">
|
|
Contacto
|
|
</Link>
|
|
</nav>
|
|
) : null}
|
|
|
|
<div className="flex items-center gap-2 sm:gap-3">
|
|
{visibility.showUserControls && headerShowManual ? (
|
|
<Link href="/manual" className="inline-flex h-11 items-center gap-2 rounded-2xl border border-[#cfd8e7] bg-[#f7f9fd] px-5 text-sm font-semibold text-[#1a2d51] transition hover:bg-white">
|
|
<span aria-hidden>◧</span>
|
|
Manual
|
|
</Link>
|
|
) : null}
|
|
|
|
{visibility.showUserControls && headerNextHref && headerNextLabel ? (
|
|
<Link href={headerNextHref} className="inline-flex items-center gap-2 text-sm font-semibold text-[#445d86] hover:text-[#1f3f84]">
|
|
{headerNextLabel}
|
|
<span aria-hidden>→</span>
|
|
</Link>
|
|
) : null}
|
|
|
|
{visibility.showUserControls && headerAction ? headerAction : null}
|
|
{visibility.showUserControls && headerPlanBadgeLabel ? <HeaderBadge label={headerPlanBadgeLabel} /> : null}
|
|
|
|
{isAdmin && currentUser && visibility.mode === "app" ? (
|
|
<Link href="/admin" className="rounded-xl border border-[#cfd8e7] px-3 py-2 text-sm font-semibold text-[#2f486f] transition-colors hover:bg-white">
|
|
Admin
|
|
</Link>
|
|
) : null}
|
|
|
|
{visibility.showUserControls && headerShowLogout ? (
|
|
<form action="/api/auth/logout" method="post">
|
|
<button
|
|
type="submit"
|
|
className="inline-flex h-11 items-center rounded-2xl border border-[#ccd6e5] px-4 text-sm font-semibold text-[#334a73] transition-colors hover:bg-white"
|
|
>
|
|
Salir
|
|
</button>
|
|
</form>
|
|
) : null}
|
|
|
|
{visibility.showAuthButtons ? (
|
|
<>
|
|
<Link href="/login" className="rounded-xl px-3 py-2 text-sm font-semibold text-[#13254a] transition-colors hover:text-[#214485]">
|
|
Iniciar Sesion
|
|
</Link>
|
|
<Link href="/register" className="rounded-2xl bg-[#1f3f84] px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-[#17356f]">
|
|
Comenzar Gratis
|
|
</Link>
|
|
</>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main className={cn("mx-auto w-full px-4 py-8 sm:px-6 lg:px-8", containerClassName)}>
|
|
{showPageHeading ? (
|
|
<section className="mb-6 flex flex-wrap items-end justify-between gap-3">
|
|
<div>
|
|
<h1 className="text-3xl font-semibold text-[#142447] [font-family:var(--font-display)] md:text-4xl">{title}</h1>
|
|
{description ? <p className="mt-1 text-sm text-[#60718f]">{description}</p> : null}
|
|
</div>
|
|
{action ? <div>{action}</div> : null}
|
|
</section>
|
|
) : null}
|
|
|
|
<section className={cn("space-y-4", className)}>{children}</section>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|