Skip to content

Show the end screen as the last block of the document - #271

Closed
PhilReinking wants to merge 19 commits into
feat/bits-282c-keyboard-movefrom
feat/bits-286-end-screen
Closed

PhilReinking wants to merge 19 commits into
feat/bits-282c-keyboard-movefrom
feat/bits-286-end-screen

Conversation

@PhilReinking

@PhilReinking PhilReinking commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

The end screen (headline, text, button) now shows as the last block of the document, after all questions and groups. Open, it edits them in place and saves through the same form update as the Settings page.

Fixes BITS-286

  • Saves like a question: after a 1 s pause or when focus leaves, with Retry, keepalive on reload or tab close.
  • Sends only changed fields; a refused link shows "Your change to the end screen wasn't saved: …" until fixed.
  • Settings and the editor load the form again over the API after Back or a running save, so the open tab stays.
  • On phones the open card has the question card's 44 px fields and tap areas.
  • While the form redirects to a link, the block only names the link.

Tested: Vitest (new tests fail without it), lint, vue-tsc, build. By hand at 1440 and 390: Settings round trip, Back, reload races, sizes, page height.

Not tested: CI, since stacked PRs get none.

🤖 Generated with Claude Code

PhilReinking and others added 3 commits October 13, 2026 02:01
Headline, text and button are edited in place and saved through the
same form update as the Settings page, after a 1 s pause or when focus
leaves the block. While the form redirects, the block only names the
link and points to Settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@PhilReinking PhilReinking left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes at ec80e90. No CI (stacked): Vitest 305, lint, vue-tsc and the build pass locally.

One must inline. Held: the new document tests fail without the block, the public end screen still cleans the text, only changed fields are sent, and a refused link keeps the draft, shows the error and is sent again. Opening the card saves nothing. app.ts only adds the flag icon.

Comment on lines +203 to +210
// save before a click on a link can load the next page
const leave = (event: FocusEvent) => {
const card = event.currentTarget as HTMLElement;

if (!card.contains(event.relatedTarget as Node | null)) {
save.flush();
}
};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Chrome a click on a link gives it focus, so a click on "Also in Settings" keeps the focus in the card and nothing saves. The page then unmounts and cancels the save: a change typed in the last second is lost, and Settings shows the old value. Save when the focus moves to a link too:

Suggested change
// save before a click on a link can load the next page
const leave = (event: FocusEvent) => {
const card = event.currentTarget as HTMLElement;
if (!card.contains(event.relatedTarget as Node | null)) {
save.flush();
}
};
// save before a click on a link can load the next page, also "Also in Settings" in the card
const leave = (event: FocusEvent) => {
const card = event.currentTarget as HTMLElement;
const next = event.relatedTarget as HTMLElement | null;
if (!card.contains(next) || next?.closest("a")) {
save.flush();
}
};

PhilReinking and others added 5 commits October 13, 2026 02:17
Back restored the old props from history, so the tabs showed values from
before an edit in the document, and Save there undid that edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the page

A click on the link inside the card kept the focus in the card, and Back
moves no focus, so a change typed in the last second was lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bare headline with the chip on its right, bare text, hidden labels for
screen readers, "Also in Settings" next to the Button switch. The button
fields say "Button text" and show "Close" and "https://" when empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The block said "No headline yet", but the public form shows
"Form Submitted". It now says "Form Submitted · default", and the open
card shows it as the placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Back from Settings showed the end screen from before the Settings change,
and editing it there undid that change. The Settings check moves into
useFreshFormAfterBack, used by both pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@PhilReinking PhilReinking left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes at dd3ac2f. No CI (stacked): Vitest 311, lint, vue-tsc and the build pass locally. One must inline.

The last must is fixed: the new tests fail on ec80e90, and a 100 ms click on "Also in Settings" showed the new headline in Settings in 8 of 8 browser runs. A flush with nothing changed sends nothing, and a normal visit doesn't reload.

