'use client' import { useEffect, useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Sparkles } from 'lucide-react' interface Countdown { id: string label: string date: string emoji?: string color?: string note?: string } interface Computed { id: string label: string emoji?: string days: number accent: string dateStr: string } const ROTATE_MS = 8_000 function resolveColor(c: Countdown): string { if (!c.color) return 'var(--data-violet)' if (c.color.startsWith('#')) return c.color // токен вида "data-rose" → "var(--data-rose)" return `var(--${c.color})` } function formatDate(iso: string): string { try { return new Date(iso + 'T00:00:00').toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', }) } catch { return iso } } function daysFromNow(iso: string): number { const target = new Date(iso + 'T00:00:00').getTime() const today = new Date() today.setHours(0, 0, 0, 0) return Math.ceil((target - today.getTime()) / 86_400_000) } function pluralizeDays(n: number): string { const a = Math.abs(n) if (a % 10 === 1 && a % 100 !== 11) return 'день' if ([2, 3, 4].includes(a % 10) && ![12, 13, 14].includes(a % 100)) return 'дня' return 'дней' } export default function CountdownCard() { const [items, setItems] = useState([]) const [idx, setIdx] = useState(0) const [loading, setLoading] = useState(true) useEffect(() => { let cancelled = false fetch('/api/countdowns') .then(r => r.json()) .then(d => { if (cancelled) return const list: Countdown[] = d.countdowns || [] const computed = list .map(c => ({ id: c.id, label: c.label, emoji: c.emoji, days: daysFromNow(c.date), accent: resolveColor(c), dateStr: formatDate(c.date), })) .filter(c => c.days >= 0) // прошедшие скрываем .sort((a, b) => a.days - b.days) setItems(computed) }) .catch(() => {}) .finally(() => { if (!cancelled) setLoading(false) }) return () => { cancelled = true } }, []) useEffect(() => { if (items.length <= 1) return const t = setInterval(() => setIdx(i => (i + 1) % items.length), ROTATE_MS) return () => clearInterval(t) }, [items.length]) if (loading) { return (
) } if (items.length === 0) { return (
Отсчёт
Добавь в настройках — отпуск, др, дедлайн.
) } const current = items[Math.min(idx, items.length - 1)] const imminent = current.days <= 3 const soon = current.days <= 7 return (
Отсчёт {items.length > 1 && (
{items.map((_, i) => (
))}
)}
{current.days === 0 ? 'сегодня' : current.days}
{current.days > 0 && (
{pluralizeDays(current.days)}
)}
{current.emoji && {current.emoji}} {current.label}
{current.dateStr}
) }