update
This commit is contained in:
@@ -36,16 +36,17 @@ export const CookieConsentBanner: React.FC = () => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.showBanner) {
|
||||
if (state.showBanner && !state.showSettings) {
|
||||
// Small delay to ensure smooth animation
|
||||
const timer = setTimeout(() => setIsVisible(true), 100);
|
||||
return () => clearTimeout(timer);
|
||||
} else {
|
||||
setIsVisible(false);
|
||||
}
|
||||
}, [state.showBanner]);
|
||||
}, [state.showBanner, state.showSettings]);
|
||||
|
||||
if (!state.showBanner || !isVisible) return null;
|
||||
// Hide banner when settings modal is open
|
||||
if (!state.showBanner || !isVisible || state.showSettings) return null;
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
@@ -205,6 +206,9 @@ export const CookieSettingsModal: React.FC = () => {
|
||||
transition={{ duration: 0.2 }}
|
||||
className="cookie-settings-overlay"
|
||||
onClick={hideSettings}
|
||||
style={{
|
||||
zIndex: 10001, // Higher than banner overlay (10000)
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
initial={{ scale: 0.9, opacity: 0 }}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import Image from "next/legacy/image";
|
||||
import location from "@/public/images/footer/location.png";
|
||||
import phone from "@/public/images/footer/phone.png";
|
||||
import gmail from "@/public/images/footer/gmail.png";
|
||||
import { useNavigationServices } from "@/lib/hooks/useServices";
|
||||
import { useJobs } from "@/lib/hooks/useCareer";
|
||||
|
||||
@@ -39,11 +36,14 @@ const Footer = () => {
|
||||
|
||||
return (
|
||||
<footer className="footer position-relative overflow-x-clip">
|
||||
{/* Decorative background elements */}
|
||||
<div className="footer-bg-decoration"></div>
|
||||
|
||||
<div className="container">
|
||||
{/* Enterprise Footer Logo Section */}
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="footer-logo-section text-center pt-40 pb-30">
|
||||
<div className="footer-logo-section text-center pt-60 pb-50">
|
||||
<div className="enterprise-logo-container">
|
||||
<div className="enterprise-security-badges">
|
||||
{/* Left Badge */}
|
||||
@@ -60,18 +60,19 @@ const Footer = () => {
|
||||
<Image
|
||||
src={logoSrc}
|
||||
alt="Logo"
|
||||
width={120}
|
||||
height={90}
|
||||
width={140}
|
||||
height={100}
|
||||
className="footer-logo-image"
|
||||
/>
|
||||
</Link>
|
||||
<p className="footer-tagline">Transforming Ideas Into Digital Excellence</p>
|
||||
</div>
|
||||
|
||||
{/* Right Badge */}
|
||||
<div className="security-badges-right">
|
||||
<div className="security-badge">
|
||||
<i className="fa-solid fa-shield-halved"></i>
|
||||
<span>Incident Management</span>
|
||||
<i className="fa-solid fa-brain"></i>
|
||||
<span>AI & Innovation</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,27 +80,22 @@ const Footer = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row vertical-column-gap-lg">
|
||||
<div className="col-12">
|
||||
<div className="pt-40">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row vertical-column-gap-lg pt-40">
|
||||
<div className="col-12 col-lg-2 col-md-6">
|
||||
<div className="row vertical-column-gap-lg pt-60 pb-50">
|
||||
<div className="col-12 col-lg-2 col-md-6 col-sm-6">
|
||||
<div className="footer-section">
|
||||
<h6 className="text-white fm fw-6 mb-24">Company</h6>
|
||||
<h6 className="footer-section-title">Company</h6>
|
||||
<ul className="footer-links">
|
||||
<li><Link href="about-us">About Us</Link></li>
|
||||
<li><Link href="career">Careers</Link></li>
|
||||
<li><Link href="case-study">Success Stories</Link></li>
|
||||
<li><Link href="contact-us">Contact Us</Link></li>
|
||||
<li><Link href="/about-us">About Us</Link></li>
|
||||
<li><Link href="/career">Careers</Link></li>
|
||||
<li><Link href="/case-study">Success Stories</Link></li>
|
||||
<li><Link href="/insights">Insights & Blog</Link></li>
|
||||
<li><Link href="/contact-us">Contact Us</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-2 col-md-6">
|
||||
<div className="col-12 col-lg-2 col-md-6 col-sm-6">
|
||||
<div className="footer-section">
|
||||
<h6 className="text-white fm fw-6 mb-24">Services</h6>
|
||||
<h6 className="footer-section-title">Services</h6>
|
||||
<ul className="footer-links">
|
||||
{servicesLoading ? (
|
||||
<>
|
||||
@@ -117,9 +113,9 @@ const Footer = () => {
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-2 col-md-6">
|
||||
<div className="col-12 col-lg-2 col-md-6 col-sm-6">
|
||||
<div className="footer-section">
|
||||
<h6 className="text-white fm fw-6 mb-24">Latest Jobs</h6>
|
||||
<h6 className="footer-section-title">Latest Jobs</h6>
|
||||
<ul className="footer-links">
|
||||
{jobsLoading ? (
|
||||
<>
|
||||
@@ -137,9 +133,9 @@ const Footer = () => {
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-2 col-md-6">
|
||||
<div className="col-12 col-lg-2 col-md-6 col-sm-6">
|
||||
<div className="footer-section">
|
||||
<h6 className="text-white fm fw-6 mb-24">Support</h6>
|
||||
<h6 className="footer-section-title">Support</h6>
|
||||
<ul className="footer-links">
|
||||
<li><Link href="/support-center">Support Center</Link></li>
|
||||
<li><Link href="/policy?type=privacy">Privacy Policy</Link></li>
|
||||
@@ -151,12 +147,16 @@ const Footer = () => {
|
||||
<div className="col-12 col-lg-4 col-md-12">
|
||||
<div className="footer-cta-section">
|
||||
<div className="cta-content">
|
||||
<h6 className="text-white fm fw-6 mb-24">Ready to Transform?</h6>
|
||||
<p className="text-white mb-30">Start your software journey with our incident management and custom development solutions.</p>
|
||||
<Link href="contact-us" className="btn-anim">
|
||||
Start Your Software Journey
|
||||
<i className="fa-solid fa-arrow-trend-up"></i>
|
||||
<span></span>
|
||||
<div className="cta-badge">
|
||||
<i className="fa-solid fa-sparkles"></i>
|
||||
<span>Get Started Today</span>
|
||||
</div>
|
||||
<h6 className="cta-title">Ready to Transform Your Business?</h6>
|
||||
<p className="cta-description">Start your software journey with our enterprise solutions, incident management, and custom development services.</p>
|
||||
<Link href="/contact-us" className="btn-luxury-cta">
|
||||
<span>Start Your Journey</span>
|
||||
<i className="fa-solid fa-arrow-right"></i>
|
||||
<div className="btn-shine"></div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,21 +164,22 @@ const Footer = () => {
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="footer__inner pt-60">
|
||||
<div className="row vertical-column-gap-lg">
|
||||
<div className="footer__inner pt-60 pb-50">
|
||||
<div className="row vertical-column-gap-lg g-4">
|
||||
<div className="col-12 col-md-6 col-lg-4">
|
||||
<div className="footer__inner-single">
|
||||
<div className="thumb">
|
||||
<Image src={location} alt="Image" width={24} height={24} />
|
||||
<div className="contact-icon-wrapper">
|
||||
<div className="contact-icon">
|
||||
<i className="fa-solid fa-location-dot"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className="content">
|
||||
<h5 className="mt-8 fm fw-6 text-white mb-24">
|
||||
Location
|
||||
</h5>
|
||||
<p className="text-quinary">
|
||||
<h5 className="contact-title">Location</h5>
|
||||
<p className="contact-text">
|
||||
<Link
|
||||
href="https://maps.google.com/?q=42.496781103070504,27.4758968970689"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
GNX Soft Ltd.<br />
|
||||
Tsar Simeon I, 56<br />
|
||||
@@ -191,30 +192,33 @@ const Footer = () => {
|
||||
</div>
|
||||
<div className="col-12 col-md-6 col-lg-4">
|
||||
<div className="footer__inner-single">
|
||||
<div className="thumb">
|
||||
<Image src={phone} alt="Image" width={24} height={24} />
|
||||
<div className="contact-icon-wrapper">
|
||||
<div className="contact-icon">
|
||||
<i className="fa-solid fa-phone"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className="content">
|
||||
<h5 className="mt-8 fm fw-6 text-white mb-24">Phone</h5>
|
||||
<p className="text-quinary mb-12">
|
||||
<Link href="tel:+359897338147">+359 897 338 147</Link>
|
||||
<h5 className="contact-title">Phone</h5>
|
||||
<p className="contact-text">
|
||||
<Link href="tel:+359896138030">+359 896 13 80 30</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-6 col-lg-4">
|
||||
<div className="footer__inner-single">
|
||||
<div className="thumb">
|
||||
<Image src={gmail} alt="Image" width={24} height={24} />
|
||||
<div className="contact-icon-wrapper">
|
||||
<div className="contact-icon">
|
||||
<i className="fa-solid fa-envelope"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div className="content">
|
||||
<h5 className="mt-8 fm fw-6 text-white mb-24">Email</h5>
|
||||
<p className="text-quinary mb-12 text-lowercase">
|
||||
<h5 className="contact-title">Email</h5>
|
||||
<p className="contact-text">
|
||||
<Link href="mailto:info@gnxsoft.com">
|
||||
info@gnxsoft.com
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,32 +229,36 @@ const Footer = () => {
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="footer-copyright">
|
||||
<div className="row align-items-center vertical-column-gap">
|
||||
<div className="row align-items-center vertical-column-gap g-3">
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="footer__copyright-text text-center text-lg-start">
|
||||
<p className="text-quinary mt-8">
|
||||
<p className="copyright-text">
|
||||
© <span id="copyrightYear">{currentYear}</span>{" "}
|
||||
<Link href="/" className="fw-6">
|
||||
GNX
|
||||
<Link href="/" className="copyright-link">
|
||||
GNX Soft Ltd.
|
||||
</Link>
|
||||
. All rights reserved. GNX Software Solutions.
|
||||
{" "}All rights reserved. Built with excellence.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="social justify-content-center justify-content-lg-end">
|
||||
<div className="social-links justify-content-center justify-content-lg-end">
|
||||
<Link
|
||||
href="https://www.linkedin.com/company/gnxtech"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="LinkedIn"
|
||||
>
|
||||
<i className="fa-brands fa-linkedin"></i>
|
||||
className="social-link"
|
||||
>
|
||||
<i className="fa-brands fa-linkedin-in"></i>
|
||||
</Link>
|
||||
<Link
|
||||
href="https://github.com/gnxtech"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="GitHub"
|
||||
>
|
||||
className="social-link"
|
||||
>
|
||||
<i className="fa-brands fa-github"></i>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { usePathname } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import OffcanvasMenu from "./OffcanvasMenu";
|
||||
import { OffcanvasData } from "@/public/data/offcanvas-data";
|
||||
import { useNavigationServices } from "@/lib/hooks/useServices";
|
||||
|
||||
const Header = () => {
|
||||
@@ -17,26 +16,65 @@ const Header = () => {
|
||||
// Fetch services from API
|
||||
const { services: apiServices, loading: servicesLoading, error: servicesError } = useNavigationServices();
|
||||
|
||||
// Create dynamic navigation data with services from API
|
||||
// Create dynamic navigation data - only use API data, no hardcoded fallback
|
||||
const navigationData = useMemo(() => {
|
||||
const baseNavigation = [...OffcanvasData];
|
||||
|
||||
// Find the Services menu item and update its submenu with API data
|
||||
const servicesIndex = baseNavigation.findIndex(item => item.title === "Services");
|
||||
if (servicesIndex !== -1 && apiServices.length > 0) {
|
||||
baseNavigation[servicesIndex] = {
|
||||
...baseNavigation[servicesIndex],
|
||||
submenu: apiServices.map(service => ({
|
||||
id: service.id + 1000, // Offset to avoid conflicts with existing IDs
|
||||
title: service.title,
|
||||
path: `/services/${service.slug}`,
|
||||
parent_id: baseNavigation[servicesIndex].id,
|
||||
display_order: service.display_order,
|
||||
created_at: service.created_at,
|
||||
updated_at: service.updated_at
|
||||
}))
|
||||
} as any;
|
||||
}
|
||||
const baseNavigation = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Home",
|
||||
path: "/",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "About Us",
|
||||
path: "/about-us",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Services",
|
||||
path: "/services",
|
||||
submenu: apiServices.length > 0
|
||||
? apiServices.map(service => ({
|
||||
id: service.id + 1000,
|
||||
title: service.title,
|
||||
path: `/services/${service.slug}`,
|
||||
display_order: service.display_order,
|
||||
}))
|
||||
: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Case Studies",
|
||||
path: "/case-study",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Insights",
|
||||
path: "/insights",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "Career",
|
||||
path: "/career",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "Support Center",
|
||||
path: "/support-center",
|
||||
submenu: null,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "Contact Us",
|
||||
path: "/contact-us",
|
||||
submenu: null,
|
||||
},
|
||||
];
|
||||
|
||||
return baseNavigation;
|
||||
}, [apiServices]);
|
||||
@@ -189,11 +227,11 @@ const Header = () => {
|
||||
<li>
|
||||
<span className="text-muted">Loading services...</span>
|
||||
</li>
|
||||
) : item.title === "Services" && servicesError ? (
|
||||
) : item.title === "Services" && (servicesError || !item.submenu || item.submenu.length === 0) ? (
|
||||
<li>
|
||||
<span className="text-danger">Failed to load services</span>
|
||||
<span className="text-muted">No data available</span>
|
||||
</li>
|
||||
) : (
|
||||
) : item.submenu ? (
|
||||
item.submenu.map((subItem, subIndex) => (
|
||||
<li key={subIndex}>
|
||||
<Link
|
||||
@@ -208,7 +246,7 @@ const Header = () => {
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
)}
|
||||
) : null}
|
||||
</ul>
|
||||
</li>
|
||||
) : (
|
||||
|
||||
@@ -4,7 +4,6 @@ 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 {
|
||||
@@ -20,7 +19,7 @@ const OffcanvasMenu = ({
|
||||
isOffcanvasOpen,
|
||||
isActive,
|
||||
handleClick,
|
||||
navigationData = OffcanvasData,
|
||||
navigationData = [],
|
||||
servicesLoading = false,
|
||||
servicesError = null
|
||||
}: OffcanvasMenuProps) => {
|
||||
@@ -81,74 +80,80 @@ const OffcanvasMenu = ({
|
||||
</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)}
|
||||
{navigationData.length === 0 ? (
|
||||
<div className="text-center py-5">
|
||||
<p className="text-muted">No data available</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul>
|
||||
{navigationData.map((item, index) =>
|
||||
item.submenu ? (
|
||||
<li
|
||||
className="navbar__item navbar__item--has-children nav-fade"
|
||||
key={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={
|
||||
mounted && pathname === subItem.path
|
||||
? " active-current-sub"
|
||||
: " "
|
||||
}
|
||||
>
|
||||
{subItem.title}
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
<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>
|
||||
)}
|
||||
</ul>
|
||||
</AnimateHeight>
|
||||
</li>
|
||||
) : (
|
||||
<li className="navbar__item nav-fade" key={index}>
|
||||
<Link
|
||||
href={item.path || "#"}
|
||||
className={
|
||||
mounted && pathname === item.path ? " active-current-link" : " "
|
||||
}
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</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 || !item.submenu || item.submenu.length === 0) ? (
|
||||
<li>
|
||||
<span className="text-muted">No data available</span>
|
||||
</li>
|
||||
) : item.submenu ? (
|
||||
item.submenu.map((subItem: any, subIndex: number) => (
|
||||
<li key={subIndex}>
|
||||
<Link
|
||||
href={subItem.path || "#"}
|
||||
className={
|
||||
mounted && pathname === subItem.path
|
||||
? " active-current-sub"
|
||||
: " "
|
||||
}
|
||||
>
|
||||
{subItem.title}
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
) : null}
|
||||
</ul>
|
||||
</AnimateHeight>
|
||||
</li>
|
||||
) : (
|
||||
<li className="navbar__item nav-fade" key={index}>
|
||||
<Link
|
||||
href={item.path || "#"}
|
||||
className={
|
||||
mounted && pathname === item.path ? " active-current-link" : " "
|
||||
}
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -159,7 +164,7 @@ const OffcanvasMenu = ({
|
||||
<div className="contact-methods">
|
||||
<a href="tel:+359896138030" className="contact-item">
|
||||
<i className="fa-solid fa-phone"></i>
|
||||
<span>+359896138030</span>
|
||||
<span>+359 896 13 80 30</span>
|
||||
</a>
|
||||
<a href="mailto:info@gnxsoft.com" className="contact-item">
|
||||
<i className="fa-solid fa-envelope"></i>
|
||||
|
||||
Reference in New Issue
Block a user