"use client"; import React, { useState, useCallback } from "react"; import { useTimers, TimerItem } from "../hooks/useTimers"; import { formatTime, copyToClipboard } from "../lib/utils"; const PRESETS = [ { label: "1 min", seconds: 60 }, { label: "3 min", seconds: 180 }, { label: "5 min", seconds: 300 }, { label: "10 min", seconds: 600 }, { label: "15 min", seconds: 900 }, { label: "30 min", seconds: 1800 }, ]; const RADIUS = 54; const CIRCUMFERENCE = 2 * Math.PI * RADIUS; function CircularProgress({ progress, finished, }: { progress: number; finished: boolean; }) { const offset = CIRCUMFERENCE * (1 - Math.max(0, Math.min(1, progress))); return ( {/* Track */} {/* Progress */} 0.25 ? "stroke-sky-500 dark:stroke-cyan-400" : progress > 0.1 ? "stroke-amber-500 dark:stroke-amber-400" : "stroke-red-500 dark:stroke-red-400" }`} /> {/* Glow when close to finish */} {progress <= 0.1 && progress > 0 && ( )} ); } function TimerCard({ timer, onToggle, onReset, onDelete, onCopyFeedback, }: { timer: TimerItem; onToggle: () => void; onReset: () => void; onDelete: () => void; onCopyFeedback: () => void; }) { const time = formatTime(timer.remaining); const progress = timer.duration > 0 ? timer.remaining / timer.duration : 0; return (
{/* Delete button */}
{/* Circular progress */}
{/* Percentage in center */}
{timer.finished ? "Fini !" : `${Math.round(progress * 100)}%`}
{/* Time + controls */}
{timer.label && (

{timer.label}

)} {/* Controls */}
{!timer.finished && ( )}
); } export default function Timer({ onCopyFeedback, }: { onCopyFeedback: () => void; }) { const { timers, addTimer, startTimer, pauseTimer, resetTimer, deleteTimer, toggleTimer, } = useTimers(); const [hours, setHours] = useState(0); const [minutes, setMinutes] = useState(5); const [seconds, setSeconds] = useState(0); const [label, setLabel] = useState(""); const handleAdd = useCallback(() => { const totalMs = (hours * 3600 + minutes * 60 + seconds) * 1000; if (totalMs <= 0) return; const id = addTimer(totalMs, label || `${hours > 0 ? hours + "h " : ""}${minutes > 0 ? minutes + "m " : ""}${seconds > 0 ? seconds + "s" : ""}`.trim()); startTimer(id); setLabel(""); }, [hours, minutes, seconds, label, addTimer, startTimer]); const handlePreset = useCallback( (totalSeconds: number) => { const h = Math.floor(totalSeconds / 3600); const m = Math.floor((totalSeconds % 3600) / 60); const s = totalSeconds % 60; setHours(h); setMinutes(m); setSeconds(s); const id = addTimer(totalSeconds * 1000, `${m > 0 ? m + " min" : ""}${s > 0 ? " " + s + "s" : ""}`); startTimer(id); }, [addTimer, startTimer] ); return (
{/* Timer creation */}
{/* Presets */}
{PRESETS.map((p) => ( ))}
{/* Time input */}
: :
{/* Label input */}
setLabel(e.target.value)} placeholder="Nom du minuteur (optionnel)" className="flex-1 px-3 py-2 rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-sm text-zinc-800 dark:text-zinc-200 placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-sky-500/40 transition-all" onKeyDown={(e) => { if (e.key === "Enter") handleAdd(); }} />
{/* Add button */}
{/* Active timers */} {timers.length > 0 && (

Minuteurs actifs ({timers.length})

{timers.map((timer) => ( toggleTimer(timer.id)} onReset={() => resetTimer(timer.id)} onDelete={() => deleteTimer(timer.id)} onCopyFeedback={onCopyFeedback} /> ))}
)} {/* Empty state */} {timers.length === 0 && (

Sélectionnez un preset ou réglez un temps personnalisé

)}
); } function TimeInput({ value, onChange, max, label, }: { value: number; onChange: (v: number) => void; max: number; label: string; }) { const increment = () => onChange(Math.min(max, value + 1)); const decrement = () => onChange(Math.max(0, value - 1)); return (
{ const v = parseInt(e.target.value) || 0; onChange(Math.max(0, Math.min(max, v))); }} className="w-16 sm:w-20 text-center text-3xl sm:text-4xl font-mono font-bold bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-xl py-2 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-sky-500/40 transition-all" min={0} max={max} /> {label}
); }