Skip to content

Change a slot from the draft review page - #535

Closed
richshaw wants to merge 5 commits into
claude/issue-503-merge-slotsfrom
claude/issue-504-edit-slot
Closed

richshaw wants to merge 5 commits into
claude/issue-503-merge-slotsfrom
claude/issue-504-edit-slot

Conversation

@richshaw

Copy link
Copy Markdown
Owner

Part of #504 (part 1 of 3: tap a slot to edit it; "Remove day" and "People for each slot", each with Undo, come next). Part of #498. Stacked on #534; the diff here is only slot editing.

What changes

On the review page ("Check your signup, then share it"), each slot row is now a button. Choosing it opens the builder's own SlotEditor under the row, with every field and Capacity:

  • Done saves in one PATCH /api/slots/[id], the route the builder uses. It sends values only when a value changed and capacity only when that changed. It closes once the page has come back from the server, puts focus back on the row, and shows "Saved" beside it.
  • Cancel (or Escape) throws the changes away. Done with nothing changed just closes.
  • One slot is open at a time. Choosing another slot while one is open saves the open one first. If that save is refused, it stays open with the reason.
  • Duplicate and Delete aren't offered here. Adding and removing slots and fields stays in the builder, through "Edit everything in the builder", as the issue says.
  • "Add to list" on a list field saves the new choice through the field route first, as the builder does.

Notes for review

  • One editor, one save path. SlotEditor gains optional onDuplicate/onDelete (hidden when absent), an optional Cancel, and a saving state. The number handling for a slot's values moved into src/components/build-shared/slotValues.ts (toStringValues, toSlotValues, slotPatch), which both the builder and the review page now build their request bodies from, so the two can't send a slot differently. useReviewSave now takes the save function, so the cards and the slot rows share the "save, refresh, then say Saved" behaviour.
  • Nothing is saved until Done. The builder saves 800 ms after typing stops; here an explicit Done means a quick close can't lose an edit, as the issue asks. The page refreshes after every save, so a change an AI assistant made meanwhile shows up.
  • The editor isn't in the first load. ReviewSlotPanel, which brings SlotEditor and the list picker with it, loads on first tap, or when a row is hovered or focused, as the share step loads its QR encoder.
  • Budgets, raised with reasons:
    • /app/signups/[id]: 113 → 114 kB (measured 113.6). The row buttons and the panel's loader are in the first load.
    • /app/signups/[id]/build: 151 → 153 kB (measured 152.4). The Build tab loads the same code as before. Because the review page now loads SlotEditor on demand, webpack moves it into a chunk of its own that both pages share, and two gzipped files cost about 1.4 kB more than one. I checked the new chunk: it holds only the editor and the list picker.
    • /login: 109 → 110 kB. Every page loads webpack's runtime, which lists the async chunks. The new one tipped /login, already at its budget, over by a rounding hair.
  • Telemetry: none new. A save writes slot.updated, as the builder's do. docs/telemetry.md now says the payload doesn't say which page it came from.

Help

"Create and publish your first signup": "To change a slot, choose it. Change what you need, like its date or its Capacity, then choose Done to save it. To close it without saving, choose Cancel." The next step now starts "To add or remove slots, choose Edit everything in the builder". A new walkthrough test sets a slot's Capacity to 3 with Done and checks that it is saved after a reload, then changes another slot and cancels. The review page's screenshot is unchanged.

Checks

  • pnpm lint && pnpm typecheck && pnpm knip && pnpm test: pass (1509)
  • pnpm test:db: pass (592)
  • pnpm build && pnpm budgets: pass with the budgets above
  • Full e2e (chromium): 63 passed

Tophat

In the running app with made-up data:

  • Computer: choosing "Till" opens the editor under it, with focus in the first box. Capacity 2 → 4, then Done: "Saved" shows, the row says "4 people", and focus is back on the row.
  • Cancel: a renamed value is thrown away.
  • Switching rows: with a change typed into one row, choosing the other row saves it ("Cash box") and opens the other.
  • Escape closes the editor.
  • Phone (390×844): the editor stacks its fields, with Cancel and Done at the top.
  • No console errors.

Generated by Claude Code

Each slot on "Check your signup, then share it" is now a button that opens
the builder's own slot editor under it. Done saves the changes in one
PATCH /api/slots/[id], the route the builder uses, sending values only when
a value changed and capacity only when it did, then closes once the page
has refreshed and says Saved beside the slot. Cancel or Escape closes
without saving, and Done with nothing changed just closes. One slot is open
at a time; choosing another saves the open one first. A refusal keeps the
slot open and says why. A new list choice is saved through the field route
first, as in the builder.

The editor loads when a slot is first opened or pointed at, so it stays out
of the page's first load. SlotEditor's Duplicate and Delete are optional
now, with an optional Cancel, and the number handling for a slot's values
moved to slotValues.ts so the builder and the review page send the same
body. useReviewSave takes the function that saves, so the slot editor
shares it with the page's cards.

