"use client"; import Link from "next/link"; import { useEffect, useState } from "react"; import { todayISO } from "@/lib/rng"; import { GAME_META, GAMES, GameId } from "@/lib/levels"; import { allStats, GameStats } from "@/lib/progress"; const GAME_SYMBOL: Record = { queens: "♛", tango: "☀", zip: "∞", sudoku: "#", patches: "▦", }; // Check if today's daily puzzle is already solved from localStorage const DAILY_STORAGE_KEY: Record string> = { queens: d => `queens-${d}`, tango: d => `tango-${d}`, zip: d => `zip-${d}`, sudoku: d => `sudoku-${d}`, patches: d => `patches-${d}`, }; function isDailySolved(game: GameId, date: string): boolean { if (typeof window === "undefined") return false; try { const s = localStorage.getItem(DAILY_STORAGE_KEY[game](date)); if (!s) return false; // Check stats — if lastDate matches today, it was solved const stats = localStorage.getItem(`stats-${game}`); if (stats) { const parsed = JSON.parse(stats); if (parsed.lastDate === date) return true; } return false; } catch { return false; } } function fmt(s: number): string { return `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`; } function ProgressBar({ pct, color }: { pct: number; color: string }) { return (
); } function SkeletonCard() { return
; } export default function Home() { const today = todayISO(); const [stats, setStats] = useState | null>(null); const [solvedToday, setSolvedToday] = useState>({} as Record); useEffect(() => { const refresh = () => { setStats(allStats()); const solved = {} as Record; for (const g of GAMES) solved[g] = isDailySolved(g, today); setSolvedToday(solved); }; refresh(); window.addEventListener("focus", refresh); document.addEventListener("visibilitychange", refresh); return () => { window.removeEventListener("focus", refresh); document.removeEventListener("visibilitychange", refresh); }; }, [today]); const dateLabel = new Date(today + "T00:00:00").toLocaleDateString("fr-FR", { weekday: "long", day: "numeric", month: "long", }); const allSolvedToday = GAMES.every(g => solvedToday[g]); const totalSolvedToday = GAMES.filter(g => solvedToday[g]).length; return (
{/* Header */}

Puzzle Trainer

{dateLabel}

{totalSolvedToday > 0 && (
{totalSolvedToday}/5 aujourd'hui {allSolvedToday && ( ✓ Tous faits ! )}
)}
{/* Daily puzzles */}

Puzzle du jour

{GAMES.map((game) => { const { name, accent, desc } = GAME_META[game]; const solved = solvedToday[game]; return ( {/* Solved badge */} {solved && ( )}
{name} {GAME_SYMBOL[game]}

{desc}

{solved && ( Résolu aujourd'hui )} ); })}
{/* Progression */}

Progression

100 niveaux par jeu
{GAMES.map((game) => { const { name, accent } = GAME_META[game]; const s = stats?.[game]; const pct = s?.pct ?? 0; const label = !s || s.completed === 0 ? "Commencer" : `Niv. ${s.nextLevel}`; return (
{name}
{s ? ( <>
{s.completed} / 100 {s.bestTime > 0 && ( ⏱ {fmt(s.bestTime)} )}
) : (
)}
{label}
); })}
Archives des puzzles quotidiens →
); }