107 lines
4.2 KiB
React
107 lines
4.2 KiB
React
import { useState, useEffect } from 'react';
|
|
import { Outlet, NavLink, useNavigate } from 'react-router-dom';
|
|
import { getClientTickets } from '../services/api';
|
|
import { LayoutDashboard, Globe, Settings, FileText } from 'lucide-react';
|
|
import ConfirmLogoutModal from '../components/ui/ConfirmLogoutModal'; // Le modal extrait !
|
|
|
|
export default function AppLayout() {
|
|
const navigate = useNavigate();
|
|
const [showLogoutModal, setShowLogoutModal] = useState(false);
|
|
const [unreadCount, setUnreadCount] = useState(0);
|
|
|
|
const checkUnreadTickets = async () => {
|
|
try {
|
|
const data = await getClientTickets();
|
|
if (data && data.list) {
|
|
const unread = data.list.filter(t => t.status === 'on_hold' || t.unread).length;
|
|
setUnreadCount(unread);
|
|
}
|
|
} catch (err) { }
|
|
};
|
|
|
|
useEffect(() => {
|
|
checkUnreadTickets();
|
|
const intervalId = setInterval(checkUnreadTickets, 120000);
|
|
return () => clearInterval(intervalId);
|
|
}, []);
|
|
|
|
const confirmLogout = () => {
|
|
setShowLogoutModal(false);
|
|
navigate('/login');
|
|
};
|
|
|
|
// 🌟 La fonction magique Tailwind pour les liens du menu
|
|
const navLinkClass = ({ isActive }) =>
|
|
`block px-6 py-4 no-underline border-l-4 transition-all uppercase tracking-widest text-sm font-mono ${isActive
|
|
? 'text-cyan-400 bg-cyan-400/5 border-cyan-400'
|
|
: 'text-[#888] border-transparent hover:text-gray-300 hover:bg-white/5'
|
|
}`;
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-[#050505] text-[#E0E0E0] font-sans">
|
|
|
|
{/* SIDEBAR */}
|
|
<aside className="w-65 bg-[#121212] border-r border-[#222222] h-screen flex flex-col fixed top-0 left-0">
|
|
|
|
<div className="px-6 py-8 border-b border-[#222]">
|
|
<h1 className="text-white m-0 text-3xl font-black tracking-widest flex items-baseline gap-2">
|
|
NEXUS
|
|
<span className="text-cyan-400 text-[10px] tracking-widest font-normal">by GISE</span>
|
|
</h1>
|
|
<p className="text-[#555] text-[10px] font-mono tracking-wider mt-2 uppercase">
|
|
Console d'infrastructure v1.0
|
|
</p>
|
|
</div>
|
|
|
|
<nav className="flex-1 mt-6">
|
|
<div className="px-6 mb-2 text-[#444] text-[10px] font-bold font-mono tracking-widest">
|
|
// SUPERVISION
|
|
</div>
|
|
<NavLink className={navLinkClass} to="/dashboard">Tableau de bord</NavLink>
|
|
<NavLink className={navLinkClass} to="/services">Inventaire Réseau</NavLink>
|
|
|
|
<div className="px-6 mt-8 mb-2 text-[#444] text-[10px] font-bold font-mono tracking-widest">
|
|
// GESTION
|
|
</div>
|
|
<NavLink className={navLinkClass} to="/support">
|
|
<div className="flex justify-between items-center w-full">
|
|
<span>Tickets Support</span>
|
|
{unreadCount > 0 && (
|
|
<span className="bg-cyan-400 text-black text-[10px] font-bold px-2 py-0.5 rounded-full shadow-[0_0_10px_rgba(0,229,255,0.6)] animate-pulse">
|
|
{unreadCount} NEW
|
|
</span>
|
|
)}
|
|
</div>
|
|
</NavLink>
|
|
|
|
<NavLink className={navLinkClass} to="/facturation">Facturation</NavLink>
|
|
|
|
<div className="flex justify-between items-center px-6 py-4 text-[#444] border-l-4 border-transparent uppercase tracking-widest text-sm font-mono cursor-not-allowed select-none">
|
|
<span>Profil & Sécurité</span>
|
|
<span className="text-[9px] text-[#333] border border-[#333] px-1.5 py-0.5 rounded font-bold">WIP</span>
|
|
</div>
|
|
</nav>
|
|
|
|
<div className="p-5 border-t border-[#222]">
|
|
<button
|
|
onClick={() => setShowLogoutModal(true)}
|
|
className="w-full p-3 bg-transparent text-[#ff003c] hover:bg-[#ff003c]/10 border border-[#ff003c] cursor-pointer font-mono text-sm tracking-widest uppercase transition-colors rounded-sm"
|
|
>
|
|
[ Déconnexion ]
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* ZONE DE CONTENU */}
|
|
<main className="ml-65 p-10 flex-1 min-h-screen">
|
|
<Outlet context={{ refreshNavbarTickets: checkUnreadTickets }} />
|
|
</main>
|
|
|
|
<ConfirmLogoutModal
|
|
isOpen={showLogoutModal}
|
|
onClose={() => setShowLogoutModal(false)}
|
|
onConfirm={confirmLogout}
|
|
/>
|
|
</div>
|
|
);
|
|
} |