'use client' import { useMemo, useState } from 'react' import { cn } from '@/lib/utils' import { useLanguage } from '@/lib/i18n' interface HeatmapDay { date: string count: number } interface RevisionHeatmapProps { data: HeatmapDay[] className?: string } function intensityClass(count: number, max: number): string { if (count <= 0) return 'bg-black/[0.06] dark:bg-white/[0.08]' const ratio = count / Math.max(max, 1) if (ratio >= 0.75) return 'bg-brand-accent' if (ratio >= 0.5) return 'bg-brand-accent/70' if (ratio >= 0.25) return 'bg-brand-accent/40' return 'bg-brand-accent/20' } function resolveDateLocale(langCode: string): string { if (langCode === 'fa') return 'fa-IR-u-ca-persian-nu-arabext' return langCode } export function RevisionHeatmap({ data, className }: RevisionHeatmapProps) { const { t, language } = useLanguage() const [hovered, setHovered] = useState<{ label: string; count: number; date: string } | null>(null) const [selected, setSelected] = useState<{ label: string; count: number; date: string } | null>(null) const dateLocale = resolveDateLocale(language ?? 'en') const { cells, maxCount, totalReviews, monthLabels } = useMemo(() => { const map = new Map(data.map((d) => [d.date, d.count])) const now = new Date() // todayUTC est le début de la journée courante à minuit UTC const todayUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())) const cells: { date: string; count: number; label: string }[] = [] const monthLabels: { index: number; label: string }[] = [] let lastMonth = -1 for (let i = 89; i >= 0; i--) { const d = new Date(todayUTC) d.setUTCDate(d.getUTCDate() - i) const key = d.toISOString().slice(0, 10) const count = map.get(key) || 0 const month = d.getUTCMonth() if (month !== lastMonth) { monthLabels.push({ index: 89 - i, label: d.toLocaleDateString(dateLocale, { month: 'short', timeZone: 'UTC' }), }) lastMonth = month } cells.push({ date: key, count, label: d.toLocaleDateString(dateLocale, { weekday: 'long', day: 'numeric', month: 'long', timeZone: 'UTC' }), }) } const maxCount = Math.max(1, ...cells.map((c) => c.count)) const totalReviews = cells.reduce((s, c) => s + c.count, 0) return { cells, maxCount, totalReviews, monthLabels } }, [data, dateLocale]) const pct = (index: number) => `${(index / 90) * 100}%` const activeInfo = hovered || selected return (
{t('flashcards.heatmapTitle')}
{totalReviews > 0 ? `${totalReviews} révisions · 90 jours` : t('flashcards.heatmapLast90')}{activeInfo.count > 0 ? `${activeInfo.count} révision${activeInfo.count > 1 ? 's' : ''}` : 'Aucune révision'} · {activeInfo.label} {selected?.date === activeInfo.date && !hovered && ( sélectionné )}
) : (Survolez ou cliquez sur un carré pour voir le détail
)} {selected && ( )}