Spaces:
Running
Running
File size: 8,249 Bytes
d7291ef 65933cd 66e0c05 d25db6b d7291ef fd3d1a8 66e0c05 fd3d1a8 c69ce84 66e0c05 a406193 66e0c05 d7291ef 66e0c05 23d1df7 d7291ef fd3d1a8 23d1df7 66e0c05 1686de5 d7291ef 1686de5 1dc6a03 d7291ef 1686de5 65933cd 7b68420 65933cd a406193 65933cd 1686de5 d7291ef 66e0c05 1dc6a03 1686de5 65933cd 26c355d 65933cd 7b68420 1686de5 65933cd ba5edb0 7b68420 ba5edb0 65933cd ba5edb0 65933cd 1686de5 66e0c05 1dc6a03 66e0c05 1dc6a03 fd3d1a8 ba5edb0 1dc6a03 ba5edb0 d7291ef 66e0c05 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
import { useLocation, useNavigate } from "react-router-dom";
import { Button, PageContainer, Container } from "@ifrc-go/ui";
import {
UploadCloudLineIcon,
AnalysisIcon,
SearchLineIcon,
QuestionLineIcon,
GoMainIcon,
SettingsIcon,
ChevronDownLineIcon,
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>
);
}
|