Refactor sidebar navigation

This commit is contained in:
gpt-engineer-app[bot]
2025-10-10 23:40:41 +00:00
parent 4ff9ca94b3
commit 5c6db629ce
4 changed files with 154 additions and 172 deletions

View File

@@ -3,6 +3,7 @@ import { Outlet, Link, useLocation } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { useLanguage } from '@/contexts/LanguageContext';
import DashboardStyles from '@/components/layouts/DashboardStyles';
import CurrencySelector from '@/components/CurrencySelector';
import {
Home,
Plus,
@@ -67,8 +68,33 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
const menuItems = [
{ icon: Home, label: 'Dashboard', path: '/dashboard' },
{ icon: Settings, label: 'Admin Panel', path: '/dashboard/admin', hasSubmenu: true },
{ icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager', hasSubmenu: true },
{
icon: Settings,
label: 'Admin Panel',
path: '/dashboard/admin',
subItems: [
{ icon: BarChart3, label: 'Resumen General', path: '/dashboard/admin?tab=overview' },
{ icon: Users, label: 'Usuarios', path: '/dashboard/admin?tab=users' },
{ icon: MapPin, label: 'Proveedores', path: '/dashboard/admin?tab=services' },
{ icon: DollarSign, label: 'Financiero', path: '/dashboard/admin?tab=financial' },
{ icon: FileText, label: 'Contenido', path: '/dashboard/admin?tab=content' },
{ icon: AlertTriangle, label: 'Emergencias', path: '/dashboard/admin?tab=emergency' },
{ icon: MessageSquare, label: 'Soporte', path: '/dashboard/admin?tab=support' },
{ icon: Settings, label: 'Configuración', path: '/dashboard/admin?tab=config' }
]
},
{
icon: Plus,
label: 'Channel Manager',
path: '/dashboard/channel-manager',
subItems: [
{ icon: BarChart3, label: 'Resumen', path: '/dashboard/channel-manager?tab=overview' },
{ icon: Zap, label: 'Canales', path: '/dashboard/channel-manager?tab=channels' },
{ icon: Home, label: 'Propiedades', path: '/dashboard/channel-manager?tab=listings' },
{ icon: BookOpen, label: 'Reservas', path: '/dashboard/channel-manager?tab=reservations' },
{ icon: BarChart3, label: 'Analytics', path: '/dashboard/channel-manager?tab=analytics' }
]
},
{
icon: Hotel,
label: 'Hotel Management',
@@ -101,50 +127,6 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
];
const channelManagerSubmenu = [
{ icon: BarChart3, label: 'Resumen', tab: 'overview' },
{ icon: Zap, label: 'Canales', tab: 'channels' },
{ icon: Home, label: 'Propiedades', tab: 'listings' },
{ icon: BookOpen, label: 'Reservas', tab: 'reservations' },
{ icon: BarChart3, label: 'Analytics', tab: 'analytics' },
];
const adminSubmenu = [
{ icon: BarChart3, label: 'Resumen General', tab: 'overview' },
{ icon: Users, label: 'Gestión de Usuarios', tab: 'users' },
{ icon: MapPin, label: 'Proveedores de Servicios', tab: 'services' },
{ icon: DollarSign, label: 'Gestión Financiera', tab: 'financial' },
{
icon: FileText,
label: 'Contenido Turístico',
tab: 'content',
subItems: [
{ icon: MapPin, label: 'Destinos', tab: 'content-destinations' },
{ icon: Star, label: 'Lugares', tab: 'content-places' },
{ icon: Users, label: 'Guías', tab: 'content-guides' },
{ icon: Car, label: 'Taxis', tab: 'content-taxis' },
{
icon: Navigation,
label: 'Geolocalización',
tab: 'content-geolocation',
subItems: [
{ icon: MapPin, label: 'Geofences', tab: 'geofences' },
{ icon: BarChart3, label: 'Analíticas', tab: 'analytics' },
{ icon: Target, label: 'Pruebas', tab: 'testing' },
{ icon: AlertTriangle, label: 'Emergencias', tab: 'emergency-geo' },
{ icon: Navigation, label: 'Navegación', tab: 'navigation' }
]
},
{ icon: Megaphone, label: 'Promocional', tab: 'content-promotional' },
{ icon: Zap, label: 'Guías IA', tab: 'content-ai-guides' },
{ icon: Eye, label: 'Realidad AR', tab: 'content-ar' }
]
},
{ icon: AlertTriangle, label: 'Emergencias', tab: 'emergency' },
{ icon: MessageSquare, label: 'Soporte', tab: 'support' },
...(user?.role === 'super_admin' ? [{ icon: Settings, label: 'Configuración', tab: 'config' }] : []),
];
const listingItems = [
{ icon: List, label: 'My Listing', path: '/dashboard/my-listings', hasSubmenu: true },
{ icon: Star, label: 'Reviews', path: '/dashboard/reviews' },
@@ -201,10 +183,8 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
{menuItems.map((item) => {
const Icon = item.icon;
const isActive = location.pathname === item.path || location.pathname.startsWith(item.path + '/');
const isAdminPanel = item.path === '/dashboard/admin';
const isChannelManager = item.path === '/dashboard/channel-manager';
const hasDirectSubItems = item.subItems && item.subItems.length > 0;
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path));
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path || location.pathname.startsWith(sub.path + '/')));
return (
<div key={item.path}>
@@ -248,12 +228,12 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
)}
</div>
{/* Direct sub-items (Hotel & Restaurant) */}
{/* Sub-items */}
{!sidebarCollapsed && hasDirectSubItems && isExpanded && (
<div className="mt-1 ml-10 space-y-1">
{item.subItems.map((sub) => {
const SubIcon = sub.icon;
const activeSubPath = location.pathname === sub.path;
const activeSubPath = location.pathname === sub.path || location.pathname.startsWith(sub.path);
return (
<Link
@@ -261,7 +241,7 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
to={sub.path}
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
>
<SubIcon className="w-4 h-4" />
<SubIcon className="h-4 w-4" />
<span>{sub.label}</span>
</Link>
);
@@ -269,123 +249,6 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
</div>
)}
{/* Channel Manager submenus */}
{!sidebarCollapsed && isChannelManager && location.pathname.startsWith('/dashboard/channel-manager') && (
<div className="mt-1 ml-10 space-y-1">
{channelManagerSubmenu.map((sub) => {
const SubIcon = sub.icon;
const activeSub = currentTab === sub.tab;
return (
<Link
key={sub.tab}
to={`/dashboard/channel-manager?tab=${sub.tab}`}
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSub ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
>
<SubIcon className="w-4 h-4" />
<span>{sub.label}</span>
</Link>
);
})}
</div>
)}
{/* Admin submenus */}
{!sidebarCollapsed && isAdminPanel && location.pathname.startsWith('/dashboard/admin') && (
<div className="mt-1 ml-10 space-y-1">
{adminSubmenu.map((sub) => {
const SubIcon = sub.icon;
const activeSub = currentTab === sub.tab;
const hasSubItems = sub.subItems && sub.subItems.length > 0;
const isExpanded = expandedItems[sub.tab] || (hasSubItems && sub.subItems.some(item => currentTab === item.tab || (item.subItems && item.subItems.some(subItem => currentTab === subItem.tab))));
return (
<div key={sub.tab}>
<div className={`flex items-center justify-between px-3 py-2 rounded-md text-sm ${activeSub ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}>
<Link
to={`/dashboard/admin?tab=${sub.tab}`}
className="flex items-center space-x-2 flex-1"
>
<SubIcon className="w-4 h-4" />
<span>{sub.label}</span>
</Link>
{hasSubItems && (
<button
onClick={() => toggleExpanded(sub.tab)}
className="p-1 hover:bg-gray-200 rounded"
>
{isExpanded ? (
<ChevronDown className="w-3 h-3" />
) : (
<ChevronRight className="w-3 h-3" />
)}
</button>
)}
</div>
{/* Sub-submenus */}
{hasSubItems && isExpanded && (
<div className="ml-6 mt-1 space-y-1">
{sub.subItems.map((subItem) => {
const SubSubIcon = subItem.icon;
const activeSubSub = currentTab === subItem.tab;
const hasSubSubItems = subItem.subItems && subItem.subItems.length > 0;
const isSubExpanded = expandedItems[subItem.tab] || (hasSubSubItems && subItem.subItems.some(item => currentTab === item.tab));
return (
<div key={subItem.tab}>
<div className={`flex items-center justify-between px-3 py-1.5 rounded-md text-xs ${activeSubSub ? 'bg-orange-100 text-orange-700' : 'text-gray-500 hover:text-orange-600 hover:bg-gray-50'}`}>
<Link
to={`/dashboard/admin?tab=${subItem.tab}`}
className="flex items-center space-x-2 flex-1"
>
<SubSubIcon className="w-3 h-3" />
<span>{subItem.label}</span>
</Link>
{hasSubSubItems && (
<button
onClick={() => toggleExpanded(subItem.tab)}
className="p-1 hover:bg-gray-200 rounded"
>
{isSubExpanded ? (
<ChevronDown className="w-3 h-3" />
) : (
<ChevronRight className="w-3 h-3" />
)}
</button>
)}
</div>
{/* Sub-sub-submenus */}
{hasSubSubItems && isSubExpanded && (
<div className="ml-4 mt-1 space-y-1">
{subItem.subItems.map((subSubItem) => {
const SubSubSubIcon = subSubItem.icon;
const activeSubSubSub = currentTab === subSubItem.tab;
return (
<Link
key={subSubItem.tab}
to={`/dashboard/admin?tab=${subSubItem.tab}`}
className={`flex items-center space-x-2 px-3 py-1 rounded-md text-xs ${activeSubSubSub ? 'bg-orange-200 text-orange-800' : 'text-gray-400 hover:text-orange-600 hover:bg-gray-50'}`}
>
<SubSubSubIcon className="w-3 h-3" />
<span>{subSubItem.label}</span>
</Link>
);
})}
</div>
)}
</div>
);
})}
</div>
)}
</div>
);
})}
</div>
)}
</div>
);
})}
@@ -524,6 +387,9 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
{/* Right Side */}
<div className="flex items-center space-x-4">
{/* Currency Selector */}
<CurrencySelector />
{/* Refresh (Admin) */}
<button
onClick={() => window.dispatchEvent(new CustomEvent('admin:refresh'))}