- Add matching lucide-react icons to tab/mode switcher buttons on payments, at-the-door, manual, email-attendees, whatsapp-attendees, and admin cashup pages, mirroring icons already used in their help menus - Fix navbar Logout button sitting lower than other nav links (missing border/padding classes that other links use for their active-underline) - Fix stat card labels getting truncated on mobile by removing the ellipsis-cut label and widening the mobile grid to one column - Fix Revenue trend / Top performing events rendering outside the viewport on mobile by containing horizontal overflow and truncating long event titles in the table
137 lines
5.7 KiB
TypeScript
137 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import Image from "next/image";
|
|
import { usePathname } from "next/navigation";
|
|
import { useAuth } from "@/hooks/useAuth";
|
|
import { useSiteSettings } from "@/contexts/SiteSettingsContext";
|
|
import { BottomNav } from "./BottomNav";
|
|
import churchLogo from "@/app/church_logo.jpg";
|
|
import { appName, brandColor } from "@/lib/siteConfig";
|
|
import { resolveToApiOrigin } from "@/lib/api";
|
|
|
|
type NavLink = {
|
|
href: string;
|
|
label: string;
|
|
onClick?: () => void;
|
|
};
|
|
|
|
export const Navbar = () => {
|
|
const { user, loading: authLoading, logout } = useAuth();
|
|
const { settings, loading: settingsLoading } = useSiteSettings();
|
|
const pathname = usePathname();
|
|
// Admin-configurable — applied ONLY to the org name text below via inline
|
|
// style. No other element in the navbar (or anywhere else) should read
|
|
// this; everything else uses the fixed brand-* palette.
|
|
const displayName = settings.org_name || appName;
|
|
const displayColor = settings.accent_color || brandColor;
|
|
const logoSrc = settings.logo_url ? resolveToApiOrigin(settings.logo_url) : null;
|
|
|
|
const isActive = (href: string) => {
|
|
if (href.includes("#")) return false;
|
|
if (href === "/") return pathname === "/";
|
|
return pathname?.startsWith(href) ?? false;
|
|
};
|
|
|
|
const handleLogout = () => {
|
|
logout();
|
|
window.location.href = "/";
|
|
};
|
|
|
|
const navLinks: NavLink[] = [
|
|
{ href: "/", label: "Home" },
|
|
{ href: "/events", label: "Events" },
|
|
{ href: "/contact", label: "Contact" },
|
|
];
|
|
|
|
const authLinks: NavLink[] = user
|
|
? [
|
|
{ href: "/dashboard", label: "Dashboard" },
|
|
{
|
|
href: "#",
|
|
label: "Logout",
|
|
onClick: handleLogout,
|
|
},
|
|
]
|
|
: [
|
|
{ href: "/login", label: "Login" },
|
|
{ href: "/register", label: "Register" },
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<header className="bg-white shadow-md sticky top-0 z-50">
|
|
<nav className="max-w-7xl mx-auto px-4 py-3 flex items-center justify-between">
|
|
<Link href="/" className="flex items-center gap-2">
|
|
{settingsLoading ? (
|
|
<div className="h-10 w-10 rounded-sm bg-gray-100 animate-pulse" />
|
|
) : logoSrc ? (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={logoSrc} alt="Logo" className="h-10 w-auto object-contain rounded-sm" />
|
|
) : (
|
|
<Image
|
|
src={churchLogo}
|
|
alt="Church logo"
|
|
width={50}
|
|
height={50}
|
|
className="rounded-sm object-contain"
|
|
priority
|
|
/>
|
|
)}
|
|
{!settingsLoading && (
|
|
<span className="text-xl font-bold" style={{ color: displayColor }}>{displayName}</span>
|
|
)}
|
|
</Link>
|
|
|
|
{/* Desktop links */}
|
|
<div className="hidden md:flex items-center space-x-6">
|
|
{navLinks.map(link => (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
className={
|
|
"text-sm pb-0.5 border-b-2 transition-colors " +
|
|
(isActive(link.href)
|
|
? "text-brand-600 border-brand-600 font-medium"
|
|
: "text-gray-700 border-transparent hover:text-brand-600")
|
|
}
|
|
>
|
|
{link.label}
|
|
</Link>
|
|
))}
|
|
|
|
{/* Auth links are only known once the token has been validated —
|
|
rendering nothing here (instead of guessing "logged out") avoids
|
|
a Login/Register -> Dashboard/Logout flash on every load. */}
|
|
{!authLoading && authLinks.map(link =>
|
|
link.onClick ? (
|
|
<button
|
|
key={link.label}
|
|
onClick={link.onClick}
|
|
className="text-sm pb-0.5 border-b-2 border-transparent text-gray-700 hover:text-brand-600 transition-colors"
|
|
>
|
|
{link.label}
|
|
</button>
|
|
) : (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
className={
|
|
"text-sm pb-0.5 border-b-2 transition-colors " +
|
|
(isActive(link.href)
|
|
? "text-brand-600 border-brand-600 font-medium"
|
|
: "text-gray-700 border-transparent hover:text-brand-600")
|
|
}
|
|
>
|
|
{link.label}
|
|
</Link>
|
|
)
|
|
)}
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
<BottomNav />
|
|
</>
|
|
);
|
|
};
|