146 lines
4.8 KiB
TypeScript
146 lines
4.8 KiB
TypeScript
import { useEffect, useRef, useState } from 'react'
|
|
import { statsData, serviceListData, commonDescriptions } from '../../data/siteData'
|
|
|
|
function useCountUp(end: number, duration: number = 2000, startCounting: boolean = false) {
|
|
const [count, setCount] = useState(0)
|
|
|
|
useEffect(() => {
|
|
if (!startCounting) return
|
|
|
|
let startTime: number
|
|
let animationFrame: number
|
|
|
|
const animate = (currentTime: number) => {
|
|
if (!startTime) startTime = currentTime
|
|
const progress = Math.min((currentTime - startTime) / duration, 1)
|
|
setCount(Math.floor(progress * end))
|
|
|
|
if (progress < 1) {
|
|
animationFrame = requestAnimationFrame(animate)
|
|
}
|
|
}
|
|
|
|
animationFrame = requestAnimationFrame(animate)
|
|
return () => cancelAnimationFrame(animationFrame)
|
|
}, [end, duration, startCounting])
|
|
|
|
return count
|
|
}
|
|
|
|
function StatItem({ value, label, startCounting }: { value: number; label: string; startCounting: boolean }) {
|
|
const count = useCountUp(value, 2000, startCounting)
|
|
return (
|
|
<div className="stats-1-left">
|
|
<h4 className="text-[36px] font-semibold mb-1.5 font-sans" style={{ color: '#ffffff' }}>{count}</h4>
|
|
<h6 className="text-lg" style={{ color: '#ffffff' }}>{label}</h6>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function Stats() {
|
|
const sectionRef = useRef<HTMLElement>(null)
|
|
const [startCounting, setStartCounting] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
if (entries[0].isIntersecting) {
|
|
setStartCounting(true)
|
|
observer.disconnect()
|
|
}
|
|
},
|
|
{ threshold: 0.3 }
|
|
)
|
|
|
|
if (sectionRef.current) {
|
|
observer.observe(sectionRef.current)
|
|
}
|
|
|
|
return () => observer.disconnect()
|
|
}, [])
|
|
|
|
return (
|
|
<section
|
|
ref={sectionRef}
|
|
className="py-16 relative"
|
|
id="stats"
|
|
style={{
|
|
backgroundImage: "url('/src/assets/images/2.jpg')",
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center',
|
|
}}
|
|
>
|
|
{/* Overlay */}
|
|
<div
|
|
className="absolute inset-0 z-0"
|
|
style={{ background: 'rgba(10, 30, 80, 0.92)' }}
|
|
/>
|
|
|
|
<div className="container mx-auto px-4 py-3 relative z-10">
|
|
{/* Section Header */}
|
|
<div className="text-center max-w-3xl mx-auto mb-8">
|
|
<h3 className="text-3xl md:text-4xl font-bold mb-4 font-sans" style={{ color: '#ffffff' }}>
|
|
{commonDescriptions.statsTitle}
|
|
</h3>
|
|
<p className="my-3" style={{ color: '#d0d0d0' }}>
|
|
{commonDescriptions.sectionDesc}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap lg:flex-nowrap gap-12 pt-8 mt-3">
|
|
{/* Left Content */}
|
|
<div className="w-full lg:w-5/12">
|
|
<h4 className="text-[38px] leading-[46px] font-semibold mb-4 font-sans" style={{ color: '#ffffff' }}>
|
|
{commonDescriptions.statsSubtitle}
|
|
</h4>
|
|
<p className="mt-2.5 text-base leading-6" style={{ color: '#d0d0d0' }}>
|
|
{commonDescriptions.statsDesc}
|
|
</p>
|
|
<p className="mt-2.5 text-base leading-6" style={{ color: '#d0d0d0' }}>
|
|
{commonDescriptions.statsDesc2}
|
|
</p>
|
|
|
|
{/* Stats Grid */}
|
|
<div className="grid grid-cols-3 gap-2.5 mt-12">
|
|
{statsData.map((stat) => (
|
|
<StatItem
|
|
key={stat.id}
|
|
value={stat.value}
|
|
label={stat.label}
|
|
startCounting={startCounting}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Content - Service List */}
|
|
<div className="w-full lg:w-7/12 my-8 lg:my-0">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[30px]">
|
|
{serviceListData.map((service) => (
|
|
<div
|
|
key={service.id}
|
|
className="group stats-service-card flex gap-4 p-10 rounded"
|
|
>
|
|
<div className="flex-shrink-0">
|
|
<span className={`fa fa-${service.icon} text-[32px] text-secondary transition-colors duration-300`} />
|
|
</div>
|
|
<div>
|
|
<h6 className="font-bold mb-2.5 service-title">
|
|
<a href="#url" className="text-white group-hover:text-title transition-colors duration-300">
|
|
{service.title}
|
|
</a>
|
|
</h6>
|
|
<p className="text-[15px] leading-[25px] mt-2.5 text-[#d0d0d0] group-hover:text-title transition-colors duration-300">
|
|
{service.description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|