194 lines
6.7 KiB
React
194 lines
6.7 KiB
React
// src/layouts/AppLayout.jsx
|
|
import { useState } from 'react';
|
|
import { Outlet, NavLink, useNavigate } from 'react-router-dom';
|
|
|
|
// ============================================================================
|
|
// COMPOSANT : MODAL DE CONFIRMATION DE DÉCONNEXION
|
|
// ============================================================================
|
|
const ConfirmLogoutModal = ({ isOpen, onClose, onConfirm }) => {
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div style={{
|
|
position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
|
|
backgroundColor: 'rgba(0,0,0,0.8)', backdropFilter: 'blur(4px)',
|
|
zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center'
|
|
}}>
|
|
<div style={{
|
|
backgroundColor: '#1A1A1A',
|
|
border: '1px solid #ff003c',
|
|
boxShadow: '0 10px 30px rgba(255, 0, 60, 0.2)',
|
|
borderRadius: '8px',
|
|
maxWidth: '400px',
|
|
width: '100%',
|
|
padding: '24px',
|
|
color: '#FFF',
|
|
fontFamily: 'monospace'
|
|
}}>
|
|
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', letterSpacing: '1px', marginBottom: '10px', color: '#ff003c', textTransform: 'uppercase' }}>
|
|
DÉCONNEXION DU TERMINAL
|
|
</h4>
|
|
<p style={{ fontSize: '0.9rem', color: '#AAA', marginBottom: '24px', lineHeight: '1.5' }}>
|
|
Êtes-vous sûr de vouloir fermer la session sécurisée et quitter l'environnement cloud ?
|
|
</p>
|
|
<div style={{ display: 'flex', gap: '10px' }}>
|
|
<button onClick={onClose} style={{
|
|
flex: 1, padding: '10px',
|
|
backgroundColor: '#333', color: '#FFF',
|
|
border: 'none', borderRadius: '4px',
|
|
fontFamily: 'monospace', fontWeight: 'bold', cursor: 'pointer', letterSpacing: '1px'
|
|
}}>
|
|
ANNULER
|
|
</button>
|
|
<button onClick={onConfirm} style={{
|
|
flex: 1, padding: '10px',
|
|
backgroundColor: '#ff003c', color: '#FFF',
|
|
border: 'none', borderRadius: '4px',
|
|
fontFamily: 'monospace', fontWeight: 'bold', cursor: 'pointer', letterSpacing: '1px'
|
|
}}>
|
|
SE DÉCONNECTER
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// ============================================================================
|
|
// COMPOSANT PRINCIPAL : LAYOUT DU PORTAIL
|
|
// ============================================================================
|
|
export default function AppLayout() {
|
|
const navigate = useNavigate();
|
|
const [showLogoutModal, setShowLogoutModal] = useState(false);
|
|
|
|
// Ouvre simplement le modal
|
|
const handleLogoutClick = () => {
|
|
setShowLogoutModal(true);
|
|
};
|
|
|
|
// Exécute la vraie déconnexion
|
|
const confirmLogout = () => {
|
|
// Ici, tu pourras effacer les tokens (ex: localStorage.removeItem('token'))
|
|
setShowLogoutModal(false);
|
|
navigate('/login');
|
|
};
|
|
|
|
// --- DESIGN SYSTEM DU BUNKER ---
|
|
const sidebarStyle = {
|
|
width: '260px',
|
|
backgroundColor: '#121212', // Gris blindage
|
|
borderRight: '1px solid #222222',
|
|
height: '100vh',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
position: 'fixed',
|
|
top: 0,
|
|
left: 0,
|
|
fontFamily: 'monospace'
|
|
};
|
|
|
|
const mainContentStyle = {
|
|
marginLeft: '260px', // Laisse la place à la sidebar
|
|
minHeight: '100vh',
|
|
backgroundColor: '#050505', // Fond abyssal
|
|
color: '#E0E0E0',
|
|
padding: '40px'
|
|
};
|
|
|
|
// Fonction pour styliser le lien actif (en Cyan)
|
|
const getNavLinkStyle = ({ isActive }) => ({
|
|
display: 'block',
|
|
padding: '15px 25px',
|
|
color: isActive ? '#00E5FF' : '#888',
|
|
backgroundColor: isActive ? 'rgba(0, 229, 255, 0.05)' : 'transparent',
|
|
textDecoration: 'none',
|
|
borderLeft: isActive ? '4px solid #00E5FF' : '4px solid transparent',
|
|
transition: 'all 0.2s',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: '1px',
|
|
fontSize: '0.9rem'
|
|
});
|
|
|
|
return (
|
|
<div style={{ display: 'block' }}>
|
|
|
|
{/* ========================================== */}
|
|
{/* BARRE LATÉRALE (SIDEBAR) */}
|
|
{/* ========================================== */}
|
|
<aside style={sidebarStyle}>
|
|
|
|
{/* En-tête de la Sidebar (Logo / Marque) */}
|
|
<div style={{ padding: '30px 25px', borderBottom: '1px solid #222' }}>
|
|
<h1 style={{
|
|
color: '#FFF',
|
|
margin: 0,
|
|
fontSize: '1.8rem',
|
|
letterSpacing: '3px',
|
|
display: 'flex',
|
|
alignItems: 'baseline',
|
|
gap: '8px'
|
|
}}>
|
|
NEXUS
|
|
<span style={{
|
|
color: '#00E5FF',
|
|
fontSize: '0.7rem',
|
|
letterSpacing: '1px',
|
|
fontWeight: 'normal',
|
|
}}>
|
|
by GISE
|
|
</span>
|
|
</h1>
|
|
<p style={{ color: '#555', fontSize: '0.7rem', margin: '8px 0 0 0' }}>
|
|
CONSOLE D'INFRASTRUCTURE v1.0
|
|
</p>
|
|
</div>
|
|
|
|
{/* Menu de Navigation */}
|
|
<nav style={{ flex: 1, marginTop: '20px' }}>
|
|
<div style={{ padding: '0 25px', marginBottom: '10px', color: '#444', fontSize: '0.7rem', fontWeight: 'bold' }}>
|
|
// SUPERVISION
|
|
</div>
|
|
<NavLink style={getNavLinkStyle} to="/dashboard">Tableau de bord</NavLink>
|
|
<NavLink style={getNavLinkStyle} to="/services">Inventaire Réseau</NavLink>
|
|
|
|
<div style={{ padding: '0 25px', marginTop: '25px', marginBottom: '10px', color: '#444', fontSize: '0.7rem', fontWeight: 'bold' }}>
|
|
// GESTION
|
|
</div>
|
|
<NavLink style={getNavLinkStyle} to="/billing">Facturation</NavLink>
|
|
<NavLink style={getNavLinkStyle} to="/support">Tickets Support</NavLink>
|
|
<NavLink style={getNavLinkStyle} to="/settings">Profil & Sécurité</NavLink>
|
|
</nav>
|
|
|
|
{/* Bas de la Sidebar (Déconnexion) */}
|
|
<div style={{ padding: '20px', borderTop: '1px solid #222' }}>
|
|
<button
|
|
onClick={handleLogoutClick}
|
|
style={{
|
|
width: '100%', padding: '12px', backgroundColor: 'transparent',
|
|
color: '#ff003c', border: '1px solid #ff003c', cursor: 'pointer',
|
|
fontFamily: 'monospace', textTransform: 'uppercase'
|
|
}}
|
|
>
|
|
[ Déconnexion ]
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* ========================================== */}
|
|
{/* ZONE DE CONTENU DYNAMIQUE */}
|
|
{/* ========================================== */}
|
|
<main style={mainContentStyle}>
|
|
{/* Le composant <Outlet /> injecte le contenu de la page demandée sans recharger la sidebar */}
|
|
<Outlet />
|
|
</main>
|
|
|
|
{/* MODAL DE DÉCONNEXION */}
|
|
<ConfirmLogoutModal
|
|
isOpen={showLogoutModal}
|
|
onClose={() => setShowLogoutModal(false)}
|
|
onConfirm={confirmLogout}
|
|
/>
|
|
|
|
</div>
|
|
);
|
|
} |