theme-color)/- - Admin Theme settings page under Settings > Theme tab/- All logo references (5 components) now pull from the theme config with fallback to default
524 lines
22 KiB
JavaScript
524 lines
22 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Link, useNavigate, useLocation } from 'react-router-dom';
|
|
import { Button } from './ui/button';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { useThemeConfig } from '../context/ThemeConfigContext';
|
|
import { ChevronDown, Menu, X } from 'lucide-react';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from './ui/dropdown-menu';
|
|
|
|
const PublicNavbar = () => {
|
|
const { user, logout } = useAuth();
|
|
const { getLogoUrl } = useThemeConfig();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
|
|
// Helper function to check if a path is active
|
|
const isActive = (path) => {
|
|
if (path.includes('#')) {
|
|
// For hash links like /#welcome
|
|
return location.pathname + location.hash === path || location.hash === path.replace('/', '');
|
|
}
|
|
return location.pathname === path || location.pathname.startsWith(path + '/');
|
|
};
|
|
|
|
// Check if any About Us sub-page is active
|
|
const isAboutActive = () => {
|
|
return location.pathname.startsWith('/about');
|
|
};
|
|
|
|
// Get logo URL from theme config (with fallback to default)
|
|
const loafLogo = getLogoUrl();
|
|
|
|
const handleAuthAction = () => {
|
|
if (user) {
|
|
logout();
|
|
navigate('/');
|
|
} else {
|
|
navigate('/login');
|
|
}
|
|
};
|
|
|
|
// Active and inactive link styles for desktop
|
|
const getDesktopLinkClasses = (path) => {
|
|
const baseClasses = "text-[17.5px] font-medium transition-all px-3 py-1 rounded-md";
|
|
if (isActive(path)) {
|
|
return `${baseClasses} text-[var(--orange-light)] hover:text-[var(--orange-coral)] `;
|
|
}
|
|
return `${baseClasses} text-white hover:opacity-80`;
|
|
};
|
|
|
|
// Active and inactive link styles for mobile
|
|
const getMobileLinkClasses = (path) => {
|
|
const baseClasses = "text-base font-medium px-4 py-3 rounded-md transition-colors";
|
|
if (isActive(path)) {
|
|
return `${baseClasses} bg-[var(--orange-light)] hover:bg-[var(--orange-coral)] text-[var(--purple-deep)]`;
|
|
}
|
|
return `${baseClasses} text-white hover:bg-[var(--purple-deep)]`;
|
|
};
|
|
|
|
// Active and inactive link styles for mobile sub-items (About Us)
|
|
const getMobileSubLinkClasses = (path) => {
|
|
const baseClasses = "text-sm font-medium px-6 py-2 rounded-md transition-colors block";
|
|
if (isActive(path)) {
|
|
return `${baseClasses} bg-[var(--orange-light)] hover:bg-[var(--orange-coral)] text-[var(--purple-deep)]`;
|
|
}
|
|
return `${baseClasses} text-[var(--neutral-800)] hover:bg-[var(--purple-deep)] hover:text-white`;
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* Top Header - Auth Actions */}
|
|
<div className='sticky top-0 inset-x-0 z-50'>
|
|
|
|
<header className="bg-gradient-to-r flex-wrap from-[var(--purple-amethyst)] to-[var(--purple-deep)] px-[20px] py-[10px] flex md:justify-end justify-between items-center gap-4 sm:gap-6">
|
|
<div className='flex gap-4 sm:gap-6 items-center'>
|
|
{user && (
|
|
<span
|
|
className="text-white text-base font-medium"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Welcome, {user.first_name}
|
|
</span>
|
|
)}
|
|
{(user?.role === 'admin' || user?.role === 'superadmin') && (
|
|
<Link
|
|
to="/admin"
|
|
className="text-white text-base font-medium hover:opacity-80 transition-opacity"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Dashboard
|
|
</Link>
|
|
)}
|
|
<button
|
|
onClick={handleAuthAction}
|
|
className="text-white text-base font-medium hover:opacity-80 transition-opacity bg-transparent border-none cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{user ? 'Logout' : 'Login'}
|
|
</button>
|
|
{!user && (
|
|
<Link
|
|
to="/register"
|
|
className="text-white text-base font-medium hover:opacity-80 transition-opacity"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Register
|
|
</Link>
|
|
)}
|
|
</div>
|
|
<Link to="/donate">
|
|
<Button
|
|
className="bg-[var(--orange-light)] hover:bg-[var(--orange-coral)] text-[var(--purple-deep)] rounded-[25px] px-[50px] py-[5px] text-[16.5px] font-semibold h-[41px]"
|
|
style={{ fontFamily: "'Montserrat', sans-serif" }}
|
|
>
|
|
Donate
|
|
</Button>
|
|
</Link>
|
|
</header>
|
|
|
|
{/* Main Header - Navigation */}
|
|
<header className=" bg-brand-purple px-[20px] py-2 flex justify-between items-center">
|
|
<Link to="/">
|
|
<img src={loafLogo} alt="LOAF Logo" className="h-16 w-16 sm:h-20 sm:w-20 md:h-28 md:w-28 object-contain" />
|
|
</Link>
|
|
|
|
{/* Mobile Menu Button */}
|
|
<button
|
|
onClick={() => setIsMobileMenuOpen(true)}
|
|
className="lg:hidden p-2 text-white hover:bg-[var(--purple-deep)] rounded-md transition-colors"
|
|
aria-label="Open menu"
|
|
>
|
|
<Menu className="size-14" />
|
|
</button>
|
|
|
|
{/* Desktop Navigation */}
|
|
<nav className="hidden lg:flex gap-6 items-center">
|
|
<Link
|
|
to="/#welcome"
|
|
className={getDesktopLinkClasses('/#welcome')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Welcome
|
|
</Link>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button
|
|
className={`${isAboutActive()
|
|
? "text-[var(--orange-light)] hover:text-[var(--orange-coral)]"
|
|
: "text-white hover:opacity-80"} text-[17.5px] font-medium transition-all flex items-center gap-1 bg-transparent border-none cursor-pointer px-3 py-1 rounded-md`}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
About Us
|
|
<ChevronDown className="h-4 w-4" />
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="start" className="bg-background min-w-[220px]">
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/about/history" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
History
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/about/mission-values" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Mission and Values
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/about/board" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Board of Directors
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
<Link
|
|
to={user ? "/dashboard" : "/become-a-member"}
|
|
className={getDesktopLinkClasses(user ? "/dashboard" : "/become-a-member")}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{user ? 'My Profile' : 'Become a Member'}
|
|
</Link>
|
|
{!user && (
|
|
<Link
|
|
to="/login"
|
|
className={getDesktopLinkClasses('/login')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Members Only
|
|
</Link>
|
|
)}
|
|
{user && (
|
|
<>
|
|
<Link
|
|
to="/events"
|
|
className={getDesktopLinkClasses('/events')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Events
|
|
</Link>
|
|
<Link
|
|
to="/members/calendar"
|
|
className={getDesktopLinkClasses('/members/calendar')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Calendar
|
|
</Link>
|
|
<Link
|
|
to="/members/directory"
|
|
className={getDesktopLinkClasses('/members/directory')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Directory
|
|
</Link>
|
|
<Link
|
|
to="/members/gallery"
|
|
className={getDesktopLinkClasses('/members/gallery')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Gallery
|
|
</Link>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button
|
|
className={`${location.pathname.startsWith('/members/newsletters') || location.pathname.startsWith('/members/financials') || location.pathname.startsWith('/members/bylaws')
|
|
? "text-[var(--orange-light)] hover:text-[var(--orange-coral)]"
|
|
: "text-white hover:opacity-80"} text-[17.5px] font-medium transition-all flex items-center gap-1 bg-transparent border-none cursor-pointer px-3 py-1 rounded-md`}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Documents
|
|
<ChevronDown className="h-4 w-4" />
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="start" className="bg-background min-w-[220px]">
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/members/newsletters" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Newsletters
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/members/financials" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Financials
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem asChild>
|
|
<Link to="/members/bylaws" className="w-full px-3 py-2 text-[var(--purple-deep)] hover:bg-[var(--lavender-300)] cursor-pointer"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Bylaws
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</>
|
|
)}
|
|
{/* <Link
|
|
to="/resources"
|
|
className={getDesktopLinkClasses('/resources')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Resources
|
|
</Link>
|
|
<Link
|
|
to="/contact-us"
|
|
className={getDesktopLinkClasses('/contact-us')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Contact Us
|
|
</Link> */}
|
|
</nav>
|
|
</header>
|
|
|
|
</div>
|
|
{/* Mobile Menu Drawer */}
|
|
{isMobileMenuOpen && (
|
|
<div className="fixed inset-0 z-50 lg:hidden">
|
|
{/* Backdrop */}
|
|
<div
|
|
className="fixed inset-0 bg-black/50 backdrop-blur-sm"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
/>
|
|
|
|
{/* Drawer */}
|
|
<div className="fixed right-0 top-0 h-full w-[280px] bg-brand-purple shadow-xl overflow-y-auto scrollbar-dashboard">
|
|
{/* Header */}
|
|
<div className="flex justify-between items-center p-6 border-b border-[var(--purple-deep)]">
|
|
<span className="text-white text-lg font-semibold" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Menu
|
|
</span>
|
|
<button
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className="p-2 text-white hover:bg-[var(--purple-deep)] rounded-md transition-colors"
|
|
aria-label="Close menu"
|
|
>
|
|
<X className="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* User Info */}
|
|
{user && (
|
|
<div className="px-6 py-4 border-b border-[var(--purple-deep)]">
|
|
<p className="text-white text-sm opacity-90" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Welcome,
|
|
</p>
|
|
<p className="text-white font-semibold text-base" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
{user.first_name} {user.last_name}
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Navigation Links */}
|
|
<nav className="flex flex-col p-6 space-y-4">
|
|
<Link
|
|
to="/#welcome"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/#welcome')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Welcome
|
|
</Link>
|
|
|
|
{/* About Us Section */}
|
|
<div className="space-y-2">
|
|
<p
|
|
className={`text-base font-semibold px-4 py-2 rounded-md ${isAboutActive() ? 'text-[var(--orange-light)]' : 'text-white'}`}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
About Us
|
|
</p>
|
|
<Link
|
|
to="/about/history"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/about/history')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
History
|
|
</Link>
|
|
<Link
|
|
to="/about/mission-values"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/about/mission-values')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Mission and Values
|
|
</Link>
|
|
<Link
|
|
to="/about/board"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/about/board')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Board of Directors
|
|
</Link>
|
|
</div>
|
|
|
|
<Link
|
|
to={user ? "/dashboard" : "/become-a-member"}
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses(user ? "/dashboard" : "/become-a-member")}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{user ? 'My Profile' : 'Become a Member'}
|
|
</Link>
|
|
|
|
{!user && (
|
|
<Link
|
|
to="/login"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/login')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Members Only
|
|
</Link>
|
|
)}
|
|
|
|
{user && (
|
|
<>
|
|
<Link
|
|
to="/events"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/events')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Events
|
|
</Link>
|
|
|
|
<Link
|
|
to="/members/calendar"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/members/calendar')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Calendar
|
|
</Link>
|
|
|
|
<Link
|
|
to="/members/directory"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/members/directory')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Directory
|
|
</Link>
|
|
|
|
<Link
|
|
to="/members/gallery"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/members/gallery')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Gallery
|
|
</Link>
|
|
|
|
{/* Documents Section */}
|
|
<div className="space-y-2">
|
|
<p
|
|
className={`text-base font-semibold px-4 py-2 rounded-md ${location.pathname.startsWith('/members/newsletters') || location.pathname.startsWith('/members/financials') || location.pathname.startsWith('/members/bylaws') ? 'text-[var(--orange-light)]' : 'text-white'}`}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Documents
|
|
</p>
|
|
<Link
|
|
to="/members/newsletters"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/members/newsletters')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Newsletters
|
|
</Link>
|
|
<Link
|
|
to="/members/financials"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/members/financials')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Financials
|
|
</Link>
|
|
<Link
|
|
to="/members/bylaws"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileSubLinkClasses('/members/bylaws')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Bylaws
|
|
</Link>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<Link
|
|
to="/resources"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/resources')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Resources
|
|
</Link>
|
|
|
|
<Link
|
|
to="/contact-us"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className={getMobileLinkClasses('/contact-us')}
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Contact Us
|
|
</Link>
|
|
|
|
{/* Auth Actions */}
|
|
<div className="pt-4 border-t border-[var(--purple-deep)] space-y-2">
|
|
{(user?.role === 'admin' || user?.role === 'superadmin') && (
|
|
<Link
|
|
to="/admin"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className="block text-white text-base font-medium hover:bg-[var(--purple-deep)] px-4 py-3 rounded-md transition-colors"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Dashboard
|
|
</Link>
|
|
)}
|
|
<button
|
|
onClick={() => {
|
|
handleAuthAction();
|
|
setIsMobileMenuOpen(false);
|
|
}}
|
|
className="w-full text-left text-white text-base font-medium hover:bg-[var(--purple-deep)] px-4 py-3 rounded-md transition-colors"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
{user ? 'Logout' : 'Login'}
|
|
</button>
|
|
{!user && (
|
|
<Link
|
|
to="/register"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className="block text-white text-base font-medium hover:bg-[var(--purple-deep)] px-4 py-3 rounded-md transition-colors"
|
|
style={{ fontFamily: "'Nunito Sans', sans-serif" }}
|
|
>
|
|
Register
|
|
</Link>
|
|
)}
|
|
<Link
|
|
to="/donate"
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
className="block w-full"
|
|
>
|
|
<Button className="w-full bg-[var(--orange-light)] hover:bg-[var(--orange-coral)] text-[var(--purple-deep)] rounded-[25px] px-6 py-3 text-base font-semibold">
|
|
Donate
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default PublicNavbar;
|