fix(state): persist to localStorage + explicit Disconnect (survive reload)
The Zustand store persisted to sessionStorage, which is tab-volatile — a hard reload / new tab / closing the tab dropped the whole session, including the board binding (device.connected, nodeUrl, teamId). The workshop runs on the team's own laptop, so switch the store (and the offline outbox) to localStorage: the binding + progress now survive a refresh, hard reload, navigation, and tab close. Clearing is now explicit only: a new `disconnect()` action drops the board binding (keeping team/domain/phases/ADD so they can re-bind and resume), surfaced as a "Disconnect" button on the claimed-board card. `reset()` still wipes everything. Tests: add an in-memory localStorage to setupTests (Node 22's disabled experimental localStorage shadows jsdom's) + clear it per test. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6a9fad9f10
commit
c12f40837b
@@ -24,13 +24,13 @@ type OutboxItem = { kind: 'team'; payload: TeamSnapshot } | { kind: 'submission'
|
||||
|
||||
function readOutbox(): OutboxItem[] {
|
||||
try {
|
||||
return JSON.parse(sessionStorage.getItem(OUTBOX_KEY) ?? '[]') as OutboxItem[]
|
||||
return JSON.parse(localStorage.getItem(OUTBOX_KEY) ?? '[]') as OutboxItem[]
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
function writeOutbox(items: OutboxItem[]): void {
|
||||
sessionStorage.setItem(OUTBOX_KEY, JSON.stringify(items))
|
||||
localStorage.setItem(OUTBOX_KEY, JSON.stringify(items))
|
||||
}
|
||||
function enqueue(item: OutboxItem): void {
|
||||
// collapse duplicate team pushes — only the latest snapshot matters
|
||||
@@ -83,7 +83,7 @@ export interface UseCollectiveSyncOptions {
|
||||
* Best-effort, offline-first sync of this team's state to the collective.
|
||||
* Mounted once near the router root. Pushes on phase changes and submission,
|
||||
* throttles stat-driven churn, and never blocks the participant flow — failed
|
||||
* pushes go to a sessionStorage outbox and retry on interval / `online`.
|
||||
* pushes go to a localStorage outbox and retry on interval / `online`.
|
||||
*/
|
||||
export function useCollectiveSync(opts: UseCollectiveSyncOptions = {}): void {
|
||||
const throttleMs = opts.throttleMs ?? 8000
|
||||
|
||||
Reference in New Issue
Block a user