fix: hydration-safe banner clock (#44, v0.10.1) #47

Merged
kamilkrzywda merged 4 commits from fix/hydration-jump-dispatch into master 2026-10-04 01:52:28 +02:00
2 changed files with 8 additions and 3 deletions
Showing only changes of commit e792c8a06c - Show all commits
+2 -1
View File
@@ -1,7 +1,8 @@
# Changelog # Changelog
## v0.10.1 — 2026-10-03 18:36 ## v0.10.1 — 2026-10-03 18:36
- Fix React 19 hydration mismatch (#418) on every production load — the banner's live clock was prerendered at build time in the static page and desynced at hydration, intermittently stranding the world-map team builder's DISPATCH button permanently disabled (jump flow unusable); e2e jump tests now green. - Fix React 19 hydration mismatch on every production load — the banner's live clock was prerendered at build time in the static page and desynced at hydration (CI-verified: no hydration errors in the job logs). A real fix, but NOT the cause of the red e2e jump specs.
- Fix the world-map jump dispatch — the actual cause of the three deterministically red e2e jump specs: TeamBuilder's `blocked` term was `undefined`, not `null`, whenever no jump was queued (`Array.find` returns `undefined`), so the roster rendered (truthiness check) while the DISPATCH button's `blocked !== null` guard read it as blocked and stayed disabled — the JUMP panel's dispatch was permanently dead on an empty queue (the 300 s `waitForResponse` timeout; present since the builder shipped in v0.10.0, so the UI-jump specs were red on every run since, on a fresh DB; non-JUMP panels were unaffected, their branch yielding `null`).
## v0.10.0 — 2026-10-03 00:57 ## v0.10.0 — 2026-10-03 00:57
- Queue-based actions (#44): every game action (jump, explore, ship upgrade/expand/build, research) is now a queued task with an assigned team — a lead + optional helpers. Validation and cost deduction happen at queue time (unknown crew → 404, busy/committed crew → 409, in-transit or second jump → 409); effects apply when the task completes, mission accept is instant and free, and mission-completion checks run when the satisfying task resolves. - Queue-based actions (#44): every game action (jump, explore, ship upgrade/expand/build, research) is now a queued task with an assigned team — a lead + optional helpers. Validation and cost deduction happen at queue time (unknown crew → 404, busy/committed crew → 409, in-transit or second jump → 409); effects apply when the task completes, mission accept is instant and free, and mission-completion checks run when the satisfying task resolves.
+6 -2
View File
@@ -23,9 +23,13 @@ export function TeamBuilder({ type, hopCount, roster, tasks, onQueue }: {
const [helperIds, setHelperIds] = useState<number[]>([]) const [helperIds, setHelperIds] = useState<number[]>([])
// Whole-builder blocks: an ACTIVE jump is in transit (all types); in the jump panel any // Whole-builder blocks: an ACTIVE jump is in transit (all types); in the jump panel any
// queued jump is — the second-jump 409 (JC-12). // queued jump is — the second-jump 409 (JC-12). The JUMP branch coalesces find()'s
// undefined to null so blocked is strictly QueueDto | null: the roster ternary below tests
// truthiness, but the button guard compares to null — undefined slipped past it and
// disabled every empty-queue JUMP dispatch (v0.10.1 e2e jump regression).
const inTransit = tasks.find((t) => t.type === 'JUMP' && t.status === 'ACTIVE') const inTransit = tasks.find((t) => t.type === 'JUMP' && t.status === 'ACTIVE')
const blocked = inTransit ?? (type === 'JUMP' ? tasks.find((t) => t.type === 'JUMP') : null) const queuedJump = type === 'JUMP' ? (tasks.find((t) => t.type === 'JUMP') ?? null) : null
const blocked = inTransit ?? queuedJump
const lead = roster.find((c) => c.id === leadId) ?? null const lead = roster.find((c) => c.id === leadId) ?? null
const helpers = roster.filter((c) => helperIds.includes(c.id)) const helpers = roster.filter((c) => helperIds.includes(c.id))