import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Smartphone, Menu, X, LogOut, Settings, Coins, Shield, Plus, ChevronDown, ChevronLeft, ChevronRight, FolderOpen, Trash2, Wrench, HelpCircle } from "lucide-react"; import { useState, useCallback, useEffect, useMemo } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; import { useAuth } from "@/contexts/AuthContext"; import { useAdminAuth } from "@/hooks/useAdminAuth"; import { useAdminExists } from "@/hooks/useAdminExists"; import { ThemeToggle } from "@/components/ThemeToggle"; import { userApi, projectsApi } from "@/lib/api"; import { useSystemSettings } from "@/hooks/useSystemSettings"; import ThemeAwareLogo from "@/components/ThemeAwareLogo"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuLabel, } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; import { formatDistanceToNow } from "date-fns"; import { toast } from "sonner"; const navSections = ['features', 'how-it-works', 'pricing', 'platforms'] as const; const PROJECTS_PER_PAGE = 5; const Navbar = () => { const [isOpen, setIsOpen] = useState(false); const [activeSection, setActiveSection] = useState(null); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [projectToDelete, setProjectToDelete] = useState<{ id: string; name: string } | null>(null); const [projectPage, setProjectPage] = useState(0); const { user, signOut } = useAuth(); const { isAdmin } = useAdminAuth(); const { hasAdmin } = useAdminExists(); const { settings } = useSystemSettings(); const navigate = useNavigate(); const location = useLocation(); const queryClient = useQueryClient(); // Track active section with IntersectionObserver useEffect(() => { if (location.pathname !== '/') { setActiveSection(null); return; } const observers: IntersectionObserver[] = []; navSections.forEach((sectionId) => { const element = document.getElementById(sectionId); if (element) { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setActiveSection(sectionId); } }); }, { rootMargin: '-20% 0px -60% 0px', threshold: 0 } ); observer.observe(element); observers.push(observer); } }); return () => { observers.forEach((observer) => observer.disconnect()); }; }, [location.pathname]); const handleSmoothScroll = useCallback((e: React.MouseEvent, targetId: string) => { e.preventDefault(); const scrollToElement = () => { const element = document.getElementById(targetId); if (element) { const navbarHeight = 80; const elementPosition = element.getBoundingClientRect().top + window.scrollY; window.scrollTo({ top: elementPosition - navbarHeight, behavior: 'smooth' }); } }; // If we're not on the home page, navigate first then scroll if (location.pathname !== '/') { navigate('/'); setTimeout(scrollToElement, 100); } else { scrollToElement(); } setIsOpen(false); }, [location.pathname, navigate]); const getNavLinkClass = (sectionId: string) => cn( "transition-colors cursor-pointer relative", activeSection === sectionId ? "text-primary font-medium" : "text-muted-foreground hover:text-foreground" ); // Fetch user profile for avatar const { data: profile } = useQuery({ queryKey: ["navbar-profile", user?.id], queryFn: async () => { if (!user?.id) return null; const { data, error } = await userApi.getProfile(); if (error) throw error; return data; }, enabled: !!user?.id, }); // Fetch all projects for builder dropdown const { data: allProjects } = useQuery({ queryKey: ["recent-projects", user?.id], queryFn: async () => { if (!user?.id) return []; const { data, error } = await projectsApi.list(); if (error) throw error; return data || []; }, enabled: !!user?.id, }); const totalProjectPages = Math.max(1, Math.ceil((allProjects?.length || 0) / PROJECTS_PER_PAGE)); const paginatedProjects = useMemo(() => { if (!allProjects) return []; const start = projectPage * PROJECTS_PER_PAGE; return allProjects.slice(start, start + PROJECTS_PER_PAGE); }, [allProjects, projectPage]); // Delete project mutation const deleteProjectMutation = useMutation({ mutationFn: async (projectId: string) => { const { error } = await projectsApi.delete(projectId); if (error) throw error; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["recent-projects"] }); toast.success("Project deleted successfully"); setDeleteDialogOpen(false); setProjectToDelete(null); }, onError: (error) => { console.error("Delete error:", error); toast.error("Failed to delete project"); }, }); const handleDeleteClick = (e: React.MouseEvent, project: { id: string; app_name: string }) => { e.preventDefault(); e.stopPropagation(); setProjectToDelete({ id: project.id, name: project.app_name }); setDeleteDialogOpen(true); }; const confirmDelete = () => { if (projectToDelete) { deleteProjectMutation.mutate(projectToDelete.id); } }; const getInitials = (name?: string | null) => { if (!name) return user?.email?.[0]?.toUpperCase() || "U"; return name .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2); }; const displayName = profile?.display_name || user?.email?.split("@")[0] || "User"; const handleSignOut = async () => { await signOut(); navigate("/"); }; return ( ); }; export default Navbar;