import { Coffee, Snail, Timer, Zap, type LucideIcon } from "lucide-react"; import { GradientIcon } from "~/components/ui/GradientIcon"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "~/components/ui/select"; import { cn } from "~/lib/utils"; // ─── Types & constants ──────────────────────────────────────────────────────── type TimeUnit = "sec" | "min" | "hr"; export const STANDARD_PRESETS: { value: string; label: string }[] = [ { value: "15", label: "15 sec" }, { value: "30", label: "30 sec" }, { value: "60", label: "1 min" }, { value: "90", label: "90 sec" }, { value: "120", label: "2 min" }, { value: "900", label: "15 min" }, { value: "3600", label: "1 hr" }, { value: "7200", label: "2 hr" }, { value: "14400", label: "4 hr" }, { value: "28800", label: "8 hr" }, { value: "43200", label: "12 hr" }, ]; export const CHESS_PRESETS: { value: string; label: string; icon: LucideIcon; desc: string; bankSec: number; incrSec: number; }[] = [ { value: "fast", label: "Fast", icon: Zap, desc: "~1 hour", bankSec: 60, incrSec: 10 }, { value: "standard", label: "Standard", icon: Timer, desc: "~90 minutes", bankSec: 120, incrSec: 15 }, { value: "slow", label: "Slow", icon: Coffee, desc: "~1 week", bankSec: 28800, incrSec: 3600 }, { value: "very-slow", label: "Very Slow", icon: Snail, desc: "~2 weeks", bankSec: 43200, incrSec: 3600 }, ]; export function isSlowPreset(s: string): boolean { return s === "slow" || s === "very-slow"; } // ─── Internal helpers ───────────────────────────────────────────────────────── function secToDisplay(sec: number): [number, TimeUnit] { if (sec >= 3600 && sec % 3600 === 0) return [sec / 3600, "hr"]; if (sec >= 60 && sec % 60 === 0) return [sec / 60, "min"]; return [sec, "sec"]; } function displayToSec(amount: string, unit: TimeUnit): number { const n = parseFloat(amount) || 0; if (unit === "hr") return Math.round(n * 3600); if (unit === "min") return Math.round(n * 60); return Math.round(n); } export function formatSec(sec: number): string { if (sec >= 3600 && sec % 3600 === 0) return `${sec / 3600} hr`; if (sec >= 60 && sec % 60 === 0) return `${sec / 60} min`; return `${sec} sec`; } export function formatDraftSpeed(speed: string, mode: "chess_clock" | "standard"): string { if (mode === "standard") { const s = parseInt(speed, 10); if (s >= 3600) return `${s / 3600} hr`; if (s >= 60) return `${s / 60} min`; return `${s} sec`; } if (speed.startsWith("custom:")) { const [, b, i] = speed.split(":"); return `Custom (${formatSec(parseInt(b, 10))} bank + ${formatSec(parseInt(i, 10))} / pick)`; } const map: Record = { fast: "Fast (1 min + 10 sec)", standard: "Standard (2 min + 15 sec)", slow: "Slow (8 hr + 1 hr)", "very-slow": "Very Slow (12 hr + 1 hr)", }; return map[speed] ?? speed; } // ─── Component ──────────────────────────────────────────────────────────────── export interface DraftSpeedPickerProps { timerMode: "chess_clock" | "standard"; value: string; onChange: (v: string) => void; disabled?: boolean; } export function DraftSpeedPicker({ timerMode, value, onChange, disabled }: DraftSpeedPickerProps) { const isStdPreset = STANDARD_PRESETS.some((p) => p.value === value); const isChessPreset = CHESS_PRESETS.some((p) => p.value === value); const isCustom = timerMode === "standard" ? !isStdPreset : !isChessPreset; // Derive display values from value prop so they always stay in sync. const stdCustomSec = timerMode === "standard" && isCustom ? (parseInt(value, 10) || 90) : 90; const [stdCustomAmt, stdCustomUnit] = secToDisplay(stdCustomSec); const chessCustomParts = value.startsWith("custom:") ? value.split(":") : []; const bankSec = chessCustomParts.length === 3 ? (parseInt(chessCustomParts[1], 10) || 120) : 120; const incrSec = chessCustomParts.length === 3 ? (parseInt(chessCustomParts[2], 10) || 15) : 15; const [bankAmt, bankUnit] = secToDisplay(bankSec); const [incrAmt, incrUnit] = secToDisplay(incrSec); if (timerMode === "standard") { return (
{STANDARD_PRESETS.map((p) => ( ))}
{isCustom && (
onChange(String(displayToSec(e.target.value, stdCustomUnit) || 90))} className="w-24" /> onChange(String(displayToSec(String(stdCustomAmt), u) || 90))} disabled={disabled} /> per pick
)}
); } return (
{CHESS_PRESETS.map((p) => { const selected = value === p.value; return ( ); })}
{isCustom && (
onChange(`custom:${displayToSec(e.target.value, bankUnit) || 120}:${incrSec}`)} className="w-20" /> onChange(`custom:${displayToSec(String(bankAmt), u) || 120}:${incrSec}`)} disabled={disabled} />
onChange(`custom:${bankSec}:${displayToSec(e.target.value, incrUnit) || 15}`)} className="w-20" /> onChange(`custom:${bankSec}:${displayToSec(String(incrAmt), u) || 15}`)} disabled={disabled} />
)}
); } function UnitSelect({ value, onChange, disabled }: { value: TimeUnit; onChange: (v: TimeUnit) => void; disabled?: boolean }) { return ( ); }