mirror of
https://github.com/OwethuManagedServices/oms-website-nextjs.git
synced 2025-12-17 17:28:09 +00:00
490 lines
19 KiB
TypeScript
490 lines
19 KiB
TypeScript
// components/HeaderClient.tsx
|
||
"use client";
|
||
|
||
import React, { useState } from "react";
|
||
import Link from "next/link";
|
||
import Image from "next/image";
|
||
import { usePathname } from "next/navigation"; // Import usePathname
|
||
import {
|
||
FiChevronDown,
|
||
FiClipboard,
|
||
FiArrowRight,
|
||
FiMenu,
|
||
FiX,
|
||
FiUsers,
|
||
FiBriefcase,
|
||
FiCpu,
|
||
FiBox,
|
||
FiFileText,
|
||
FiUserCheck,
|
||
} from "react-icons/fi";
|
||
import ThemeToggle from "./ThemeToggle";
|
||
|
||
const omsLogoUrl = "/oms-logo.svg";
|
||
|
||
type DropdownLinkProps = {
|
||
href: string;
|
||
children: React.ReactNode;
|
||
onClick?: () => void;
|
||
};
|
||
const DropdownLink = ({ href, children, onClick }: DropdownLinkProps) => (
|
||
<Link
|
||
href={href}
|
||
onClick={onClick}
|
||
className="block w-full text-left px-4 py-2 text-sm text-card-foreground hover:bg-secondary hover:text-primary transition-colors duration-150"
|
||
>
|
||
{children}
|
||
</Link>
|
||
);
|
||
|
||
const HeaderClient = () => {
|
||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||
const toggleMenu = () => setIsMenuOpen((open) => !open);
|
||
const handleMobileLinkClick = () => setIsMenuOpen(false);
|
||
|
||
const [servicesDropdownOpen, setServicesDropdownOpen] = useState(false);
|
||
const [productsDropdownOpen, setProductsDropdownOpen] = useState(false);
|
||
const [joinUsDropdownOpen, setJoinUsDropdownOpen] = useState(false);
|
||
|
||
const handleServicesMouseEnter = () => setServicesDropdownOpen(true);
|
||
const handleServicesMouseLeave = () => setServicesDropdownOpen(false);
|
||
|
||
const handleProductsMouseEnter = () => setProductsDropdownOpen(true);
|
||
const handleProductsMouseLeave = () => setProductsDropdownOpen(false);
|
||
|
||
const handleJoinUsMouseEnter = () => setJoinUsDropdownOpen(true);
|
||
const handleJoinUsMouseLeave = () => setJoinUsDropdownOpen(false);
|
||
|
||
const pathname = usePathname(); // Get current path
|
||
|
||
// Helper function to check if a path is active (exact match for simple links, startsWith for base paths)
|
||
const isActive = (href: string, exact = false) => {
|
||
if (exact) {
|
||
return pathname === href;
|
||
}
|
||
// Handle root path specifically
|
||
if (href === "/") {
|
||
return pathname === "/";
|
||
}
|
||
return pathname.startsWith(href);
|
||
};
|
||
|
||
const megaMenuTriggerClasses = `
|
||
relative inline-flex items-center text-sm font-medium text-primary-foreground
|
||
hover:opacity-90 transition-opacity duration-150 ease-in-out pb-1
|
||
after:content-[''] after:absolute after:left-0 after:bottom-0 after:h-[2px]
|
||
after:w-0 after:bg-primary-foreground/80 after:transition-all after:duration-300 after:ease-out
|
||
`;
|
||
|
||
const megaMenuItemClasses = `
|
||
flex items-center p-3 -m-3 rounded-lg
|
||
hover:bg-secondary transition-colors duration-150 ease-in-out
|
||
`;
|
||
const megaMenuIconClasses = `flex-shrink-0 h-6 w-6 text-primary mr-4`;
|
||
const megaMenuTextWrapperClasses = `text-sm`;
|
||
const megaMenuTitleClasses = `font-semibold text-card-foreground`;
|
||
|
||
return (
|
||
<header className="sticky top-0 z-50 shadow-md bg-background border-b border-border">
|
||
{/* Top Row */}
|
||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="flex justify-between items-center h-16">
|
||
<Link
|
||
href="/"
|
||
className="flex items-center space-x-2"
|
||
title="OMS Home"
|
||
>
|
||
<Image
|
||
src={omsLogoUrl}
|
||
alt="OMS Logo"
|
||
width={40}
|
||
height={40}
|
||
priority
|
||
/>
|
||
<span className="text-xl font-bold text-foreground hidden sm:inline">
|
||
Owethu Managed Services
|
||
</span>
|
||
</Link>
|
||
|
||
<nav className="hidden md:flex items-center space-x-6 lg:space-x-8">
|
||
<Link
|
||
href="/"
|
||
className={`text-sm font-medium transition ${
|
||
isActive("/")
|
||
? "text-primary"
|
||
: "text-foreground/80 hover:text-primary"
|
||
}`} // Apply active class
|
||
>
|
||
Home
|
||
</Link>
|
||
<Link
|
||
href="/tech-talk"
|
||
className={`text-sm font-medium transition ${
|
||
isActive("/tech-talk")
|
||
? "text-primary"
|
||
: "text-foreground/80 hover:text-primary"
|
||
}`} // Apply active class
|
||
>
|
||
Tech Talk
|
||
</Link>
|
||
<Link
|
||
href="/about"
|
||
className={`text-sm font-medium transition ${
|
||
isActive("/about")
|
||
? "text-primary"
|
||
: "text-foreground/80 hover:text-primary"
|
||
}`} // Apply active class
|
||
>
|
||
About Us
|
||
</Link>
|
||
<Link
|
||
href="/contact"
|
||
className={`text-sm font-medium transition ${
|
||
isActive("/contact")
|
||
? "text-primary"
|
||
: "text-foreground/80 hover:text-primary"
|
||
}`} // Apply active class
|
||
>
|
||
Contact Us
|
||
</Link>
|
||
</nav>
|
||
|
||
<div className="hidden md:flex items-center space-x-4">
|
||
<ThemeToggle />
|
||
<Link
|
||
href="/request-demo"
|
||
className="flex items-center text-sm font-medium bg-primary text-primary-foreground px-3 py-1.5 rounded-lg hover:bg-opacity-90 transition-colors"
|
||
title="Request a Demo"
|
||
>
|
||
<FiClipboard className="w-4 h-4 mr-1.5" />
|
||
Request OBSE Demo
|
||
</Link>
|
||
</div>
|
||
|
||
<div className="md:hidden flex items-center">
|
||
<ThemeToggle />
|
||
<button
|
||
onClick={toggleMenu}
|
||
className="text-foreground/60 hover:text-primary focus:outline-none ml-3"
|
||
aria-label="Toggle menu"
|
||
aria-expanded={isMenuOpen}
|
||
aria-controls="mobile-menu"
|
||
>
|
||
{isMenuOpen ? (
|
||
<FiX className="w-6 h-6" />
|
||
) : (
|
||
<FiMenu className="w-6 h-6" />
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Secondary Row w/ Mega Menus */}
|
||
<div className="bg-primary relative">
|
||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="hidden md:flex justify-between items-center h-12">
|
||
{/* Wrap nav and link in a flex container */}
|
||
<div className="flex items-center space-x-8 lg:space-x-10">
|
||
<nav className="flex items-center space-x-8 lg:space-x-10">
|
||
{/* Services */}
|
||
<div
|
||
className={`group ${isActive("/services") ? "active" : ""}`} // Add active class to group
|
||
onMouseEnter={handleServicesMouseEnter}
|
||
onMouseLeave={handleServicesMouseLeave}
|
||
>
|
||
<button
|
||
className={`${megaMenuTriggerClasses} ${
|
||
isActive("/services") ? "after:w-full" : ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply underline based on active state */}
|
||
Services
|
||
<FiChevronDown className="w-4 h-4 ml-1.5 opacity-70 transition-transform duration-200" />
|
||
</button>
|
||
<div
|
||
className={`
|
||
absolute left-0 top-full w-full shadow-lg z-40
|
||
bg-card border-x border-b border-border rounded-b-lg
|
||
opacity-0 invisible translate-y-[-10px]
|
||
${
|
||
servicesDropdownOpen
|
||
? "opacity-100 visible translate-y-0"
|
||
: ""
|
||
}
|
||
transition-all duration-300 ease-out transform
|
||
`}
|
||
>
|
||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-5">
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-x-8 gap-y-6">
|
||
<Link
|
||
href="/services/resource-augmentation"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/services/resource-augmentation")
|
||
? "text-primary"
|
||
: ""
|
||
}`} // Apply active class
|
||
>
|
||
<FiUsers className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
Resource Augmentation
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
{/* Add more service links here
|
||
<Link
|
||
href="/services/project-management"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/services/project-management")
|
||
? "text-primary"
|
||
: ""
|
||
}`} // Apply active class
|
||
>
|
||
<FiBriefcase className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
Project Management
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
*/}
|
||
<Link
|
||
href="/services/product-development"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/services/product-development")
|
||
? "text-primary"
|
||
: ""
|
||
}`} // Apply active class
|
||
>
|
||
<FiCpu className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
Product Development
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{/* Products */}
|
||
<div
|
||
className={`group ${isActive("/obse") ? "active" : ""}`} // Add active class to group
|
||
onMouseEnter={handleProductsMouseEnter}
|
||
onMouseLeave={handleProductsMouseLeave}
|
||
>
|
||
<button
|
||
className={`${megaMenuTriggerClasses} ${
|
||
isActive("/obse") ? "after:w-full" : ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply underline based on active state */}
|
||
Products
|
||
<FiChevronDown className="w-4 h-4 ml-1.5 opacity-70 transition-transform duration-200" />
|
||
</button>
|
||
<div
|
||
className={`
|
||
absolute left-0 top-full w-full shadow-lg z-1000
|
||
bg-card border-x border-b border-border rounded-b-lg
|
||
opacity-0 invisible translate-y-[-10px]
|
||
${
|
||
productsDropdownOpen
|
||
? "opacity-100 visible translate-y-0"
|
||
: ""
|
||
}
|
||
transition-all duration-300 ease-out transform
|
||
`}
|
||
>
|
||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-5">
|
||
<div className="max-w-md">
|
||
<Link
|
||
href="/obse"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/obse") ? "text-primary" : ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply active class */}
|
||
<FiBox className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
OBSE Platform
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{/* Join Our Team */}
|
||
<div
|
||
className={`group ${
|
||
isActive("/join-us") ||
|
||
isActive("/vacancies") ||
|
||
isActive("/portal")
|
||
? "active"
|
||
: ""
|
||
}`} // Add active class to group (check all related paths)
|
||
onMouseEnter={handleJoinUsMouseEnter}
|
||
onMouseLeave={handleJoinUsMouseLeave}
|
||
>
|
||
<button
|
||
className={`${megaMenuTriggerClasses} ${
|
||
isActive("/join-us") ||
|
||
isActive("/vacancies") ||
|
||
isActive("/portal")
|
||
? "after:w-full"
|
||
: ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply underline based on active state */}
|
||
Join Our Team
|
||
<FiChevronDown className="w-4 h-4 ml-1.5 opacity-70 transition-transform duration-200" />
|
||
</button>
|
||
<div
|
||
className={`
|
||
absolute left-0 top-full w-full shadow-lg z-1000
|
||
bg-card border-x border-b border-border rounded-b-lg
|
||
opacity-0 invisible translate-y-[-10px]
|
||
${
|
||
joinUsDropdownOpen
|
||
? "opacity-100 visible translate-y-0"
|
||
: ""
|
||
}
|
||
transition-all duration-300 ease-out transform
|
||
`}
|
||
>
|
||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-5">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6 max-w-xl">
|
||
<Link
|
||
href="/vacancies"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/vacancies") ? "text-primary" : ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply active class */}
|
||
<FiFileText className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
Current Vacancies
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
<Link
|
||
href="/portal"
|
||
className={`${megaMenuItemClasses} ${
|
||
isActive("/portal") ? "text-primary" : ""
|
||
}`}
|
||
>
|
||
{" "}
|
||
{/* Apply active class */}
|
||
<FiUserCheck className={megaMenuIconClasses} />
|
||
<div className={megaMenuTextWrapperClasses}>
|
||
<p className={megaMenuTitleClasses}>
|
||
Recruitment Portal
|
||
</p>
|
||
</div>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
{/* ← Here’s the Explore Our Offerings link, back in its original spot */}
|
||
<Link
|
||
href="/services" // Assuming this link goes to the main services page
|
||
className={`flex items-center text-sm font-medium hover:opacity-80 transition-opacity group ${
|
||
isActive("/services")
|
||
? "text-primary"
|
||
: "text-primary-foreground"
|
||
}`} // Apply active class
|
||
>
|
||
Explore Our Offerings
|
||
<FiArrowRight className="w-4 h-4 ml-1.5 transition-transform duration-200 group-hover:translate-x-1" />
|
||
</Link>
|
||
</div>{" "}
|
||
{/* Close the new flex container */}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Mobile Menu */}
|
||
<div
|
||
id="mobile-menu"
|
||
className={`md:hidden absolute top-full left-0 w-full shadow-lg transition-all duration-300 ease-in-out overflow-hidden bg-card border-t border-border ${
|
||
isMenuOpen
|
||
? "max-h-[calc(100vh-4rem)] py-4 overflow-y-auto"
|
||
: "max-h-0 py-0"
|
||
}`}
|
||
>
|
||
<nav className="container mx-auto px-4 sm:px-6 lg:px-8 flex flex-col space-y-1 text-foreground">
|
||
<DropdownLink href="/" onClick={handleMobileLinkClick}>
|
||
Home
|
||
</DropdownLink>
|
||
<DropdownLink href="/about" onClick={handleMobileLinkClick}>
|
||
About Us
|
||
</DropdownLink>
|
||
<span className="pt-3 pb-1 text-xs uppercase text-muted-foreground">
|
||
Services
|
||
</span>
|
||
<DropdownLink
|
||
href="/services/resource-augmentation"
|
||
onClick={handleMobileLinkClick}
|
||
>
|
||
Resource Augmentation
|
||
</DropdownLink>
|
||
<DropdownLink
|
||
href="/services/project-management"
|
||
onClick={handleMobileLinkClick}
|
||
>
|
||
Project Management
|
||
</DropdownLink>
|
||
<DropdownLink
|
||
href="/services/product-development"
|
||
onClick={handleMobileLinkClick}
|
||
>
|
||
Product Development
|
||
</DropdownLink>
|
||
<span className="pt-3 pb-1 text-xs uppercase text-muted-foreground">
|
||
Products
|
||
</span>
|
||
<DropdownLink href="/obse" onClick={handleMobileLinkClick}>
|
||
OBSE
|
||
</DropdownLink>
|
||
<span className="pt-3 pb-1 text-xs uppercase text-muted-foreground">
|
||
Join Us
|
||
</span>
|
||
<DropdownLink href="/vacancies" onClick={handleMobileLinkClick}>
|
||
Vacancies
|
||
</DropdownLink>
|
||
<DropdownLink href="/portal" onClick={handleMobileLinkClick}>
|
||
Recruitment Portal
|
||
</DropdownLink>
|
||
<DropdownLink href="/contact" onClick={handleMobileLinkClick}>
|
||
Contact Us
|
||
</DropdownLink>
|
||
<div className="pt-4">
|
||
<Link
|
||
href="/request-demo"
|
||
onClick={handleMobileLinkClick}
|
||
className="flex w-full justify-center items-center text-sm font-medium bg-primary text-primary-foreground px-4 py-2 rounded-lg hover:bg-opacity-90 transition-colors"
|
||
title="Request a Demo"
|
||
>
|
||
<FiClipboard className="w-4 h-4 mr-1.5" /> Request OBSE Demo
|
||
</Link>
|
||
</div>
|
||
<div className="pt-4 border-t border-border mt-4"></div>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
);
|
||
};
|
||
|
||
export default HeaderClient;
|