Implement the 008-persist-encounter feature that saves encounter state to localStorage so it survives page reloads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-05 16:24:00 +01:00
parent c4a90c9982
commit a9c280a6d6
12 changed files with 818 additions and 4 deletions

View File

@@ -12,7 +12,11 @@ import {
createEncounter,
isDomainError,
} from "@initiative/domain";
import { useCallback, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import {
loadEncounter,
saveEncounter,
} from "../persistence/encounter-storage.js";
function createDemoEncounter(): Encounter {
const result = createEncounter([
@@ -28,12 +32,34 @@ function createDemoEncounter(): Encounter {
return result;
}
function initializeEncounter(): Encounter {
const stored = loadEncounter();
if (stored !== null) return stored;
return createDemoEncounter();
}
function deriveNextId(encounter: Encounter): number {
let max = 0;
for (const c of encounter.combatants) {
const match = /^c-(\d+)$/.exec(c.id);
if (match) {
const n = Number.parseInt(match[1], 10);
if (n > max) max = n;
}
}
return max;
}
export function useEncounter() {
const [encounter, setEncounter] = useState<Encounter>(createDemoEncounter);
const [encounter, setEncounter] = useState<Encounter>(initializeEncounter);
const [events, setEvents] = useState<DomainEvent[]>([]);
const encounterRef = useRef(encounter);
encounterRef.current = encounter;
useEffect(() => {
saveEncounter(encounter);
}, [encounter]);
const makeStore = useCallback((): EncounterStore => {
return {
get: () => encounterRef.current,
@@ -51,7 +77,7 @@ export function useEncounter() {
setEvents((prev) => [...prev, ...result]);
}, [makeStore]);
const nextId = useRef(0);
const nextId = useRef(deriveNextId(encounter));
const addCombatant = useCallback(
(name: string) => {