Skip to content

Remove a whole day from the draft review page, with Undo - #536

Closed
richshaw wants to merge 3 commits into
claude/issue-504-edit-slotfrom
claude/issue-504-remove-day
Closed

richshaw wants to merge 3 commits into
claude/issue-504-edit-slotfrom
claude/issue-504-remove-day

Conversation

@richshaw

@richshaw richshaw commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Part of #504 (part 2 of 3; part 1 is #535, "People for each slot" comes next). Part of #498. Stacked on #535; the diff here is only Remove day.

What changes

When a draft's slots are grouped by a date field, each day on the review page has Remove day. It removes that day and all its slots, then says "Removed Thu, Jun 6 and its 2 slots." with Undo, which puts them all back.

  • Where it sits: the button is at the top of the day's group, not inside the group's header. A button inside <summary> would toggle the group, and axe flags it as nested-interactive.
  • Name: its accessible name is "Remove day: Thu, Jun 6".
  • Where it doesn't show: there's no button on an ungrouped page, on a group by a non-date field, or on the "(no date)" group. It isn't offered when that day's slots are the only ones with anything filled in, because removing it would send the draft back to the builder and lose Undo.
  • An open slot saves first: any slot editor that's open (Change a slot from the draft review page #535) is saved before Remove day, a one-tap fix or Undo runs. If that save is refused, the change doesn't run.

