/** * DashboardShell — real sidebar + header layout wrapper. * Used for pages that need actual backend connectivity * (My Profile, My Portfolio, Verification) instead of the preview mock. */ import { For, JSX, Show, createMemo, createSignal, onMount } from 'solid-js'; import { User, Briefcase, LayoutDashboard, FolderOpen, MapPin, Star, CreditCard, Globe, ShieldCheck, HelpCircle, Settings, RefreshCw, LogOut, Bell, ChevronRight, } from 'lucide-solid'; // ── Icon map (matches DashboardDesignPreview sidebar keys) ──────────────────── const ICON_MAP: Record = { 'my dashboard': LayoutDashboard, 'my profile': User, 'my portfolio': FolderOpen, 'leads': MapPin, 'my responses': Star, 'credits': CreditCard, 'explore nxtgauge': Globe, 'verification': ShieldCheck, 'help center': HelpCircle, 'settings': Settings, 'switch services': RefreshCw, 'jobs': Briefcase, 'applications': Briefcase, 'shortlisted candidates': User, 'my applications': FolderOpen, 'saved jobs': Star, 'my requirements': FolderOpen, 'received responses': Bell, 'shortlisted responses': Star, 'logout': LogOut, }; function SidebarIcon(props: { label: string }) { const key = props.label.toLowerCase(); const Icon = ICON_MAP[key] || ChevronRight; return ; } function titleCase(value: string) { return String(value || '') .toLowerCase() .replace(/_/g, ' ') .replace(/\b\w/g, (c) => c.toUpperCase()); } // ── Types ───────────────────────────────────────────────────────────────────── interface Props { sidebarItems: string[]; activeSidebar: string; onSidebarSelect: (item: string) => void; roleKey: string; userName?: string; children: JSX.Element; } // ── Brand colours ───────────────────────────────────────────────────────────── const ORANGE = '#FF5E13'; const NAVY = '#0D0D2A'; // ── Component ───────────────────────────────────────────────────────────────── export default function DashboardShell(props: Props) { const roleLabel = createMemo(() => { const k = String(props.roleKey || '').replace(/_/g, ' '); return k.charAt(0).toUpperCase() + k.slice(1).toLowerCase(); }); const [unreadCount, setUnreadCount] = createSignal(0); // Fetch unread notification count const fetchUnreadCount = async () => { try { const token = typeof window !== 'undefined' ? window.sessionStorage.getItem('nxtgauge_access_token') || '' : ''; if (!token) return; const res = await fetch('/api/me/notifications/unread-count', { headers: { Authorization: `Bearer ${token}` }, credentials: 'include', }); if (res.ok) { const data = await res.json(); setUnreadCount(data.unread_count || 0); } } catch (e) { console.error('Failed to fetch unread count:', e); } }; // Start polling on mount onMount(() => { fetchUnreadCount(); const interval = setInterval(fetchUnreadCount, 30000); return () => clearInterval(interval); }); return (
{/* ── Sidebar ──────────────────────────────────────────────────────── */} {/* ── Main content ─────────────────────────────────────────────────── */}
{/* Top bar */}

{titleCase(props.activeSidebar)}

{(props.userName || 'U').charAt(0).toUpperCase()}
{/* Page content */}
{props.children}
); } // ── Shared UI primitives ────────────────────────────────────────────────────── export const CARD = { background: '#fff', border: '1px solid #E5E7EB', 'border-radius': '14px', padding: '20px', 'box-shadow': '0 1px 4px rgba(0,0,0,0.06)', } as const; export const BTN_PRIMARY = { height: '38px', 'border-radius': '10px', border: 'none', background: NAVY, color: '#fff', padding: '0 18px', 'font-size': '13px', 'font-weight': '700', cursor: 'pointer', } as const; export const BTN_ORANGE = { height: '38px', 'border-radius': '10px', border: 'none', background: ORANGE, color: '#fff', padding: '0 18px', 'font-size': '13px', 'font-weight': '700', cursor: 'pointer', } as const; export const BTN_GHOST = { height: '38px', 'border-radius': '10px', border: '1px solid #E5E7EB', background: '#fff', color: '#374151', padding: '0 18px', 'font-size': '13px', 'font-weight': '600', cursor: 'pointer', } as const; export const INPUT = { height: '40px', width: '100%', 'border-radius': '8px', border: '1px solid #E5E7EB', padding: '0 12px', 'font-size': '14px', color: '#111827', background: '#fff', 'box-sizing': 'border-box', } as const; export const LABEL = { display: 'block', 'font-size': '12px', 'font-weight': '600', color: '#374151', 'margin-bottom': '6px', } as const;