Repository navigation
Show the end screen as the last block of the document - #271
PhilReinking wants to merge 19 commits into
Conversation
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>
…nto feat/bits-286-end-screen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PhilReinking
left a comment
There was a problem hiding this comment.
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.
| // 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(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
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:
| // 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(); | |
| } | |
| }; |
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
left a comment
There was a problem hiding this comment.
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.
| router.visit(location.href, { | ||
| only: ["form"], | ||
| replace: true, | ||
| preserveScroll: true, | ||
| }); |
There was a problem hiding this comment.
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.
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
left a comment
There was a problem hiding this comment.
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.
…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
left a comment
There was a problem hiding this comment.
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.
…280's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Landed in main with #282 (the editor rebuild as one PR); this PR's commits are part of it. |
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
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