Replace panel mode booleans with discriminated union
Three mutually exclusive state variables (selectedCreatureId, bulkImportMode, sourceManagerMode) replaced with a single PanelView union type, eliminating impossible states and boolean-clearing boilerplate in handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,12 @@ import { useBulkImport } from "./hooks/use-bulk-import";
|
|||||||
import { useEncounter } from "./hooks/use-encounter";
|
import { useEncounter } from "./hooks/use-encounter";
|
||||||
import { usePlayerCharacters } from "./hooks/use-player-characters";
|
import { usePlayerCharacters } from "./hooks/use-player-characters";
|
||||||
|
|
||||||
|
type PanelView =
|
||||||
|
| { mode: "closed" }
|
||||||
|
| { mode: "creature"; creatureId: CreatureId }
|
||||||
|
| { mode: "bulk-import" }
|
||||||
|
| { mode: "source-manager" };
|
||||||
|
|
||||||
function rollDice(): number {
|
function rollDice(): number {
|
||||||
return Math.floor(Math.random() * 20) + 1;
|
return Math.floor(Math.random() * 20) + 1;
|
||||||
}
|
}
|
||||||
@@ -116,10 +122,11 @@ export function App() {
|
|||||||
|
|
||||||
const [rollSkippedCount, setRollSkippedCount] = useState(0);
|
const [rollSkippedCount, setRollSkippedCount] = useState(0);
|
||||||
|
|
||||||
const [selectedCreatureId, setSelectedCreatureId] =
|
const [panelView, setPanelView] = useState<PanelView>({ mode: "closed" });
|
||||||
useState<CreatureId | null>(null);
|
const selectedCreatureId =
|
||||||
const [bulkImportMode, setBulkImportMode] = useState(false);
|
panelView.mode === "creature" ? panelView.creatureId : null;
|
||||||
const [sourceManagerMode, setSourceManagerMode] = useState(false);
|
const bulkImportMode = panelView.mode === "bulk-import";
|
||||||
|
const sourceManagerMode = panelView.mode === "source-manager";
|
||||||
const [isRightPanelFolded, setIsRightPanelFolded] = useState(false);
|
const [isRightPanelFolded, setIsRightPanelFolded] = useState(false);
|
||||||
const [pinnedCreatureId, setPinnedCreatureId] = useState<CreatureId | null>(
|
const [pinnedCreatureId, setPinnedCreatureId] = useState<CreatureId | null>(
|
||||||
null,
|
null,
|
||||||
@@ -151,9 +158,7 @@ export function App() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleCombatantStatBlock = useCallback((creatureId: string) => {
|
const handleCombatantStatBlock = useCallback((creatureId: string) => {
|
||||||
setSelectedCreatureId(creatureId as CreatureId);
|
setPanelView({ mode: "creature", creatureId: creatureId as CreatureId });
|
||||||
setBulkImportMode(false);
|
|
||||||
setSourceManagerMode(false);
|
|
||||||
setIsRightPanelFolded(false);
|
setIsRightPanelFolded(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -177,23 +182,17 @@ export function App() {
|
|||||||
.replace(/[^a-z0-9]+/g, "-")
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
.replace(/(^-|-$)/g, "");
|
.replace(/(^-|-$)/g, "");
|
||||||
const cId = `${result.source.toLowerCase()}:${slug}` as CreatureId;
|
const cId = `${result.source.toLowerCase()}:${slug}` as CreatureId;
|
||||||
setSelectedCreatureId(cId);
|
setPanelView({ mode: "creature", creatureId: cId });
|
||||||
setBulkImportMode(false);
|
|
||||||
setSourceManagerMode(false);
|
|
||||||
setIsRightPanelFolded(false);
|
setIsRightPanelFolded(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleBulkImport = useCallback(() => {
|
const handleBulkImport = useCallback(() => {
|
||||||
setBulkImportMode(true);
|
setPanelView({ mode: "bulk-import" });
|
||||||
setSourceManagerMode(false);
|
|
||||||
setSelectedCreatureId(null);
|
|
||||||
setIsRightPanelFolded(false);
|
setIsRightPanelFolded(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOpenSourceManager = useCallback(() => {
|
const handleOpenSourceManager = useCallback(() => {
|
||||||
setSourceManagerMode(true);
|
setPanelView({ mode: "source-manager" });
|
||||||
setBulkImportMode(false);
|
|
||||||
setSelectedCreatureId(null);
|
|
||||||
setIsRightPanelFolded(false);
|
setIsRightPanelFolded(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -210,14 +209,12 @@ export function App() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleBulkImportDone = useCallback(() => {
|
const handleBulkImportDone = useCallback(() => {
|
||||||
setBulkImportMode(false);
|
setPanelView({ mode: "closed" });
|
||||||
bulkImport.reset();
|
bulkImport.reset();
|
||||||
}, [bulkImport.reset]);
|
}, [bulkImport.reset]);
|
||||||
|
|
||||||
const handleDismissBrowsePanel = useCallback(() => {
|
const handleDismissBrowsePanel = useCallback(() => {
|
||||||
setSelectedCreatureId(null);
|
setPanelView({ mode: "closed" });
|
||||||
setBulkImportMode(false);
|
|
||||||
setSourceManagerMode(false);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleToggleFold = useCallback(() => {
|
const handleToggleFold = useCallback(() => {
|
||||||
@@ -258,9 +255,10 @@ export function App() {
|
|||||||
if (!window.matchMedia("(min-width: 1024px)").matches) return;
|
if (!window.matchMedia("(min-width: 1024px)").matches) return;
|
||||||
const active = encounter.combatants[encounter.activeIndex];
|
const active = encounter.combatants[encounter.activeIndex];
|
||||||
if (!active?.creatureId || !isLoaded) return;
|
if (!active?.creatureId || !isLoaded) return;
|
||||||
setSelectedCreatureId(active.creatureId as CreatureId);
|
setPanelView({
|
||||||
setBulkImportMode(false);
|
mode: "creature",
|
||||||
setSourceManagerMode(false);
|
creatureId: active.creatureId as CreatureId,
|
||||||
|
});
|
||||||
}, [encounter.activeIndex, encounter.combatants, isLoaded]);
|
}, [encounter.activeIndex, encounter.combatants, isLoaded]);
|
||||||
|
|
||||||
const isEmpty = encounter.combatants.length === 0;
|
const isEmpty = encounter.combatants.length === 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user