import useNow from '@/hooks/use-now'; import { Text, Group } from '@mantine/core'; import { useMemo } from 'react'; import { useLingui } from '@lingui/react/macro'; import classes from './countdown.module.css'; interface CountdownProps { date: Date; label?: string; color?: string; } interface TimeLeft { days: number; hours: number; minutes: number; seconds: number; } function calculateTimeLeft(targetDate: Date, currentTime = new Date()): TimeLeft { const difference = targetDate.getTime() - currentTime.getTime(); if (difference <= 0) { return { days: 0, hours: 0, minutes: 0, seconds: 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) }; } const pad = (num: number) => num.toString().padStart(2, '0'); export function Countdown({ date, label, color }: CountdownProps) { const { t } = useLingui(); const now = useNow(); const timeLeft = useMemo(() => calculateTimeLeft(date, now), [date, now]); const totalSecondsLeft = Math.max( 0, Math.floor((date.getTime() - now.getTime()) / 1000) ); const isFinalStretch = totalSecondsLeft > 0 && totalSecondsLeft <= 10; const prefix = timeLeft.days > 0 ? `${t`${timeLeft.days}d`} ${pad(timeLeft.hours)}:${pad(timeLeft.minutes)}:` : `${pad(timeLeft.hours)}:${pad(timeLeft.minutes)}:`; return ( {label && {label}:} {/* Server and client render different seconds; the first client tick corrects it. */} {prefix} {pad(timeLeft.seconds)} ); } export default Countdown;