From 0c7a5f50fcc9f6c793ff916da3029b9ec2a15d9c Mon Sep 17 00:00:00 2001 From: Hikari Date: Tue, 24 Mar 2026 11:23:31 -0700 Subject: [PATCH] fix: guard against undefined counts in sync and force-unlock messages Closes #125 --- apps/web/src/components/game/debugPanel.tsx | 76 +++++++++++---------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/apps/web/src/components/game/debugPanel.tsx b/apps/web/src/components/game/debugPanel.tsx index 32f04bd..6953a2f 100644 --- a/apps/web/src/components/game/debugPanel.tsx +++ b/apps/web/src/components/game/debugPanel.tsx @@ -13,18 +13,22 @@ import { ConfirmationModal } from "../ui/confirmationModal.js"; type ActiveModal = "force-unlocks" | "hard-reset" | "sync-new-content" | null; interface SyncNewContentResult { - achievementsAdded: number; - adventurersAdded: number; - bossesAdded: number; - bossRewardsPatched: number; - equipmentAdded: number; - explorationAreasAdded: number; - questRewardsPatched: number; - questsAdded: number; - upgradesAdded: number; - zonesAdded: number; + achievementsAdded: number | undefined; + adventurersAdded: number | undefined; + bossesAdded: number | undefined; + bossRewardsPatched: number | undefined; + equipmentAdded: number | undefined; + explorationAreasAdded: number | undefined; + questRewardsPatched: number | undefined; + questsAdded: number | undefined; + upgradesAdded: number | undefined; + zonesAdded: number | undefined; } +const safeNumber = (value: number | undefined): number => { + return value ?? 0; +}; + /** * Builds a human-readable summary of what the sync-new-content operation added. * @param result - The counts returned by the operation. @@ -32,16 +36,16 @@ interface SyncNewContentResult { */ const buildSyncNewContentMessage = (result: SyncNewContentResult): string => { const entries: Array<[ number, string ]> = [ - [ result.zonesAdded, "zone(s)" ], - [ result.questsAdded, "quest(s)" ], - [ result.questRewardsPatched, "quest reward(s) patched" ], - [ result.bossesAdded, "boss(es)" ], - [ result.bossRewardsPatched, "boss reward(s) patched" ], - [ result.explorationAreasAdded, "exploration area(s)" ], - [ result.adventurersAdded, "adventurer tier(s)" ], - [ result.upgradesAdded, "upgrade(s)" ], - [ result.equipmentAdded, "equipment item(s)" ], - [ result.achievementsAdded, "achievement(s)" ], + [ safeNumber(result.zonesAdded), "zone(s)" ], + [ safeNumber(result.questsAdded), "quest(s)" ], + [ safeNumber(result.questRewardsPatched), "quest reward(s) patched" ], + [ safeNumber(result.bossesAdded), "boss(es)" ], + [ safeNumber(result.bossRewardsPatched), "boss reward(s) patched" ], + [ safeNumber(result.explorationAreasAdded), "exploration area(s)" ], + [ safeNumber(result.adventurersAdded), "adventurer tier(s)" ], + [ safeNumber(result.upgradesAdded), "upgrade(s)" ], + [ safeNumber(result.equipmentAdded), "equipment item(s)" ], + [ safeNumber(result.achievementsAdded), "achievement(s)" ], ]; const parts = entries. filter(([ count ]) => { @@ -60,14 +64,14 @@ const buildSyncNewContentMessage = (result: SyncNewContentResult): string => { }; interface ForceUnlocksResult { - adventurersUnlocked: number; - bossesUnlocked: number; - equipmentUnlocked: number; - explorationUnlocked: number; - questsUnlocked: number; - storyUnlocked: number; - upgradesUnlocked: number; - zonesUnlocked: number; + adventurersUnlocked: number | undefined; + bossesUnlocked: number | undefined; + equipmentUnlocked: number | undefined; + explorationUnlocked: number | undefined; + questsUnlocked: number | undefined; + storyUnlocked: number | undefined; + upgradesUnlocked: number | undefined; + zonesUnlocked: number | undefined; } /** @@ -77,14 +81,14 @@ interface ForceUnlocksResult { */ const buildForceUnlocksMessage = (result: ForceUnlocksResult): string => { const entries: Array<[ number, string ]> = [ - [ result.zonesUnlocked, "zone(s)" ], - [ result.questsUnlocked, "quest(s)" ], - [ result.bossesUnlocked, "boss(es)" ], - [ result.explorationUnlocked, "exploration area(s)" ], - [ result.adventurersUnlocked, "adventurer tier(s)" ], - [ result.upgradesUnlocked, "upgrade(s)" ], - [ result.equipmentUnlocked, "equipment item(s)" ], - [ result.storyUnlocked, "story chapter(s)" ], + [ safeNumber(result.zonesUnlocked), "zone(s)" ], + [ safeNumber(result.questsUnlocked), "quest(s)" ], + [ safeNumber(result.bossesUnlocked), "boss(es)" ], + [ safeNumber(result.explorationUnlocked), "exploration area(s)" ], + [ safeNumber(result.adventurersUnlocked), "adventurer tier(s)" ], + [ safeNumber(result.upgradesUnlocked), "upgrade(s)" ], + [ safeNumber(result.equipmentUnlocked), "equipment item(s)" ], + [ safeNumber(result.storyUnlocked), "story chapter(s)" ], ]; const parts = entries. filter(([ count ]) => {