Files
aegis/src/layouts/DashboardLayout.tsx
T
2026-07-23 14:21:29 +02:00

141 lines
6.0 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { pb } from '../config/pocketbase';
interface User {
id: string;
email: string;
emailVisibility: boolean;
verified: boolean;
name: string;
role: string;
company: string;
mfa_enabled: boolean;
created: string;
updated: string
}
interface Company {
id: string;
name: string;
no: string;
vip_level: string;
created: string;
updated: string
}
// Définition stricte des propriétés attendues par le Layout
interface DashboardLayoutProps {
children: React.ReactNode;
activeView: 'dashboard' | 'support' | 'vault' | 'account';
onNavigate: (view: 'dashboard' | 'support' | 'vault' | 'account') => void;
onLogout: () => void;
}
export default function DashboardLayout({ children, activeView, onNavigate, onLogout }: DashboardLayoutProps) {
const [user, setUser] = useState<User | null>(null);
const [company, setCompany] = useState<Company | null>(null);
const [isLoading, setIsLoading] = useState(true);
const fetchInformations = async () => {
setIsLoading(true);
try {
const userRecords = await pb.collection('aegis_users').getFullList<User>();
setUser(userRecords[0]);
const companyRecords = await pb.collection('aegis_companies').getFullList<Company>();
setCompany(companyRecords[0])
} catch (error) {
console.error("Erreur lors de la récupération des infos utilisateur :", error);
} finally {
setIsLoading(false);
}
};
useEffect(()=>{
fetchInformations();
},[]);
const navItems = [
{ id: 'dashboard', label: 'Tableau de bord', icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" /></svg>
)},
{ id: 'support', label: 'Centre de Support', icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M18.364 5.636l-3.536 3.536m0 5.656l3.536 3.536M9.172 9.172L5.636 5.636m3.536 9.192l-3.536 3.536M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-5 0a4 4 0 11-8 0 4 4 0 018 0z" /></svg>
)},
{ id: 'vault', label: 'Coffre-Fort', icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg>
)}
];
return (
<div className="flex h-screen bg-slate-50 overflow-hidden font-sans selection:bg-blue-900 selection:text-white">
{/* Sidebar Latérale (Institutionnelle) */}
<aside className="w-64 bg-white border-r border-slate-200 flex flex-col justify-between shadow-sm z-10">
{/* En-tête Sidebar */}
<div>
<div className="h-20 flex items-center px-8 border-b border-slate-100">
<h2 className="text-2xl font-bold tracking-tight text-slate-900">
AEGIS <span className="text-xs font-semibold text-blue-900 ml-1 bg-blue-50 px-2 py-1 rounded">VIP</span>
</h2>
</div>
{/* Navigation */}
<nav className="p-4 space-y-1">
{navItems.map((item) => (
<button
key={item.id}
onClick={() => onNavigate(item.id as any)}
className={`w-full flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-colors duration-200 ${
activeView === item.id
? 'bg-blue-50 text-blue-900'
: 'text-slate-600 hover:bg-slate-50 hover:text-slate-900'
}`}
>
<span className={`mr-3 ${activeView === item.id ? 'text-blue-900' : 'text-slate-400'}`}>
{item.icon}
</span>
{item.label}
</button>
))}
</nav>
</div>
{/* Pied de la Sidebar (Profil & Déconnexion) */}
<div className="p-4 border-t border-slate-100">
<button
onClick={() => onNavigate('account')}
className={`w-full flex items-center px-4 py-3 rounded-lg transition-colors duration-200 text-left ${
activeView === 'account' ? 'bg-slate-100 ring-1 ring-slate-200' : 'hover:bg-slate-50'
}`}
>
<div className="w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 font-bold text-sm shrink-0">
{isLoading? "":user?.name.split(" ").map((n)=>n[0]).join("")}
</div>
<div className="ml-3 overflow-hidden">
{isLoading?
<p className="text-sm font-medium text-slate-200 bg-slate-200 rounded ">*</p>
:
<p className="text-sm font-medium text-slate-900 truncate">{user?.name}</p>
}
<p className="text-xs text-slate-500 truncate">Paramètres du compte</p>
</div>
</button>
<button
onClick={onLogout}
className="w-full flex items-center px-4 py-2 text-sm font-medium text-red-600 rounded-lg hover:bg-red-50 transition-colors duration-200"
>
<svg className="w-4 h-4 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
Verrouiller la session
</button>
</div>
</aside>
{/* Zone de contenu principal */}
<main className="flex-1 overflow-y-auto">
{children}
</main>
</div>
);
}