From 541e04b732c6545ae75387ed4ff98db2c1dfe46a Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 27 Mar 2026 00:06:50 +0100 Subject: [PATCH] Wrap initiative rolls with undo so they produce undo entries Initiative rolls (single and bulk) called makeStore() directly from useInitiativeRolls, bypassing the withUndo wrapper. Expose withUndo from the encounter context and wrap both roll paths. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../__tests__/turn-navigation.test.tsx | 1 + apps/web/src/hooks/use-encounter.ts | 1 + apps/web/src/hooks/use-initiative-rolls.ts | 21 +++++++------------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/apps/web/src/components/__tests__/turn-navigation.test.tsx b/apps/web/src/components/__tests__/turn-navigation.test.tsx index 618c622..8a559a3 100644 --- a/apps/web/src/components/__tests__/turn-navigation.test.tsx +++ b/apps/web/src/components/__tests__/turn-navigation.test.tsx @@ -54,6 +54,7 @@ function mockContext(overrides: Partial = {}) { addFromBestiary: vi.fn(), addFromPlayerCharacter: vi.fn(), makeStore: vi.fn(), + withUndo: vi.fn((action: () => unknown) => action()), undo: vi.fn(), redo: vi.fn(), canUndo: false, diff --git a/apps/web/src/hooks/use-encounter.ts b/apps/web/src/hooks/use-encounter.ts index 5de527b..79dbd37 100644 --- a/apps/web/src/hooks/use-encounter.ts +++ b/apps/web/src/hooks/use-encounter.ts @@ -430,5 +430,6 @@ export function useEncounter() { undo: undoAction, redo: redoAction, makeStore, + withUndo, } as const; } diff --git a/apps/web/src/hooks/use-initiative-rolls.ts b/apps/web/src/hooks/use-initiative-rolls.ts index ae54168..6cbf050 100644 --- a/apps/web/src/hooks/use-initiative-rolls.ts +++ b/apps/web/src/hooks/use-initiative-rolls.ts @@ -17,7 +17,7 @@ function rollDice(): number { } export function useInitiativeRolls() { - const { encounter, makeStore } = useEncounterContext(); + const { encounter, makeStore, withUndo } = useEncounterContext(); const { getCreature } = useBestiaryContext(); const { showCreature } = useSidePanelContext(); @@ -28,12 +28,8 @@ export function useInitiativeRolls() { (id: CombatantId, mode: RollMode = "normal") => { const diceRolls: [number, ...number[]] = mode === "normal" ? [rollDice()] : [rollDice(), rollDice()]; - const result = rollInitiativeUseCase( - makeStore(), - id, - diceRolls, - getCreature, - mode, + const result = withUndo(() => + rollInitiativeUseCase(makeStore(), id, diceRolls, getCreature, mode), ); if (isDomainError(result)) { setRollSingleSkipped(true); @@ -43,22 +39,19 @@ export function useInitiativeRolls() { } } }, - [makeStore, getCreature, encounter.combatants, showCreature], + [makeStore, getCreature, withUndo, encounter.combatants, showCreature], ); const handleRollAllInitiative = useCallback( (mode: RollMode = "normal") => { - const result = rollAllInitiativeUseCase( - makeStore(), - rollDice, - getCreature, - mode, + const result = withUndo(() => + rollAllInitiativeUseCase(makeStore(), rollDice, getCreature, mode), ); if (!isDomainError(result) && result.skippedNoSource > 0) { setRollSkippedCount(result.skippedNoSource); } }, - [makeStore, getCreature], + [makeStore, getCreature, withUndo], ); return {