Spaces:
Sleeping
Sleeping
| import { useLocation, useNavigate } from "react-router-dom"; | |
| import { Button, PageContainer, Container } from "@ifrc-go/ui"; | |
| import { | |
| UploadCloudLineIcon, | |
| AnalysisIcon, | |
| SearchLineIcon, | |
| QuestionLineIcon, | |
| GoMainIcon, | |
| SettingsIcon, | |
| MenuLineIcon, | |
| } from "@ifrc-go/icons"; | |
| import { useState, useEffect, useRef } from "react"; | |
| import styles from './HeaderNav.module.css'; | |
| declare global { | |
| interface Window { | |
| confirmNavigationIfNeeded?: (to: string) => void; | |
| } | |
| } | |
| const navItems = [ | |
| { to: "/upload", label: "Upload", Icon: UploadCloudLineIcon }, | |
| { to: "/explore", label: "Explore", Icon: SearchLineIcon }, | |
| { to: "/analytics", label: "Analytics", Icon: AnalysisIcon }, | |
| ]; | |
| export default function HeaderNav() { | |
| const location = useLocation(); | |
| const navigate = useNavigate(); | |
| const [isDropdownOpen, setIsDropdownOpen] = useState(false); | |
| const dropdownRef = useRef<HTMLDivElement>(null); | |
| // Close dropdown when clicking outside | |
| useEffect(() => { | |
| const handleClickOutside = (event: MouseEvent) => { | |
| if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { | |
| setIsDropdownOpen(false); | |
| } | |
| }; | |
| document.addEventListener('mousedown', handleClickOutside); | |
| return () => { | |
| document.removeEventListener('mousedown', handleClickOutside); | |
| }; | |
| }, []); | |
| return ( | |
| <nav className="border-b border-gray-200 bg-white shadow-sm sticky top-0 z-50 backdrop-blur-sm bg-white/95"> | |
| <PageContainer | |
| className="border-b-2 border-ifrcRed" | |
| contentClassName="grid grid-cols-3 items-center py-6" | |
| > | |
| <div | |
| className="flex items-center gap-4 min-w-0 cursor-pointer group transition-all duration-200 hover:scale-105" | |
| onClick={() => { | |
| // Prevent navigation to home when already on upload page | |
| if (location.pathname === "/upload" || location.pathname === "/") { | |
| return; | |
| } | |
| if (location.pathname === "/upload") { | |
| if (window.confirmNavigationIfNeeded) { | |
| window.confirmNavigationIfNeeded('/'); | |
| return; | |
| } | |
| if (!confirm("You have unsaved changes. Are you sure you want to leave?")) { | |
| return; | |
| } | |
| } | |
| navigate('/'); | |
| }} | |
| > | |
| <div className="p-2 rounded-lg bg-gradient-to-br from-ifrcRed/10 to-ifrcRed/20 group-hover:from-ifrcRed/20 group-hover:to-ifrcRed/30 transition-all duration-200"> | |
| <GoMainIcon className="h-8 w-8 flex-shrink-0 text-ifrcRed" /> | |
| </div> | |
| <div className="flex flex-col"> | |
| <span className="font-bold text-xl text-gray-900 leading-tight">PromptAid Vision</span> | |
| </div> | |
| </div> | |
| <div className="flex justify-center"> | |
| <nav className="flex items-center space-x-4 bg-gray-50/80 rounded-xl p-2 backdrop-blur-sm"> | |
| {navItems.map(({ to, label, Icon }) => { | |
| const isActive = location.pathname === to || | |
| (to === '/upload' && location.pathname === '/') || | |
| (to === '/explore' && location.pathname.startsWith('/map/')); | |
| const isUploadPage = location.pathname === "/upload" || location.pathname === "/"; | |
| const isUploadOrHomeNav = to === "/upload" || to === "/"; | |
| return ( | |
| <div key={to} className="relative"> | |
| <Container withInternalPadding className="p-2"> | |
| <Button | |
| name={label.toLowerCase()} | |
| variant={isActive ? "primary" : "tertiary"} | |
| size={1} | |
| className={`transition-all duration-200 ${ | |
| isActive | |
| ? 'shadow-lg shadow-ifrcRed/20 transform scale-105' | |
| : 'hover:bg-white hover:shadow-md hover:scale-105' | |
| }`} | |
| onClick={() => { | |
| if (isUploadPage && isUploadOrHomeNav) { | |
| return; | |
| } | |
| if (location.pathname === "/upload") { | |
| if (window.confirmNavigationIfNeeded) { | |
| window.confirmNavigationIfNeeded(to); | |
| return; | |
| } | |
| if (!confirm("You have unsaved changes. Are you sure you want to leave?")) { | |
| return; | |
| } | |
| } | |
| navigate(to); | |
| }} | |
| > | |
| <Icon className={`w-4 h-4 transition-transform duration-200 ${ | |
| isActive ? 'scale-110' : 'group-hover:scale-110' | |
| }`} /> | |
| <span className="inline ml-2 font-semibold">{label}</span> | |
| </Button> | |
| </Container> | |
| {isActive && ( | |
| <div className="absolute -bottom-2 left-1/2 transform -translate-x-1/2 w-8 h-1 bg-ifrcRed rounded-full animate-pulse"></div> | |
| )} | |
| </div> | |
| ); | |
| })} | |
| </nav> | |
| </div> | |
| <div className="flex justify-end"> | |
| <div className={styles.dropdownContainer} ref={dropdownRef}> | |
| <Container withInternalPadding className="p-2"> | |
| <Button | |
| name="more-options" | |
| variant={isDropdownOpen ? "primary" : "tertiary"} | |
| size={1} | |
| className="transition-all duration-200" | |
| onClick={() => setIsDropdownOpen(!isDropdownOpen)} | |
| > | |
| <MenuLineIcon className="w-4 h-4" /> | |
| </Button> | |
| </Container> | |
| {/* Enhanced Dropdown Menu */} | |
| {isDropdownOpen && ( | |
| <div className={styles.dropdownMenu}> | |
| <div className={styles.dropdownContent}> | |
| <Container withInternalPadding className="p-2"> | |
| <Button | |
| name="help-support" | |
| variant="tertiary" | |
| size={1} | |
| className="w-full justify-start" | |
| onClick={() => { | |
| setIsDropdownOpen(false); | |
| if (location.pathname === "/upload") { | |
| if (window.confirmNavigationIfNeeded) { | |
| window.confirmNavigationIfNeeded('/help'); | |
| return; | |
| } | |
| if (!confirm("You have unsaved changes. Are you sure you want to leave?")) { | |
| return; | |
| } | |
| } | |
| navigate('/help'); | |
| }} | |
| > | |
| <QuestionLineIcon className="w-4 h-4" /> | |
| <span className="ml-2 font-semibold">Help & Support</span> | |
| </Button> | |
| </Container> | |
| <Container withInternalPadding className="p-2"> | |
| <Button | |
| name="dev" | |
| variant="tertiary" | |
| size={1} | |
| className="w-full justify-start" | |
| onClick={() => { | |
| setIsDropdownOpen(false); | |
| if (location.pathname === "/upload") { | |
| if (window.confirmNavigationIfNeeded) { | |
| window.confirmNavigationIfNeeded('/admin'); | |
| return; | |
| } | |
| if (!confirm("You have unsaved changes. Are you sure you want to leave?")) { | |
| return; | |
| } | |
| } | |
| navigate('/admin'); | |
| }} | |
| > | |
| <SettingsIcon className="w-4 h-4" /> | |
| <span className="ml-2 font-semibold">Dev</span> | |
| </Button> | |
| </Container> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| </PageContainer> | |
| </nav> | |
| ); | |
| } | |