import React, { useState, useEffect, useMemo, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
const AnimatedDigit = ({ value }) => (
<div
style={{
position: "relative",
width: "0.6em",
height: "1.2em",
display: "inline-block",
overflow: "hidden",
}}
>
<AnimatePresence mode="wait">
<motion.span
key={value}
initial={{ y: "100%", filter: "blur(5px)" }}
animate={{ y: 0, filter: "blur(0px)" }}
exit={{ y: "-100%", filter: "blur(5px)" }}
transition={{ duration: 0.3, ease: "easeInOut" }}
style={{
position: "absolute",
left: 0,
right: 0,
top: 0,
bottom: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{value}
</motion.span>
</AnimatePresence>
</div>
);
const useCountdown = (targetDate) => {
const [timeLeft, setTimeLeft] = useState({});
useEffect(() => {
const calculateTimeLeft = () => {
const difference = +new Date(targetDate) - +new Date();
if (difference > 0) {
return {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60),
};
}
return {};
};
setTimeLeft(calculateTimeLeft());
const timer = setInterval(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
return () => clearInterval(timer);
}, [targetDate]);
return timeLeft;
};
const TimeUnit = React.memo(({ interval, value }) => (
<div className="flex flex-col items-center bg-secondary p-4 rounded-lg">
<div className="text-4xl font-bold text-foreground px-2">
{String(value)
.padStart(2, "0")
.split("")
.map((digit, index) => (
<AnimatedDigit key={`${interval}-${index}`} value={digit} />
))}
</div>
<span className="text-sm text-foreground">{interval}</span>
</div>
));
const Countdown = ({ targetDate }) => {
const timeLeft = useCountdown(targetDate);
const timeUnits = useMemo(() => Object.entries(timeLeft), [timeLeft]);
return (
<div className="flex justify-center items-center space-x-4">
{timeUnits.map(([interval, value]) => (
<TimeUnit key={interval} interval={interval} value={value} />
))}
</div>
);
};
export default Countdown;