This commit is contained in:
Marcelo Dares
2026-04-29 01:15:50 +02:00
parent 65aaf9275e
commit ea23136288
172 changed files with 30358 additions and 353 deletions

View File

@@ -3,6 +3,7 @@ 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;
@@ -10,98 +11,139 @@ type PageShellProps = {
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";
};
const navLinks = [
{ href: "/dashboard", label: "Dashboard" },
{ href: "/diagnostic", label: "Diagnostico" },
{ href: "/dashboard#modulos", label: "Modulos" },
{ href: "/talleres-desarrollo", label: "Talleres" },
{ href: "/licitations", label: "Licitaciones" },
{ href: "/results", label: "Results" },
{ href: "/recommendations", label: "Recommendations" },
{ href: "/manual", label: "Manual" },
];
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 }: PageShellProps) {
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="mx-auto flex w-full max-w-[1200px] items-center justify-between gap-3 px-4 py-3 sm:px-6 lg:px-8">
<Link href="/">
<KontiaMark />
</Link>
<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>
)}
<nav className="hidden items-center gap-5 md:flex">
{currentUser ? (
navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className="text-sm font-medium text-[#516180] transition-colors hover:text-[#223f7c]"
>
{link.label}
</Link>
))
) : (
<>
<Link href="/#metodologia" className="text-sm font-medium text-[#516180] transition-colors hover:text-[#223f7c]">
Metodologia
</Link>
<Link href="/#modulos" className="text-sm font-medium text-[#516180] transition-colors hover:text-[#223f7c]">
Modulos
</Link>
<Link href="/#beneficios" className="text-sm font-medium text-[#516180] transition-colors hover:text-[#223f7c]">
Beneficios
</Link>
</>
)}
{isAdmin && currentUser ? (
<Link href="/admin" className="text-sm font-semibold text-[#1f3f82] transition-colors hover:text-[#17336c]">
{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}
</nav>
{currentUser ? (
<div className="flex items-center gap-2">
<p className="hidden text-xs font-semibold text-[#5f6c84] sm:block">{currentUser.email}</p>
{visibility.showUserControls && headerShowLogout ? (
<form action="/api/auth/logout" method="post">
<button
type="submit"
className="rounded-xl border border-[#ccd6e5] px-3 py-1.5 text-xs font-semibold text-[#334a73] transition-colors hover:bg-white"
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"
>
Logout
Salir
</button>
</form>
</div>
) : (
<div className="flex items-center gap-2 text-xs font-semibold text-[#5f6c84]">
<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>
</div>
)}
) : 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="mx-auto w-full max-w-[1200px] px-4 py-8 sm:px-6 lg:px-8">
<section className="mb-6 flex flex-wrap items-end justify-between gap-3">
<div>
<h1 className="text-4xl font-semibold text-[#142447] [font-family:var(--font-display)] md:text-5xl">{title}</h1>
{description ? <p className="mt-1 text-sm text-[#60718f]">{description}</p> : null}
</div>
{action ? <div>{action}</div> : null}
</section>
<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>