diff --git a/src/client/components/Controls.tsx b/src/client/components/Controls.tsx index 66ba1b0..d308113 100644 --- a/src/client/components/Controls.tsx +++ b/src/client/components/Controls.tsx @@ -1,14 +1,13 @@ import type { LaneId } from "../../shared/custom.ts"; import type { Region } from "../../shared/schema.ts"; +import { REGION_LABEL } from "../../shared/time.ts"; import { useGameMeta } from "../state/gameMeta.tsx"; import type { Prefs } from "../state/usePrefs.ts"; import { YourOwn } from "./YourOwn.tsx"; -const REGIONS: Array<{ id: Region; label: string }> = [ - { id: "america", label: "America" }, - { id: "europe", label: "Europe" }, - { id: "asia", label: "Asia" }, -]; +const REGIONS: Array<{ id: Region; label: string }> = ( + ["america", "europe", "asia"] as const +).map((id) => ({ id, label: REGION_LABEL[id] })); export function Controls({ games, diff --git a/src/client/components/EventDetail.tsx b/src/client/components/EventDetail.tsx index 38176c8..febf37e 100644 --- a/src/client/components/EventDetail.tsx +++ b/src/client/components/EventDetail.tsx @@ -8,7 +8,11 @@ import { } from "../../shared/custom.ts"; import type { EventDraft } from "../state/useCustom.ts"; import { EventForm } from "./CustomForms.tsx"; -import { formatAbsolute, formatRemaining } from "../../shared/time.ts"; +import { + formatAbsolute, + formatRemaining, + REGION_LABEL, +} from "../../shared/time.ts"; import type { RowEvent } from "./EventRow.tsx"; import { pressure, pressureReason, type Effort } from "../../shared/effort.ts"; import type { Status } from "../state/useProgress.ts"; @@ -132,14 +136,17 @@ export function EventDetail({
+ {/* Off the clock, not off the event: a day-precision boundary is + resolved to the game's reset there, and printing the stored + 00:00Z instead would name a different day to the countdown. */} - {formatAbsolute(event.startsAt, event.startPrecision === "exact")} + {formatAbsolute(clock.startsMs, event.startPrecision === "exact")} - {event.endsAt === null ? ( + {clock.endsMs === null ? ( Not announced ) : ( - formatAbsolute(event.endsAt, event.endPrecision === "exact") + formatAbsolute(clock.endsMs, event.endPrecision === "exact") )} @@ -267,8 +274,10 @@ export function EventDetail({ {event.endPrecision === "day" && event.endsAt !== null && (

- The source gave a date but no time of day, so this end is accurate to - the day only. Check in-game before the last hours. + The source gave a date but no time of day, so this counts down to + that day's {REGION_LABEL[region]} server reset — where these usually land, but a + reading rather than a stated time. Check in-game before the last + hours.

)} diff --git a/src/shared/time.ts b/src/shared/time.ts index 430b394..67bbbfc 100644 --- a/src/shared/time.ts +++ b/src/shared/time.ts @@ -21,6 +21,13 @@ export const REGION_RESET_UTC_OFFSET: Record = { europe: 1, }; +/** What a region is called when the reader is shown one. */ +export const REGION_LABEL: Record = { + america: "America", + europe: "Europe", + asia: "Asia", +}; + /** * Gacha servers roll the day at 04:00 local server time, not midnight — a * player finishing at 02:00 is still on the previous day's dailies. Getting @@ -224,8 +231,16 @@ export function formatRemaining(msRemaining: number): string { return `${seconds}s`; } -/** Absolute date for the detail view, in the reader's own timezone. */ -export function formatAbsolute(iso: string, withTime: boolean): string { +/** + * Absolute date for the detail view, in the reader's own timezone. + * + * Takes an instant rather than only an ISO string so a caller with a resolved + * boundary can print the one the countdown is counting to. A day-precision date + * read straight off the event says 00:00Z, which renders as the *previous* day + * to every reader west of UTC — the sheet would then name one day while the + * timer beside it ran to another. + */ +export function formatAbsolute(iso: string | number, withTime: boolean): string { const d = new Date(iso); const date = d.toLocaleDateString(undefined, { weekday: "short",