| import React, { useState, useEffect } from "react"; | |
| import { Link, useLocation } from "react-router-dom"; | |
| import { createPageUrl } from "@/utils"; | |
| import { | |
| BookOpen, | |
| Brain, | |
| Target, | |
| BarChart3, | |
| Atom, | |
| User, | |
| Menu, | |
| X, | |
| Sparkles, | |
| Trophy | |
| } from "lucide-react"; | |
| import { User as UserEntity } from "@/entities/User"; | |
| import { | |
| Sidebar, | |
| SidebarContent, | |
| SidebarGroup, | |
| SidebarGroupContent, | |
| SidebarGroupLabel, | |
| SidebarMenu, | |
| SidebarMenuButton, | |
| SidebarMenuItem, | |
| SidebarHeader, | |
| SidebarFooter, | |
| SidebarProvider, | |
| SidebarTrigger, | |
| } from "@/components/ui/sidebar"; | |
| const navigationItems = [ | |
| { | |
| title: "Dashboard", | |
| url: createPageUrl("Dashboard"), | |
| icon: BarChart3, | |
| description: "Overview & Progress" | |
| }, | |
| { | |
| title: "Practice", | |
| url: createPageUrl("Practice"), | |
| icon: Brain, | |
| description: "AI-Generated Problems" | |
| }, | |
| { | |
| title: "Molecular Viewer", | |
| url: createPageUrl("MolecularViewer"), | |
| icon: Atom, | |
| description: "3D Visualizations" | |
| }, | |
| { | |
| title: "Study Materials", | |
| url: createPageUrl("StudyMaterials"), | |
| icon: BookOpen, | |
| description: "Custom Learning Resources" | |
| } | |
| ]; | |
| export default function Layout({ children, currentPageName }) { | |
| const location = useLocation(); | |
| const [user, setUser] = useState(null); | |
| const [loading, setLoading] = useState(true); | |
| useEffect(() => { | |
| loadUser(); | |
| }, []); | |
| const loadUser = async () => { | |
| try { | |
| const userData = await UserEntity.me(); | |
| setUser(userData); | |
| } catch (error) { | |
| console.log("User not logged in"); | |
| } | |
| setLoading(false); | |
| }; | |
| if (loading) { | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center"> | |
| <div className="flex items-center gap-3"> | |
| <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div> | |
| <span className="text-slate-600 font-medium">Loading ChemTutor AI...</span> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <SidebarProvider> | |
| <div className="min-h-screen flex w-full bg-gradient-to-br from-slate-50 to-blue-50"> | |
| <Sidebar className="border-r border-slate-200 bg-white/80 backdrop-blur-sm"> | |
| <SidebarHeader className="border-b border-slate-200 p-6"> | |
| <div className="flex items-center gap-3"> | |
| <div className="relative w-10 h-10 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-xl flex items-center justify-center shadow-lg"> | |
| <Atom className="w-6 h-6 text-white" /> | |
| <div className="absolute -top-1 -right-1 w-4 h-4 bg-gradient-to-r from-emerald-400 to-teal-500 rounded-full flex items-center justify-center"> | |
| <Sparkles className="w-2.5 h-2.5 text-white" /> | |
| </div> | |
| </div> | |
| <div> | |
| <h2 className="text-xl font-bold bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent"> | |
| ChemTutor AI | |
| </h2> | |
| <p className="text-sm text-slate-500">Intelligent Chemistry Learning</p> | |
| </div> | |
| </div> | |
| </SidebarHeader> | |
| <SidebarContent className="p-4"> | |
| <SidebarGroup> | |
| <SidebarGroupLabel className="text-xs font-semibold text-slate-500 uppercase tracking-wider px-3 py-2"> | |
| Learning Hub | |
| </SidebarGroupLabel> | |
| <SidebarGroupContent> | |
| <SidebarMenu> | |
| {navigationItems.map((item) => ( | |
| <SidebarMenuItem key={item.title}> | |
| <SidebarMenuButton | |
| asChild | |
| className={`group hover:bg-blue-50 hover:text-blue-700 transition-all duration-200 rounded-xl mb-1 ${ | |
| location.pathname === item.url | |
| ? 'bg-gradient-to-r from-blue-50 to-indigo-50 text-blue-700 shadow-sm border border-blue-100' | |
| : '' | |
| }`} | |
| > | |
| <Link to={item.url} className="flex items-center gap-4 px-4 py-3"> | |
| <item.icon className="w-5 h-5 group-hover:scale-110 transition-transform duration-200" /> | |
| <div> | |
| <span className="font-semibold">{item.title}</span> | |
| <p className="text-xs text-slate-500 group-hover:text-blue-600 transition-colors"> | |
| {item.description} | |
| </p> | |
| </div> | |
| </Link> | |
| </SidebarMenuButton> | |
| </SidebarMenuItem> | |
| ))} | |
| </SidebarMenu> | |
| </SidebarGroupContent> | |
| </SidebarGroup> | |
| {user && ( | |
| <SidebarGroup className="mt-6"> | |
| <SidebarGroupLabel className="text-xs font-semibold text-slate-500 uppercase tracking-wider px-3 py-2"> | |
| Your Progress | |
| </SidebarGroupLabel> | |
| <SidebarGroupContent> | |
| <div className="px-4 py-3 space-y-3"> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center gap-2"> | |
| <Trophy className="w-4 h-4 text-amber-500" /> | |
| <span className="text-sm font-medium text-slate-700">Problems Solved</span> | |
| </div> | |
| <span className="text-lg font-bold text-blue-600"> | |
| {user.total_problems_solved || 0} | |
| </span> | |
| </div> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center gap-2"> | |
| <Target className="w-4 h-4 text-emerald-500" /> | |
| <span className="text-sm font-medium text-slate-700">Current Streak</span> | |
| </div> | |
| <span className="text-lg font-bold text-emerald-600"> | |
| {user.current_streak || 0} days | |
| </span> | |
| </div> | |
| <div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg p-3 border border-blue-100"> | |
| <p className="text-xs font-medium text-blue-700 mb-1">Learning Level</p> | |
| <p className="text-sm font-bold text-blue-900 capitalize"> | |
| {user.learning_level || 'Beginner'} | |
| </p> | |
| </div> | |
| </div> | |
| </SidebarGroupContent> | |
| </SidebarGroup> | |
| )} | |
| </SidebarContent> | |
| <SidebarFooter className="border-t border-slate-200 p-4"> | |
| {user ? ( | |
| <div className="flex items-center gap-3 p-3 rounded-xl bg-gradient-to-r from-slate-50 to-blue-50 border border-slate-200"> | |
| <div className="w-10 h-10 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-full flex items-center justify-center"> | |
| <User className="w-5 h-5 text-white" /> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <p className="font-semibold text-slate-900 text-sm truncate"> | |
| {user.full_name || 'Student'} | |
| </p> | |
| <p className="text-xs text-slate-500 truncate">{user.email}</p> | |
| </div> | |
| </div> | |
| ) : ( | |
| <button | |
| onClick={() => UserEntity.login()} | |
| className="w-full bg-gradient-to-r from-blue-600 to-indigo-700 text-white font-semibold py-3 px-4 rounded-xl hover:from-blue-700 hover:to-indigo-800 transition-all duration-200 shadow-lg hover:shadow-xl" | |
| > | |
| Start Learning | |
| </button> | |
| )} | |
| </SidebarFooter> | |
| </Sidebar> | |
| <main className="flex-1 flex flex-col"> | |
| {/* Mobile header */} | |
| <header className="bg-white/80 backdrop-blur-sm border-b border-slate-200 px-6 py-4 md:hidden"> | |
| <div className="flex items-center gap-4"> | |
| <SidebarTrigger className="hover:bg-slate-100 p-2 rounded-lg transition-colors duration-200" /> | |
| <div className="flex items-center gap-2"> | |
| <Atom className="w-6 h-6 text-blue-600" /> | |
| <h1 className="text-lg font-bold text-slate-900">ChemTutor AI</h1> | |
| </div> | |
| </div> | |
| </header> | |
| {/* Main content area */} | |
| <div className="flex-1 overflow-auto"> | |
| {children} | |
| </div> | |
| </main> | |
| </div> | |
| </SidebarProvider> | |
| ); | |
| } |