"use client" import { ReactNode, useState, useEffect, useRef } from "react" import { BookOpen, LayoutDashboard, Settings, FileText, Activity, LineChart, Trophy, User, ChevronUp, Lock, ShieldAlert, Flame, Target, Gauge, Zap, Calendar, Clock, BrainCircuit, BarChart3, School, CheckSquare, MessageSquare } from "lucide-react" import Link from "next/link" import { usePathname, useRouter } from "next/navigation" import { LanguageToggle } from "@/components/LanguageToggle" import { Logo } from "@/components/Logo" import { ThemeToggle } from "@/components/ThemeToggle" import { TierBadge } from "@/components/TierBadge" import { StreakCounter } from "@/components/StreakCounter" import { AITutorChat } from "@/components/AI/AITutorChat" import { useActiveUser, DEMO_USERS, isDemoUser } from "@/hooks/useActiveUser" import { StreakOnboardingModal } from "@/components/Dashboard/StreakOnboardingModal" import { Badge } from "@/components/ui/badge" import MaintenanceScreen from "@/components/MaintenanceScreen" export const dynamic = 'force-dynamic'; export default function DashboardLayout({ children }: { children: ReactNode }) { const pathname = usePathname() const [dropdownOpen, setDropdownOpen] = useState(false) const dropdownRef = useRef(null) const { userId, user, globalSettings, switchUser, logout, hasAccessTo, loading, switching, trialInfo } = useActiveUser(); const [maintenance, setMaintenance] = useState(false); const [checkingMaintenance, setCheckingMaintenance] = useState(true); useEffect(() => { if (globalSettings !== undefined && globalSettings !== null) { if (globalSettings.maintenance_mode) { setMaintenance(true); } else { setMaintenance(false); } setCheckingMaintenance(false); } else if (globalSettings === null && !loading) { // If we finished loading but settings failed to load setCheckingMaintenance(false); } }, [globalSettings, loading]); // Close dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setDropdownOpen(false) } } document.addEventListener("mousedown", handleClickOutside) return () => document.removeEventListener("mousedown", handleClickOutside) }, []) // BUG-05 fix: strip any parenthetical role annotations from display names // e.g. "Rahul (AI Coach)" → "Rahul", "Priya (NEET Aspirant)" → "Priya" const cleanDisplayName = (name: string) => name.replace(/\s*\([^)]*\)\s*$/, '').trim(); const userInitials = user ? cleanDisplayName(user.name).split(" ").filter(n => /^[a-zA-Z]/.test(n)).slice(0, 2).map(n => n[0]).join("").toUpperCase() : "DS" const targetExamLabel = user?.target_exam === "JEE_Main" ? "JEE" : user?.target_exam === "JEE_Advanced" ? "JEE Advanced" : user?.target_exam === "NEET" ? "NEET" : "JEE + NEET" const router = useRouter(); if (maintenance) { return ; } // Redirect to login (or admin) if no user is found after loading if (!loading && !switching && !user) { if (typeof window !== 'undefined') { const activeId = localStorage.getItem("activeUserId"); if (activeId === "admin") { router.replace("/admin"); } else { router.replace("/login"); } } return null; } if (loading || !user) { return (
); } return (
{/* Demo Account Switch — slim top progress bar, no full-page reload */} {switching && (
)} {/* Sidebar */} {/* Main Content Area */}
{/* Top Header Static Bar */}

{user ? `Welcome back, ${cleanDisplayName(user.name).split(" ")[0]}!` : "Welcome back!"}

{user && ( {targetExamLabel} Target )}
{/* Streak count moved to top header */} {user && ( )} {/* Demo Switcher — only visible when logged in as a known demo account */} {isDemoUser(userId) && (
{switching && ( Switching… )} {!switching && ( Demo: )}
)}
{/* */}
{/* Free Trial Banner */} {trialInfo.isTrialActive && (
{trialInfo.trialDaysRemaining} Days Remaining out of {trialInfo.trialTotalDays} Days in Free Trial
)} {/* Scrollable page body */}
{children}
{/* Global AI Tutor Chat */} {hasAccessTo("ai-tutor-chat") && } {/* Onboarding Motivation Popup */}
) } function NavItem({ href, icon, label, active, isLocked, section }: { href: string, icon: React.ReactNode, label: string, active?: boolean, isLocked?: boolean, section?: "pro" | "ai" }) { // We no longer return null for isLocked. We render it with a disabled appearance. // Section-aware active color tokens (light mode only, dark mode falls back to cyan) const activeClasses = active ? section === "pro" ? "bg-yellow-50 light:bg-yellow-50 text-yellow-700 dark:bg-[var(--cyan-ai-10)] dark:text-[var(--cyan-ai)] font-semibold border border-yellow-300/60 dark:border-[var(--cyan-ai-20)] shadow-[0_0_12px_-4px_rgba(234,179,8,0.2)] dark:shadow-[0_0_12px_-4px_rgba(12,96,96,0.3)]" : section === "ai" ? "bg-cyan-50 dark:bg-[var(--cyan-ai-10)] text-cyan-800 dark:text-[var(--cyan-ai)] font-semibold border border-cyan-300/60 dark:border-[var(--cyan-ai-20)] shadow-[0_0_12px_-4px_rgba(6,182,212,0.2)] dark:shadow-[0_0_12px_-4px_rgba(12,96,96,0.3)]" : "bg-[var(--cyan-ai-10)] text-[var(--cyan-ai)] font-semibold border border-[var(--cyan-ai-20)] shadow-[0_0_12px_-4px_rgba(12,96,96,0.3)]" : "text-muted-foreground/80 hover:bg-secondary/60 hover:text-foreground border border-transparent hover:border-border/40" const iconActiveClass = active ? section === "pro" ? "text-yellow-600 dark:text-[var(--cyan-ai)]" : section === "ai" ? "text-cyan-700 dark:text-[var(--cyan-ai)]" : "text-[var(--cyan-ai)]" : "text-muted-foreground/60 group-hover:text-foreground/80" const activeBarClass = active ? section === "pro" ? "w-1 h-4 rounded-full bg-yellow-500 dark:bg-[var(--cyan-ai)] shrink-0 shadow-[0_0_6px_rgba(234,179,8,0.6)] dark:shadow-[0_0_6px_rgba(12,96,96,0.8)]" : section === "ai" ? "w-1 h-4 rounded-full bg-cyan-600 dark:bg-[var(--cyan-ai)] shrink-0 shadow-[0_0_6px_rgba(6,182,212,0.6)] dark:shadow-[0_0_6px_rgba(12,96,96,0.8)]" : "w-1 h-4 rounded-full bg-[var(--cyan-ai)] shrink-0 shadow-[0_0_6px_rgba(12,96,96,0.8)]" : "" return (
{icon} {label}
{isLocked && } {!isLocked && active && }
) } function BrainCircuitIcon() { return ( ) }