From 80bfa3035f9fd70f17c2bd432877b92f3b27d123 Mon Sep 17 00:00:00 2001 From: Marcos Fargas Date: Sat, 17 Oct 2026 19:36:53 +0200 Subject: [PATCH] feat(shell): selector de cliente en sidebar, layout fijo, cabecera contextual y reordenacion de menu --- .gitignore | 2 + src/app/dashboard/layout.tsx | 1 + src/components/DashboardShell.tsx | 166 ++++++------ src/components/SidebarTenantSwitcher.tsx | 305 +++++++++++++++++++++++ src/lib/tenant-modules.ts | 44 +--- 5 files changed, 393 insertions(+), 125 deletions(-) create mode 100644 src/components/SidebarTenantSwitcher.tsx diff --git a/.gitignore b/.gitignore index b5ec615..ae3e28d 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ coverage/ .turbo/ .ops/gitea-deploy/ +design-backup/ +login_*.png diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index d228934..3349343 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -104,6 +104,7 @@ export default async function DashboardLayout({ role={role} isAgency={isAgency} viewName={viewName} + activeTenantId={isAgency ? viewId : null} enabledModules={enabledModules} clientLogoUrl={!isAgency ? clientLogoUrl : null} brandLabel={brandLabel} diff --git a/src/components/DashboardShell.tsx b/src/components/DashboardShell.tsx index fbf5539..ea3edea 100644 --- a/src/components/DashboardShell.tsx +++ b/src/components/DashboardShell.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useState } from 'react'; -import Image from 'next/image'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { @@ -26,11 +25,10 @@ import { Images, History, } from 'lucide-react'; -import TenantSwitcher from '@/components/TenantSwitcher'; +import SidebarTenantSwitcher from '@/components/SidebarTenantSwitcher'; import type { DashboardModuleId } from '@/lib/tenant-modules'; import DateRangePicker from '@/components/DateRangePicker'; import { useDateRange } from '@/components/DateRangeContext'; -import SyncNowButton from '@/components/SyncNowButton'; type NavItem = { href: string; @@ -69,13 +67,6 @@ const NAV_ITEMS: NavItem[] = [ iconClass: 'text-emerald-500', moduleId: 'estrategia', }, - { - href: '/dashboard/marca', - label: 'Zona de marca', - icon: BookMarked, - iconClass: 'text-rose-500', - moduleId: 'marca', - }, { href: '/dashboard/ad-tracker', label: 'Ads', @@ -97,6 +88,13 @@ const NAV_ITEMS: NavItem[] = [ iconClass: 'text-lime-600', moduleId: 'organico', }, + { + href: '/dashboard/marca', + label: 'Zona de marca', + icon: BookMarked, + iconClass: 'text-rose-500', + moduleId: 'marca', + }, { href: '/dashboard/activos', label: 'Biblioteca de Activos', @@ -120,6 +118,23 @@ const NAV_ITEMS: NavItem[] = [ }, ]; +const EXCLUDED_DATE_HEADER_ROUTES = [ + '/dashboard/seguimiento', + '/dashboard/marca', + '/dashboard/activos', + '/dashboard/creatividades', + '/dashboard/creatives', + '/dashboard/asistente', + '/dashboard/agencia', +]; + +function shouldShowDateHeader(pathname: string | null): boolean { + if (!pathname) return true; + return !EXCLUDED_DATE_HEADER_ROUTES.some( + (route) => pathname === route || pathname.startsWith(route + '/') + ); +} + function isActive(pathname: string, href: string): boolean { if (pathname === href) return true; if (href !== '/dashboard' && pathname.startsWith(href + '/')) return true; @@ -163,6 +178,7 @@ export default function DashboardShell({ role, isAgency, viewName, + activeTenantId, enabledModules, clientLogoUrl, brandLabel, @@ -174,6 +190,7 @@ export default function DashboardShell({ role: string; isAgency: boolean; viewName?: string; + activeTenantId?: string | null; /** null = show all (agency default). */ enabledModules?: Record | null; clientLogoUrl?: string | null; @@ -184,6 +201,7 @@ export default function DashboardShell({ const close = () => setOpen(false); const dateRange = useDateRange(); const pathname = usePathname(); + const showDateHeader = shouldShowDateHeader(pathname); const moduleOn = (id: DashboardModuleId) => { if (isAgency) return true; @@ -193,48 +211,17 @@ export default function DashboardShell({ const visibleNav = NAV_ITEMS.filter((item) => moduleOn(item.moduleId)); - // Agencia siempre mantiene identidad 4Ventures (aunque esté "viendo" un cliente). - const title = isAgency - ? '4VENTURES' - : clientLogoUrl - ? brandLabel || company - : '4VENTURES'; - const subtitle = isAgency - ? viewName - ? `Agencia · viendo ${viewName}` - : 'Centro de Mando' - : 'Portal cliente'; - const sidebar = (
-
- {clientLogoUrl ? ( - // eslint-disable-next-line @next/next/no-img-element - {title} - ) : ( - 4Ventures - )} -
-

- {title} -

-

- {subtitle} -

-
+
+
-