176 lines
8 KiB
TypeScript
176 lines
8 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
||
|
|
import { NavLink, useNavigate } from 'react-router-dom';
|
||
|
|
import {
|
||
|
|
LayoutDashboard, Search, History, Boxes, Store, Users, TrendingUp, LogOut, Wallet,
|
||
|
|
ChevronDown, Package, FileText, Factory, Menu, ShoppingCart, Settings, BarChart3
|
||
|
|
} from 'lucide-react';
|
||
|
|
import { useCRM } from '../context/CRMContext';
|
||
|
|
import clsx from 'clsx';
|
||
|
|
import Logo from '../components/Logo';
|
||
|
|
|
||
|
|
const TopBar: React.FC = () => {
|
||
|
|
const { users, signOut } = useCRM();
|
||
|
|
const currentUser = users[0];
|
||
|
|
const navigate = useNavigate();
|
||
|
|
|
||
|
|
// Dropdown States
|
||
|
|
const [openMenu, setOpenMenu] = useState<string | null>(null);
|
||
|
|
|
||
|
|
const handleSignOut = async () => {
|
||
|
|
await signOut();
|
||
|
|
navigate('/login');
|
||
|
|
};
|
||
|
|
|
||
|
|
const navStructure = [
|
||
|
|
{
|
||
|
|
label: 'Dashboard',
|
||
|
|
to: '/',
|
||
|
|
icon: LayoutDashboard,
|
||
|
|
type: 'link'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Vendas',
|
||
|
|
to: '/sales',
|
||
|
|
icon: ShoppingCart,
|
||
|
|
type: 'link'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Arbitragem',
|
||
|
|
icon: Search,
|
||
|
|
type: 'dropdown',
|
||
|
|
items: [
|
||
|
|
{ label: 'Sourcing Intel', to: '/sourcing', icon: Search },
|
||
|
|
{ label: 'Minhas Ordens', to: '/orders', icon: History },
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Cadastros',
|
||
|
|
icon: FileText,
|
||
|
|
type: 'dropdown',
|
||
|
|
items: [
|
||
|
|
{ label: 'Clientes', to: '/customers', icon: Users },
|
||
|
|
{ label: 'Fornecedores', to: '/suppliers', icon: Store },
|
||
|
|
{ label: 'Produtos', to: '/products', icon: Package },
|
||
|
|
{ label: 'Estoque', to: '/inventory', icon: Boxes },
|
||
|
|
{ label: 'Usuários', to: '/users', icon: Users },
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Produção',
|
||
|
|
icon: Factory,
|
||
|
|
type: 'nav-link', // Future placeholder
|
||
|
|
to: '#', // Placeholder
|
||
|
|
items: [], // Empty for now or future items
|
||
|
|
disabled: true
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Relatórios',
|
||
|
|
to: '/reports',
|
||
|
|
icon: BarChart3,
|
||
|
|
type: 'link'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Financeiro',
|
||
|
|
to: '/financial',
|
||
|
|
icon: Wallet,
|
||
|
|
type: 'link'
|
||
|
|
}
|
||
|
|
];
|
||
|
|
|
||
|
|
return (
|
||
|
|
<header className="h-[72px] bg-background/80 backdrop-blur-xl border-b border-border flex items-center px-8 justify-between sticky top-0 z-50">
|
||
|
|
|
||
|
|
{/* LOGO */}
|
||
|
|
<div onClick={() => navigate('/')} className="cursor-pointer">
|
||
|
|
<Logo />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* NAV MENU CASCATA */}
|
||
|
|
<nav className="flex-1 flex justify-center items-center gap-2">
|
||
|
|
{navStructure.map((item, idx) => (
|
||
|
|
<div
|
||
|
|
key={idx}
|
||
|
|
className="relative group"
|
||
|
|
onMouseEnter={() => item.type === 'dropdown' && setOpenMenu(item.label)}
|
||
|
|
onMouseLeave={() => setOpenMenu(null)}
|
||
|
|
>
|
||
|
|
{item.type === 'link' ? (
|
||
|
|
<NavLink
|
||
|
|
to={item.to!}
|
||
|
|
className={({ isActive }) => clsx(
|
||
|
|
"px-5 py-2.5 rounded-xl text-sm font-bold flex items-center gap-2 transition-all duration-200 hover:bg-accent/50",
|
||
|
|
isActive ? "text-foreground bg-accent shadow-sm border border-border" : "text-muted-foreground"
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
<item.icon size={16} />
|
||
|
|
{item.label}
|
||
|
|
</NavLink>
|
||
|
|
) : (
|
||
|
|
<button className={clsx(
|
||
|
|
"px-5 py-2.5 rounded-xl text-sm font-bold flex items-center gap-2 transition-all duration-200 hover:bg-accent/50 group-hover:text-foreground",
|
||
|
|
openMenu === item.label ? "text-foreground bg-accent" : "text-muted-foreground"
|
||
|
|
)}>
|
||
|
|
<item.icon size={16} />
|
||
|
|
{item.label}
|
||
|
|
<ChevronDown size={12} className={clsx("transition-transform duration-200", openMenu === item.label && "rotate-180")} />
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* DROPDOWN MENU */}
|
||
|
|
{item.type === 'dropdown' && (
|
||
|
|
<div className={clsx(
|
||
|
|
"absolute top-full left-1/2 -translate-x-1/2 pt-4 w-[240px] transition-all duration-200 origin-top z-50",
|
||
|
|
openMenu === item.label ? "opacity-100 scale-100 visible" : "opacity-0 scale-95 invisible"
|
||
|
|
)}>
|
||
|
|
<div className="bg-popover border border-border rounded-2xl shadow-xl p-2 flex flex-col gap-1 backdrop-blur-3xl">
|
||
|
|
<div className="absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-popover border-t border-l border-border rotate-45"></div>
|
||
|
|
{item.items?.map((subItem, subIdx) => (
|
||
|
|
<NavLink
|
||
|
|
key={subIdx}
|
||
|
|
to={subItem.to}
|
||
|
|
className={({ isActive }) => clsx(
|
||
|
|
"w-full text-left px-4 py-3 rounded-xl text-xs font-bold flex items-center gap-3 transition-colors hover:bg-accent",
|
||
|
|
isActive ? "text-foreground bg-accent" : "text-muted-foreground"
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
{({ isActive }) => (
|
||
|
|
<>
|
||
|
|
<subItem.icon size={14} className={isActive ? "text-primary" : "text-slate-500"} />
|
||
|
|
{subItem.label}
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</NavLink>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</nav>
|
||
|
|
|
||
|
|
{/* USER ACTIONS */}
|
||
|
|
<div className="flex items-center gap-4 w-[200px] justify-end">
|
||
|
|
<button
|
||
|
|
onClick={() => navigate('/settings')}
|
||
|
|
className="w-10 h-10 rounded-2xl bg-secondary/50 border border-border flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-secondary transition-all"
|
||
|
|
title="Configurações"
|
||
|
|
>
|
||
|
|
<Settings size={20} />
|
||
|
|
</button>
|
||
|
|
|
||
|
|
<div onClick={handleSignOut} className="flex items-center gap-3 pl-4 pr-2 py-1.5 rounded-2xl bg-secondary/50 border border-border hover:bg-destructive/10 hover:border-destructive/20 transition-all cursor-pointer group">
|
||
|
|
<div className="text-right hidden xl:block">
|
||
|
|
<p className="text-xs font-bold text-foreground leading-none">{currentUser?.name || 'Admin'}</p>
|
||
|
|
<p className="text-[9px] text-muted-foreground font-bold uppercase mt-0.5">Online</p>
|
||
|
|
</div>
|
||
|
|
<div className="w-8 h-8 rounded-full bg-slate-800 border border-border flex items-center justify-center group-hover:scale-105 transition-transform overflow-hidden">
|
||
|
|
<img src={currentUser?.avatar || "https://api.dicebear.com/7.x/avataaars/svg?seed=Admin"} alt="Avatar" className="w-full h-full object-cover" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</header>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default TopBar;
|