Reported: during a loading screen (freezing a deck) the Study deck / Make my homework switch stayed live, so the run could be swapped out mid-flight; a request that finished afterwards could even save a deck the user never saw and navigate them into it. - New lib/wizard-busy.ts: a tiny store both wizards publish to while phase === 'loading' (UploadScreen) or view.kind === 'loading' (HomeworkScreen); WizardModeSwitch hides itself while busy. - Both wizards abort the in-flight request on unmount, so leaving via the header logo or the Back gesture stops the run instead of letting it finish invisibly and save/navigate later. - Deck Cancel keeps its long-standing behaviour (wizard + cancelled notice + Retry), matching the freeze-loading suite. Verified: wizard suite 92 checks (mode switch hidden during deck and homework runs, it returns after Cancel, and a delayed reply after leaving mid-run saves nothing and navigates nowhere) plus mobile 134/134 (also de-flaked the sheet's Escape close by waiting for detach), regression 74/74, declutter 116/116, animation 8/8, native 35/35, i18n 25/25, phase1 38/38, phase2 43/43, phase3 20/20, freeze-loading 6/6. Lint + build clean. SW freezmo-v29.
34 lines
904 B
TypeScript
34 lines
904 B
TypeScript
"use client";
|
|
|
|
/**
|
|
* True while either wizard is generating. The in-page mode switch reads this
|
|
* and hides itself, so a loading run can't be swapped out mid-flight — the
|
|
* loading screen owns the page until it finishes or is cancelled.
|
|
*/
|
|
|
|
import { useSyncExternalStore } from "react";
|
|
|
|
let busy = false;
|
|
const listeners = new Set<() => void>();
|
|
|
|
export const wizardBusy = {
|
|
subscribe(listener: () => void): () => void {
|
|
listeners.add(listener);
|
|
return () => listeners.delete(listener);
|
|
},
|
|
getSnapshot(): boolean {
|
|
return busy;
|
|
},
|
|
getServerSnapshot(): boolean {
|
|
return false;
|
|
},
|
|
set(value: boolean): void {
|
|
if (busy === value) return;
|
|
busy = value;
|
|
listeners.forEach((listener) => listener());
|
|
},
|
|
};
|
|
|
|
export function useWizardBusy(): boolean {
|
|
return useSyncExternalStore(wizardBusy.subscribe, wizardBusy.getSnapshot, wizardBusy.getServerSnapshot);
|
|
}
|