216 lines
7.4 KiB
TypeScript
216 lines
7.4 KiB
TypeScript
"use client";
|
|
import { useState, useEffect } from "react";
|
|
import { usePathname } from "next/navigation";
|
|
import AnimateHeight from "react-animate-height";
|
|
import Image from "next/legacy/image";
|
|
import Link from "next/link";
|
|
import { OffcanvasData } from "@/public/data/offcanvas-data";
|
|
import logoLight from "@/public/images/logo-light.png";
|
|
|
|
interface OffcanvasMenuProps {
|
|
isOffcanvasOpen: boolean;
|
|
isActive: boolean;
|
|
handleClick: () => void;
|
|
navigationData?: any[];
|
|
servicesLoading?: boolean;
|
|
servicesError?: string | null;
|
|
}
|
|
|
|
const OffcanvasMenu = ({
|
|
isOffcanvasOpen,
|
|
isActive,
|
|
handleClick,
|
|
navigationData = OffcanvasData,
|
|
servicesLoading = false,
|
|
servicesError = null
|
|
}: OffcanvasMenuProps) => {
|
|
const [openDropdown, setOpenDropdown] = useState(null);
|
|
|
|
const handleDropdownToggle = (index: any) => {
|
|
setOpenDropdown((prev) => (prev === index ? null : index));
|
|
};
|
|
|
|
const pathname = usePathname();
|
|
useEffect(() => {
|
|
const parentItems = document.querySelectorAll(
|
|
".navbar__item--has-children"
|
|
);
|
|
|
|
parentItems.forEach((parentItem) => {
|
|
const childItems = parentItem.querySelectorAll(".active-current-sub");
|
|
|
|
if (childItems.length > 0) {
|
|
parentItem.classList.add("active-current-parent");
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="offcanvas-nav">
|
|
<div
|
|
className={
|
|
"offcanvas-menu" + (isOffcanvasOpen ? " show-offcanvas-menu" : " ")
|
|
}
|
|
>
|
|
<nav
|
|
className={
|
|
"offcanvas-menu__wrapper" + (isActive ? " " : " nav-fade-active")
|
|
}
|
|
data-lenis-prevent
|
|
>
|
|
<div className="offcanvas-menu__header nav-fade">
|
|
<div className="logo">
|
|
<Link href="/" className="logo-img">
|
|
<Image src={logoLight} priority alt="Image" title="Logo" width={160} height={60} />
|
|
</Link>
|
|
</div>
|
|
<button
|
|
aria-label="close offcanvas menu"
|
|
className="close-offcanvas-menu"
|
|
onClick={handleClick}
|
|
>
|
|
<i className="fa-solid fa-xmark"></i>
|
|
</button>
|
|
</div>
|
|
<div className="offcanvas-menu__list">
|
|
<div className="navbar__menu">
|
|
<ul>
|
|
{navigationData.map((item, index) =>
|
|
item.submenu ? (
|
|
<li
|
|
className="navbar__item navbar__item--has-children nav-fade"
|
|
key={index}
|
|
>
|
|
<button
|
|
aria-label="dropdown menu"
|
|
className={
|
|
"navbar__dropdown-label" +
|
|
(openDropdown === index
|
|
? " navbar__item-active"
|
|
: " ")
|
|
}
|
|
onClick={() => handleDropdownToggle(index)}
|
|
>
|
|
{item.title}
|
|
{item.title === "Services" && servicesLoading && (
|
|
<span className="loading-indicator">⏳</span>
|
|
)}
|
|
</button>
|
|
<AnimateHeight
|
|
duration={400}
|
|
height={openDropdown === index ? "auto" : 0}
|
|
>
|
|
<ul className="navbar__sub-menu">
|
|
{item.title === "Services" && servicesLoading ? (
|
|
<li>
|
|
<span className="text-muted">Loading services...</span>
|
|
</li>
|
|
) : item.title === "Services" && servicesError ? (
|
|
<li>
|
|
<span className="text-danger">Failed to load services</span>
|
|
</li>
|
|
) : (
|
|
item.submenu.map((subItem: any, subIndex: number) => (
|
|
<li key={subIndex}>
|
|
<Link
|
|
href={subItem.path || "#"}
|
|
className={
|
|
pathname === subItem.path
|
|
? " active-current-sub"
|
|
: " "
|
|
}
|
|
>
|
|
{subItem.title}
|
|
</Link>
|
|
</li>
|
|
))
|
|
)}
|
|
</ul>
|
|
</AnimateHeight>
|
|
</li>
|
|
) : (
|
|
<li className="navbar__item nav-fade" key={index}>
|
|
<Link
|
|
href={item.path || "#"}
|
|
className={
|
|
pathname === item.path ? " active-current-link" : " "
|
|
}
|
|
>
|
|
{item.title}
|
|
</Link>
|
|
</li>
|
|
)
|
|
)}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<div className="offcanvas-menu__enterprise-info nav-fade">
|
|
<div className="enterprise-contact">
|
|
<h4>Get in Touch</h4>
|
|
<p>Ready to transform your business?</p>
|
|
<div className="contact-methods">
|
|
<a href="tel:+1-800-ENTERPRISE" className="contact-item">
|
|
<i className="fa-solid fa-phone"></i>
|
|
<span>+1 (800) ENTERPRISE</span>
|
|
</a>
|
|
<a href="mailto:solutions@enterprise.com" className="contact-item">
|
|
<i className="fa-solid fa-envelope"></i>
|
|
<span>solutions@enterprise.com</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<ul className="enterprise-social nav-fade">
|
|
<li>
|
|
<Link
|
|
href="https://www.linkedin.com/company/enterprise"
|
|
target="_blank"
|
|
aria-label="Connect with us on LinkedIn"
|
|
>
|
|
<i className="fa-brands fa-linkedin-in"></i>
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="https://www.twitter.com/enterprise"
|
|
target="_blank"
|
|
aria-label="Follow us on Twitter"
|
|
>
|
|
<i className="fa-brands fa-twitter"></i>
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="https://www.youtube.com/enterprise"
|
|
target="_blank"
|
|
aria-label="Watch our videos on YouTube"
|
|
>
|
|
<i className="fa-brands fa-youtube"></i>
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="https://github.com/enterprise"
|
|
target="_blank"
|
|
aria-label="View our code on GitHub"
|
|
>
|
|
<i className="fa-brands fa-github"></i>
|
|
</Link>
|
|
</li>
|
|
</ul>
|
|
<div className="anime">
|
|
<span className="nav-fade"></span>
|
|
<span className="nav-fade"></span>
|
|
<span className="nav-fade"></span>
|
|
<span className="nav-fade"></span>
|
|
<span className="nav-fade"></span>
|
|
<span className="nav-fade"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default OffcanvasMenu;
|