2025-12-18 18:47:56 +05:30

135 lines
4.8 KiB
TypeScript

'use client';
import Image from 'next/image';
import { useState, useEffect, useRef } from 'react';
import styles from './StatsCounter.module.css';
export default function StatsCounter() {
const [hasAnimated, setHasAnimated] = useState(false);
const sectionRef = useRef<HTMLElement>(null);
// Stats State
const [counts, setCounts] = useState({
users: 0,
posts: 0,
satisfaction: 0
});
const targets = {
users: 15, // 15K+
posts: 2, // 2M+
satisfaction: 99 // 99%
};
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && !hasAnimated) {
setHasAnimated(true);
}
},
{ threshold: 0.5 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, [hasAnimated]);
useEffect(() => {
if (!hasAnimated) return;
const duration = 2000; // 2s
const steps = 60;
const intervalTime = duration / steps;
let currentStep = 0;
const timer = setInterval(() => {
currentStep++;
const progress = Math.min(currentStep / steps, 1);
// Easing function for smooth count
const easeOutQuart = (x: number) => 1 - Math.pow(1 - x, 4);
const value = easeOutQuart(progress);
setCounts({
users: Math.floor(targets.users * value),
posts: Math.floor(targets.posts * value * 10) / 10, // Keep decimal for smaller numbers if needed, here integers roughly
satisfaction: Math.floor(targets.satisfaction * value)
});
if (currentStep >= steps) clearInterval(timer);
}, intervalTime);
return () => clearInterval(timer);
}, [hasAnimated]);
return (
<section className={styles.statsSection} ref={sectionRef}>
<div className={styles.container}>
<div className={styles.statsGrid}>
{/* Stat 1 */}
<div className={styles.statItem}>
<div className={styles.iconWrapper}>
<div className={styles.iconBg}></div>
<Image
src="/images/home/growing.webp"
alt="Growing Community"
width={38}
height={44}
/>
</div>
<div className={styles.textContent}>
<div className={styles.numberWrapper}>
{hasAnimated ? counts.users : 0}k+
</div>
<p className={styles.label}>Growing Community</p>
</div>
</div>
{/* Stat 2 */}
<div className={styles.statItem}>
<div className={styles.iconWrapper}>
<div className={styles.iconBg}></div>
<Image
src="/images/home/content.webp"
alt="Content Published"
width={38}
height={44}
/>
</div>
<div className={styles.textContent}>
<div className={styles.numberWrapper}>
{hasAnimated ? '2' : '0'}M+
</div>
<p className={styles.label}>Content Published</p>
</div>
</div>
{/* Stat 3 */}
<div className={styles.statItem}>
<div className={styles.iconWrapper}>
<div className={styles.iconBg}></div>
<Image
src="/images/home/approval.webp"
alt="Customer Approval"
width={38}
height={44}
/>
</div>
<div className={styles.textContent}>
<div className={styles.numberWrapper}>
{hasAnimated ? counts.satisfaction : 0}%
</div>
<p className={styles.label}>Customer Approval</p>
</div>
</div>
</div>
</div>
</section>
);
}