The help page says how to change a slot there, and its walkthrough changes
one and cancels another. docs/telemetry.md notes that slot.updated doesn't
say which page it came from.

Part of #504.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
The review page's first load grows from 112.7 to 113.6 kB with the slot
rows' buttons and the lazy editor's loader, so its budget goes from 113 to
114 kB. The Build tab loads the same code as before, but now that the
review page loads SlotEditor on demand, webpack moves it into a chunk of
its own that both pages share, and two gzipped files cost about 1.4 kB
more than one: 151.0 to 152.4 kB, so its budget goes from 151 to 153 kB.

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

Every page loads webpack's runtime, which lists the async chunks; the
review page's lazily loaded slot editor adds one. /login was already at
its 109 kB budget and now reads 109.0 kB over it, so its budget goes to
110 kB.

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

A slot's save could move it to another group, such as a new date in a list
grouped by date. Its row was then a new one, and the editor that waited for
the page to refresh before closing went with the old row: the slot stayed
open, empty, with no Saved, focus lost, and a slot chosen meanwhile never
opened. The slot list now does the waiting. The editor only saves and hands
over; the list refreshes the page, then closes the slot or opens the one
chosen meanwhile, says Saved from one live region that stays put, and gives
focus back to the slot's row, opening its group if it is folded, or to the
list if the slot moved past the fold.

Nothing is saved until Done now, list choices included. "Add to list" holds
the new choice in the editor; Done saves it through the field route with
only the list's config, so a field whose type changed meanwhile is refused
rather than changed back, and then saves the slot. Cancel drops it. If the
choice saved but the slot was refused, the page refreshes so the list shows
it.

A row's name for screen readers is now "Edit slot — " and the text the row
shows, plus its group's value in a grouped list, rather than a label that
left the row's other text out. Each row carries its own slot, so only the
rows drawn go to the page's script, and the review page and the builder map
fields through one shared toBuildFields. useReviewSave is back to what the
cards need.

The changelog no longer says a quick close can't lose a change: it says
nothing is saved until Done, that leaving with a slot open and changed drops
the change, and that a save replaces the slot's values whole. The telemetry
doc says each refresh after a save on the review page writes
signup.editor_opened and review.notice_shown again. The walkthrough now also
moves a slot to another date's group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
The test's draft kept the template's empty slot, which grouping by date
put in an open "(no date)" group of its own, leaving the dated groups
folded and their rows out of reach. It now removes the empty slot and
opens the page with every group shown, as Show all does.

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).

  • Computer. Choosing "Till" opens the builder's editor under it, with focus in the first box. Capacity 2 → 4 and Done shows "Saved"; the row reads "4 people" and focus returns to the row.
  • Cancel throws away a renamed value.
  • Switching rows. With a change typed into one row, choosing the other row saves the first and opens the second. Escape closes the editor.
  • A save that moves the slot (on 70f93ac, grouped by date). Changing "Setup crew" from Thu, May 2 to Fri, May 3 and pressing Done closes the editor and shows "Saved". The slot now sits in the Fri, May 3 group (2 slots), with focus on its row. Before the review fixes, this left the editor stuck open.
  • Phone (390×844). The editor stacks its fields, with Cancel and Done at the top. No console errors.

Code review on this PR. Fixed in 4e78ab5:

  • Saving a slot that moves no longer leaves the editor stuck. The list (ReviewSlotEditing) now owns save → refresh → close, so a row that moves to another group comes back closed with "Saved", and its folded group opens to take focus. Two component tests remount the row under a new group key.
  • List choices wait for Done. Cancel and Escape drop them.
  • Add to list sends only { config }, so a stale page can't turn a field back into a list.
  • Row names are an sr-only "Edit slot — " plus the row's visible text and its group's date, so the name contains what's on screen and rows on different days can be told apart.
  • The page sends only the rows it draws, and toBuildFields is now one shared function.
  • Docs. docs/telemetry.md notes that signup.editor_opened/review.notice_shown are written again on each refresh. The CHANGELOG says plainly that nothing is saved until Done, that leaving with an open, changed slot drops the change, and that a save replaces the slot's values whole, as the builder's does.

70f93ac fixes the walkthrough's setup: it removes the template's empty slot and opens every group.

Left as is:

  • No unload or navigation guard for an open, changed slot. Nothing is saved until Done, and the PR and CHANGELOG say so.
  • No per-key merge on PATCH /api/slots/[id]. Last save wins, as in the builder; that's an API change for its own PR.
  • The builder still sends fieldType with Add to list (useBuildState's updateField). That's outside this PR.

Checks.

  • On 70f93ac: the help walkthrough spec, 6/6.
  • On 4e78ab5:
    • lint, typecheck, knip;
    • unit (1514) and test:db (592);
    • build + budgets (/app/signups/[id] 113.7 / 114 kB; /login 109.0 / 110);
    • e2e 62/63, the one failure being the walkthrough setup fixed in 70f93ac.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Closing without merging. If the fixes move into the Build page (#498), slots are already edited there, so this page's editor isn't needed. The branch stays.


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