152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
"use client";
|
|
import { useState, useEffect } from "react";
|
|
import { usePathname } from "next/navigation";
|
|
import Image from "next/image";
|
|
import "./Preloader.css";
|
|
|
|
interface PreloaderProps {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
const Preloader = ({ children }: PreloaderProps) => {
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isMounted, setIsMounted] = useState(false);
|
|
const [progress, setProgress] = useState(0);
|
|
const pathname = usePathname();
|
|
|
|
// Initial mount - show preloader on first load
|
|
useEffect(() => {
|
|
setIsMounted(true);
|
|
setIsLoading(true);
|
|
setProgress(0);
|
|
|
|
// Simulate loading progress
|
|
const progressInterval = setInterval(() => {
|
|
setProgress((prev) => {
|
|
if (prev >= 90) {
|
|
clearInterval(progressInterval);
|
|
return 90;
|
|
}
|
|
return prev + Math.random() * 15 + 5;
|
|
});
|
|
}, 50);
|
|
|
|
// Complete loading after minimum duration
|
|
const completeTimer = setTimeout(() => {
|
|
setProgress(100);
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
}, 200);
|
|
}, 600);
|
|
|
|
return () => {
|
|
clearInterval(progressInterval);
|
|
clearTimeout(completeTimer);
|
|
};
|
|
}, []);
|
|
|
|
// Handle route changes
|
|
useEffect(() => {
|
|
if (!isMounted) return;
|
|
|
|
// Show preloader on route change
|
|
setIsLoading(true);
|
|
setProgress(0);
|
|
|
|
// Simulate loading progress
|
|
const progressInterval = setInterval(() => {
|
|
setProgress((prev) => {
|
|
if (prev >= 90) {
|
|
clearInterval(progressInterval);
|
|
return 90;
|
|
}
|
|
return prev + Math.random() * 20 + 10;
|
|
});
|
|
}, 40);
|
|
|
|
// Complete loading
|
|
const completeTimer = setTimeout(() => {
|
|
setProgress(100);
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
}, 150);
|
|
}, 400);
|
|
|
|
return () => {
|
|
clearInterval(progressInterval);
|
|
clearTimeout(completeTimer);
|
|
};
|
|
}, [pathname, isMounted]);
|
|
|
|
return (
|
|
<>
|
|
{isLoading && (
|
|
<div className="gnx-preloader-overlay">
|
|
{/* Geometric background pattern */}
|
|
<div className="gnx-preloader-bg-pattern"></div>
|
|
|
|
<div className="gnx-preloader-container">
|
|
{/* Logo with professional wrapper */}
|
|
<div className="gnx-preloader-logo">
|
|
<div className="gnx-logo-wrapper">
|
|
<div className="gnx-logo-border"></div>
|
|
<Image
|
|
src="/images/logo.png"
|
|
alt="GNX Logo"
|
|
width={100}
|
|
height={75}
|
|
className="gnx-logo-image"
|
|
priority
|
|
unoptimized
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Enterprise branding */}
|
|
<div className="gnx-enterprise-brand">
|
|
<h1 className="gnx-brand-title">GNX Enterprise</h1>
|
|
<p className="gnx-brand-subtitle">Digital Transformation Solutions</p>
|
|
</div>
|
|
|
|
{/* Professional progress indicator */}
|
|
<div className="gnx-progress-container">
|
|
<div className="gnx-progress-bar">
|
|
<div
|
|
className="gnx-progress-fill"
|
|
style={{ width: `${progress}%` }}
|
|
>
|
|
<div className="gnx-progress-shine"></div>
|
|
</div>
|
|
</div>
|
|
<div className="gnx-progress-info">
|
|
<span className="gnx-progress-text">Loading</span>
|
|
<span className="gnx-progress-percentage">{Math.round(progress)}%</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Professional loading indicator */}
|
|
<div className="gnx-loading-indicator">
|
|
<div className="gnx-spinner">
|
|
<div className="gnx-spinner-ring"></div>
|
|
<div className="gnx-spinner-ring"></div>
|
|
<div className="gnx-spinner-ring"></div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Corporate footer */}
|
|
<div className="gnx-preloader-footer">
|
|
<p className="gnx-footer-text">Powered by Advanced Technology</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className={isLoading ? "gnx-content-hidden" : "gnx-content-visible"}>
|
|
{children}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Preloader;
|