Files
initiative/apps/web/src/hooks/use-encounter.ts

104 lines
2.2 KiB
TypeScript

import type { EncounterStore } from "@initiative/application";
import {
addCombatantUseCase,
advanceTurnUseCase,
editCombatantUseCase,
removeCombatantUseCase,
} from "@initiative/application";
import type { CombatantId, DomainEvent, Encounter } from "@initiative/domain";
import {
combatantId,
createEncounter,
isDomainError,
} from "@initiative/domain";
import { useCallback, useRef, useState } from "react";
function createDemoEncounter(): Encounter {
const result = createEncounter([
{ id: combatantId("1"), name: "Aria" },
{ id: combatantId("2"), name: "Brak" },
{ id: combatantId("3"), name: "Cael" },
]);
if (isDomainError(result)) {
throw new Error(`Failed to create demo encounter: ${result.message}`);
}
return result;
}
export function useEncounter() {
const [encounter, setEncounter] = useState<Encounter>(createDemoEncounter);
const [events, setEvents] = useState<DomainEvent[]>([]);
const encounterRef = useRef(encounter);
encounterRef.current = encounter;
const makeStore = useCallback((): EncounterStore => {
return {
get: () => encounterRef.current,
save: (e) => setEncounter(e),
};
}, []);
const advanceTurn = useCallback(() => {
const result = advanceTurnUseCase(makeStore());
if (isDomainError(result)) {
return;
}
setEvents((prev) => [...prev, ...result]);
}, [makeStore]);
const nextId = useRef(0);
const addCombatant = useCallback(
(name: string) => {
const id = combatantId(`c-${++nextId.current}`);
const result = addCombatantUseCase(makeStore(), id, name);
if (isDomainError(result)) {
return;
}
setEvents((prev) => [...prev, ...result]);
},
[makeStore],
);
const removeCombatant = useCallback(
(id: CombatantId) => {
const result = removeCombatantUseCase(makeStore(), id);
if (isDomainError(result)) {
return;
}
setEvents((prev) => [...prev, ...result]);
},
[makeStore],
);
const editCombatant = useCallback(
(id: CombatantId, newName: string) => {
const result = editCombatantUseCase(makeStore(), id, newName);
if (isDomainError(result)) {
return;
}
setEvents((prev) => [...prev, ...result]);
},
[makeStore],
);
return {
encounter,
events,
advanceTurn,
addCombatant,
removeCombatant,
editCombatant,
} as const;
}