213 lines
8.4 KiB
TypeScript
213 lines
8.4 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
LayoutDashboard,
|
|
ShoppingCart,
|
|
Layers,
|
|
Clock,
|
|
BarChart3,
|
|
Settings as SettingsIcon,
|
|
Sparkles,
|
|
PackagePlus,
|
|
Coins,
|
|
Cpu,
|
|
Database,
|
|
RefreshCw,
|
|
} from 'lucide-react';
|
|
import { useApp } from '../../context/AppContext';
|
|
import { formatCurrency } from '../../utils/calculations';
|
|
|
|
export const TopHeader: React.FC = () => {
|
|
const {
|
|
currentTab,
|
|
inventory,
|
|
projects,
|
|
dbSyncStatus,
|
|
setShowNewProjectModal,
|
|
setShowNewInventoryModal,
|
|
authSession,
|
|
setShowAuthModal,
|
|
} = useApp();
|
|
|
|
// Quick topbar calculations
|
|
const totalStockValuation = inventory.reduce(
|
|
(acc, item) =>
|
|
acc +
|
|
item.quantityInStock *
|
|
(item.unitPurchasePrice + (item.shippingCostShare || 0) + (item.taxImportShare || 0)),
|
|
0
|
|
);
|
|
|
|
const activeProjectsCount = projects.filter(
|
|
(p) => p.status === 'in_progress' || p.status === 'qc_testing'
|
|
).length;
|
|
|
|
const getPageInfo = () => {
|
|
switch (currentTab) {
|
|
case 'dashboard':
|
|
return {
|
|
title: 'Tableau de Bord & Finances',
|
|
subtitle: 'Vue d\'ensemble des performances, graphiques et pipeline d\'atelier',
|
|
icon: LayoutDashboard,
|
|
iconColor: 'text-pink-400',
|
|
};
|
|
case 'purchases':
|
|
return {
|
|
title: 'Achats & Gestion des Stocks',
|
|
subtitle: 'Consoles donneuses, écrans IPS, coques, composants et alertes de stock',
|
|
icon: ShoppingCart,
|
|
iconColor: 'text-cyan-400',
|
|
};
|
|
case 'projects':
|
|
return {
|
|
title: 'Centre de Dépenses Projets',
|
|
subtitle: 'Nomenclature pièces (BOM), temps d\'atelier, coût de revient et certificats',
|
|
icon: Layers,
|
|
iconColor: 'text-purple-400',
|
|
};
|
|
case 'timetracker':
|
|
return {
|
|
title: 'Chronomètre d\'Atelier & Main d\'Œuvre',
|
|
subtitle: 'Chronométrage des sessions de modding et valorisation horaire en direct',
|
|
icon: Clock,
|
|
iconColor: 'text-amber-400',
|
|
};
|
|
case 'analytics':
|
|
return {
|
|
title: 'Rentabilité & Simulateur de Prix',
|
|
subtitle: 'Calculateur de marge nette, point mort (break-even) et analyse par console',
|
|
icon: BarChart3,
|
|
iconColor: 'text-emerald-400',
|
|
};
|
|
case 'settings':
|
|
return {
|
|
title: 'Paramètres & Sauvegardes',
|
|
subtitle: 'Identité de l\'atelier, taux horaire par défaut, thèmes et connexion NoCodeBackend',
|
|
icon: SettingsIcon,
|
|
iconColor: 'text-slate-300',
|
|
};
|
|
default:
|
|
return {
|
|
title: 'uwuFinances',
|
|
subtitle: 'Console Modding Studio Hub',
|
|
icon: LayoutDashboard,
|
|
iconColor: 'text-pink-400',
|
|
};
|
|
}
|
|
};
|
|
|
|
const pageInfo = getPageInfo();
|
|
const Icon = pageInfo.icon;
|
|
|
|
return (
|
|
<header className="sticky top-0 z-30 w-full theme-header backdrop-blur-xl border-b border-slate-800/80 px-4 sm:px-8 py-3.5 flex items-center justify-between no-print">
|
|
{/* Page Title & Breadcrumb */}
|
|
<div className="flex items-center space-x-3.5">
|
|
<div className="p-2 rounded-xl bg-slate-900 border border-slate-800 hidden sm:flex items-center justify-center shadow-inner">
|
|
<Icon className={`w-5 h-5 ${pageInfo.iconColor}`} />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-base sm:text-lg font-bold text-white tracking-tight flex items-center space-x-2">
|
|
<span>{pageInfo.title}</span>
|
|
</h2>
|
|
<p className="text-xs text-slate-400 hidden md:block">
|
|
{pageInfo.subtitle}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Stats & Quick Actions */}
|
|
<div className="flex items-center space-x-2 sm:space-x-3">
|
|
{/* User Profile & JWT Button */}
|
|
<button
|
|
onClick={() => setShowAuthModal(true)}
|
|
className={`flex items-center space-x-2 px-2.5 py-1.5 rounded-xl text-xs border transition-all cursor-pointer ${
|
|
authSession.isAuthenticated
|
|
? 'bg-slate-900 border-pink-500/30 hover:border-pink-500/60 text-slate-200'
|
|
: 'bg-slate-900/60 border-slate-800 hover:border-slate-700 text-slate-400'
|
|
}`}
|
|
title="Gérer la session utilisateur, le jeton JWT et la liaison NCB"
|
|
>
|
|
<div className="relative">
|
|
<img
|
|
src={authSession.user?.avatarUrl || 'https://api.dicebear.com/7.x/bottts/svg?seed=uwu'}
|
|
alt={authSession.user?.name}
|
|
className="w-5 h-5 rounded-full bg-slate-800 object-cover border border-slate-700"
|
|
/>
|
|
{authSession.isAuthenticated && (
|
|
<span className="absolute -top-0.5 -right-0.5 w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
|
)}
|
|
</div>
|
|
<span className="font-semibold text-xs text-slate-200 hidden md:inline truncate max-w-[120px]">
|
|
{authSession.user?.name?.split(' ')[0] || 'Utilisateur'}
|
|
</span>
|
|
<span className="px-1.5 py-0.2 rounded text-[9px] font-mono font-bold uppercase bg-pink-500/15 text-pink-300 hidden lg:inline border border-pink-500/30">
|
|
JWT
|
|
</span>
|
|
</button>
|
|
|
|
{/* Cloud Database Status indicator */}
|
|
<button
|
|
onClick={() => setShowAuthModal(true)}
|
|
className={`hidden md:flex items-center space-x-1.5 px-2.5 py-1.5 rounded-xl text-xs border transition-all cursor-pointer ${
|
|
dbSyncStatus === 'connected'
|
|
? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30 hover:bg-emerald-500/20'
|
|
: dbSyncStatus === 'syncing'
|
|
? 'bg-amber-500/10 text-amber-400 border-amber-500/30'
|
|
: 'bg-rose-500/10 text-rose-400 border-rose-500/30 hover:bg-rose-500/20'
|
|
}`}
|
|
title="Statut Cloud Database NoCodeBackend (54770_uwu_finances) - Cliquez pour gérer"
|
|
>
|
|
{dbSyncStatus === 'syncing' ? (
|
|
<RefreshCw className="w-3 h-3 animate-spin text-amber-400" />
|
|
) : (
|
|
<span className={`w-2 h-2 rounded-full ${
|
|
dbSyncStatus === 'connected' ? 'bg-emerald-400 animate-pulse' : 'bg-rose-400'
|
|
}`} />
|
|
)}
|
|
<Database className="w-3 h-3 text-slate-400" />
|
|
<span className="font-mono text-[11px] font-semibold">NCB EU</span>
|
|
</button>
|
|
|
|
{/* Quick Inventory Stock Valuation badge */}
|
|
<div className="hidden xl:flex items-center space-x-2 px-3 py-1.5 rounded-xl bg-slate-900/80 border border-slate-800 text-xs">
|
|
<Coins className="w-3.5 h-3.5 text-cyan-400" />
|
|
<span className="text-slate-400">Stock valorisé:</span>
|
|
<span className="font-mono font-bold text-cyan-300">
|
|
{formatCurrency(totalStockValuation)}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Active Projects badge */}
|
|
<div className="hidden xl:flex items-center space-x-2 px-3 py-1.5 rounded-xl bg-slate-900/80 border border-slate-800 text-xs">
|
|
<Cpu className="w-3.5 h-3.5 text-purple-400" />
|
|
<span className="text-slate-400">En cours:</span>
|
|
<span className="font-mono font-bold text-purple-300">
|
|
{activeProjectsCount} projet{activeProjectsCount > 1 ? 's' : ''}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Quick Add Part */}
|
|
<button
|
|
onClick={() => setShowNewInventoryModal(true)}
|
|
className="flex items-center space-x-1.5 px-3 py-1.5 sm:px-3.5 sm:py-2 rounded-xl text-xs sm:text-sm font-semibold bg-slate-900 text-cyan-300 border border-cyan-500/30 hover:bg-cyan-500/10 hover:border-cyan-500/60 shadow-sm transition-all duration-200"
|
|
title="Ajouter un achat de pièces au stock"
|
|
>
|
|
<PackagePlus className="w-4 h-4 text-cyan-400" />
|
|
<span className="hidden sm:inline">Achat Pièce</span>
|
|
</button>
|
|
|
|
{/* Quick New Project */}
|
|
<button
|
|
onClick={() => setShowNewProjectModal(true)}
|
|
className="flex items-center space-x-1.5 px-3 py-1.5 sm:px-3.5 sm:py-2 rounded-xl text-xs sm:text-sm font-bold bg-gradient-to-r from-pink-500 via-purple-600 to-pink-600 text-white shadow-lg shadow-pink-500/20 hover:shadow-pink-500/35 hover:scale-[1.02] active:scale-[0.98] transition-all duration-200"
|
|
title="Créer une nouvelle console custom"
|
|
>
|
|
<Sparkles className="w-4 h-4 text-pink-200" />
|
|
<span>Nouveau Projet</span>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
);
|
|
};
|
|
|