Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { useCallback, useEffect, useRef, useState } from "react";
2
3type TimeLeft = {
4 days: number;
5 hours: number;
6 minutes: number;
7 seconds: number;
8};
9
10interface CountdownTimerProps {
11 targetDate: string;
12}
13
14const CountdownTimer = ({ targetDate }: CountdownTimerProps) => {
15 const intervalRef = useRef<NodeJS.Timeout | null>(null);
16 const targetTimeRef = useRef<number>(new Date(targetDate).getTime() - 30000);
17
18 const calculateTimeLeft = useCallback((): TimeLeft => {
19 const now = new Date().getTime();
20 const timeDiff = targetTimeRef.current - now;
21
22 if (timeDiff <= 0) {
23 return { days: 0, hours: 0, minutes: 0, seconds: 0 };
24 }
25
26 const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
27 const hours = Math.floor((timeDiff / (1000 * 60 * 60)) % 24);
28 const minutes = Math.floor((timeDiff / (1000 * 60)) % 60);
29 const seconds = Math.floor((timeDiff / 1000) % 60);
30
31 return { days, hours, minutes, seconds };
32 }, []);
33
34 const [timeLeft, setTimeLeft] = useState<TimeLeft>(calculateTimeLeft);
35
36 useEffect(() => {
37 targetTimeRef.current = new Date(targetDate).getTime() - 30000;
38 setTimeLeft(calculateTimeLeft());
39 }, [targetDate, calculateTimeLeft]);
40
41 useEffect(() => {
42 const updateTimer = () => {
43 const newTimeLeft = calculateTimeLeft();
44 setTimeLeft(newTimeLeft);
45
46 // Stop interval when countdown reaches zero
47 if (
48 newTimeLeft.days === 0 &&
49 newTimeLeft.hours === 0 &&
50 newTimeLeft.minutes === 0 &&
51 newTimeLeft.seconds === 0
52 ) {
53 if (intervalRef.current) {
54 clearInterval(intervalRef.current);
55 intervalRef.current = null;
56 }
57 }
58 };
59
60 intervalRef.current = setInterval(updateTimer, 1000);
61
62 return () => {
63 if (intervalRef.current) {
64 clearInterval(intervalRef.current);
65 intervalRef.current = null;
66 }
67 };
68 }, [calculateTimeLeft]);
69
70 const formatTimeValue = (value: number, label: string): string => {
71 return value > 0 ? `${value}${label} ` : "";
72 };
73
74 return (
75 <span>
76 {formatTimeValue(timeLeft.days, "d")}
77 {formatTimeValue(timeLeft.hours, "h")}
78 {formatTimeValue(timeLeft.minutes, "m")}
79 {formatTimeValue(timeLeft.seconds, "s")}
80 </span>
81 );
82};
83
84export default CountdownTimer;