Layout.jsx
1 import { NavLink, Outlet, useLocation } from 'react-router-dom'; 2 import { useQueryClient } from '@tanstack/react-query'; 3 import { useState } from 'react'; 4 import { refreshCache } from '../api'; 5 6 const NAV = [ 7 { path: '/overview', label: 'Overview', icon: '📊' }, 8 { path: '/outreach', label: 'Outreach', icon: '📤' }, 9 { path: '/conversations', label: 'Conversations', icon: '💬' }, 10 { path: '/operations', label: 'Operations', icon: '⚙️' }, 11 { path: '/quality', label: 'Quality', icon: '🔬' }, 12 { path: '/compliance', label: 'Compliance', icon: '✅' }, 13 { path: '/review', label: 'Review', icon: '🤝' }, 14 ]; 15 16 export default function Layout() { 17 const qc = useQueryClient(); 18 const [refreshing, setRefreshing] = useState(false); 19 const location = useLocation(); 20 const pageTitle = NAV.find(n => location.pathname.startsWith(n.path))?.label ?? 'Audit&Fix'; 21 22 async function handleRefresh() { 23 setRefreshing(true); 24 try { 25 await refreshCache(); 26 qc.invalidateQueries(); 27 } catch (e) { 28 console.error(e); 29 } finally { 30 setRefreshing(false); 31 } 32 } 33 34 return ( 35 <div className="flex h-screen overflow-hidden bg-slate-900"> 36 {/* Sidebar */} 37 <aside className="flex w-52 flex-shrink-0 flex-col border-r border-slate-700 bg-slate-900"> 38 {/* Logo */} 39 <div className="flex h-14 items-center px-4 border-b border-slate-700"> 40 <img src="/assets/img/logo.svg" alt="Audit&Fix" className="h-9" /> 41 </div> 42 43 {/* Nav links */} 44 <nav className="flex-1 overflow-y-auto py-3 px-2 space-y-0.5"> 45 {NAV.map(({ path, label, icon }) => ( 46 <NavLink 47 key={path} 48 to={path} 49 className={({ isActive }) => 50 `flex items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium transition-colors ${ 51 isActive 52 ? 'bg-brand-orange/15 text-brand-orange' 53 : 'text-slate-400 hover:bg-slate-800 hover:text-slate-200' 54 }` 55 } 56 > 57 <span>{icon}</span> 58 {label} 59 </NavLink> 60 ))} 61 </nav> 62 63 {/* Refresh button */} 64 <div className="border-t border-slate-700 p-3"> 65 <button 66 onClick={handleRefresh} 67 disabled={refreshing} 68 className="w-full rounded-md bg-slate-800 px-3 py-2 text-xs text-slate-400 69 hover:bg-slate-700 hover:text-slate-200 disabled:opacity-50 transition-colors" 70 > 71 {refreshing ? '⏳ Refreshing…' : '🔄 Refresh Cache'} 72 </button> 73 </div> 74 </aside> 75 76 {/* Main content */} 77 <div className="flex flex-1 flex-col overflow-hidden"> 78 {/* Top bar */} 79 <header className="flex h-14 items-center border-b border-slate-700 px-6"> 80 <h1 className="text-base font-semibold text-slate-100">{pageTitle}</h1> 81 </header> 82 83 {/* Page content */} 84 <main className="flex-1 overflow-y-auto p-6"> 85 <Outlet /> 86 </main> 87 </div> 88 </div> 89 ); 90 }