'use client';
/**
* PortalSidebar — vertical sidebar navigation for the Client Portal.
*
* Renders navigation items vertically in a fixed left sidebar below the TopNav.
* "Analítica" is a collapsible section with sub-items (Overview, Top Songs,
* Income Groups, Territories, Exploitation Sources).
*
* Features:
* - Fixed left sidebar (200px) on desktop (≥1024px)
* - Active item highlighted with accent left border + accent text + accent bg
* - Collapsible "Analítica" section with smooth animation
* - Icons for each tab and sub-item
* - Mobile hamburger menu + overlay drawer for viewports below 1024px
*/
import { useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { PORTAL_TABS, PORTAL_ANALYTICS_SUBITEMS } from '@/lib/constants/portal-navigation';
import { usePortalSidebarStore } from '@/lib/stores/portal-sidebar-store';
// ── Icon components ──────────────────────────────────────────────────────────
function HomeIcon({ className }: { className?: string }) {
return (
);
}
function ChartIcon({ className }: { className?: string }) {
return (
);
}
function MusicIcon({ className }: { className?: string }) {
return (
);
}
function DocumentIcon({ className }: { className?: string }) {
return (
);
}
function ChartOverviewIcon({ className }: { className?: string }) {
return (
);
}
function TopSongsIcon({ className }: { className?: string }) {
return (
);
}
function IncomeGroupsIcon({ className }: { className?: string }) {
return (
);
}
function TerritoriesIcon({ className }: { className?: string }) {
return (
);
}
function SourcesIcon({ className }: { className?: string }) {
return (
);
}
function ChevronIcon({ expanded, className }: { expanded: boolean; className?: string }) {
return (
);
}
/** Map sub-item href to its icon component */
function SubItemIcon({ href, className }: { href: string; className?: string }) {
switch (href) {
case '/portal/analytics':
return ;
case '/portal/analytics/top-songs':
return ;
case '/portal/analytics/income-groups':
return ;
case '/portal/analytics/territories':
return ;
case '/portal/analytics/sources':
return ;
default:
return ;
}
}
/** Map tab href to its icon component */
function TabIcon({ href, className }: { href: string; className?: string }) {
switch (href) {
case '/portal':
return ;
case '/portal/analytics':
return ;
case '/portal/songs':
return ;
case '/portal/documents':
return ;
default:
return ;
}
}
// ── Helper: check if current path is within analytics section ─────────────────
function isAnalyticsPath(pathname: string): boolean {
return pathname.startsWith('/portal/analytics');
}
// ── PortalSidebar component ──────────────────────────────────────────────────
export default function PortalSidebar() {
const pathname = usePathname();
const { isMobileOpen, closeMobile, toggleMobile } = usePortalSidebarStore();
const [analyticsExpanded, setAnalyticsExpanded] = useState(true);
// Filter out the "Analítica" tab — it becomes a section header
const mainTabs = PORTAL_TABS.filter((tab) => tab.href !== '/portal/analytics');
const renderNavContent = (onItemClick?: () => void) => (
<>
{/* Inicio */}
{mainTabs
.filter((tab) => tab.href === '/portal')
.map((tab) => {
const isActive = pathname === tab.href;
return (
{isActive && (
)}
{tab.label}
);
})}
{/* Analítica collapsible section */}
{/* Collapsible sub-items */}
{PORTAL_ANALYTICS_SUBITEMS.map((item) => {
const isActive = pathname === item.href;
return (
{isActive && (
)}
{item.label}
);
})}
{/* Canciones & Documentos */}
{mainTabs
.filter((tab) => tab.href !== '/portal')
.map((tab) => {
const isActive = pathname === tab.href;
return (
{isActive && (
)}
{tab.label}
);
})}
>
);
return (
<>
{/* ─── Desktop sidebar (≥1024px) ─────────────────────────────────── */}
{/* ─── Mobile hamburger button (visible below lg) ───────────────── */}
{/* ─── Mobile overlay + drawer (below lg) ───────────────────────── */}
{isMobileOpen && (
<>
{/* Backdrop */}
{/* Drawer */}
>
)}
>
);
}