/** * 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 { AiChatWidget } from "./AiChatWidget"; 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;