"use client"import React from "react"import { useEffect, useState } from "react"import Link from "next/link"import { usePathname, useRouter } from "next/navigation"import axios from "axios"import toast from "react-hot-toast"import { DarkModeToggle } from "./DarkModeToggle"import { Button } from "@/components/ui/button"import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu"import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"import { Menu, User, Settings, LogOut, Home, Info, Mail, Zap, GalleryHorizontal, MonitorPlayIcon as TvMinimalPlay,} from "lucide-react"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"import Image from "next/image"import logo from "@/images/logo.png" // Adjust the path as necessaryconst ListItem = React.forwardRef<React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>( ({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <Link ref={ref} className={`block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground ${className}`} href={props.href ?? "#"} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">{children}</p> </Link> </NavigationMenuLink> </li> ) },)ListItem.displayName = "ListItem"const Navbar = () => { const router = useRouter() const [isOpen, setIsOpen] = useState(false) const [user, setUser] = useState<any>(null) const [loading, setLoading] = useState(true) const navigationItems = [ { name: "Home", href: "/", icon: Home }, { name: "Contact", href: "/contact", icon: Mail }, { name: "Blog", href: "/blog", icon: TvMinimalPlay }, ] const universityDropdownItems = [ { title: "Programs", href: "/university/programs", description: "Explore our degree programs and courses" }, { title: "Admissions", href: "/university/admissions", description: "Application process and requirements" }, { title: "Campus Life", href: "/university/campus", description: "Student life and campus facilities" }, { title: "Faculty", href: "/university/faculty", description: "Meet our experienced faculty members" }, { title: "Research", href: "/university/research", description: "Research opportunities and projects" }, { title: "Alumni", href: "/university/alumni", description: "Connect with our alumni network" }, ] const aboutDropdownItems = [ { title: "Our Story", href: "/about/story", description: "Learn about our journey and mission" }, { title: "Why Choose Us", href: "/about/why-choose-us", description: "Discover what makes us different" }, { title: "Our Team", href: "/about/team", description: "Meet our dedicated professionals" }, { title: "Accreditation", href: "/about/accreditation", description: "Our certifications and partnerships" }, { title: "Values", href: "/about/values", description: "Our core principles and beliefs" }, { title: "Gallery", href: "/gallery", description: "Our milestones and achievements" }, ] const coursesDropdownItems = [ { title: "IELTS Preparation", href: "/courses/ielts", description: "Comprehensive IELTS training program" }, { title: "PTE Academic", href: "/courses/pte", description: "Complete PTE Academic preparation course" }, { title: "TOEFL Training", href: "/courses/toefl", description: "TOEFL iBT preparation and practice" }, { title: "General English", href: "/courses/general-english", description: "Improve your overall English skills" }, { title: "Business English", href: "/courses/business-english", description: "Professional English for workplace" }, { title: "Academic Writing", href: "/courses/academic-writing", description: "Master academic writing techniques" }, { title: "Speaking & Pronunciation", href: "/courses/speaking", description: "Enhance your speaking confidence" }, { title: "Online Courses", href: "/courses/online", description: "Flexible online learning options" }, ] const filterOptions = { categories: [ { title: "Test Preparation", value: "Test Preparation" }, { title: "English Skills", value: "English Skills" }, { title: "Specialized Programs", value: "Specialized Programs" }, ], levels: [ { title: "Beginner", value: "Beginner" }, { title: "Intermediate", value: "Intermediate" }, { title: "Advanced", value: "Advanced" }, ], languages: [ { title: "English", value: "English" }, { title: "Spanish", value: "Spanish" }, { title: "French", value: "French" }, ], } // Fetch user data on component mount useEffect(() => { const fetchUserData = async () => { try { setLoading(true) const response = await axios.get("/api/users/me", { withCredentials: true, }) if (response.data && response.data.data) { setUser(response.data.data) } else { setUser(null) } } catch (error: any) { console.error("Failed to fetch user data:", error.message) setUser(null) } finally { setLoading(false) } } fetchUserData() }, []) const handleLogout = async () => { try { await axios.get("/api/users/logout", { withCredentials: true }) setUser(null) // Clear user state toast.success("Logout successful") router.push("/login") } catch (error: any) { console.error("Logout failed:", error.message) toast.error(error.response?.data?.error || "Logout failed") } } const getInitials = (name: string) => { return ( name ?.split(" ") .map((n) => n[0]) .join("") .toUpperCase() || "U" ) } const pathname = usePathname() if (pathname.startsWith("/admin")) return null // const components: { title: string; href: string; description: string }[] = [ // { // title: "Alert Dialog", // href: "/docs/primitives/alert-dialog", // description: "A modal dialog that interrupts the user with important content and expects a response.", // }, // { // title: "Hover Card", // href: "/docs/primitives/hover-card", // description: "For sighted users to preview content available behind a link.", // }, // { // title: "Progress", // href: "/docs/primitives/progress", // description: // "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", // }, // { // title: "Scroll-area", // href: "/docs/primitives/scroll-area", // description: "Visually or semantically separates content.", // }, // { // title: "Tabs", // href: "/docs/primitives/tabs", // description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", // }, // { // title: "Tooltip", // href: "/docs/primitives/tooltip", // description: // "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", // }, // ] return ( <nav className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> <div className="container mx-auto px-4"> <div className="flex h-16 items-center justify-between"> {/* Logo */} {/* Logo */} <div className="flex items-center space-x-2"> <Link href="/" className="flex items-center space-x-2 group"> <div className="relative"> <div className="flex items-center justify-center bg-white rounded-lg p-1 shadow-sm"> <Image width={200} height={24} src={logo || "/placeholder.svg"} alt="Logo" className="object-contain h-6 w-auto sm:h-8 md:h-10 lg:h-12 max-w-[120px] sm:max-w-[140px] md:max-w-[160px] lg:max-w-[200px]" priority /> </div> <div className="absolute -inset-1 rounded-lg blur opacity-20 group-hover:opacity-30 transition-opacity duration-300"></div> </div> </Link> </div> {/* Desktop Navigation */} <div className="hidden md:flex items-center space-x-1"> <NavigationMenu className="relative z-[100] max-w-max"> <NavigationMenuList className="flex-wrap gap-1"> {navigationItems.map((item) => { const IconComponent = item.icon const isActive = pathname === item.href return ( <NavigationMenuItem key={item.name}> <Link href={item.href} legacyBehavior passHref> <NavigationMenuLink className={navigationMenuTriggerStyle()}> <div className={`flex items-center space-x-2 ${ isActive ? "text-primary" : "text-muted-foreground" }`} > <IconComponent className="h-4 w-4" /> <span>{item.name}</span> </div> </NavigationMenuLink> </Link> </NavigationMenuItem> ) })} {/* Courses Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <GalleryHorizontal className="h-4 w-4" /> <span>Courses</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> {/* Featured Section */} <li className="md:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-center rounded-lg bg-gradient-to-br from-green-500/10 to-green-600/10 p-4 sm:p-6 lg:p-8 no-underline outline-none focus:shadow-md border border-green-200/50 min-h-[160px] sm:min-h-[200px]" href="/courses" > <div className="flex items-center space-x-3 sm:space-x-4 mb-4 sm:mb-6"> <div className="h-12 w-12 sm:h-16 sm:w-16 rounded-xl bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center shadow-lg"> <GalleryHorizontal className="h-6 w-6 sm:h-8 sm:w-8 text-white" /> </div> <div> <div className="text-xl sm:text-2xl lg:text-3xl font-bold">Our Courses</div> <div className="text-xs sm:text-sm text-muted-foreground">Expert Training Programs</div> </div> </div> <p className="text-sm sm:text-base leading-relaxed text-muted-foreground mb-3 sm:mb-4"> Master English proficiency with our comprehensive courses including IELTS, PTE, TOEFL preparation, and specialized programs designed by expert instructors. </p> <div className="inline-flex items-center text-xs sm:text-sm font-medium text-green-600 hover:text-green-700"> Explore All Courses → </div> </Link> </NavigationMenuLink> </li> {/* Test Preparation */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Test Preparation </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/ielts" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">IELTS Preparation</div> <div className="text-xs text-muted-foreground">Complete IELTS training</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/pte" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">PTE Academic</div> <div className="text-xs text-muted-foreground">PTE preparation course</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/toefl" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">TOEFL Training</div> <div className="text-xs text-muted-foreground">TOEFL iBT preparation</div> </Link> </NavigationMenuLink> </div> </li> {/* English Skills */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> English Skills </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/general-english" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">General English</div> <div className="text-xs text-muted-foreground">Overall English improvement</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/business-english" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Business English</div> <div className="text-xs text-muted-foreground">Professional workplace English</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/speaking" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Speaking & Pronunciation</div> <div className="text-xs text-muted-foreground">Improve speaking confidence</div> </Link> </NavigationMenuLink> </div> </li> {/* Specialized Programs */} <li className="space-y-3 sm:space-y-4 hidden lg:block"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Specialized Programs </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/academic-writing" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Academic Writing</div> <div className="text-xs text-muted-foreground">Master academic writing</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/online" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Online Courses</div> <div className="text-xs text-muted-foreground">Flexible online learning</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/private-tutoring" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Private Tutoring</div> <div className="text-xs text-muted-foreground">One-on-one sessions</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> {/* University Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <TvMinimalPlay className="h-4 w-4" /> <span>University</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> {/* Featured Section */} <li className="sm:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-center rounded-lg bg-gradient-to-br from-brand-500/10 to-brand-600/10 p-4 sm:p-6 lg:p-8 no-underline outline-none focus:shadow-md border border-brand-200/50 min-h-[160px] sm:min-h-[200px]" href="/university" > <div className="flex items-center space-x-3 sm:space-x-4 mb-4 sm:mb-6"> <div className="h-12 w-12 sm:h-16 sm:w-16 rounded-xl bg-gradient-to-br from-brand-500 to-brand-600 flex items-center justify-center shadow-lg"> <TvMinimalPlay className="h-6 w-6 sm:h-8 sm:w-8 text-white" /> </div> <div> <div className="text-xl sm:text-2xl lg:text-3xl font-bold">University</div> <div className="text-xs sm:text-sm text-muted-foreground">Academic Excellence</div> </div> </div> <p className="text-sm sm:text-base leading-relaxed text-muted-foreground mb-3 sm:mb-4"> Discover our comprehensive educational programs, world-class faculty, and cutting-edge research opportunities that prepare students for success in their chosen fields. </p> <div className="inline-flex items-center text-xs sm:text-sm font-medium text-brand-600 hover:text-brand-700"> Explore University → </div> </Link> </NavigationMenuLink> </li> {/* Academic Section */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Academic </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/programs" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Programs</div> <div className="text-xs text-muted-foreground">Degree programs & courses</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/admissions" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Admissions</div> <div className="text-xs text-muted-foreground">Application process</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/faculty" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Faculty</div> <div className="text-xs text-muted-foreground">Meet our professors</div> </Link> </NavigationMenuLink> </div> </li> {/* Campus Life Section */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Campus Life </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/campus" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Campus</div> <div className="text-xs text-muted-foreground">Facilities & student life</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/research" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Research</div> <div className="text-xs text-muted-foreground">Research opportunities</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/alumni" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Alumni</div> <div className="text-xs text-muted-foreground">Alumni network</div> </Link> </NavigationMenuLink> </div> </li> {/* Additional Section for larger screens */} <li className="space-y-3 sm:space-y-4 hidden lg:block"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Resources </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/library" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Library</div> <div className="text-xs text-muted-foreground">Digital & physical resources</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/support" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Student Support</div> <div className="text-xs text-muted-foreground">Academic & personal support</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/events" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Events</div> <div className="text-xs text-muted-foreground">Campus events & activities</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> {/* About Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <Info className="h-4 w-4" /> <span>About</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> <li className="md:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-between rounded-lg bg-gradient-to-br from-blue-500/10 to-blue-600/10 p-8 no-underline outline-none focus:shadow-md border border-blue-200/50 min-h-[200px]" href="/about" > <div className="flex items-center space-x-4 mb-6"> <div className="h-16 w-16 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center shadow-lg"> <Info className="h-8 w-8 text-white" /> </div> <div> <div className="text-3xl font-bold">About Us</div> <div className="text-sm text-muted-foreground">Our Story & Mission</div> </div> </div> <p className="text-base leading-relaxed text-muted-foreground mb-4"> Discover our journey, values, and the passionate team behind our success. Learn why thousands choose us for their educational and professional growth. </p> <div className="inline-flex items-center text-sm font-medium text-blue-600 hover:text-blue-700"> Learn More About Us → </div> </Link> </NavigationMenuLink> </li> {/* Our Story & Mission */} <li className="space-y-4"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Our Story</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/story" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Journey</div> <div className="text-xs text-muted-foreground">How we started & evolved</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/values" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Values</div> <div className="text-xs text-muted-foreground">Core principles & beliefs</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/gallery" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Gallery</div> <div className="text-xs text-muted-foreground">Milestones & achievements</div> </Link> </NavigationMenuLink> </div> </li> {/* Why Choose Us */} <li className="space-y-4"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Why Choose Us</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/why-choose-us" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Advantages</div> <div className="text-xs text-muted-foreground">What sets us apart</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/accreditation" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Accreditation</div> <div className="text-xs text-muted-foreground">Certifications & partnerships</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/testimonials" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Testimonials</div> <div className="text-xs text-muted-foreground">What our clients say</div> </Link> </NavigationMenuLink> </div> </li> {/* Team & Leadership */} <li className="space-y-4 hidden xl:block"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Our Team</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/team" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Meet the Team</div> <div className="text-xs text-muted-foreground">Our dedicated professionals</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/leadership" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Leadership</div> <div className="text-xs text-muted-foreground">Executive team & board</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/careers" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Careers</div> <div className="text-xs text-muted-foreground">Join our team</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <Zap className="h-4 w-4" /> <span>Browse</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[700px]"> <li className="md:col-span-2"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-end rounded-lg bg-gradient-to-br from-yellow-500/10 to-yellow-600/10 p-6 no-underline outline-none focus:shadow-md border border-yellow-200/50 min-h-[120px]" href="/courses" > <div className="mb-2 mt-4 text-lg font-medium">Explore All Courses</div> <p className="text-sm leading-tight text-muted-foreground"> Find the perfect course for your learning journey. </p> </Link> </NavigationMenuLink> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Categories</h4> <div className="space-y-2"> {filterOptions.categories.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?category=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Levels</h4> <div className="space-y-2"> {filterOptions.levels.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?level=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Languages</h4> <div className="space-y-2"> {filterOptions.languages.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?language=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> {/* Right Side - Desktop */} <div className="hidden md:flex items-center space-x-4"> <DarkModeToggle /> {loading ? ( // Loading state <div className="h-10 w-10 rounded-full bg-muted animate-pulse"></div> ) : user ? ( // User is logged in - show user dropdown <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" className="relative h-10 w-10 rounded-full"> <Avatar className="h-10 w-10 border-2 border-primary/20 hover:border-primary/40 transition-colors"> <AvatarImage src={user.avatar || "/placeholder.svg?height=40&width=40"} alt={user.username || user.name} /> <AvatarFallback className="bg-gradient-to-br from-brand-500 to-brand-600 text-white font-semibold"> {getInitials(user.username || user.name)} </AvatarFallback> </Avatar> </Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-56" align="end" forceMount> <DropdownMenuLabel className="font-normal"> <div className="flex flex-col space-y-1"> <p className="text-sm font-medium leading-none">{user.username || user.name}</p> <p className="text-xs leading-none text-muted-foreground">{user.email}</p> </div> </DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem onClick={() => router.push("/profile")} className="cursor-pointer"> <User className="mr-2 h-4 w-4" /> <span>Profile</span> </DropdownMenuItem> <DropdownMenuItem onClick={() => router.push("/settings")} className="cursor-pointer"> <Settings className="mr-2 h-4 w-4" /> <span>Settings</span> </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem onClick={handleLogout} className="text-destructive cursor-pointer"> <LogOut className="mr-2 h-4 w-4" /> <span>Log out</span> </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ) : ( // User is not logged in - show login/register buttons <div className="flex items-center space-x-2"> <Button variant="ghost" onClick={() => router.push("/login")} className="text-sm font-medium"> Login </Button> <Button onClick={() => router.push("/signup")} className="text-sm font-medium bg-gradient-to-r from-brand-500 to-brand-600 hover:from-brand-600 hover:to-brand-700 text-white shadow-lg hover:shadow-brand-500/25 transition-all duration-300" > Register </Button> </div> )} </div> {/* Mobile Menu Button */} <div className="md:hidden flex items-center space-x-2"> <DarkModeToggle /> <Sheet open={isOpen} onOpenChange={setIsOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="md:hidden h-10 w-10"> <Menu className="h-5 w-5" /> <span className="sr-only">Toggle menu</span> </Button> </SheetTrigger> <SheetContent side="right" className="w-full sm:w-[400px] p-0 overflow-y-auto"> <div className="flex flex-col h-full"> {/* Mobile Header */} {/* Logo */} <div className="flex items-center space-x-2"> <Link href="/" className="flex items-center space-x-2 group"> <div className="relative"> <div className="flex items-center justify-center bg-white rounded-lg p-1 shadow-sm"> <Image width={250} height={30} src={logo || "/placeholder.svg"} alt="Logo" className="object-contain h-6 w-auto sm:h-8 md:h-10 lg:h-12 max-w-[120px] sm:max-w-[140px] md:max-w-[160px] lg:max-w-[200px]" priority /> </div> <div className="absolute -inset-1 rounded-lg blur opacity-20 group-hover:opacity-30 transition-opacity duration-300"></div> </div> </Link> </div> {/* Mobile Content */} <div className="flex-1 px-4 py-4 space-y-6"> {/* User Section - Mobile (only show if user is logged in) */} {user && ( <div className="flex items-center space-x-3 p-4 rounded-xl bg-gradient-to-r from-brand-50 to-brand-100 border border-brand-200/50"> <Avatar className="h-12 w-12 border-2 border-brand-200"> <AvatarImage src={user.avatar || "/placeholder.svg?height=48&width=48"} alt={user.username || user.name} /> <AvatarFallback className="bg-gradient-to-br from-brand-500 to-brand-600 text-white font-semibold"> {getInitials(user.username || user.name)} </AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-semibold text-brand-900 truncate">{user.username || user.name}</p> <p className="text-xs text-brand-600 truncate">{user.email}</p> </div> </div> )} {/* Quick Navigation - Mobile */} <div className="space-y-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider px-2"> Quick Navigation </h3> <div className="grid grid-cols-2 gap-2"> {navigationItems.map((item) => { const IconComponent = item.icon const isActive = pathname === item.href return ( <Link key={item.name} href={item.href}> <Button variant="ghost" className={`w-full h-16 flex flex-col items-center justify-center space-y-1 rounded-xl border-2 transition-all duration-200 ${ isActive ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <IconComponent className="h-5 w-5" /> <span className="text-xs font-medium">{item.name}</span> </Button> </Link> ) })} </div> </div> {/* Courses Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> Our Courses </h3> <Link href="/courses"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> {/* Featured Courses */} <div className="space-y-2"> <Link href="/courses"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/courses" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center"> <GalleryHorizontal className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">All Courses</div> <div className="text-xs text-muted-foreground">Browse our programs</div> </div> </Button> </Link> {/* Popular Courses */} <div className="grid grid-cols-1 gap-2"> {[ { title: "IELTS Preparation", href: "/courses/ielts", desc: "Complete IELTS training", color: "from-blue-500 to-blue-600", }, { title: "PTE Academic", href: "/courses/pte", desc: "PTE preparation course", color: "from-purple-500 to-purple-600", }, { title: "General English", href: "/courses/general-english", desc: "Improve overall English", color: "from-orange-500 to-orange-600", }, ].map((course) => { const isActive = pathname === course.href return ( <Link key={course.title} href={course.href}> <Button variant="ghost" className={`w-full h-12 flex items-center justify-start space-x-3 rounded-lg transition-all duration-200 ${ isActive ? "text-primary bg-primary/10 border border-primary/20" : "hover:bg-accent" }`} onClick={() => setIsOpen(false)} > <div className={`h-6 w-6 rounded bg-gradient-to-br ${course.color} flex items-center justify-center`} > <div className="h-2 w-2 bg-white rounded-full" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">{course.title}</div> <div className="text-xs text-muted-foreground">{course.desc}</div> </div> </Button> </Link> ) })} </div> {/* More Courses Expandable */} <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">More Courses</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {coursesDropdownItems.slice(3).map((item) => { const isActive = pathname === item.href return ( <Link key={item.title} href={item.href}> <Button variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ) })} </div> </details> </div> </div> {/* University Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> University </h3> <Link href="/university"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> <Link href="/university"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/university" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-brand-500 to-brand-600 flex items-center justify-center"> <TvMinimalPlay className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">University</div> <div className="text-xs text-muted-foreground">Academic programs</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">University Programs</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {universityDropdownItems.map((item) => { const isActive = pathname === item.href return ( <Link key={item.title} href={item.href}> <Button variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ) })} </div> </details> </div> {/* About Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> About Us </h3> <Link href="/about"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> Learn More </Button> </Link> </div> <Link href="/about"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/about" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center"> <Info className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">About Us</div> <div className="text-xs text-muted-foreground">Our story & mission</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">More About Us</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {aboutDropdownItems.map((item) => { const isActive = pathname === item.href return ( <Link key={item.title} href={item.href}> <Button variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ) })} </div> </details> </div> {/* Browse Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> Browse Courses </h3> <Link href="/courses"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> <Link href="/courses"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/courses" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-yellow-500 to-yellow-600 flex items-center justify-center"> <Zap className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">All Courses</div> <div className="text-xs text-muted-foreground">Explore all programs</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Category</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.categories.map((item) => ( <Link key={item.title} href={`/courses?category=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Level</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.levels.map((item) => ( <Link key={item.title} href={`/courses?level=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Language</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.languages.map((item) => ( <Link key={item.title} href={`/courses?language=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> </div> </div> {/* Mobile Footer Actions */} <div className="px-4 py-4 border-t bg-background/95 backdrop-blur sticky bottom-0"> {user ? ( // User is logged in - show profile/settings/logout <div className="space-y-2"> <div className="grid grid-cols-2 gap-2"> <Button variant="outline" className="h-12 flex items-center justify-center space-x-2 bg-transparent" onClick={() => { router.push("/profile") setIsOpen(false) }} > <User className="h-4 w-4" /> <span className="text-sm">Profile</span> </Button> <Button variant="outline" className="h-12 flex items-center justify-center space-x-2 bg-transparent" onClick={() => { router.push("/settings") setIsOpen(false) }} > <Settings className="h-4 w-4" /> <span className="text-sm">Settings</span> </Button> </div> <Button variant="destructive" className="w-full h-12 flex items-center justify-center space-x-2" onClick={() => { handleLogout() setIsOpen(false) }} > <LogOut className="h-4 w-4" /> <span className="text-sm font-medium">Log out</span> </Button> </div> ) : ( // User is not logged in - show login/register <div className="space-y-3"> <Button variant="outline" className="w-full h-12 text-sm font-medium bg-transparent" onClick={() => { router.push("/login") setIsOpen(false) }} > Login to Your Account </Button> <Button className="w-full h-12 bg-gradient-to-r from-brand-500 to-brand-600 hover:from-brand-600 hover:to-brand-700 text-white text-sm font-medium shadow-lg" onClick={() => { router.push("/signup") setIsOpen(false) }} > Create New Account </Button> </div> )} </div> </div> </SheetContent> </Sheet> </div> </div> </div> </nav> )}export default Navbar
This Navbar
component provides a comprehensive and responsive navigation solution for a Next.js application, leveraging shadcn/ui
components and modern React hooks.
Here's a breakdown of its key features and structure:
Responsive Design:
shadcn/ui
's NavigationMenu
for a sleek, multi-level desktop navigation experience.Sheet
component for a full-screen mobile menu, triggered by a hamburger icon, ensuring usability on smaller screens.Dynamic Navigation Content:
Rich Dropdown Menus: Features three detailed dropdown menus for "Courses", "University", and "About", each with:
<details>
HTML element) to organize the extensive list of links within the mobile sheet.User Authentication Handling:
/api/users/me
using axios
and useEffect
on component mount. It manages user
and loading
states to conditionally render UI elements.DropdownMenu
for "Profile", "Settings", and "Log out" actions.handleLogout
function makes an API call to /api/users/logout
, clears the user state, and redirects to the login page, providing toast notifications for success or failure.Theming:
DarkModeToggle
component, allowing users to switch between light and dark themes.Routing and Navigation:
next/link
for efficient client-side navigation, preventing full page reloads.useRouter
and usePathname
from next/navigation
to programmatically navigate and determine the active route for styling.Conditional Rendering:
Navbar
component is conditionally rendered, returning null
if the current path starts with /admin
, indicating a separate navigation might be used for administrative sections.Styling and Components:
shadcn/ui
components such as Button
, Avatar
, DropdownMenu
, Sheet
, and NavigationMenu
for a consistent and modern UI.ListItem
component, forwarded with React.forwardRef
, to standardize the appearance of links within the NavigationMenuContent
.Image Handling:
logo.png
image and uses next/image
for optimized image loading, including the priority
prop for the logo.This component is a well-structured example of a modern, responsive navigation bar in a Next.js application, demonstrating effective use of client components, state management, and UI libraries.
"use client"import { useState, useEffect } from "react"import CoursesHero from "./components/CoursesHero" import CoursesFilters from "./components/CoursesFilters" import CoursesList from "./components/CoursesList" import CourseStats from "./components/CourseStats" import toast from "react-hot-toast"import { Filter, X } from "lucide-react"import { Button } from "@/components/ui/button"interface Course { _id: string title: string slug: string shortDescription: string description: string thumbnail: string previewVideo: string category: string subcategory: string level: string language: string price: { original: number current: number currency: string } isFree: boolean offers: { isOnSale: boolean saleEndDate?: string discountPercentage: number couponCode: string } instructor: { name: string email: string bio: string avatar: string } duration: { total: number lectures: number } status: "draft" | "published" | "archived" | "coming_soon" featured: boolean bestseller: boolean new: boolean enrollments: number rating: { average: number count: number } tags: string[] createdAt: string lastUpdated: string publishedAt?: string}interface CourseStatsType { totalCourses: number publishedCourses: number draftCourses: number featuredCourses: number freeCourses: number totalEnrollments: number averageRating: number categoryStats: { _id: string; count: number }[] levelStats: { _id: string; count: number }[] revenueStats: { totalRevenue: number; averagePrice: number }}interface Filters { search: string category: string level: string priceRange: string rating: string duration: string language: string sortBy: string sortOrder: string}export default function CoursesPage() { const [courses, setCourses] = useState<Course[]>([]) const [stats, setStats] = useState<CourseStatsType | null>(null) const [loading, setLoading] = useState(true) const [featuredCourses, setFeaturedCourses] = useState<Course[]>([]) const [currentPage, setCurrentPage] = useState(1) const [totalPages, setTotalPages] = useState(1) const [totalCourses, setTotalCourses] = useState(0) const coursesPerPage = 12 const [showMobileFilters, setShowMobileFilters] = useState(false) const [filters, setFilters] = useState<Filters>({ search: "", category: "all", level: "all", priceRange: "all", rating: "all", duration: "all", language: "all", sortBy: "createdAt", sortOrder: "desc", }) useEffect(() => { fetchCourses() fetchStats() }, [filters, currentPage]) useEffect(() => { fetchFeaturedCourses() }, []) const fetchCourses = async () => { try { setLoading(true) const params = new URLSearchParams({ page: currentPage.toString(), limit: coursesPerPage.toString(), status: "published", sortBy: filters.sortBy, sortOrder: filters.sortOrder, }) if (filters.search) params.append("search", filters.search) if (filters.category !== "all") params.append("category", filters.category) if (filters.level !== "all") params.append("level", filters.level) if (filters.language !== "all") params.append("language", filters.language) // Handle price range filter if (filters.priceRange !== "all") { if (filters.priceRange === "free") { params.append("isFree", "true") } else if (filters.priceRange === "paid") { params.append("isFree", "false") } } const response = await fetch(`/api/courses?${params.toString()}`) if (!response.ok) throw new Error("Failed to fetch courses") const data = await response.json() let filteredCourses = data.courses // Apply client-side filters that aren't handled by the API if (filters.rating !== "all") { const minRating = Number.parseFloat(filters.rating) filteredCourses = filteredCourses.filter((course: Course) => course.rating.average >= minRating) } if (filters.duration !== "all") { filteredCourses = filteredCourses.filter((course: Course) => { const hours = course.duration.total / 60 switch (filters.duration) { case "short": return hours < 3 case "medium": return hours >= 3 && hours <= 10 case "long": return hours > 10 default: return true } }) } setCourses(filteredCourses) setTotalPages(data.pagination.pages) setTotalCourses(data.pagination.total) } catch (error) { console.error("Error fetching courses:", error) toast.error("Failed to load courses") } finally { setLoading(false) } } const fetchFeaturedCourses = async () => { try { const response = await fetch("/api/courses?status=published&featured=true&limit=6") if (!response.ok) throw new Error("Failed to fetch featured courses") const data = await response.json() setFeaturedCourses(data.courses) } catch (error) { console.error("Error fetching featured courses:", error) } } const fetchStats = async () => { try { const response = await fetch("/api/courses/stats") if (!response.ok) throw new Error("Failed to fetch stats") const data = await response.json() setStats(data) } catch (error) { console.error("Failed to load stats:", error) } } const handleFilterChange = (newFilters: Partial<Filters>) => { setFilters((prev) => ({ ...prev, ...newFilters })) setCurrentPage(1) // Reset to first page when filters change } const handlePageChange = (page: number) => { setCurrentPage(page) window.scrollTo({ top: 0, behavior: "smooth" }) } const hasActiveFilters = Object.entries(filters).some(([key, value]) => { if (key === "sortBy" || key === "sortOrder" || key === "search") return false return value !== "all" && value !== "" }) return ( <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-gray-900 dark:to-gray-800 relative overflow-hidden"> <CoursesHero featuredCourses={featuredCourses} /> {stats && <CourseStats stats={stats} />} <div className="container mx-auto px-4 sm:px-6 py-8 sm:py-12"> <div className="grid grid-cols-1 lg:grid-cols-4 gap-6 lg:gap-8"> {/* Mobile Filter Toggle - Only visible on mobile */} <div className="lg:hidden mb-6"> <Button onClick={() => setShowMobileFilters(true)} variant="outline" className="w-full flex items-center justify-center gap-2" > <Filter className="w-4 h-4" /> Show Filters {hasActiveFilters && ( <span className="bg-green-500 text-white text-xs px-2 py-1 rounded-full ml-2"> { Object.values(filters).filter((v) => v !== "all" && v !== "" && v !== "createdAt" && v !== "desc") .length } </span> )} </Button> </div> {/* Desktop Filters Sidebar */} <div className="hidden lg:block lg:col-span-1"> <CoursesFilters filters={filters} onFilterChange={handleFilterChange} stats={stats} /> </div> {/* Mobile Filters Overlay */} {showMobileFilters && ( <div className="lg:hidden fixed inset-0 z-50 bg-black bg-opacity-50"> <div className="absolute right-0 top-0 h-full w-80 max-w-[85vw] bg-white dark:bg-gray-900 shadow-xl overflow-y-auto"> <div className="p-4 border-b flex items-center justify-between"> <h2 className="text-lg font-semibold">Filters</h2> <Button variant="ghost" size="sm" onClick={() => setShowMobileFilters(false)}> <X className="w-5 h-5" /> </Button> </div> <div className="p-4"> <CoursesFilters filters={filters} onFilterChange={(newFilters) => { handleFilterChange(newFilters) // Don't close on filter change to allow multiple selections }} stats={stats} /> </div> </div> </div> )} {/* Courses List */} <div className="lg:col-span-3"> <CoursesList courses={courses} loading={loading} currentPage={currentPage} totalPages={totalPages} totalCourses={totalCourses} onPageChange={handlePageChange} filters={filters} onFilterChange={handleFilterChange} /> </div> </div> </div> </div> )}"use client"import { useEffect, useState } from "react"import { Card, CardContent } from "@/components/ui/card"import { Badge } from "@/components/ui/badge"import { Button } from "@/components/ui/button"import { Star, Users, Clock, BookOpen, Play, Globe, Award, CheckCircle, ArrowLeft, Calendar, Target, Lightbulb, UserCheck, Tag, ChevronLeft, ChevronRight,} from "lucide-react"import Link from "next/link"import Image from "next/image"interface Course { _id: string title: string slug: string shortDescription: string fullDescription?: string description?: string thumbnail: string previewVideo?: string category: string subcategory?: string level: string language: string difficulty?: string status: string price: { original: number current: number currency: string } isFree: boolean offers?: { isOnSale: boolean discountPercentage: number } instructor: { name: string email?: string bio?: string avatar?: string rating?: number students?: number courses?: number } duration: { total: number lectures: number } enrollments: number rating?: { average: number count: number } featured: boolean bestseller: boolean new: boolean tags?: string[] modules?: Array<{ title: string lessons: Array<{ title: string duration: number videoUrl?: string isFree?: boolean }> }> requirements?: string[] whatYouWillLearn?: string[] targetAudience?: string[] certificate?: { available: boolean } lastUpdated: string}export default function CourseDetailsClient({ params }: { params: { id: string } }) { const [course, setCourse] = useState<Course | null>(null) const [recommendedCourses, setRecommendedCourses] = useState<Course[]>([]) const [activeTab, setActiveTab] = useState<"overview" | "curriculum" | "instructor" | "reviews">("overview") const [loading, setLoading] = useState(true) useEffect(() => { const fetchCourse = async () => { try { const response = await fetch(`/api/courses/${params.id}`) if (response.ok) { const courseData = await response.json() setCourse(courseData) // Fetch recommended courses based on category const recommendedResponse = await fetch( `/api/courses?category=${courseData.category}&limit=8&exclude=${params.id}`, ) if (recommendedResponse.ok) { const recommendedData = await recommendedResponse.json() setRecommendedCourses(recommendedData.courses || []) } } } catch (error) { console.error("Error fetching course:", error) } finally { setLoading(false) } } fetchCourse() }, [params.id]) if (loading) { return <CourseDetailsLoading /> } if (!course) { return ( <div className="min-h-screen bg-gray-50 dark:bg-gray-800 flex items-center justify-center"> <Card className="max-w-md w-full mx-4"> <CardContent className="p-8 text-center"> <BookOpen className="w-16 h-16 mx-auto text-slate-300 mb-4" /> <h1 className="text-2xl font-bold text-slate-800 dark:text-white mb-2">Course Not Found</h1> <p className="text-slate-600 dark:text-white mb-6">The course you are looking for does not exist.</p> <Link href="/courses"> <Button> <ArrowLeft className="w-4 h-4 mr-2" /> Back to Courses </Button> </Link> </CardContent> </Card> </div> ) } const formatDuration = (minutes: number) => { const hours = Math.floor(minutes / 60) const mins = minutes % 60 if (hours > 0) { return `${hours}h ${mins}m` } return `${mins}m` } const getLevelColor = (level: string) => { switch (level) { case "Beginner": return "bg-green-100 text-green-800" case "Intermediate": return "bg-yellow-100 text-yellow-800" case "Advanced": return "bg-red-100 text-red-800" case "All Levels": return "bg-green-100 text-green-800" default: return "bg-gray-100 text-gray-800" } } const totalLessons = course.modules?.reduce((total, module) => total + module.lessons.length, 0) || course.duration.lectures return ( <div className="min-h-screen bg-gray-50 dark:bg-gray-800 relative overflow-hidden"> {/* Hero Section */} <div className="bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 text-white"> <div className="container mx-auto px-4 py-8"> <div className="flex items-center mb-6"> <Link href="/courses" className="flex items-center text-slate-300 hover:text-white transition-colors"> <ArrowLeft className="w-4 h-4 mr-2" /> Back to Courses </Link> </div> <div className="grid lg:grid-cols-3 gap-8"> <div className="lg:col-span-2"> <div className="flex items-center space-x-2 mb-4"> <Badge variant="outline" className="bg-white/10 border-white/20 text-white"> {course.category} </Badge> {course.subcategory && ( <Badge variant="outline" className="bg-white/10 border-white/20 text-white"> {course.subcategory} </Badge> )} <Badge className={`${getLevelColor(course.level)} border-0`}>{course.level}</Badge> {course.featured && <Badge className="bg-yellow-600">Featured</Badge>} {course.bestseller && <Badge className="bg-orange-600">Bestseller</Badge>} {course.new && <Badge className="bg-green-600">New</Badge>} </div> <h1 className="text-3xl lg:text-4xl font-bold mb-4">{course.title}</h1> <p className="text-xl text-slate-300 mb-6">{course.shortDescription}</p> <div className="flex flex-wrap items-center gap-6 text-sm mb-6"> {course.rating && ( <div className="flex items-center"> <Star className="w-4 h-4 text-yellow-400 fill-current mr-1" /> <span className="font-semibold">{course.rating.average.toFixed(1)}</span> <span className="text-slate-300 ml-1">({course.rating.count} ratings)</span> </div> )} <div className="flex items-center"> <Users className="w-4 h-4 mr-1" /> {course.enrollments.toLocaleString()} students </div> <div className="flex items-center"> <Clock className="w-4 h-4 mr-1" /> {formatDuration(course.duration.total)} </div> <div className="flex items-center"> <BookOpen className="w-4 h-4 mr-1" /> {totalLessons} lectures </div> <div className="flex items-center"> <Globe className="w-4 h-4 mr-1" /> {course.language} </div> </div> <div className="flex items-center space-x-4"> <div className="flex items-center"> <div className="w-10 h-10 bg-slate-600 rounded-full flex items-center justify-center mr-3"> <UserCheck className="w-5 h-5" /> </div> <div> <p className="text-white font-semibold">{course.instructor.name}</p> <p className="text-slate-400 text-sm">Instructor</p> </div> </div> <div className="flex items-center text-slate-400"> <Calendar className="w-4 h-4 mr-1" /> Updated {new Date(course.lastUpdated).toLocaleDateString()} </div> </div> </div> {/* Course Preview Card - Information Only */} <div className="lg:col-span-1"> <Card className="sticky top-8 shadow-2xl"> <div className="relative"> <Image src={course.thumbnail || "/placeholder.svg"} alt={course.title} width={400} height={225} className="w-full h-48 object-cover rounded-t-lg" /> {course.previewVideo && ( <div className="absolute inset-0 bg-black/30 flex items-center justify-center rounded-t-lg"> <Button variant="outline" size="lg" className="bg-white/20 border-white/30 text-white hover:bg-white/30" > <Play className="w-6 h-6 mr-2" /> Preview Course </Button> </div> )} </div> <CardContent className="p-6"> <div className="text-center mb-6"> <h3 className="text-xl font-bold text-slate-800 mb-2 dark:text-green-600">Course Information</h3> <div className="text-2xl font-bold text-green-600"> {course.isFree ? "Free Course" : "Premium Course"} </div> </div> <div className="space-y-3 text-sm"> <div className="flex items-center"> <Clock className="w-4 h-4 mr-2 text-slate-500" /> {formatDuration(course.duration.total)} total content </div> <div className="flex items-center"> <BookOpen className="w-4 h-4 mr-2 text-slate-500" /> {totalLessons} lectures </div> <div className="flex items-center"> <Globe className="w-4 h-4 mr-2 text-slate-500" /> Available in {course.language} </div> <div className="flex items-center"> <Users className="w-4 h-4 mr-2 text-slate-500" /> {course.enrollments.toLocaleString()} students enrolled </div> {course.certificate?.available && ( <div className="flex items-center"> <Award className="w-4 h-4 mr-2 text-slate-500" /> Certificate included </div> )} </div> </CardContent> </Card> </div> </div> </div> </div> {/* Main Content */} <div className="container mx-auto px-4 py-8"> <div className="grid lg:grid-cols-4 gap-8"> <div className="lg:col-span-3"> {/* Tabs */} <div className="flex space-x-1 mb-6 bg-white dark:bg-gray-700 p-1 rounded-lg shadow-sm border"> {[ { id: "overview", label: "Overview" }, { id: "instructor", label: "Instructor" }, ].map((tab) => ( <button key={tab.id} onClick={() => setActiveTab(tab.id as any)} className={`flex-1 py-3 px-4 rounded-md text-sm font-medium transition-colors ${ activeTab === tab.id ? "bg-green-600 text-white shadow-sm" : "text-slate-600 hover:text-slate-900 hover:bg-slate-50" }`} > {tab.label} </button> ))} </div> {/* Tab Content */} <Card className="shadow-lg"> <CardContent className="p-8"> {activeTab === "overview" && ( <div className="space-y-8"> <div> <h3 className="text-2xl font-bold mb-4 flex items-center"> <BookOpen className="w-6 h-6 mr-2 text-green-600" /> About this course </h3> <p className="text-slate-600 leading-relaxed text-lg"> {course.fullDescription || course.description || course.shortDescription} </p> </div> {course.whatYouWillLearn && course.whatYouWillLearn.length > 0 && ( <div> <h3 className="text-2xl font-bold mb-4 flex items-center"> <Lightbulb className="w-6 h-6 mr-2 text-yellow-600" /> What you will learn </h3> <div className="grid md:grid-cols-2 gap-4"> {course.whatYouWillLearn.map((item, index) => ( <div key={index} className="flex items-start p-3 bg-green-50 dark:bg-gray-700 rounded-lg"> <CheckCircle className="w-5 h-5 text-green-600 mr-3 mt-0.5 flex-shrink-0" /> <span className="text-slate-700 dark:text-white">{item}</span> </div> ))} </div> </div> )} {course.requirements && course.requirements.length > 0 && ( <div> <h3 className="text-2xl font-bold mb-4 flex items-center"> <Target className="w-6 h-6 mr-2 text-red-600" /> Requirements </h3> <div className="bg-slate-50 dark:bg-gray-700 rounded-lg p-6"> <ul className="space-y-3"> {course.requirements.map((requirement, index) => ( <li key={index} className="flex items-start"> <span className="w-2 h-2 bg-slate-400 rounded-full mr-3 mt-2 flex-shrink-0" /> <span className="text-slate-600 dark:text-white">{requirement}</span> </li> ))} </ul> </div> </div> )} {course.targetAudience && course.targetAudience.length > 0 && ( <div> <h3 className="text-2xl font-bold mb-4 flex items-center"> <Users className="w-6 h-6 mr-2 text-purple-600" /> Who this course is for </h3> <div className="bg-purple-50 dark:bg-gray-700 rounded-lg p-6"> <ul className="space-y-3"> {course.targetAudience.map((audience, index) => ( <li key={index} className="flex items-start"> <UserCheck className="w-5 h-5 text-purple-600 mr-3 mt-0.5 flex-shrink-0" /> <span className="text-slate-700 dark:text-white">{audience}</span> </li> ))} </ul> </div> </div> )} {course.tags && course.tags.length > 0 && ( <div> <h3 className="text-2xl font-bold mb-4 flex items-center"> <Tag className="w-6 h-6 mr-2 text-green-600" /> Tags </h3> <div className="flex flex-wrap gap-2"> {course.tags.map((tag, index) => ( <Badge key={index} variant="outline" className="px-3 py-1"> {tag} </Badge> ))} </div> </div> )} </div> )} {activeTab === "instructor" && ( <div> <h3 className="text-2xl font-bold mb-6">Meet Your Instructor</h3> <div className="flex items-start space-x-6"> <div className="w-24 h-24 bg-gradient-to-br from-green-600 to-purple-600 rounded-full flex items-center justify-center text-white text-2xl font-bold flex-shrink-0"> {course.instructor.name.charAt(0)} </div> <div className="flex-1"> <h4 className="text-2xl font-semibold mb-2">{course.instructor.name}</h4> {course.instructor.email && <p className="text-slate-600 mb-4">{course.instructor.email}</p>} <div className="flex items-center space-x-6 text-sm text-slate-600 mb-4"> {course.instructor.rating && ( <div className="flex items-center"> <Star className="w-4 h-4 text-yellow-400 fill-current mr-1" /> {course.instructor.rating} rating </div> )} {course.instructor.students && ( <div className="flex items-center"> <Users className="w-4 h-4 mr-1" /> {course.instructor.students.toLocaleString()} students </div> )} {course.instructor.courses && ( <div className="flex items-center"> <BookOpen className="w-4 h-4 mr-1" /> {course.instructor.courses} courses </div> )} </div> {course.instructor.bio && ( <p className="text-slate-600 leading-relaxed">{course.instructor.bio}</p> )} </div> </div> </div> )} {/* {activeTab === "reviews" && ( <div> <h3 className="text-2xl font-bold mb-6">Student Reviews</h3> <div className="text-center py-12 text-slate-500"> <Star className="w-16 h-16 mx-auto mb-4 text-slate-300" /> <h4 className="text-lg font-semibold mb-2">No reviews yet</h4> <p>Reviews will be displayed here when available.</p> </div> </div> )} */} </CardContent> </Card> </div> {/* Sidebar */} <div className="lg:col-span-1"> <div className="space-y-6"> {/* Course Stats */} <Card> <CardContent className="p-6"> <h3 className="font-bold mb-4">Course Details</h3> <div className="space-y-3 text-sm"> <div className="flex justify-between"> <span className="text-slate-600">Status:</span> <Badge variant="outline">{course.status}</Badge> </div> <div className="flex justify-between"> <span className="text-slate-600">Level:</span> <span className="font-medium">{course.level}</span> </div> <div className="flex justify-between"> <span className="text-slate-600">Language:</span> <span className="font-medium">{course.language}</span> </div> <div className="flex justify-between"> <span className="text-slate-600">Certificate:</span> <span className="font-medium">{course.certificate?.available ? "Yes" : "No"}</span> </div> <div className="flex justify-between"> <span className="text-slate-600">Duration:</span> <span className="font-medium">{formatDuration(course.duration.total)}</span> </div> <div className="flex justify-between"> <span className="text-slate-600">Lectures:</span> <span className="font-medium">{totalLessons}</span> </div> </div> </CardContent> </Card> </div> </div> </div> {/* Recommended Courses Carousel */} {recommendedCourses.length > 0 && ( <div className="mt-16"> <div className="text-center mb-8"> <h2 className="text-3xl font-bold text-slate-800 mb-4">Related Courses</h2> <p className="text-slate-600">More courses in {course.category}</p> </div> <RecommendedCoursesCarousel courses={recommendedCourses} /> </div> )} </div> </div> )}// Recommended Courses Carousel Componentfunction RecommendedCoursesCarousel({ courses }: { courses: Course[] }) { const [currentIndex, setCurrentIndex] = useState(0) const [itemsPerView, setItemsPerView] = useState(4) useEffect(() => { const handleResize = () => { if (window.innerWidth < 640) { setItemsPerView(1) } else if (window.innerWidth < 768) { setItemsPerView(2) } else if (window.innerWidth < 1024) { setItemsPerView(3) } else { setItemsPerView(4) } } handleResize() window.addEventListener("resize", handleResize) return () => window.removeEventListener("resize", handleResize) }, []) const maxIndex = Math.max(0, courses.length - itemsPerView) const nextSlide = () => { setCurrentIndex((prev) => (prev >= maxIndex ? 0 : prev + 1)) } const prevSlide = () => { setCurrentIndex((prev) => (prev <= 0 ? maxIndex : prev - 1)) } const formatPrice = (price: number, currency: string) => { return new Intl.NumberFormat("en-US", { style: "currency", currency: currency, }).format(price) } const formatDuration = (minutes: number) => { const hours = Math.floor(minutes / 60) const mins = minutes % 60 if (hours > 0) { return `${hours}h ${mins}m` } return `${mins}m` } return ( <div className="relative"> {/* Navigation Buttons */} <div className="flex justify-between items-center mb-4"> <div className="flex space-x-2"> <Button variant="outline" size="sm" onClick={prevSlide} disabled={courses.length <= itemsPerView} className="h-10 w-10 p-0" > <ChevronLeft className="w-4 h-4" /> </Button> <Button variant="outline" size="sm" onClick={nextSlide} disabled={courses.length <= itemsPerView} className="h-10 w-10 p-0" > <ChevronRight className="w-4 h-4" /> </Button> </div> <div className="text-sm text-slate-500"> {currentIndex + 1} - {Math.min(currentIndex + itemsPerView, courses.length)} of {courses.length} </div> </div> {/* Carousel Container */} <div className="overflow-hidden"> <div className="flex transition-transform duration-300 ease-in-out" style={{ transform: `translateX(-${currentIndex * (100 / itemsPerView)}%)`, }} > {courses.map((course) => ( <div key={course._id} className="flex-shrink-0 px-2" style={{ width: `${100 / itemsPerView}%` }}> <Card className="overflow-hidden hover:shadow-lg transition-all duration-300 group h-full"> <div className="relative"> <Image src={course.thumbnail || "/placeholder.svg"} alt={course.title} width={300} height={180} className="w-full h-40 object-cover group-hover:scale-105 transition-transform duration-300" /> <div className="absolute top-2 right-2"> <Badge variant="outline" className="bg-white/90 text-slate-700 text-xs"> {course.category} </Badge> </div> {course.featured && ( <div className="absolute top-2 left-2"> <Badge className="bg-yellow-600 text-xs">Featured</Badge> </div> )} </div> <CardContent className="p-4"> <h4 className="font-bold text-slate-800 mb-2 line-clamp-2 group-hover:text-green-600 transition-colors text-sm"> {course.title} </h4> <p className="text-slate-600 text-xs mb-3 line-clamp-2">{course.shortDescription}</p> <div className="flex items-center justify-between text-xs text-slate-500 mb-3"> <div className="flex items-center"> <Clock className="w-3 h-3 mr-1" /> {formatDuration(course.duration.total)} </div> <div className="flex items-center"> <Users className="w-3 h-3 mr-1" /> {course.enrollments} </div> </div> <div className="flex items-center justify-between mb-3"> <div className="text-xs text-slate-600">by {course.instructor.name}</div> <div className="text-right"> {course.isFree ? ( <span className="text-green-600 font-bold text-xs">Free</span> ) : ( <span className="text-slate-800 font-bold text-xs"> {formatPrice(course.price.current, course.price.currency)} </span> )} </div> </div> <Link href={`/courses/${course._id}`} className="block"> <Button size="sm" className="w-full bg-gradient-to-r from-green-600 to-purple-600 hover:from-green-700 hover:to-purple-700 text-xs" > View Details </Button> </Link> </CardContent> </Card> </div> ))} </div> </div> {/* Dots Indicator */} {courses.length > itemsPerView && ( <div className="flex justify-center mt-4 space-x-2"> {Array.from({ length: maxIndex + 1 }).map((_, index) => ( <button key={index} onClick={() => setCurrentIndex(index)} className={`w-2 h-2 rounded-full transition-colors ${ index === currentIndex ? "bg-green-600" : "bg-slate-300" }`} /> ))} </div> )} </div> )}// Loading Componentfunction CourseDetailsLoading() { return ( <div className="min-h-screen bg-gray-50"> {/* Header Skeleton */} <div className="bg-slate-900 text-white"> <div className="container mx-auto px-4 py-8"> <div className="grid lg:grid-cols-3 gap-8"> <div className="lg:col-span-2"> <div className="space-y-4"> <div className="flex space-x-2"> <div className="h-6 w-20 bg-slate-700 rounded animate-pulse" /> <div className="h-6 w-24 bg-slate-700 rounded animate-pulse" /> </div> <div className="h-10 w-3/4 bg-slate-700 rounded animate-pulse" /> <div className="h-6 w-full bg-slate-700 rounded animate-pulse" /> <div className="flex space-x-4"> <div className="h-4 w-20 bg-slate-700 rounded animate-pulse" /> <div className="h-4 w-24 bg-slate-700 rounded animate-pulse" /> <div className="h-4 w-16 bg-slate-700 rounded animate-pulse" /> </div> </div> </div> <div className="lg:col-span-1"> <Card> <div className="w-full h-48 bg-slate-200 animate-pulse rounded-t-lg" /> <CardContent className="p-6"> <div className="space-y-4"> <div className="h-6 w-32 bg-slate-200 rounded animate-pulse mx-auto" /> <div className="h-4 w-full bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-3/4 bg-slate-200 rounded animate-pulse" /> </div> </CardContent> </Card> </div> </div> </div> </div> {/* Content Skeleton */} <div className="container mx-auto px-4 py-8"> <div className="grid lg:grid-cols-4 gap-8"> <div className="lg:col-span-3"> <div className="space-y-6"> <div className="flex space-x-1 bg-white p-1 rounded-lg"> {[1, 2, 3, 4].map((i) => ( <div key={i} className="flex-1 h-10 bg-slate-200 rounded animate-pulse" /> ))} </div> <Card> <CardContent className="p-8"> <div className="space-y-4"> <div className="h-6 w-48 bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-full bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-3/4 bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-5/6 bg-slate-200 rounded animate-pulse" /> </div> </CardContent> </Card> </div> </div> <div className="lg:col-span-1"> <Card> <CardContent className="p-6"> <div className="space-y-3"> <div className="h-6 w-32 bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-full bg-slate-200 rounded animate-pulse" /> <div className="h-4 w-2/3 bg-slate-200 rounded animate-pulse" /> </div> </CardContent> </Card> </div> </div> </div> </div> )}import { type NextRequest, NextResponse } from "next/server"import { v2 as cloudinary } from "cloudinary"import Course from "@/models/courseModel"import { connect } from "@/dbConfig/dbConfig"// Cloudinary configcloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET,})// GET - Fetch all coursesexport async function GET(request: NextRequest) { try { await connect() const { searchParams } = new URL(request.url) const page = Number.parseInt(searchParams.get("page") || "1") const limit = Number.parseInt(searchParams.get("limit") || "10") const status = searchParams.get("status") const category = searchParams.get("category") const level = searchParams.get("level") const search = searchParams.get("search") const featured = searchParams.get("featured") const isFree = searchParams.get("isFree") const sortBy = searchParams.get("sortBy") || "createdAt" const sortOrder = searchParams.get("sortOrder") || "desc" const skip = (page - 1) * limit // Build query const query: any = {} if (status && status !== "all") { query.status = status } if (category && category !== "all") { query.category = category } if (level && level !== "all") { query.level = level } if (featured === "true") { query.featured = true } if (isFree === "true") { query.isFree = true } else if (isFree === "false") { query.isFree = false } if (search) { query.$or = [ { title: { $regex: search, $options: "i" } }, { shortDescription: { $regex: search, $options: "i" } }, { "instructor.name": { $regex: search, $options: "i" } }, { tags: { $in: [new RegExp(search, "i")] } }, ] } // Build sort object const sort: any = {} sort[sortBy] = sortOrder === "desc" ? -1 : 1 const courses = await Course.find(query).sort(sort).skip(skip).limit(limit) const total = await Course.countDocuments(query) return NextResponse.json({ courses, pagination: { page, limit, total, pages: Math.ceil(total / limit), }, }) } catch (error) { console.error("Error fetching courses:", error) return NextResponse.json({ error: "Failed to fetch courses" }, { status: 500 }) }}// POST - Create new course// POST - Create new courseexport async function POST(request: NextRequest) { try { await connect(); const formData = await request.formData(); const title = formData.get("title") as string; const shortDescription = formData.get("shortDescription") as string; const description = formData.get("description") as string; const category = formData.get("category") as string; const subcategory = formData.get("subcategory") as string; const level = formData.get("level") as string; const language = formData.get("language") as string; const originalPrice = Number.parseFloat(formData.get("originalPrice") as string); const currency = formData.get("currency") as string; const instructorName = formData.get("instructorName") as string; const instructorEmail = formData.get("instructorEmail") as string; const instructorBio = formData.get("instructorBio") as string; const requirements = formData.get("requirements") as string; const whatYouWillLearn = formData.get("whatYouWillLearn") as string; const targetAudience = formData.get("targetAudience") as string; const tags = formData.get("tags") as string; const status = formData.get("status") as string; const featured = formData.get("featured") === "true"; const thumbnailFile = formData.get("thumbnail") as File; const previewVideoFile = formData.get("previewVideo") as File; if ( !title || !shortDescription || !description || !category || !level || !instructorName || !instructorEmail || !thumbnailFile ) { return NextResponse.json( { error: "Title, descriptions, category, level, instructor details, and thumbnail are required.", }, { status: 400 }, ); } // Upload thumbnail to Cloudinary const thumbnailBuffer = Buffer.from(await thumbnailFile.arrayBuffer()); const thumbnailUpload: any = await new Promise((resolve, reject) => { cloudinary.uploader .upload_stream( { resource_type: "image", folder: "courses/thumbnails", }, (error, result) => { if (error) reject(error); else resolve(result); }, ) .end(thumbnailBuffer); }); // Upload preview video if provided let previewVideoUrl = ""; if (previewVideoFile && previewVideoFile.size > 0) { const videoBuffer = Buffer.from(await previewVideoFile.arrayBuffer()); const videoUpload: any = await new Promise((resolve, reject) => { cloudinary.uploader .upload_stream( { resource_type: "video", folder: "courses/previews", }, (error, result) => { if (error) reject(error); else resolve(result); }, ) .end(videoBuffer); }); previewVideoUrl = videoUpload.secure_url; } // Manually generate slug from title const slug = title .toLowerCase() .replace(/[^a-zA-Z0-9 ]/g, "") .replace(/\s+/g, "-") .trim(); // Build course object const course = new Course({ title, slug, // Include slug manually shortDescription, description, thumbnail: thumbnailUpload.secure_url, previewVideo: previewVideoUrl, category, subcategory: subcategory || "", level, language: language || "English", price: { original: originalPrice || 0, current: originalPrice || 0, currency: currency || "USD", }, instructor: { name: instructorName, email: instructorEmail, bio: instructorBio || "", }, requirements: requirements ? requirements.split("\n").filter((req) => req.trim()) : [], whatYouWillLearn: whatYouWillLearn ? whatYouWillLearn.split("\n").filter((item) => item.trim()) : [], targetAudience: targetAudience ? targetAudience.split("\n").filter((item) => item.trim()) : [], tags: tags ? tags .split(",") .map((tag) => tag.trim()) .filter((tag) => tag) : [], status: status || "draft", featured, modules: [], }); // Save the course (ensures all pre-save hooks are triggered) await course.save(); return NextResponse.json( { message: "Course created successfully", data: course, }, { status: 201 }, ); } catch (error: any) { console.error("Course creation error:", error); return NextResponse.json( { error: error.message || "Failed to create course", }, { status: 500 }, ); }}import { type NextRequest, NextResponse } from "next/server";import { v2 as cloudinary } from "cloudinary";import Course from "@/models/courseModel";import { connect } from "@/dbConfig/dbConfig";// Cloudinary configcloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET,});// GET - Fetch single courseexport async function GET(request: NextRequest, context: { params: { id: string } }) { try { await connect(); const awaitedParams = await context.params; const { id } = awaitedParams; const course = await Course.findById(id); if (!course) { return NextResponse.json({ error: "Course not found" }, { status: 404 }); } return NextResponse.json(course); } catch (error) { console.error("Error fetching course:", error); return NextResponse.json({ error: "Failed to fetch course" }, { status: 500 }); }}// PUT - Update courseexport async function PUT(request: NextRequest, context: { params: { id: string } }) { try { await connect(); const awaitedParams = await context.params; const { id } = awaitedParams; const body = await request.json(); const updatedCourse = await Course.findByIdAndUpdate( id, { ...body, lastUpdated: new Date(), }, { new: true, runValidators: true } ); if (!updatedCourse) { return NextResponse.json({ error: "Course not found" }, { status: 404 }); } return NextResponse.json({ message: "Course updated successfully", data: updatedCourse, }); } catch (error: any) { console.error("Error updating course:", error); return NextResponse.json( { error: error.message || "Failed to update course", }, { status: 500 } ); }}// DELETE - Delete courseexport async function DELETE(request: NextRequest, context: { params: { id: string } }) { try { await connect(); const awaitedParams = await context.params; const { id } = awaitedParams; const course = await Course.findById(id); if (!course) { return NextResponse.json({ error: "Course not found" }, { status: 404 }); } const deletePromises = []; if (course.thumbnail) { const publicId = course.thumbnail.split("/").pop()?.split(".")[0]; if (publicId) { deletePromises.push(cloudinary.uploader.destroy(`courses/thumbnails/${publicId}`)); } } if (course.previewVideo) { const publicId = course.previewVideo.split("/").pop()?.split(".")[0]; if (publicId) { deletePromises.push( cloudinary.uploader.destroy(`courses/previews/${publicId}`, { resource_type: "video" }) ); } } course.modules.forEach((module: { lessons: { videoUrl?: string }[] }) => { module.lessons.forEach((lesson: { videoUrl?: string }) => { if (lesson.videoUrl) { const publicId = lesson.videoUrl.split("/").pop()?.split(".")[0]; if (publicId) { deletePromises.push( cloudinary.uploader.destroy(`courses/lessons/${publicId}`, { resource_type: "video" }) ); } } }); }); try { await Promise.all(deletePromises); } catch (cloudinaryError) { console.error("Error deleting files from Cloudinary:", cloudinaryError); } await Course.findByIdAndDelete(id); return NextResponse.json({ message: "Course deleted successfully" }); } catch (error: any) { console.error("Error deleting course:", error); return NextResponse.json( { error: error.message || "Failed to delete course", }, { status: 500 } ); }}import { NextResponse } from "next/server"import Course from "@/models/courseModel"import { connect } from "@/dbConfig/dbConfig"export async function GET() { try { await connect() const totalCourses = await Course.countDocuments() const publishedCourses = await Course.countDocuments({ status: "published" }) const draftCourses = await Course.countDocuments({ status: "draft" }) const featuredCourses = await Course.countDocuments({ featured: true }) const freeCourses = await Course.countDocuments({ isFree: true }) const totalEnrollments = await Course.aggregate([{ $group: { _id: null, total: { $sum: "$enrollments" } } }]) const averageRating = await Course.aggregate([ { $match: { "rating.count": { $gt: 0 } } }, { $group: { _id: null, avgRating: { $avg: "$rating.average" } } }, ]) const categoryStats = await Course.aggregate([ { $group: { _id: "$category", count: { $sum: 1 } } }, { $sort: { count: -1 } }, ]) const levelStats = await Course.aggregate([ { $group: { _id: "$level", count: { $sum: 1 } } }, { $sort: { count: -1 } }, ]) const revenueStats = await Course.aggregate([ { $match: { isFree: false } }, { $group: { _id: null, totalRevenue: { $sum: { $multiply: ["$price.current", "$enrollments"] } }, averagePrice: { $avg: "$price.current" }, }, }, ]) return NextResponse.json({ totalCourses, publishedCourses, draftCourses, featuredCourses, freeCourses, totalEnrollments: totalEnrollments[0]?.total || 0, averageRating: averageRating[0]?.avgRating || 0, categoryStats, levelStats, revenueStats: revenueStats[0] || { totalRevenue: 0, averagePrice: 0 }, }) } catch (error) { console.error("Error fetching course stats:", error) return NextResponse.json({ error: "Failed to fetch course stats" }, { status: 500 }) }}now create search functiion for course form title name, language categorire and other details like: _id: string title: string slug: string shortDescription: string fullDescription?: string description?: string thumbnail: string previewVideo?: string category: string subcategory?: string level: string language: string difficulty?: string status: stringand then impement the navebar to search the courses form here?const coursesDropdownItems = [ { title: "IELTS Preparation", href: "/courses/ielts", description: "Comprehensive IELTS training program" }, { title: "PTE Academic", href: "/courses/pte", description: "Complete PTE Academic preparation course" }, { title: "TOEFL Training", href: "/courses/toefl", description: "TOEFL iBT preparation and practice" }, { title: "General English", href: "/courses/general-english", description: "Improve your overall English skills" }, { title: "Business English", href: "/courses/business-english", description: "Professional English for workplace" }, { title: "Academic Writing", href: "/courses/academic-writing", description: "Master academic writing techniques" }, { title: "Speaking & Pronunciation", href: "/courses/speaking", description: "Enhance your speaking confidence" }, { title: "Online Courses", href: "/courses/online", description: "Flexible online learning options" }, ]
To implement the search functionality for courses, I will modify the Navbar
component to include a search input and update the CoursesPage
component to read the search query from the URL and apply it to the course filtering. I will also provide a basic CoursesFilters
component to demonstrate how the search input would be handled within the filters sidebar.
Now, when you type a search query in the navbar's search bar and press Enter, it will navigate to the /courses
page, and the CoursesPage
component will automatically fetch and display courses filtered by your search term. The CoursesFilters
component will also reflect the active search query.
You can install this code by clicking the "Download Code" button at the top right of the Block view.
I have a list of popular courses displayed as buttons. Each course has a title, description, and a color for styling. Instead of linking directly to a static course page URL, I want to:When the user clicks on a course button, close the dropdown/menu if it’s open.Redirect the user to a search page (e.g., /courses/search) with the course title passed as a query parameter named query.This search page will then use the query parameter to search and display relevant courses matching that title.The button should visually indicate if the current page matches the course's original href (active state).Navigation should happen programmatically via Next.js router (using router.push), not by wrapping buttons in <Link>.Please provide a React component that implements this behavior with proper styles and clean code."use client"import React from "react"import { useEffect, useState } from "react"import Link from "next/link"import { usePathname, useRouter } from "next/navigation"import axios from "axios"import toast from "react-hot-toast"import { DarkModeToggle } from "./DarkModeToggle"import { Button } from "@/components/ui/button"import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,} from "@/components/ui/dropdown-menu"import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"import { Menu, User, Settings, LogOut, Home, Info, Mail, Zap, GalleryHorizontal, MonitorPlayIcon as TvMinimalPlay, Search, X,} from "lucide-react"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"import { Input } from "@/components/ui/input" // Import Input componentimport Image from "next/image"import logo from "@/images/logo.png" // Adjust the path as necessaryconst ListItem = React.forwardRef<React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>( ({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <Link ref={ref} className={`block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground ${className}`} href={props.href ?? "#"} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground">{children}</p> </Link> </NavigationMenuLink> </li> ) },)ListItem.displayName = "ListItem"const Navbar = () => { const router = useRouter() const [isOpen, setIsOpen] = useState(false) const [user, setUser] = useState<any>(null) const [loading, setLoading] = useState(true) const [searchQuery, setSearchQuery] = useState("") // State for search query const navigationItems = [ { name: "Home", href: "/", icon: Home }, { name: "Contact", href: "/contact", icon: Mail }, { name: "Blog", href: "/blog", icon: TvMinimalPlay }, ] const universityDropdownItems = [ { title: "Programs", href: "/university/programs", description: "Explore our degree programs and courses" }, { title: "Admissions", href: "/university/admissions", description: "Application process and requirements" }, { title: "Campus Life", href: "/university/campus", description: "Student life and campus facilities" }, { title: "Faculty", href: "/university/faculty", description: "Meet our experienced faculty members" }, { title: "Research", href: "/university/research", description: "Research opportunities and projects" }, { title: "Alumni", href: "/university/alumni", description: "Connect with our alumni network" }, ] const aboutDropdownItems = [ { title: "Our Story", href: "/about/story", description: "Learn about our journey and mission" }, { title: "Why Choose Us", href: "/about/why-choose-us", description: "Discover what makes us different" }, { title: "Our Team", href: "/about/team", description: "Meet our dedicated professionals" }, { title: "Accreditation", href: "/about/accreditation", description: "Our certifications and partnerships" }, { title: "Values", href: "/about/values", description: "Our core principles and beliefs" }, { title: "Gallery", href: "/gallery", description: "Our milestones and achievements" }, ] const coursesDropdownItems = [ { title: "IELTS Preparation", href: "/courses/ielts", description: "Comprehensive IELTS training program" }, { title: "PTE Academic", href: "/courses/pte", description: "Complete PTE Academic preparation course" }, { title: "TOEFL Training", href: "/courses/toefl", description: "TOEFL iBT preparation and practice" }, { title: "General English", href: "/courses/general-english", description: "Improve your overall English skills" }, { title: "Business English", href: "/courses/business-english", description: "Professional English for workplace" }, { title: "Academic Writing", href: "/courses/academic-writing", description: "Master academic writing techniques" }, { title: "Speaking & Pronunciation", href: "/courses/speaking", description: "Enhance your speaking confidence" }, { title: "Online Courses", href: "/courses/online", description: "Flexible online learning options" }, ] const filterOptions = { categories: [ { title: "Test Preparation", value: "Test Preparation" }, { title: "English Skills", value: "English Skills" }, { title: "Specialized Programs", value: "Specialized Programs" }, ], levels: [ { title: "Beginner", value: "Beginner" }, { title: "Intermediate", value: "Intermediate" }, { title: "Advanced", value: "Advanced" }, ], languages: [ { title: "English", value: "English" }, { title: "Spanish", value: "Spanish" }, { title: "French", value: "French" }, ], } // Fetch user data on component mount useEffect(() => { const fetchUserData = async () => { try { setLoading(true) const response = await axios.get("/api/users/me", { withCredentials: true, }) if (response.data && response.data.data) { setUser(response.data.data) } else { setUser(null) } } catch (error: any) { console.error("Failed to fetch user data:", error.message) setUser(null) } finally { setLoading(false) } } fetchUserData() }, []) const handleLogout = async () => { try { await axios.get("/api/users/logout", { withCredentials: true }) setUser(null) // Clear user state toast.success("Logout successful") router.push("/login") } catch (error: any) { console.error("Logout failed:", error.message) toast.error(error.response?.data?.error || "Logout failed") } } const handleSearch = (e: React.KeyboardEvent<HTMLInputElement>) => { if (e.key === "Enter" && searchQuery.trim()) { router.push(`/courses?search=${encodeURIComponent(searchQuery.trim())}`) setIsOpen(false) // Close mobile menu after search } } const getInitials = (name: string) => { return ( name ?.split(" ") .map((n) => n[0]) .join("") .toUpperCase() || "U" ) } const pathname = usePathname() if (pathname.startsWith("/admin")) return null return ( <nav className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> <div className="container mx-auto px-4"> <div className="flex h-16 items-center justify-between"> {/* Logo */} <div className="flex items-center space-x-2"> <Link href="/" className="flex items-center space-x-2 group"> <div className="relative"> <div className="flex items-center justify-center bg-white rounded-lg p-1 shadow-sm"> <Image width={200} height={24} src={logo || "/placeholder.svg"} alt="Logo" className="object-contain h-6 w-auto sm:h-8 md:h-10 lg:h-12 max-w-[120px] sm:max-w-[140px] md:max-w-[160px] lg:max-w-[200px]" priority /> </div> <div className="absolute -inset-1 rounded-lg blur opacity-20 group-hover:opacity-30 transition-opacity duration-300"></div> </div> </Link> </div> {/* Desktop Navigation */} <div className="hidden md:flex items-center space-x-1"> <NavigationMenu className="relative z-[100] max-w-max"> <NavigationMenuList className="flex-wrap gap-1"> {navigationItems.map((item) => { const IconComponent = item.icon const isActive = pathname === item.href return ( <NavigationMenuItem key={item.name}> <Link href={item.href} legacyBehavior passHref> <NavigationMenuLink className={navigationMenuTriggerStyle()}> <div className={`flex items-center space-x-2 ${ isActive ? "text-primary" : "text-muted-foreground" }`} > <IconComponent className="h-4 w-4" /> <span>{item.name}</span> </div> </NavigationMenuLink> </Link> </NavigationMenuItem> ) })} {/* Courses Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <GalleryHorizontal className="h-4 w-4" /> <span>Courses</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> {/* Featured Section */} <li className="md:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-center rounded-lg bg-gradient-to-br from-green-500/10 to-green-600/10 p-4 sm:p-6 lg:p-8 no-underline outline-none focus:shadow-md border border-green-200/50 min-h-[160px] sm:min-h-[200px]" href="/courses" > <div className="flex items-center space-x-3 sm:space-x-4 mb-4 sm:mb-6"> <div className="h-12 w-12 sm:h-16 sm:w-16 rounded-xl bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center shadow-lg"> <GalleryHorizontal className="h-6 w-6 sm:h-8 sm:w-8 text-white" /> </div> <div> <div className="text-xl sm:text-2xl lg:text-3xl font-bold">Our Courses</div> <div className="text-xs sm:text-sm text-muted-foreground">Expert Training Programs</div> </div> </div> <p className="text-sm sm:text-base leading-relaxed text-muted-foreground mb-3 sm:mb-4"> Master English proficiency with our comprehensive courses including IELTS, PTE, TOEFL preparation, and specialized programs designed by expert instructors. </p> <div className="inline-flex items-center text-xs sm:text-sm font-medium text-green-600 hover:text-green-700"> Explore All Courses → </div> </Link> </NavigationMenuLink> </li> {/* Test Preparation */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Test Preparation </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/ielts" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">IELTS Preparation</div> <div className="text-xs text-muted-foreground">Complete IELTS training</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/pte" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">PTE Academic</div> <div className="text-xs text-muted-foreground">PTE preparation course</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/toefl" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">TOEFL Training</div> <div className="text-xs text-muted-foreground">TOEFL iBT preparation</div> </Link> </NavigationMenuLink> </div> </li> {/* English Skills */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> English Skills </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/general-english" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">General English</div> <div className="text-xs text-muted-foreground">Overall English improvement</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/business-english" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Business English</div> <div className="text-xs text-muted-foreground">Professional workplace English</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/speaking" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Speaking & Pronunciation</div> <div className="text-xs text-muted-foreground">Improve speaking confidence</div> </Link> </NavigationMenuLink> </div> </li> {/* Specialized Programs */} <li className="space-y-3 sm:space-y-4 hidden lg:block"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Specialized Programs </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/courses/academic-writing" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Academic Writing</div> <div className="text-xs text-muted-foreground">Master academic writing</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/online" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Online Courses</div> <div className="text-xs text-muted-foreground">Flexible online learning</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/courses/private-tutoring" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Private Tutoring</div> <div className="text-xs text-muted-foreground">One-on-one sessions</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> {/* University Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <TvMinimalPlay className="h-4 w-4" /> <span>University</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> {/* Featured Section */} <li className="sm:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-center rounded-lg bg-gradient-to-br from-brand-500/10 to-brand-600/10 p-4 sm:p-6 lg:p-8 no-underline outline-none focus:shadow-md border border-brand-200/50 min-h-[160px] sm:min-h-[200px]" href="/university" > <div className="flex items-center space-x-3 sm:space-x-4 mb-4 sm:mb-6"> <div className="h-12 w-12 sm:h-16 sm:w-16 rounded-xl bg-gradient-to-br from-brand-500 to-brand-600 flex items-center justify-center shadow-lg"> <TvMinimalPlay className="h-6 w-6 sm:h-8 sm:w-8 text-white" /> </div> <div> <div className="text-xl sm:text-2xl lg:text-3xl font-bold">University</div> <div className="text-xs sm:text-sm text-muted-foreground">Academic Excellence</div> </div> </div> <p className="text-sm sm:text-base leading-relaxed text-muted-foreground mb-3 sm:mb-4"> Discover our comprehensive educational programs, world-class faculty, and cutting-edge research opportunities that prepare students for success in their chosen fields. </p> <div className="inline-flex items-center text-xs sm:text-sm font-medium text-brand-600 hover:text-brand-700"> Explore University → </div> </Link> </NavigationMenuLink> </li> {/* Academic Section */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Academic </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/programs" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Programs</div> <div className="text-xs text-muted-foreground">Degree programs & courses</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/admissions" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Admissions</div> <div className="text-xs text-muted-foreground">Application process</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/faculty" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Faculty</div> <div className="text-xs text-muted-foreground">Meet our professors</div> </Link> </NavigationMenuLink> </div> </li> {/* Campus Life Section */} <li className="space-y-3 sm:space-y-4"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Campus Life </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/campus" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Campus</div> <div className="text-xs text-muted-foreground">Facilities & student life</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/research" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Research</div> <div className="text-xs text-muted-foreground">Research opportunities</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/alumni" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Alumni</div> <div className="text-xs text-muted-foreground">Alumni network</div> </Link> </NavigationMenuLink> </div> </li> {/* Additional Section for larger screens */} <li className="space-y-3 sm:space-y-4 hidden lg:block"> <h4 className="text-xs sm:text-sm font-semibold text-foreground mb-3 sm:mb-4 pb-2 border-b"> Resources </h4> <div className="space-y-2 sm:space-y-3"> <NavigationMenuLink asChild> <Link href="/university/library" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Library</div> <div className="text-xs text-muted-foreground">Digital & physical resources</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/support" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Student Support</div> <div className="text-xs text-muted-foreground">Academic & personal support</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/university/events" className="block rounded-lg p-3 sm:p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-xs sm:text-sm mb-1">Events</div> <div className="text-xs text-muted-foreground">Campus events & activities</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> {/* About Dropdown */} <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <Info className="h-4 w-4" /> <span>About</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[900px]"> <li className="md:col-span-2 lg:col-span-2 xl:col-span-3"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-between rounded-lg bg-gradient-to-br from-blue-500/10 to-blue-600/10 p-8 no-underline outline-none focus:shadow-md border border-blue-200/50 min-h-[200px]" href="/about" > <div className="flex items-center space-x-4 mb-6"> <div className="h-16 w-16 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center shadow-lg"> <Info className="h-8 w-8 text-white" /> </div> <div> <div className="text-3xl font-bold">About Us</div> <div className="text-sm text-muted-foreground">Our Story & Mission</div> </div> </div> <p className="text-base leading-relaxed text-muted-foreground mb-4"> Discover our journey, values, and the passionate team behind our success. Learn why thousands choose us for their educational and professional growth. </p> <div className="inline-flex items-center text-sm font-medium text-blue-600 hover:text-blue-700"> Learn More About Us → </div> </Link> </NavigationMenuLink> </li> {/* Our Story & Mission */} <li className="space-y-4"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Our Story</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/story" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Journey</div> <div className="text-xs text-muted-foreground">How we started & evolved</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/values" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Values</div> <div className="text-xs text-muted-foreground">Core principles & beliefs</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/gallery" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Gallery</div> <div className="text-xs text-muted-foreground">Milestones & achievements</div> </Link> </NavigationMenuLink> </div> </li> {/* Why Choose Us */} <li className="space-y-4"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Why Choose Us</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/why-choose-us" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Our Advantages</div> <div className="text-xs text-muted-foreground">What sets us apart</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/accreditation" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Accreditation</div> <div className="text-xs text-muted-foreground">Certifications & partnerships</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/testimonials" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Testimonials</div> <div className="text-xs text-muted-foreground">What our clients say</div> </Link> </NavigationMenuLink> </div> </li> {/* Team & Leadership */} <li className="space-y-4 hidden xl:block"> <h4 className="text-sm font-semibold text-foreground mb-4 pb-2 border-b">Our Team</h4> <div className="space-y-3"> <NavigationMenuLink asChild> <Link href="/about/team" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Meet the Team</div> <div className="text-xs text-muted-foreground">Our dedicated professionals</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/leadership" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Leadership</div> <div className="text-xs text-muted-foreground">Executive team & board</div> </Link> </NavigationMenuLink> <NavigationMenuLink asChild> <Link href="/about/careers" className="block rounded-lg p-4 hover:bg-accent hover:text-accent-foreground transition-colors border border-transparent hover:border-border" > <div className="font-medium text-sm mb-1">Careers</div> <div className="text-xs text-muted-foreground">Join our team</div> </Link> </NavigationMenuLink> </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger className="flex items-center space-x-2"> <Zap className="h-4 w-4" /> <span>Browse</span> </NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[700px]"> <li className="md:col-span-2"> <NavigationMenuLink asChild> <Link className="flex h-full w-full select-none flex-col justify-end rounded-lg bg-gradient-to-br from-yellow-500/10 to-yellow-600/10 p-6 no-underline outline-none focus:shadow-md border border-yellow-200/50 min-h-[120px]" href="/courses" > <div className="mb-2 mt-4 text-lg font-medium">Explore All Courses</div> <p className="text-sm leading-tight text-muted-foreground"> Find the perfect course for your learning journey. </p> </Link> </NavigationMenuLink> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Categories</h4> <div className="space-y-2"> {filterOptions.categories.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?category=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Levels</h4> <div className="space-y-2"> {filterOptions.levels.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?level=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> <li className="space-y-3"> <h4 className="text-sm font-semibold text-foreground mb-2 pb-1 border-b">Languages</h4> <div className="space-y-2"> {filterOptions.languages.map((item) => ( <NavigationMenuLink asChild key={item.title}> <Link href={`/courses?language=${encodeURIComponent(item.value)}`} className="block rounded-md p-2 hover:bg-accent hover:text-accent-foreground transition-colors" > <div className="text-sm font-medium leading-none">{item.title}</div> </Link> </NavigationMenuLink> ))} </div> </li> </ul> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> {/* Right Side - Desktop */} <div className="hidden md:flex items-center space-x-4"> {/* Search Input for Desktop */} <div className="relative"> <Input type="text" placeholder="Search courses..." className="pl-8 pr-2 py-2 rounded-md w-48" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} onKeyDown={handleSearch} /> <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> </div> <DarkModeToggle /> {loading ? ( // Loading state <div className="h-10 w-10 rounded-full bg-muted animate-pulse"></div> ) : user ? ( // User is logged in - show user dropdown <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" className="relative h-10 w-10 rounded-full"> <Avatar className="h-10 w-10 border-2 border-primary/20 hover:border-primary/40 transition-colors"> <AvatarImage src={user.avatar || "/placeholder.svg?height=40&width=40"} alt={user.username || user.name} /> <AvatarFallback className="bg-gradient-to-br from-brand-500 to-brand-600 text-white font-semibold"> {getInitials(user.username || user.name)} </AvatarFallback> </Avatar> </Button> </DropdownMenuTrigger> <DropdownMenuContent className="w-56" align="end" forceMount> <DropdownMenuLabel className="font-normal"> <div className="flex flex-col space-y-1"> <p className="text-sm font-medium leading-none">{user.username || user.name}</p> <p className="text-xs leading-none text-muted-foreground">{user.email}</p> </div> </DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem onClick={() => router.push("/profile")} className="cursor-pointer"> <User className="mr-2 h-4 w-4" /> <span>Profile</span> </DropdownMenuItem> <DropdownMenuItem onClick={() => router.push("/settings")} className="cursor-pointer"> <Settings className="mr-2 h-4 w-4" /> <span>Settings</span> </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuItem onClick={handleLogout} className="text-destructive cursor-pointer"> <LogOut className="mr-2 h-4 w-4" /> <span>Log out</span> </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ) : ( // User is not logged in - show login/register buttons <div className="flex items-center space-x-2"> <Button variant="ghost" onClick={() => router.push("/login")} className="text-sm font-medium"> Login </Button> <Button onClick={() => router.push("/signup")} className="text-sm font-medium bg-gradient-to-r from-brand-500 to-brand-600 hover:from-brand-600 hover:to-brand-700 text-white shadow-lg hover:shadow-brand-500/25 transition-all duration-300" > Register </Button> </div> )} </div> {/* Mobile Menu Button */} <div className="md:hidden flex items-center space-x-2"> <DarkModeToggle /> <Sheet open={isOpen} onOpenChange={setIsOpen}> <SheetTrigger asChild> <Button variant="ghost" size="icon" className="md:hidden h-10 w-10"> <Menu className="h-5 w-5" /> <span className="sr-only">Toggle menu</span> </Button> </SheetTrigger> <SheetContent side="right" className="w-full sm:w-[400px] p-0 overflow-y-auto"> <div className="flex flex-col h-full"> {/* Mobile Header */} <div className="flex items-center justify-between p-4 border-b"> <Link href="/" className="flex items-center space-x-2 group" onClick={() => setIsOpen(false)}> <div className="relative"> <div className="flex items-center justify-center bg-white rounded-lg p-1 shadow-sm"> <Image width={250} height={30} src={logo || "/placeholder.svg"} alt="Logo" className="object-contain h-6 w-auto sm:h-8 md:h-10 lg:h-12 max-w-[120px] sm:max-w-[140px] md:max-w-[160px] lg:max-w-[200px]" priority /> </div> <div className="absolute -inset-1 rounded-lg blur opacity-20 group-hover:opacity-30 transition-opacity duration-300"></div> </div> </Link> <Button variant="ghost" size="icon" onClick={() => setIsOpen(false)}> <X className="h-5 w-5" /> <span className="sr-only">Close menu</span> </Button> </div> {/* Mobile Content */} <div className="flex-1 px-4 py-4 space-y-6"> {/* Search Input for Mobile */} <div className="relative mb-4"> <Input type="text" placeholder="Search courses..." className="pl-8 pr-2 py-2 rounded-md w-full" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} onKeyDown={handleSearch} /> <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> </div> {/* User Section - Mobile (only show if user is logged in) */} {user && ( <div className="flex items-center space-x-3 p-4 rounded-xl bg-gradient-to-r from-brand-50 to-brand-100 border border-brand-200/50"> <Avatar className="h-12 w-12 border-2 border-brand-200"> <AvatarImage src={user.avatar || "/placeholder.svg?height=48&width=48"} alt={user.username || user.name} /> <AvatarFallback className="bg-gradient-to-br from-brand-500 to-brand-600 text-white font-semibold"> {getInitials(user.username || user.name)} </AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-semibold text-brand-900 truncate">{user.username || user.name}</p> <p className="text-xs text-brand-600 truncate">{user.email}</p> </div> </div> )} {/* Quick Navigation - Mobile */} <div className="space-y-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider px-2"> Quick Navigation </h3> <div className="grid grid-cols-2 gap-2"> {navigationItems.map((item) => { const IconComponent = item.icon const isActive = pathname === item.href return ( <Link key={item.name} href={item.href}> <Button variant="ghost" className={`w-full h-16 flex flex-col items-center justify-center space-y-1 rounded-xl border-2 transition-all duration-200 ${ isActive ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <IconComponent className="h-5 w-5" /> <span className="text-xs font-medium">{item.name}</span> </Button> </Link> ) })} </div> </div> {/* Courses Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> Our Courses </h3> <Link href="/courses"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> {/* Featured Courses */} <div className="space-y-2"> <Link href="/courses"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/courses" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center"> <GalleryHorizontal className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">All Courses</div> <div className="text-xs text-muted-foreground">Browse our programs</div> </div> </Button> </Link> {/* Popular Courses */} <div className="grid grid-cols-1 gap-2"> {[ { title: "IELTS Preparation", href: "/courses/ielts", desc: "Complete IELTS training", color: "from-blue-500 to-blue-600", }, { title: "PTE Academic", href: "/courses/pte", desc: "PTE preparation course", color: "from-purple-500 to-purple-600", }, { title: "General English", href: "/courses/general-english", desc: "Improve overall English", color: "from-orange-500 to-orange-600", }, ].map((course) => { const isActive = pathname === course.href return ( <Link key={course.title} href={course.href}> <Button key={course.title} variant="ghost" className={`w-full h-12 flex items-center justify-start space-x-3 rounded-lg transition-all duration-200 ${ isActive ? "text-primary bg-primary/10 border border-primary/20" : "hover:bg-accent" }`} onClick={() => { setIsOpen(false) router.push(`/courses/search?query=${encodeURIComponent(course.title)}`) }} > <div className={`h-6 w-6 rounded bg-gradient-to-br ${course.color} flex items-center justify-center`} > <div className="h-2 w-2 bg-white rounded-full" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">{course.title}</div> <div className="text-xs text-muted-foreground">{course.desc}</div> </div> </Button> </Link> ) })} </div> {/* More Courses Expandable */} <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">More Courses</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {coursesDropdownItems.slice(3).map((item) => { const isActive = pathname === item.href return ( <Button key={item.title} variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => { setIsOpen(false) // redirect to search page with title as query router.push(`/courses/search?query=${encodeURIComponent(item.title)}`) }} > {item.title} </Button> ) })} </div> </details> </div> </div> {/* University Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> University </h3> <Link href="/university"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> <Link href="/university"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/university" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-brand-500 to-brand-600 flex items-center justify-center"> <TvMinimalPlay className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">University</div> <div className="text-xs text-muted-foreground">Academic programs</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">University Programs</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {universityDropdownItems.map((item) => { const isActive = pathname === item.href return ( <Link key={item.title} href={item.href}> <Button variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ) })} </div> </details> </div> {/* About Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> About Us </h3> <Link href="/about"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> Learn More </Button> </Link> </div> <Link href="/about"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/about" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center"> <Info className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">About Us</div> <div className="text-xs text-muted-foreground">Our story & mission</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">More About Us</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {aboutDropdownItems.map((item) => { const isActive = pathname === item.href return ( <Link key={item.title} href={item.href}> <Button variant="ghost" size="sm" className={`w-full justify-start text-sm h-10 ${ isActive ? "text-primary bg-primary/10" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground" }`} onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ) })} </div> </details> </div> {/* Browse Section - Mobile */} <div className="space-y-3"> <div className="flex items-center justify-between px-2"> <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> Browse Courses </h3> <Link href="/courses"> <Button variant="ghost" size="sm" className="text-xs h-7" onClick={() => setIsOpen(false)}> View All </Button> </Link> </div> <Link href="/courses"> <Button variant="ghost" className={`w-full h-14 flex items-center justify-start space-x-3 rounded-xl border-2 transition-all duration-200 ${ pathname === "/courses" ? "text-primary bg-primary/10 border-primary/20 shadow-sm" : "hover:bg-accent border-transparent hover:border-border" }`} onClick={() => setIsOpen(false)} > <div className="h-8 w-8 rounded-lg bg-gradient-to-br from-yellow-500 to-yellow-600 flex items-center justify-center"> <Zap className="h-4 w-4 text-white" /> </div> <div className="flex-1 text-left"> <div className="font-medium text-sm">All Courses</div> <div className="text-xs text-muted-foreground">Explore all programs</div> </div> </Button> </Link> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Category</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.categories.map((item) => ( <Link key={item.title} href={`/courses?category=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Level</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.levels.map((item) => ( <Link key={item.title} href={`/courses?level=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> <details className="group"> <summary className="flex items-center justify-between p-3 rounded-lg hover:bg-accent cursor-pointer transition-colors"> <span className="text-sm font-medium">Filter by Language</span> <svg className="h-4 w-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /> </svg> </summary> <div className="mt-2 space-y-1 pl-4"> {filterOptions.languages.map((item) => ( <Link key={item.title} href={`/courses?language=${encodeURIComponent(item.value)}`}> <Button variant="ghost" size="sm" className="w-full justify-start text-sm h-10 text-muted-foreground hover:bg-accent hover:text-accent-foreground" onClick={() => setIsOpen(false)} > {item.title} </Button> </Link> ))} </div> </details> </div> </div> {/* Mobile Footer Actions */} <div className="px-4 py-4 border-t bg-background/95 backdrop-blur sticky bottom-0"> {user ? ( // User is logged in - show profile/settings/logout <div className="space-y-2"> <div className="grid grid-cols-2 gap-2"> <Button variant="outline" className="h-12 flex items-center justify-center space-x-2 bg-transparent" onClick={() => { router.push("/profile") setIsOpen(false) }} > <User className="h-4 w-4" /> <span className="text-sm">Profile</span> </Button> <Button variant="outline" className="h-12 flex items-center justify-center space-x-2 bg-transparent" onClick={() => { router.push("/settings") setIsOpen(false) }} > <Settings className="h-4 w-4" /> <span className="text-sm">Settings</span> </Button> </div> <Button variant="destructive" className="w-full h-12 flex items-center justify-center space-x-2" onClick={() => { handleLogout() setIsOpen(false) }} > <LogOut className="h-4 w-4" /> <span className="text-sm font-medium">Log out</span> </Button> </div> ) : ( // User is not logged in - show login/register <div className="space-y-3"> <Button variant="outline" className="w-full h-12 text-sm font-medium bg-transparent" onClick={() => { router.push("/login") setIsOpen(false) }} > Login to Your Account </Button> <Button className="w-full h-12 bg-gradient-to-r from-brand-500 to-brand-600 hover:from-brand-600 hover:to-brand-700 text-white text-sm font-medium shadow-lg" onClick={() => { router.push("/signup") setIsOpen(false) }} > Create New Account </Button> </div> )} </div> </div> </SheetContent> </Sheet> </div> </div> </div> </nav> )}export default Navbar