How it works

  • One Undo line for the card. The status line, Undo, error and focus handling moved out of NoticeFixes into a small provider, ReviewChanges.tsx. The notices' one-tap fixes and Remove day share one line and one last-action Undo. A Remove day refusal shows under the button that was pressed.
  • Same path as the fixes. removeDayAction goes through runFix to removeDraftDay in src/services/draft-fixes.ts, which:
    • shares loadDraft, so it works on drafts only and refuses viewers;
    • compares a fingerprint of the day's slots, as the page showed them, with the day on fresh data. If they differ: "That changed since you opened this page, so nothing was done."
  • All-or-nothing delete. The new deleteDraftSlots service in src/services/slots.ts runs in one transaction. It re-checks under the signup lock that the signup is still a draft, so a publish landing mid-way loses nothing. It refuses unknown or booked slots and writes one slot.deleted row { bulk: true, slotIds, count }. "Remove it" (empty slots, Fix four kinds of draft problem in one tap on the review page, with Undo #533) uses it too, so neither can stop partway.
  • Undo goes through undoDraftFixAction like every fix and restores through addSlotsBulk, closing again any slots that were closed. It's refused ("That changed again since…") when the date field is gone or no longer a date, or any slot is on that date again. That last check also stops a second Undo.
  • One grouping rule. The group-key rule is now groupKeyOf in src/lib/slot-label.ts, and formatGroupLabel moved beside it, so the page, the button and the server group and name days the same way.
  • Telemetry. review.slots_edited { kind: 'remove_day' } is written after a Remove day, and Undo writes review.fix_undone { kind: 'remove_day' }. docs/telemetry.md and the privacy page say so.

Budget

/app/signups/[id]: 114 → 115 kB (measured 114.5). The first load now includes the button and the shared change line that moved out of the notices' island.

Help

"Create and publish your first signup": "If your slots are grouped by date, choose Remove day under a date to remove it and all its slots. Right after, Undo puts them back." A new walkthrough test removes a day, checks that its rows are gone and that Undo has focus, then undoes and reloads.

Checks

  • pnpm lint && pnpm typecheck && pnpm knip && pnpm test: pass (1550)
  • pnpm test:db: pass (611), including the new delete service's tests and the action tests
  • pnpm build && pnpm budgets: pass
  • Full e2e (chromium): 64 passed

Tophat and the code-review fixes are in the comments.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm

On a review page grouped by a date field, each date's group now has
Remove day, which deletes that date's slots, folded or not. The page then
says "Removed Sat, Apr 6 and its 4 slots." with Undo, which puts the slots
back with their values, spots, places and closed state.

The notices' one-tap fixes and Remove day now share one status line and one
Undo, for whichever was last: a small client provider around the card's
notices and slot list holds it, lifted out of NoticeFixes, while the rows
stay server-rendered.

Remove day is offered only for a group with a date, of up to 500 slots, and
not for a date whose slots are the only filled-in ones, as the draft would
then open in the builder and lose its Undo. The server finds the day again
on fresh data by the same rule the page groups by, and removes nothing
unless it has exactly the slots the page showed, so a slot moved or added
there meanwhile, by another tab or an AI assistant, is refused. Slots are
deleted through the per-slot loop the empty-slot fix already used, now
shared, and Undo goes through the same undo action as a fix. It refuses
once the date field is gone or no longer a date, or a slot is on that date
again. A slot editor left open on a removed day closes.

Undo writes review.fix_undone with kind remove_day; the remove itself is
recorded by each slot's slot.deleted row. The help page names the button
and its walkthrough removes a date and undoes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
The page's first load grows from 113.7 to 114.1 kB with the Remove day
button and the shared change line it moves out of the notices' island,
so its budget goes from 114 to 115 kB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
…-page change

Code-review fixes for Remove day.

Slots now go all together or not at all. A new service, deleteDraftSlots,
deletes several of a draft's slots in one transaction under the signup lock.
It refuses a signup that is no longer a draft, including one published
while it waited, a slot that isn't the signup's any more, and any slot
someone has signed up for, and writes one slot.deleted row with a bulk
payload. Remove day and the empty-slot fix both use it, so neither can stop
partway any more, and the "Removed 2 of the 4 slots" wording is gone.

The page no longer sends every slot id of a day. It sends a short
fingerprint of them, which the server works out again from the slots as
they are now. The day is named by the group header's own formatter, now
shared from src/lib/slot-label.ts, for both the button's name and the done
text, and the request reuses the slot-field RefSchema.

A slot left open with unsaved changes is saved before a fix, Remove day or
Undo is made, as choosing another slot saves it. If that save is refused,
the slot stays open saying why and the change isn't made. The slot list
closes an open slot whose row is missing only when every row is drawn, so
a slot that is merely folded away stays open.

A refused Remove day now says why under its own button and takes focus. If
the day has gone from the page that came back, the message moves to the
card's line.

Remove day records a new review.slots_edited event with kind remove_day,
next to its Undo's review.fix_undone. The telemetry doc, the privacy page
and the changelog say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm

Copy link
Copy Markdown
Owner Author

Tophat: pass, in the running app with made-up data (pat@example.com). The draft is grouped by date: Thu, Jun 6 has Front desk and Story time; Thu, Jun 13 has two more.

  • Remove day on Jun 6 gives "Removed Thu, Jun 6 and its 2 slots." with focus on Undo. Undo brings back the day and its 2 slots, then says "Undone." with focus on that line. (8dcd11c)
  • An open, changed slot saves before Remove day runs. With "Front desk" open and set to 5, Remove day on Jun 13 first saves the edit (Front desk now shows "5 people"), then removes Jun 13. Undo puts Jun 13 back. Before the review fixes, the open edit could be thrown away. (a120590)
  • Activity rows:
    • Remove day writes one slot.deleted with { bulk: true, count: 2, slotIds, commitmentsRemoved: 0 }, then review.slots_edited {kind: remove_day}.
    • Undo writes one bulk slot.created, then review.fix_undone {kind: remove_day}.
  • No console errors.

Code review on this PR. Fixed in a120590:

  • All-or-nothing delete. A new deleteDraftSlots service runs in one transaction. It re-checks that the signup is a draft under the signup lock (a publish landing mid-way is refused), refuses unknown or booked slots, and writes one slot.deleted row. Remove day and "Remove it" both use it, so partial removals, the Undo that could never run after one, and the "Removed 2 of the 4" wording are gone.
  • Save first. An open slot editor saves before any fix, Remove day or Undo. If that save is refused, the change doesn't run. A row that is only folded away keeps its editor open.
  • Less sent to the browser. The button sends a fingerprint of the day's slots, not every slot id.
  • Refusals where you pressed. A Remove day refusal shows under the button that was pressed and takes focus.
  • review.slots_edited {kind} records Remove day. docs/telemetry.md and the privacy page are updated.
  • Shared formatting. It reuses RefSchema, and one day label (formatGroupLabel) feeds both the button's name and the done text.

Checks on a120590: lint, typecheck, knip, unit (1550), test:db (611), build + budgets (/app/signups/[id] 114.5 / 115 kB), e2e 64/64.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Closing without merging, as part of the redesign in #498. The branch stays: deleteDraftSlots and the remove-day service and their tests are meant to be reused.


Generated by Claude Code

@richshaw richshaw closed this Oct 22, 2026
@richshaw
richshaw removed this pull request from stack #549 October 23, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants