Sidebar.tsx
Golden-Hour-backend-layer-2/components/Sidebar.tsx
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { ModuleType } from '../types';
interface SidebarProps {
activeModule: ModuleType;
isOpen: boolean;
}
const navItems = [
{
id: 'I',
label: 'Overview',
module: ModuleType.DASHBOARD,
icon: 'fa-compass',
subItems: [{ id: '1-1', label: 'Dashboard', path: '/dashboard' }]
},
{
id: 'II',
label: 'Content Management',
subLabel: '(Create, Edit, Delete, Search)',
module: ModuleType.CONTENT,
icon: 'fa-feather-pointed',
subItems: [
{ id: '2-1', label: 'Maisons', path: '/content/maisons' },
{ id: '2-2', label: 'Experiences', path: '/content/experiences' },
{ id: '2-3', label: 'Services', path: '/content/services' },
{ id: '2-4', label: 'Products', path: '/content/products' },
{ id: '2-5', label: 'Blog', path: '/content/blog' },
{ id: '2-6', label: 'Downloads', path: '/content/downloads' }
]
},
{
id: 'III',
label: 'Order Management',
subLabel: '(Create, Edit, Delete, Search)',
module: ModuleType.ORDERS,
icon: 'fa-bag-shopping',
subItems: [
{ id: '3-1', label: 'Maisons Orders', path: '/orders/maisons' },
{ id: '3-2', label: 'Experiences Orders', path: '/orders/experiences' },
{ id: '3-3', label: 'Services Orders', path: '/orders/services' },
{ id: '3-4', label: 'Products Orders', path: '/orders/products' },
{ id: '3-5', label: 'Returns / Refunds', path: '/orders/returns' }
]
},
{
id: 'IV',
label: 'Customer Information',
subLabel: '(Create, Edit, Delete, Search)',
module: ModuleType.CUSTOMERS,
icon: 'fa-user-tag',
subItems: [{ id: '4-1', label: 'Customer List', path: '/customers' }]
},
{
id: 'V',
label: 'Customer Service',
subLabel: '(Guest Relations Protocol)',
module: ModuleType.SERVICE,
icon: 'fa-bell-concierge',
subItems: [
{ id: '5-1', label: 'System Email', path: '/service/email' },
{ id: '5-2', label: 'Check-in System', path: '/service/checkin' },
{ id: '5-3', label: 'Messages', path: '/service/messages' },
{ id: '5-4', label: 'FAQ / Templates', path: '/service/faq' }
]
},
{
id: 'VI',
label: 'Payments ( Stripe )',
module: ModuleType.PAYMENTS,
icon: 'fa-vault'
},
{
id: 'VII',
label: 'Invoices',
subLabel: '(Create, Edit, Delete, Search)',
module: ModuleType.INVOICES,
icon: 'fa-file-invoice-dollar',
subItems: [
{ id: '7-1', label: 'Company Invoices', path: '/invoices/company' },
{ id: '7-2', label: 'Customer Invoices', path: '/invoices/customer' },
{ id: '7-3', label: 'Supplier Invoices', path: '/invoices/supplier' },
{ id: '7-4', label: 'Procurement Invoices', path: '/invoices/procurement' },
{ id: '7-5', label: 'Invoice Settings', path: '/invoices/settings' }
]
},
{
id: 'VIII',
label: 'Staff Management',
module: ModuleType.STAFF,
icon: 'fa-user-tie',
subItems: [
{ id: '8-1', label: 'Staff dashboard', path: '/staff' },
{ id: '8-2', label: 'Attendance / Scheduling', path: '/staff' },
{ id: '8-3', label: 'Staff setting', path: '/staff' }
]
},
{
id: 'IX',
label: 'Permissions Management',
module: ModuleType.PERMISSIONS,
icon: 'fa-shield-halved',
subItems: [
{ id: '9-1', label: 'Role Settings (Admin, Manager, Clerk, etc.)', path: '/permissions' },
{ id: '9-2', label: 'Role-to-Module Access Mapping', path: '/permissions' },
{ id: '9-3', label: 'Permissions setting', path: '/permissions' }
]
},
];
const Sidebar: React.FC<SidebarProps> = ({ activeModule, isOpen }) => {
const navigate = useNavigate();
const handleNavClick = (module: ModuleType, path?: string) => {
// Only navigate when switching to a different module; avoid going back to first sub-item when already in that section
if (activeModule !== module && path) {
navigate(path);
}
};
return (
<aside className={`${isOpen ? 'w-64' : 'w-16'} flex-shrink-0 bg-white transition-all duration-700 h-screen overflow-hidden z-20 flex flex-col border-r border-[#c5a059]/10`}>
<div className={`py-8 flex flex-col items-center transition-all duration-700 ${isOpen ? 'px-6' : 'px-0'}`}>
<div className="text-[#c5a059] font-serif italic text-3xl mb-0 select-none tracking-tighter">G.H</div>
<div className={`text-center transition-all duration-700 overflow-hidden whitespace-nowrap ${isOpen ? 'max-h-12 opacity-100 mt-2' : 'max-h-0 opacity-0 mt-0'}`}>
<h1 className="font-medium text-[8px] uppercase tracking-[0.5em] text-slate-800 font-serif italic">Atelier Suite</h1>
<div className="w-3 h-[0.5px] bg-[#c5a059]/30 mx-auto mt-2"></div>
</div>
</div>
<nav className="mt-2 flex-1 overflow-y-auto no-scrollbar px-3 pb-8">
{navItems.map((item) => (
<div key={item.id} className="mb-0.5">
<button
onClick={() => handleNavClick(item.module, item.subItems?.[0]?.path)}
className={`w-full flex items-center py-2 px-3 transition-all duration-500 group rounded-md ${
activeModule === item.module
? 'bg-[#fdfcf9] text-slate-900 border border-[#c5a059]/10 shadow-sm'
: 'text-slate-400 hover:text-slate-700 hover:bg-[#fdfcf9]/50'
}`}
>
<div className={`flex items-center w-full ${!isOpen ? 'justify-center' : 'justify-start'}`}>
<span className={`font-serif italic text-[11px] w-6 transition-all duration-700 ${isOpen ? 'mr-1 opacity-20' : 'opacity-0 w-0'}`}>
{item.id}
</span>
<i className={`fa-solid ${item.icon} text-[9px] transition-all duration-500 ${isOpen ? 'mr-3' : 'mx-0 scale-110'} ${activeModule === item.module ? 'text-[#c5a059]' : 'opacity-20 group-hover:opacity-100'}`}></i>
<div className={`flex flex-col transition-all duration-700 ${isOpen ? 'max-w-xs opacity-100' : 'max-w-0 opacity-0'}`}>
<span className="text-[9px] font-bold uppercase tracking-[0.1em] whitespace-nowrap overflow-hidden">
{item.label}
</span>
{item.subLabel && isOpen && (
<span className="text-[6px] text-slate-400 font-medium uppercase tracking-[0.05em] mt-0.5 whitespace-nowrap overflow-hidden opacity-60">
{item.subLabel}
</span>
)}
</div>
</div>
</button>
<div className={`overflow-hidden transition-all duration-700 ${isOpen && activeModule === item.module ? 'max-h-[500px] opacity-100 mt-1' : 'max-h-0 opacity-0'}`}>
<div className="pl-11 pr-2 pb-2 space-y-1.5 border-l border-[#c5a059]/5 ml-3.5">
{item.subItems?.map((sub: any) => (
<button
key={sub.id}
onClick={() => navigate(sub.path)}
className="w-full text-left py-0.5 text-[8.5px] font-medium uppercase tracking-[0.08em] text-slate-400 hover:text-[#c5a059] transition-all flex items-center group/sub"
>
<span className="text-[10px] mr-2 opacity-30">•</span>
{sub.label}
</button>
))}
</div>
</div>
</div>
))}
</nav>
<div className={`p-6 transition-all duration-700 overflow-hidden ${isOpen ? 'opacity-100' : 'opacity-0 h-0 p-0'}`}>
<div className="flex items-center justify-between border-t border-[#c5a059]/10 pt-4">
<span className="text-[7px] font-serif italic text-slate-300 uppercase tracking-widest">v4.0.2 Atelier</span>
<div className="w-1 h-1 rounded-full bg-[#c5a059]/20"></div>
</div>
</div>
</aside>
);
};
export default Sidebar;
Articoli correlati
App.tsx
App.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/App.tsx).
Leggi l'articolo →Header.tsx
Header.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/components/Header.tsx).
Leggi l'articolo →index.tsx
index.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/index.tsx).
Leggi l'articolo →ContentManagement.tsx
ContentManagement.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/pages/ContentManagement.tsx).
Leggi l'articolo →CustomerManagement.tsx
CustomerManagement.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/pages/CustomerManagement.tsx).
Leggi l'articolo →CustomerService.tsx
CustomerService.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/pages/CustomerService.tsx).
Leggi l'articolo →