2026-03-09 20:14:42 +05:30

108 lines
3.2 KiB
TypeScript

"use client";
import React, { useState, useEffect, useRef } from 'react';
interface CounterProps {
end: number;
duration?: number;
}
const Counter: React.FC<CounterProps> = ({ end, duration = 2000 }) => {
const [count, setCount] = useState(0);
const countRef = useRef<HTMLSpanElement>(null);
const [hasStarted, setHasStarted] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setHasStarted(true);
} else {
setHasStarted(false);
setCount(0);
}
},
{ threshold: 0.1 }
);
if (countRef.current) {
observer.observe(countRef.current);
}
return () => observer.disconnect();
}, []);
useEffect(() => {
if (!hasStarted) return;
let startTimestamp: number | null = null;
let animationFrameId: number;
const step = (timestamp: number) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
setCount(Math.floor(progress * end));
if (progress < 1) {
animationFrameId = window.requestAnimationFrame(step);
}
};
animationFrameId = window.requestAnimationFrame(step);
return () => window.cancelAnimationFrame(animationFrameId);
}, [hasStarted, end, duration]);
return <span ref={countRef}>{count}</span>;
};
const counterItems = [
{
icon: "/assets/images/home/5/projects.webp",
count: 100,
suffix: "+",
text: "Projects Completed"
},
{
icon: "/assets/images/home/5/active.webp",
count: 50,
suffix: "+",
text: "Active Clients"
},
{
icon: "/assets/images/home/5/expert.webp",
count: 20,
suffix: "+",
text: "Expert People"
},
{
icon: "/assets/images/home/5/happy.webp",
count: 100,
suffix: "+",
text: "Happy Clients"
}
];
const CounterAreaTwo: React.FC = () => {
return (
<section className="counter-area-two">
<div className="container">
<ul className="counter-area-two__list">
{counterItems.map((item, index) => (
<li key={index} className="counter-area-two__item count-box">
<div className="counter-area-two__icon">
<img src={item.icon} alt={item.text} />
</div>
<div className="counter-area-two__content">
<h3 className="counter-area-two__count">
<Counter end={item.count} />
{item.suffix}
</h3>
<p className="counter-area-two__text">{item.text}</p>
</div>
</li>
))}
</ul>
</div>
</section>
);
};
export default CounterAreaTwo;