Revert sidebar changes
This commit is contained in:
367
src/components/AppSidebar.tsx
Normal file
367
src/components/AppSidebar.tsx
Normal file
@@ -0,0 +1,367 @@
|
||||
import { useState } from "react";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubItem,
|
||||
SidebarMenuSubButton,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import {
|
||||
Home,
|
||||
Plus,
|
||||
Wallet,
|
||||
List,
|
||||
MessageSquare,
|
||||
Star,
|
||||
BookOpen,
|
||||
Heart,
|
||||
FileText,
|
||||
User,
|
||||
Users,
|
||||
Settings,
|
||||
LogOut,
|
||||
CreditCard,
|
||||
BarChart3,
|
||||
MapPin,
|
||||
DollarSign,
|
||||
AlertTriangle,
|
||||
Car,
|
||||
Target,
|
||||
Zap,
|
||||
Eye,
|
||||
Megaphone,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Hotel,
|
||||
UtensilsCrossed,
|
||||
Brain,
|
||||
DoorOpen,
|
||||
BellRing,
|
||||
Key,
|
||||
Receipt,
|
||||
ChefHat,
|
||||
Grid3x3,
|
||||
Package,
|
||||
Globe,
|
||||
Compass,
|
||||
Map,
|
||||
Shield,
|
||||
Radio,
|
||||
Sparkles,
|
||||
Leaf,
|
||||
Store,
|
||||
Navigation,
|
||||
} from "lucide-react";
|
||||
|
||||
export function AppSidebar() {
|
||||
const { open, openMobile, isMobile } = useSidebar();
|
||||
const collapsed = !open && !isMobile;
|
||||
const location = useLocation();
|
||||
const { logout } = useAuth();
|
||||
const [expandedItems, setExpandedItems] = useState<Record<string, boolean>>({});
|
||||
|
||||
const toggleExpanded = (itemPath: string) => {
|
||||
setExpandedItems((prev) => ({
|
||||
...prev,
|
||||
[itemPath]: !prev[itemPath],
|
||||
}));
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{ icon: Home, label: "Dashboard", path: "/dashboard" },
|
||||
{
|
||||
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",
|
||||
subItems: [
|
||||
{ icon: Globe, label: "Destinos", path: "/dashboard/admin?tab=content-destinations" },
|
||||
{ icon: MapPin, label: "Lugares", path: "/dashboard/admin?tab=content-places" },
|
||||
{ icon: BookOpen, label: "Guías", path: "/dashboard/admin?tab=content-guides" },
|
||||
{ icon: Car, label: "Taxis", path: "/dashboard/admin?tab=content-taxis" },
|
||||
{ icon: Navigation, label: "Geolocalización", path: "/dashboard/admin?tab=content-geolocation" },
|
||||
{ icon: Megaphone, label: "Promocional", path: "/dashboard/admin?tab=content-promotional" },
|
||||
{ icon: Sparkles, label: "AI Guías", path: "/dashboard/admin?tab=content-ai-guides" },
|
||||
{ icon: Eye, label: "AR Content", path: "/dashboard/admin?tab=content-ar" },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Map,
|
||||
label: "Geolocalización",
|
||||
path: "/dashboard/admin?tab=geofences",
|
||||
subItems: [
|
||||
{ icon: Target, label: "Geofences", path: "/dashboard/admin?tab=geofences" },
|
||||
{ icon: BarChart3, label: "Analytics", path: "/dashboard/admin?tab=analytics" },
|
||||
{ icon: Zap, label: "Testing", path: "/dashboard/admin?tab=testing" },
|
||||
{ icon: Shield, label: "Emergencia Geo", path: "/dashboard/admin?tab=emergency-geo" },
|
||||
{ icon: Compass, label: "Navegación", path: "/dashboard/admin?tab=navigation" },
|
||||
],
|
||||
},
|
||||
{ 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",
|
||||
path: "/dashboard/hotel",
|
||||
subItems: [
|
||||
{ icon: Home, label: "Habitaciones", path: "/dashboard/hotel/rooms" },
|
||||
{ icon: DoorOpen, label: "Check-in", path: "/dashboard/hotel/checkin" },
|
||||
{ icon: BellRing, label: "Room Service", path: "/dashboard/hotel/room-service" },
|
||||
{ icon: Key, label: "Acceso", path: "/dashboard/hotel/keyless" },
|
||||
{ icon: Users, label: "Personal", path: "/dashboard/hotel/staff" },
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: UtensilsCrossed,
|
||||
label: "Restaurant POS",
|
||||
path: "/dashboard/restaurant",
|
||||
subItems: [
|
||||
{ icon: CreditCard, label: "POS Terminal", path: "/dashboard/restaurant/pos" },
|
||||
{ icon: Receipt, label: "Pedidos", path: "/dashboard/restaurant/orders" },
|
||||
{ icon: ChefHat, label: "Cocina", path: "/dashboard/restaurant/kitchen" },
|
||||
{ icon: Receipt, label: "Cuentas", path: "/dashboard/restaurant/bills" },
|
||||
{ icon: Grid3x3, label: "Mesas", path: "/dashboard/restaurant/tables" },
|
||||
{ icon: UtensilsCrossed, label: "Menú", path: "/dashboard/restaurant/menu" },
|
||||
{ icon: Package, label: "Inventario", path: "/dashboard/restaurant/inventory" },
|
||||
{ icon: Users, label: "Personal", path: "/dashboard/restaurant/staff" },
|
||||
],
|
||||
},
|
||||
{ icon: Brain, label: "Personalization", path: "/dashboard/personalization" },
|
||||
{ icon: Shield, label: "Security", path: "/dashboard/security" },
|
||||
{ icon: Car, label: "Vehicle Management", path: "/dashboard/vehicle-management" },
|
||||
{ icon: Leaf, label: "Sustainability", path: "/dashboard/sustainability" },
|
||||
{ icon: Store, label: "Comercios", path: "/dashboard/establishments" },
|
||||
{ icon: Wallet, label: "Wallet", path: "/dashboard/wallet" },
|
||||
{ icon: MessageSquare, label: "Message", path: "/dashboard/messages", badge: "2" },
|
||||
];
|
||||
|
||||
const listingItems = [
|
||||
{ icon: List, label: "My Listing", path: "/dashboard/my-listings" },
|
||||
{ icon: Star, label: "Reviews", path: "/dashboard/reviews" },
|
||||
{ icon: BookOpen, label: "Bookings", path: "/dashboard/bookings" },
|
||||
{ icon: Heart, label: "Bookmark", path: "/dashboard/bookmarks" },
|
||||
{ icon: FileText, label: "Invoice", path: "/dashboard/invoices" },
|
||||
];
|
||||
|
||||
const accountItems = [
|
||||
{ icon: User, label: "Edit Profile", path: "/dashboard/profile" },
|
||||
{ icon: CreditCard, label: "Wallet", path: "/dashboard/wallet" },
|
||||
{ icon: Settings, label: "Setting", path: "/dashboard/settings" },
|
||||
];
|
||||
|
||||
const isActive = (path: string) => {
|
||||
if (path.includes("?tab=")) {
|
||||
const [basePath, tabQuery] = path.split("?tab=");
|
||||
return (
|
||||
location.pathname === basePath &&
|
||||
location.search.includes(tabQuery)
|
||||
);
|
||||
}
|
||||
return location.pathname === path || location.pathname.startsWith(path + "/");
|
||||
};
|
||||
|
||||
const hasActiveChild = (items: any[]) => {
|
||||
return items.some((item) => {
|
||||
if (isActive(item.path)) return true;
|
||||
if (item.subItems) return hasActiveChild(item.subItems);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
const renderMenuItem = (item: any, level = 0) => {
|
||||
const Icon = item.icon;
|
||||
const active = isActive(item.path);
|
||||
const hasSubItems = item.subItems && item.subItems.length > 0;
|
||||
const isExpanded = expandedItems[item.path] || hasActiveChild(item.subItems || []);
|
||||
|
||||
if (hasSubItems) {
|
||||
return (
|
||||
<Collapsible
|
||||
key={item.path}
|
||||
open={isExpanded}
|
||||
onOpenChange={() => toggleExpanded(item.path)}
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<CollapsibleTrigger asChild>
|
||||
<SidebarMenuButton
|
||||
className={`${
|
||||
active ? "bg-primary text-primary-foreground" : ""
|
||||
} ${collapsed && level === 0 ? "justify-center" : ""}`}
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
{!collapsed && <span>{item.label}</span>}
|
||||
{!collapsed && (
|
||||
<ChevronRight
|
||||
className={`ml-auto h-4 w-4 transition-transform ${
|
||||
isExpanded ? "rotate-90" : ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.subItems.map((subItem: any) =>
|
||||
renderSubMenuItem(subItem, level + 1)
|
||||
)}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarMenuItem key={item.path}>
|
||||
<SidebarMenuButton asChild isActive={active}>
|
||||
<Link to={item.path} className={collapsed && level === 0 ? "justify-center" : ""}>
|
||||
<Icon className="h-4 w-4" />
|
||||
{!collapsed && <span>{item.label}</span>}
|
||||
{!collapsed && item.badge && (
|
||||
<span className="ml-auto bg-green-500 text-white text-xs px-2 py-0.5 rounded-full">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSubMenuItem = (item: any, level: number) => {
|
||||
const Icon = item.icon;
|
||||
const active = isActive(item.path);
|
||||
const hasSubItems = item.subItems && item.subItems.length > 0;
|
||||
const isExpanded = expandedItems[item.path] || hasActiveChild(item.subItems || []);
|
||||
|
||||
if (hasSubItems) {
|
||||
return (
|
||||
<Collapsible
|
||||
key={item.path}
|
||||
open={isExpanded}
|
||||
onOpenChange={() => toggleExpanded(item.path)}
|
||||
>
|
||||
<SidebarMenuSubItem>
|
||||
<CollapsibleTrigger asChild>
|
||||
<SidebarMenuSubButton
|
||||
className={active ? "bg-primary/10 text-primary" : ""}
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
<span>{item.label}</span>
|
||||
<ChevronRight
|
||||
className={`ml-auto h-4 w-4 transition-transform ${
|
||||
isExpanded ? "rotate-90" : ""
|
||||
}`}
|
||||
/>
|
||||
</SidebarMenuSubButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.subItems.map((subItem: any) =>
|
||||
renderSubMenuItem(subItem, level + 1)
|
||||
)}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuSubItem>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarMenuSubItem key={item.path}>
|
||||
<SidebarMenuSubButton asChild isActive={active}>
|
||||
<Link to={item.path}>
|
||||
<Icon className="h-4 w-4" />
|
||||
<span>{item.label}</span>
|
||||
</Link>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Sidebar className={collapsed ? "w-14" : "w-80"} collapsible="icon">
|
||||
<SidebarContent className="overflow-y-auto">
|
||||
{/* Logo */}
|
||||
<div className="flex items-center justify-center p-6 border-b">
|
||||
<Link to="/dashboard">
|
||||
<img
|
||||
src="https://karibeo.com/desktop/assets/images/logo.png"
|
||||
alt="Karibeo"
|
||||
className={collapsed ? "w-8 h-8" : "w-24 h-24"}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Main Menu */}
|
||||
<SidebarGroup>
|
||||
{!collapsed && <SidebarGroupLabel>Main Menu</SidebarGroupLabel>}
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>{menuItems.map((item) => renderMenuItem(item))}</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
{/* Listing */}
|
||||
<SidebarGroup>
|
||||
{!collapsed && <SidebarGroupLabel>Listing</SidebarGroupLabel>}
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>{listingItems.map((item) => renderMenuItem(item))}</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
{/* Account */}
|
||||
<SidebarGroup>
|
||||
{!collapsed && <SidebarGroupLabel>Account</SidebarGroupLabel>}
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{accountItems.map((item) => renderMenuItem(item))}
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton onClick={logout} className={collapsed ? "justify-center" : ""}>
|
||||
<LogOut className="h-4 w-4" />
|
||||
{!collapsed && <span>Logout</span>}
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
@@ -1,446 +1,47 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Outlet, Link, useLocation } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { 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 { AppSidebar } from '@/components/AppSidebar';
|
||||
import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar';
|
||||
import {
|
||||
Home,
|
||||
Plus,
|
||||
Wallet,
|
||||
List,
|
||||
MessageSquare,
|
||||
Star,
|
||||
BookOpen,
|
||||
Heart,
|
||||
FileText,
|
||||
User,
|
||||
Users,
|
||||
Settings,
|
||||
LogOut,
|
||||
Search,
|
||||
Bell,
|
||||
Menu,
|
||||
Sun,
|
||||
Moon,
|
||||
Maximize,
|
||||
CreditCard,
|
||||
BarChart3,
|
||||
MapPin,
|
||||
DollarSign,
|
||||
AlertTriangle,
|
||||
RefreshCw,
|
||||
Navigation,
|
||||
Car,
|
||||
Target,
|
||||
Zap,
|
||||
Eye,
|
||||
Megaphone,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Hotel,
|
||||
UtensilsCrossed,
|
||||
Brain,
|
||||
DoorOpen,
|
||||
BellRing,
|
||||
Key,
|
||||
Receipt,
|
||||
ChefHat,
|
||||
Grid3x3,
|
||||
Package,
|
||||
Globe,
|
||||
Compass,
|
||||
Map,
|
||||
Shield,
|
||||
Radio,
|
||||
Sparkles,
|
||||
Leaf,
|
||||
Store
|
||||
} from 'lucide-react';
|
||||
|
||||
const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
const { user, logout } = useAuth();
|
||||
const { user } = useAuth();
|
||||
const { t } = useLanguage();
|
||||
const location = useLocation();
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
const [expandedItems, setExpandedItems] = useState<Record<string, boolean>>({});
|
||||
|
||||
const currentTab = new URLSearchParams(location.search).get('tab') || 'overview';
|
||||
|
||||
const toggleExpanded = (itemTab: string) => {
|
||||
setExpandedItems(prev => ({
|
||||
...prev,
|
||||
[itemTab]: !prev[itemTab]
|
||||
}));
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{ icon: Home, label: 'Dashboard', path: '/dashboard' },
|
||||
{
|
||||
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',
|
||||
subItems: [
|
||||
{ icon: Globe, label: 'Destinos', path: '/dashboard/admin?tab=content-destinations' },
|
||||
{ icon: MapPin, label: 'Lugares', path: '/dashboard/admin?tab=content-places' },
|
||||
{ icon: BookOpen, label: 'Guías', path: '/dashboard/admin?tab=content-guides' },
|
||||
{ icon: Car, label: 'Taxis', path: '/dashboard/admin?tab=content-taxis' },
|
||||
{ icon: Navigation, label: 'Geolocalización', path: '/dashboard/admin?tab=content-geolocation' },
|
||||
{ icon: Megaphone, label: 'Promocional', path: '/dashboard/admin?tab=content-promotional' },
|
||||
{ icon: Sparkles, label: 'AI Guías', path: '/dashboard/admin?tab=content-ai-guides' },
|
||||
{ icon: Eye, label: 'AR Content', path: '/dashboard/admin?tab=content-ar' }
|
||||
]
|
||||
},
|
||||
{
|
||||
icon: Map,
|
||||
label: 'Geolocalización',
|
||||
path: '/dashboard/admin?tab=geofences',
|
||||
subItems: [
|
||||
{ icon: Target, label: 'Geofences', path: '/dashboard/admin?tab=geofences' },
|
||||
{ icon: BarChart3, label: 'Analytics', path: '/dashboard/admin?tab=analytics' },
|
||||
{ icon: Zap, label: 'Testing', path: '/dashboard/admin?tab=testing' },
|
||||
{ icon: Shield, label: 'Emergencia Geo', path: '/dashboard/admin?tab=emergency-geo' },
|
||||
{ icon: Compass, label: 'Navegación', path: '/dashboard/admin?tab=navigation' }
|
||||
]
|
||||
},
|
||||
{ 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',
|
||||
path: '/dashboard/hotel',
|
||||
subItems: [
|
||||
{ icon: Home, label: 'Habitaciones', path: '/dashboard/hotel/rooms' },
|
||||
{ icon: DoorOpen, label: 'Check-in', path: '/dashboard/hotel/checkin' },
|
||||
{ icon: BellRing, label: 'Room Service', path: '/dashboard/hotel/room-service' },
|
||||
{ icon: Key, label: 'Acceso', path: '/dashboard/hotel/keyless' },
|
||||
{ icon: Users, label: 'Personal', path: '/dashboard/hotel/staff' }
|
||||
]
|
||||
},
|
||||
{
|
||||
icon: UtensilsCrossed,
|
||||
label: 'Restaurant POS',
|
||||
path: '/dashboard/restaurant',
|
||||
subItems: [
|
||||
{ icon: CreditCard, label: 'POS Terminal', path: '/dashboard/restaurant/pos' },
|
||||
{ icon: Receipt, label: 'Pedidos', path: '/dashboard/restaurant/orders' },
|
||||
{ icon: ChefHat, label: 'Cocina', path: '/dashboard/restaurant/kitchen' },
|
||||
{ icon: Receipt, label: 'Cuentas', path: '/dashboard/restaurant/bills' },
|
||||
{ icon: Grid3x3, label: 'Mesas', path: '/dashboard/restaurant/tables' },
|
||||
{ icon: UtensilsCrossed, label: 'Menú', path: '/dashboard/restaurant/menu' },
|
||||
{ icon: Package, label: 'Inventario', path: '/dashboard/restaurant/inventory' },
|
||||
{ icon: Users, label: 'Personal', path: '/dashboard/restaurant/staff' }
|
||||
]
|
||||
},
|
||||
{ icon: Brain, label: 'Personalization', path: '/dashboard/personalization' },
|
||||
{ icon: Shield, label: 'Security', path: '/dashboard/security' },
|
||||
{ icon: Car, label: 'Vehicle Management', path: '/dashboard/vehicle-management' },
|
||||
{ icon: Leaf, label: 'Sustainability', path: '/dashboard/sustainability' },
|
||||
{ icon: Store, label: 'Comercios', path: '/dashboard/establishments' },
|
||||
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
|
||||
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
|
||||
];
|
||||
|
||||
const listingItems = [
|
||||
{ icon: List, label: 'My Listing', path: '/dashboard/my-listings', hasSubmenu: true },
|
||||
{ icon: Star, label: 'Reviews', path: '/dashboard/reviews' },
|
||||
{ icon: BookOpen, label: 'Bookings', path: '/dashboard/bookings' },
|
||||
{ icon: Heart, label: 'Bookmark', path: '/dashboard/bookmarks' },
|
||||
{ icon: FileText, label: 'Invoice', path: '/dashboard/invoices' },
|
||||
];
|
||||
|
||||
const accountItems = [
|
||||
{ icon: User, label: 'Edit Profile', path: '/dashboard/profile' },
|
||||
{ icon: CreditCard, label: 'Wallet', path: '/dashboard/wallet' },
|
||||
{ icon: Settings, label: 'Setting', path: '/dashboard/settings' },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<DashboardStyles />
|
||||
<div className="min-h-screen" style={{ fontFamily: '"Wix Madefor Display", sans-serif', backgroundColor: '#f8f4f3' }}>
|
||||
<SidebarProvider>
|
||||
<div className="min-h-screen w-full flex" style={{ fontFamily: '"Wix Madefor Display", sans-serif', backgroundColor: '#f8f4f3' }}>
|
||||
{/* Background decorations */}
|
||||
<div className="decoration blur-2"></div>
|
||||
<div className="decoration blur-3"></div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<nav className={`fixed top-0 left-0 z-50 h-screen bg-white border-r-4 border-white transition-all duration-300 ${sidebarCollapsed ? 'w-16' : 'w-80'}`} style={{ minWidth: sidebarCollapsed ? '64px' : '320px', maxWidth: sidebarCollapsed ? '64px' : '320px', backdropFilter: 'blur(15px)', backgroundColor: 'rgba(255, 255, 255, 0.9)' }}>
|
||||
{/* Sidebar Header */}
|
||||
<div className="flex items-center justify-between p-6 h-20 border-b border-gray-100">
|
||||
<Link to="/dashboard" className={`flex items-center space-x-2 ${sidebarCollapsed ? 'justify-center' : ''}`}>
|
||||
<div className="w-24 h-24 rounded-lg flex items-center justify-center">
|
||||
<img
|
||||
src="https://karibeo.com/desktop/assets/images/logo.png"
|
||||
alt="Karibeo"
|
||||
className="w-full h-full object-contain rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Sidebar Navigation */}
|
||||
<div className="p-4 h-full overflow-y-auto" style={{ height: 'calc(100vh - 80px)' }}>
|
||||
{/* Main Menu */}
|
||||
<div className="mb-6">
|
||||
{!sidebarCollapsed && (
|
||||
<div className="flex items-center justify-between mb-4 px-4 py-3">
|
||||
<span className="text-xs font-semibold text-gray-600 uppercase tracking-wider">Main Menu</span>
|
||||
<div className="flex space-x-1">
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-1 pr-8">
|
||||
{menuItems.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const isActive = location.pathname === item.path || location.pathname.startsWith(item.path + '/');
|
||||
const hasDirectSubItems = item.subItems && item.subItems.length > 0;
|
||||
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path || location.pathname.startsWith(sub.path + '/')));
|
||||
|
||||
return (
|
||||
<div key={item.path}>
|
||||
<div className={`flex items-center justify-between ${sidebarCollapsed ? '' : 'pr-2'}`}>
|
||||
<Link
|
||||
to={item.path}
|
||||
className={`flex items-center space-x-3 px-7 py-2.5 rounded-none transition-all border-l-4 flex-1 ${
|
||||
isActive
|
||||
? 'text-white border-l-4 rounded-r-full'
|
||||
: 'text-gray-700 hover:text-red-500 border-transparent rounded-r-full'
|
||||
} ${sidebarCollapsed ? 'justify-center px-2' : ''}`}
|
||||
style={{
|
||||
backgroundColor: isActive ? 'rgba(248, 69, 37, 1)' : 'transparent',
|
||||
borderLeftColor: isActive ? '#F84525' : 'transparent',
|
||||
color: isActive ? '#F84525' : '#433c3a'
|
||||
}}
|
||||
>
|
||||
<Icon className="w-5 h-5 flex-shrink-0" />
|
||||
{!sidebarCollapsed && (
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<span className="font-medium">{item.label}</span>
|
||||
{item.badge && (
|
||||
<span className="bg-green-500 text-white text-xs px-2 py-0.5 rounded-full">
|
||||
{item.badge}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
{!sidebarCollapsed && hasDirectSubItems && (
|
||||
<button
|
||||
onClick={() => toggleExpanded(item.path)}
|
||||
className="p-1 hover:bg-gray-200 rounded mr-2"
|
||||
>
|
||||
{isExpanded ? (
|
||||
<ChevronDown className="w-3 h-3" />
|
||||
) : (
|
||||
<ChevronRight className="w-3 h-3" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 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 || location.pathname.startsWith(sub.path) || (sub.path.includes('?tab=') && location.search.includes(sub.path.split('?tab=')[1]));
|
||||
const hasSubSubItems = sub.subItems && sub.subItems.length > 0;
|
||||
const isSubExpanded = expandedItems[sub.path] || (hasSubSubItems && sub.subItems.some(subsub => location.search.includes(subsub.path.split('?tab=')[1])));
|
||||
|
||||
return (
|
||||
<div key={sub.path}>
|
||||
<div className="flex items-center justify-between">
|
||||
<Link
|
||||
to={sub.path}
|
||||
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm flex-1 ${activeSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
|
||||
>
|
||||
<SubIcon className="h-4 w-4" />
|
||||
<span>{sub.label}</span>
|
||||
</Link>
|
||||
{hasSubSubItems && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
toggleExpanded(sub.path);
|
||||
}}
|
||||
className="p-1 hover:bg-gray-200 rounded mr-1"
|
||||
>
|
||||
{isSubExpanded ? (
|
||||
<ChevronDown className="w-3 h-3" />
|
||||
) : (
|
||||
<ChevronRight className="w-3 h-3" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sub-sub-items */}
|
||||
{hasSubSubItems && isSubExpanded && (
|
||||
<div className="mt-1 ml-6 space-y-1">
|
||||
{sub.subItems.map((subsub) => {
|
||||
const SubSubIcon = subsub.icon;
|
||||
const activeSubSubPath = location.search.includes(subsub.path.split('?tab=')[1]);
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={subsub.path}
|
||||
to={subsub.path}
|
||||
className={`flex items-center space-x-2 px-3 py-1.5 rounded-md text-xs ${activeSubSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-500 hover:text-orange-600 hover:bg-gray-50'}`}
|
||||
>
|
||||
<SubSubIcon className="h-3 w-3" />
|
||||
<span>{subsub.label}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Listing Section */}
|
||||
<div className="mb-6">
|
||||
{!sidebarCollapsed && (
|
||||
<div className="flex items-center justify-between mb-4 px-4 py-3">
|
||||
<span className="text-xs font-semibold text-gray-600 uppercase tracking-wider">Listing</span>
|
||||
<div className="flex space-x-1">
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-1 pr-8">
|
||||
{listingItems.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const isActive = location.pathname === item.path;
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`flex items-center space-x-3 px-7 py-2.5 rounded-none transition-all border-l-4 ${
|
||||
isActive
|
||||
? 'text-white border-l-4 rounded-r-full'
|
||||
: 'text-gray-700 hover:text-red-500 border-transparent rounded-r-full'
|
||||
} ${sidebarCollapsed ? 'justify-center px-2' : ''}`}
|
||||
style={{
|
||||
backgroundColor: isActive ? 'rgba(248, 69, 37, 0.1)' : 'transparent',
|
||||
borderLeftColor: isActive ? '#F84525' : 'transparent',
|
||||
color: isActive ? '#F84525' : '#433c3a'
|
||||
}}
|
||||
>
|
||||
<Icon className="w-5 h-5 flex-shrink-0" />
|
||||
{!sidebarCollapsed && <span className="font-medium">{item.label}</span>}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Account Section */}
|
||||
<div className="mb-6">
|
||||
{!sidebarCollapsed && (
|
||||
<div className="flex items-center justify-between mb-4 px-4 py-3">
|
||||
<span className="text-xs font-semibold text-gray-600 uppercase tracking-wider">Account</span>
|
||||
<div className="flex space-x-1">
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
<div className="w-1 h-1 bg-gray-400 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-1 pr-8">
|
||||
{accountItems.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const isActive = location.pathname === item.path;
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`flex items-center space-x-3 px-7 py-2.5 rounded-none transition-all border-l-4 ${
|
||||
isActive
|
||||
? 'text-white border-l-4 rounded-r-full'
|
||||
: 'text-gray-700 hover:text-red-500 border-transparent rounded-r-full'
|
||||
} ${sidebarCollapsed ? 'justify-center px-2' : ''}`}
|
||||
style={{
|
||||
backgroundColor: isActive ? 'rgba(248, 69, 37, 0.1)' : 'transparent',
|
||||
borderLeftColor: isActive ? '#F84525' : 'transparent',
|
||||
color: isActive ? '#F84525' : '#433c3a'
|
||||
}}
|
||||
>
|
||||
<Icon className="w-5 h-5 flex-shrink-0" />
|
||||
{!sidebarCollapsed && <span className="font-medium">{item.label}</span>}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
<button
|
||||
onClick={logout}
|
||||
className={`flex items-center space-x-3 px-7 py-2.5 rounded-r-full transition-all text-gray-700 hover:text-red-600 w-full border-l-4 border-transparent ${sidebarCollapsed ? 'justify-center px-2' : ''}`}
|
||||
>
|
||||
<LogOut className="w-5 h-5 flex-shrink-0" />
|
||||
{!sidebarCollapsed && <span className="font-medium">Logout</span>}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
<AppSidebar />
|
||||
|
||||
{/* Main Content Area */}
|
||||
<div className={`transition-all duration-300 ${sidebarCollapsed ? 'ml-16' : 'ml-80'}`}>
|
||||
<div className="flex-1 flex flex-col w-full">
|
||||
{/* Top Navigation */}
|
||||
<nav className="h-20 px-6 py-4 z-10 relative" style={{ backgroundColor: 'rgba(255, 255, 255, 0.7)', backdropFilter: 'blur(15px)' }}>
|
||||
<div className="flex items-center justify-between">
|
||||
{/* Left Side */}
|
||||
<div className="flex items-center space-x-4">
|
||||
<button
|
||||
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
className="p-2 rounded-full text-white transition-colors"
|
||||
style={{ backgroundColor: '#F84525' }}
|
||||
>
|
||||
<SidebarTrigger className="p-2 rounded-full text-white transition-colors" style={{ backgroundColor: '#F84525' }}>
|
||||
<Menu className="w-5 h-5" />
|
||||
</button>
|
||||
</SidebarTrigger>
|
||||
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
@@ -455,10 +56,20 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
backgroundColor: '#fff',
|
||||
borderColor: '#fff',
|
||||
height: '48px',
|
||||
borderRadius: '0.8rem'
|
||||
borderRadius: '0.8rem',
|
||||
}}
|
||||
/>
|
||||
<span className="absolute inset-y-0 right-0 pr-3 flex items-center text-xs font-bold px-2 py-1 rounded" style={{ backgroundColor: '#f8f4f3', borderColor: '#f8f4f3', top: '50%', transform: 'translateY(-50%)', right: '8px', fontSize: '12px' }}>
|
||||
<span
|
||||
className="absolute inset-y-0 right-0 pr-3 flex items-center text-xs font-bold px-2 py-1 rounded"
|
||||
style={{
|
||||
backgroundColor: '#f8f4f3',
|
||||
borderColor: '#f8f4f3',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
right: '8px',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
>
|
||||
(Ctrl+/)
|
||||
</span>
|
||||
</div>
|
||||
@@ -480,18 +91,30 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
</button>
|
||||
|
||||
{/* Notifications */}
|
||||
<button className="p-2 rounded-xl transition-colors relative" style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }} title="Notificaciones">
|
||||
<button
|
||||
className="p-2 rounded-xl transition-colors relative"
|
||||
style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }}
|
||||
title="Notificaciones"
|
||||
>
|
||||
<Bell className="w-5 h-5" />
|
||||
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[10px] px-1 py-0.5 rounded-full">!</span>
|
||||
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-[10px] px-1 py-0.5 rounded-full">
|
||||
!
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Theme Toggle */}
|
||||
<button className="p-2 rounded-xl transition-colors" style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }}>
|
||||
<button
|
||||
className="p-2 rounded-xl transition-colors"
|
||||
style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }}
|
||||
>
|
||||
<Sun className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
{/* Fullscreen */}
|
||||
<button className="p-2 rounded-xl transition-colors" style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }}>
|
||||
<button
|
||||
className="p-2 rounded-xl transition-colors"
|
||||
style={{ backgroundColor: '#21272f', borderColor: '#21272f', color: '#F84525' }}
|
||||
>
|
||||
<Maximize className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
@@ -508,12 +131,12 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
<div className="font-semibold text-gray-800 text-sm flex items-center space-x-2">
|
||||
<span>{user?.name || 'Usuario'}</span>
|
||||
{user?.role === 'super_admin' && (
|
||||
<span className="bg-gradient-to-r from-orange-400 to-red-500 text-white text-[10px] px-1.5 py-0.5 rounded">Super Admin</span>
|
||||
<span className="bg-gradient-to-r from-orange-400 to-red-500 text-white text-[10px] px-1.5 py-0.5 rounded">
|
||||
Super Admin
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{user?.email || 'example@gmail.com'}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">{user?.email || 'example@gmail.com'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -522,11 +145,10 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
</nav>
|
||||
|
||||
{/* Page Content */}
|
||||
<main className="p-6">
|
||||
{children}
|
||||
</main>
|
||||
<main className="p-6 flex-1">{children}</main>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user