Say how often, and say what a reschedule costs

Occurrence ids carry their own start day, so moving the anchor or the
interval re-keys every occurrence and the marks under the old ids stop
being reachable. Nothing is rewritten — removeEvent makes the same trade,
and useMarkSet never removes because nothing else holds a copy — but the
reader is told the count first, the way removeGame reports blockedBy
instead of cascading.

Informs, never blocks. Renaming still costs nothing: the token is random
precisely so fixing a typo never moves an id, and movesOccurrences is what
keeps the warning off a rename and off a bare change of `until`.

cadenceLabel sits beside the form's own vocabulary so the sheet cannot
describe a rule differently from the control that set it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5 committed 2026-08-28 05:04:39 +02:00
1 parent c161c4a0dc
commit c5c578ae7e
4 files changed
+141 -15

No files matched your search

+7 -1
View File
@@ -7,7 +7,7 @@ import {
type LaneId,
} from "../../shared/custom.ts";
import type { EventDraft } from "../state/useCustom.ts";
import { EventForm } from "./CustomForms.tsx";
import { cadenceLabel, EventForm } from "./CustomForms.tsx";
import {
formatAbsolute,
formatRemaining,
@@ -76,6 +76,7 @@ export function EventDetail({
games: CustomGames;
onSave: (id: string, draft: EventDraft) => void;
onDelete: (id: string) => void;
strandedBy: (draft: EventDraft) => number;
}
| undefined;
}) {
@@ -159,6 +160,10 @@ export function EventDetail({
<Field label="Type">{event.type}</Field>
</dl>
{cadenceLabel(own?.record.repeat ?? null) !== null && (
<p className="text-xs text-faint">{cadenceLabel(own!.record.repeat)}</p>
)}
{risk !== "fine" && effort !== undefined && clock.msRemaining !== null && (
<p
className="mt-4 rounded-lg border px-3 py-2 text-xs leading-relaxed"
@@ -241,6 +246,7 @@ export function EventDetail({
setEditing(false);
}}
onCancel={() => setEditing(false)}
strandedBy={own.strandedBy}
/>
) : (
<div className="flex gap-2">