forked from TanStack/tanstack.com
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCountdownTimerSmall.tsx
More file actions
83 lines (70 loc) · 2.36 KB
/
CountdownTimerSmall.tsx
File metadata and controls
83 lines (70 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { Fragment, useEffect, useState } from 'react'
interface CountdownProps {
targetDate: string // YYYY-MM-DD format
}
interface TimeLeft {
days: number
hours: number
minutes: number
}
function calculateTimeLeft(targetDate: string): TimeLeft {
const target = new Date(`${targetDate}T00:00:00-08:00`)
const now = new Date()
const difference = +target - +now
if (difference <= 0) {
return {
days: 0,
hours: 0,
minutes: 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),
}
}
const formatNumber = (number: number) => number.toString().padStart(2, '0')
const Countdown: React.FC<CountdownProps> = ({ targetDate }) => {
const [timeLeft, setTimeLeft] = useState<TimeLeft>(
calculateTimeLeft(targetDate)
)
useEffect(() => {
const timer = setInterval(() => {
const newTimeLeft = calculateTimeLeft(targetDate)
setTimeLeft(newTimeLeft)
if (
newTimeLeft.days === 0 &&
newTimeLeft.hours === 0 &&
newTimeLeft.minutes === 0
) {
clearInterval(timer)
}
}, 1000)
return () => clearInterval(timer)
}, [targetDate])
if (timeLeft.days === 0 && timeLeft.hours === 0 && timeLeft.minutes === 0) {
return null
}
return (
<div className="countdown flex gap-1.5 justify-center">
{['days', 'hours', 'minutes'].map((unit, index) => (
<Fragment key={unit}>
{index > 0 && (
<span className="h-[1.4em] grid place-content-center">:</span>
)}
<div className={`${unit} grid grid-cols-2 gap-x-1 gap-y-1.5`}>
<span className="h-[1.8em] w-[1.7em] grid place-content-center rounded-sm bg-gray-200 bg-opacity-75 dark:bg-gray-600 dark:bg-opacity-50 text-sm font-semibold">
{formatNumber(timeLeft[unit as keyof TimeLeft]).charAt(0)}
</span>
<span className="h-[1.8em] w-[1.7em] grid place-content-center rounded-sm bg-gray-200 bg-opacity-75 dark:bg-gray-600 dark:bg-opacity-50 text-sm font-semibold">
{formatNumber(timeLeft[unit as keyof TimeLeft]).charAt(1)}
</span>
<p className="col-span-full text-[.65rem]">{unit}</p>
</div>
</Fragment>
))}
</div>
)
}
export default Countdown