feat: uwuFinances app with themes, JWT auth and NoCodeBackend sync
This commit is contained in:
212
src/components/common/TopHeader.tsx
Normal file
212
src/components/common/TopHeader.tsx
Normal file
@@ -0,0 +1,212 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user