Comment on lines +21 to +25
router.visit(location.href, {
only: ["form"],
replace: true,
preserveScroll: true,
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On browser Back from the editor, the end screen's flushed save and this reload start a few ms apart. On a server with 4 PHP workers the reload came back first in 6 of 10 runs, and Settings showed the old headline. Save Completion Page then wrote the old headline over the new one. Maybe reload once the flushed save is done (I haven't run this):

// a save flushed on Back must land before the reload reads the form
let pendingSave: Promise<unknown> | undefined;
export const finishBeforeReload = (save?: Promise<unknown>) => {
  pendingSave = save;
};

// in useFreshFormAfterBack
Promise.resolve(pendingSave).finally(() => router.visit(/* as now */));

// EndScreenBlock.vue
useEventListener(window, "popstate", () => finishBeforeReload(save.flush()));

A visit the user starts meanwhile should still win over the late reload.

PhilReinking and others added 8 commits October 13, 2026 02:39
With several PHP workers the reload could finish before the save, so
Settings showed the old headline and its Save wrote it back. A visit
started while waiting still wins over the late reload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its way

A click on a link right after typing could load Settings before the save
landed, and its Save wrote the old headline back. Every end screen save
is now tracked; a page that loads meanwhile waits for it, then loads the
form again. The helper is renamed useFreshForm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Back, or a page opened while an end screen save was on its way,
the page reloaded itself through Inertia. That reload wrote the old tab
back into the address and remounted Settings on it. Now the page loads
the form over the API and remounts only the open Settings panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The editor no longer remounts when the fresh form lands. A card opened
before that copied the older text, and its next save sent it back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto feat/bits-286-end-screen

# Conflicts:
#	resources/js/Pages/Forms/Edit.vue
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The end screen now saves like a question: the save status shows it, a
failed save gets Retry, and a change still in its pause goes out with
keepalive on pagehide or beforeunload. Retry only writes to the form it
was made in, and a closed block no longer leaves the status on Saving.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to feat/bits-286-end-screen

# Conflicts:
#	resources/js/components/Factory/Document/FormDocument.test.ts
#	resources/js/components/Factory/Document/FormDocument.vue
@PhilReinking
PhilReinking changed the base branch from feat/bits-282-document-editor to feat/bits-282c-keyboard-move October 13, 2026 01:25

@PhilReinking PhilReinking left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK at bcb79eb, now on part c. No CI (stacked), local runs: Vitest 383, lint, vue-tsc, build.

The must is fixed: after Back, Settings loads the form once the end screen save has landed (new headline in 10 of 10 runs, 4 PHP workers). Held: the 10 new tests fail on the old code, "Also in Settings" kept the change (16 of 16), reload and tab close saved it (12 of 12), and a refused link shows Retry.

PhilReinking and others added 3 commits October 13, 2026 03:46
…ocus bar

touch-fields on the card (44 px fields with 16 px text, 44 px switch tap
area below 1024), a 44 px tap area on "Also in Settings", the number
column at w-8 below 640 like the questions, and no wrapper bar around the
text: the bare editor draws its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Your change to the end screen wasn't saved.", like a question's error
names the question. The questions' text stays the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The closed row's absolute sr-only label had no positioned parent up to
the editor's outer box, so it stretched the page past the document's
scroll box: the page grew to over 3000 px and could scroll the top bar
out of view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@PhilReinking PhilReinking left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK at 4b57119. No CI (stacked), local runs: Vitest 385, lint, vue-tsc, build.

The 3 changed tests fail on bcb79eb. At 1440 the page stays 900 px tall with question 4 or the end card open, and each control in the open card shows its own focus by keyboard, one bar on the text. At 390 fields are 44 px with 16 px text, switch and link tap areas 44 px. Other save errors keep their text.

PhilReinking added a commit that referenced this pull request Oct 13, 2026
…280's

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PhilReinking

Copy link
Copy Markdown
Contributor Author

Landed in main with #282 (the editor rebuild as one PR); this PR's commits are part of it.

ferbinu pushed a commit to ferbinu/input that referenced this pull request Oct 15, 2026
… merging deck9#276 and deck9#271

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant