brackt/app/components/league/TimezonePromptBanner.tsx
Chris Parsons dbc23f14ce
Add overnight pause for draft timers (#335)
* Add overnight pause feature for draft timers

Protects players from having their pick timer expire while asleep.
Admins configure a nightly window (league-wide or per-user timezone);
the timer freezes during that window while autodraft can still fire.

Fixes #66

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix TS error: guard getUserDisplayName against undefined user

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:31:52 -07:00

72 lines
2.1 KiB
TypeScript

import { useState } from "react";
import { TIMEZONE_OPTIONS } from "~/components/league/TimezoneSelect";
const VALID_TIMEZONES = new Set(
TIMEZONE_OPTIONS.flatMap((g) => g.zones.map((z) => z.value))
);
interface TimezonePromptBannerProps {
/** Called with the saved timezone value after a successful POST. */
onSaved?: (timezone: string) => void;
}
export function TimezonePromptBanner({ onSaved }: TimezonePromptBannerProps) {
const [dismissed, setDismissed] = useState(false);
const [saving, setSaving] = useState(false);
const [saved, setSaved] = useState(false);
if (dismissed || saved) return null;
const detectedTz =
typeof window !== "undefined"
? (() => {
try {
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
return VALID_TIMEZONES.has(tz) ? tz : null;
} catch {
return null;
}
})()
: null;
if (!detectedTz) return null;
const handleSave = async () => {
setSaving(true);
try {
const body = new FormData();
body.set("timezone", detectedTz);
const res = await fetch("/api/user/timezone", { method: "POST", body });
if (res.ok) {
setSaved(true);
onSaved?.(detectedTz);
}
} finally {
setSaving(false);
}
};
return (
<div className="flex items-center justify-between gap-3 px-4 py-2 bg-blue-950/40 border-b border-blue-800/40 text-sm text-blue-200">
<span>
Set your timezone to <strong>{detectedTz}</strong> for overnight pick
protection?
</span>
<div className="flex items-center gap-2 shrink-0">
<button
onClick={handleSave}
disabled={saving}
className="px-3 py-1 rounded bg-blue-700 hover:bg-blue-600 text-white text-xs font-medium disabled:opacity-50"
>
{saving ? "Saving…" : "Save"}
</button>
<button
onClick={() => setDismissed(true)}
className="text-blue-400 hover:text-blue-200 text-xs"
>
Dismiss
</button>
</div>
</div>
);
}