fix: delay boss lore toasts until battle animation reveals result
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m3s
CI / Lint, Build & Test (push) Successful in 1m6s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 19:18:46 -07:00
committed by Naomi Carrigan
parent 5a065998b6
commit 6e2cb45553
2 changed files with 47 additions and 4 deletions
+8 -1
View File
@@ -58,7 +58,12 @@ const BattleModal = ({
onDismiss,
}: BattleModalProperties): JSX.Element => {
const { result, bossName } = battle;
const { enableNotifications, enableSounds, formatNumber } = useGame();
const {
enableNotifications,
enableSounds,
flushBossLoreToasts,
formatNumber,
} = useGame();
const [ phase, setPhase ] = useState<"animating" | "result">("animating");
@@ -111,6 +116,7 @@ const BattleModal = ({
const revealTimeout = setTimeout(() => {
setPhase("result");
flushBossLoreToasts();
if (result.won) {
if (enableSounds) {
playSound("bossVictory");
@@ -132,6 +138,7 @@ const BattleModal = ({
bossStartPercent,
enableNotifications,
enableSounds,
flushBossLoreToasts,
partyEndPercent,
result.won,
]);
+39 -3
View File
@@ -455,6 +455,11 @@ interface GameContextValue {
*/
dismissCodexEntry: (id: string)=> void;
/**
* Flush pending boss lore codex toasts — call after the battle animation reveals the result.
*/
flushBossLoreToasts: ()=> void;
/**
* Perform a transcendence — nuclear reset, earning echoes.
*/
@@ -613,6 +618,7 @@ export const GameProvider = ({
Array<string>
>([]);
const codexProcessedReference = useRef<Set<string>>(new Set());
const pendingBossCodexIdsReference = useRef<Array<string>>([]);
const [ unlockedStoryChapterIds, setUnlockedStoryChapterIds ] = useState<
Array<string>
>([]);
@@ -880,12 +886,30 @@ export const GameProvider = ({
};
});
if (!isFirstRun) {
setUnlockedCodexEntryIds((previous) => {
return [ ...previous, ...addedIds ];
const bossIds = addedIds.filter((id) => {
return id.startsWith("boss_");
});
const otherIds = addedIds.filter((id) => {
return !id.startsWith("boss_");
});
if (bossIds.length > 0) {
if (battleResult === null) {
otherIds.push(...bossIds);
} else {
pendingBossCodexIdsReference.current = [
...pendingBossCodexIdsReference.current,
...bossIds,
];
}
}
if (otherIds.length > 0) {
setUnlockedCodexEntryIds((previous) => {
return [ ...previous, ...otherIds ];
});
}
}
}
}, [ state ]);
}, [ battleResult, state ]);
// Detect newly unlocked story chapters
useEffect(() => {
@@ -1836,6 +1860,16 @@ export const GameProvider = ({
});
}, []);
const flushBossLoreToasts = useCallback(() => {
const pending = pendingBossCodexIdsReference.current;
if (pending.length > 0) {
pendingBossCodexIdsReference.current = [];
setUnlockedCodexEntryIds((previous) => {
return [ ...previous, ...pending ];
});
}
}, []);
const dismissStoryChapter = useCallback((id: string) => {
setUnlockedStoryChapterIds((previous) => {
return previous.filter((chapter) => {
@@ -1935,6 +1969,7 @@ export const GameProvider = ({
equipItem,
error,
failedQuestToasts,
flushBossLoreToasts,
forceSync,
formatNumber,
handleClick,
@@ -2001,6 +2036,7 @@ export const GameProvider = ({
enableSounds,
equipItem,
error,
flushBossLoreToasts,
forceSync,
handleClick,
isLoading,