Add rules covering bug prevention (noLeakedRender, noFloatingPromises, noImportCycles, noReactForwardRef), security (noScriptUrl, noAlert), performance (noAwaitInLoops, useTopLevelRegex), and code style (noNestedTernary, useGlobalThis, useNullishCoalescing, useSortedClasses, plus ~40 more). Fix all violations: extract top-level regex constants, guard React && renders with boolean coercion, refactor nested ternaries, replace window with globalThis, sort Tailwind classes, and introduce expectDomainError test helper to eliminate conditional expects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
94 lines
2.2 KiB
TypeScript
94 lines
2.2 KiB
TypeScript
import type { PlayerCharacter, PlayerCharacterId } from "@initiative/domain";
|
|
import { type RefObject, useImperativeHandle, useState } from "react";
|
|
import { CreatePlayerModal } from "./create-player-modal.js";
|
|
import { PlayerManagement } from "./player-management.js";
|
|
|
|
export interface PlayerCharacterSectionHandle {
|
|
openManagement: () => void;
|
|
}
|
|
|
|
interface PlayerCharacterSectionProps {
|
|
characters: readonly PlayerCharacter[];
|
|
onCreateCharacter: (
|
|
name: string,
|
|
ac: number,
|
|
maxHp: number,
|
|
color: string | undefined,
|
|
icon: string | undefined,
|
|
) => void;
|
|
onEditCharacter: (
|
|
id: PlayerCharacterId,
|
|
fields: {
|
|
name?: string;
|
|
ac?: number;
|
|
maxHp?: number;
|
|
color?: string | null;
|
|
icon?: string | null;
|
|
},
|
|
) => void;
|
|
onDeleteCharacter: (id: PlayerCharacterId) => void;
|
|
}
|
|
|
|
export const PlayerCharacterSection = function PlayerCharacterSectionInner({
|
|
characters,
|
|
onCreateCharacter,
|
|
onEditCharacter,
|
|
onDeleteCharacter,
|
|
ref,
|
|
}: PlayerCharacterSectionProps & {
|
|
ref?: RefObject<PlayerCharacterSectionHandle | null>;
|
|
}) {
|
|
const [managementOpen, setManagementOpen] = useState(false);
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
const [editingPlayer, setEditingPlayer] = useState<
|
|
PlayerCharacter | undefined
|
|
>();
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
openManagement: () => setManagementOpen(true),
|
|
}));
|
|
|
|
return (
|
|
<>
|
|
<CreatePlayerModal
|
|
open={createOpen}
|
|
onClose={() => {
|
|
setCreateOpen(false);
|
|
setEditingPlayer(undefined);
|
|
setManagementOpen(true);
|
|
}}
|
|
onSave={(name, ac, maxHp, color, icon) => {
|
|
if (editingPlayer) {
|
|
onEditCharacter(editingPlayer.id, {
|
|
name,
|
|
ac,
|
|
maxHp,
|
|
color: color ?? null,
|
|
icon: icon ?? null,
|
|
});
|
|
} else {
|
|
onCreateCharacter(name, ac, maxHp, color, icon);
|
|
}
|
|
}}
|
|
playerCharacter={editingPlayer}
|
|
/>
|
|
<PlayerManagement
|
|
open={managementOpen}
|
|
onClose={() => setManagementOpen(false)}
|
|
characters={characters}
|
|
onEdit={(pc) => {
|
|
setEditingPlayer(pc);
|
|
setCreateOpen(true);
|
|
setManagementOpen(false);
|
|
}}
|
|
onDelete={(id) => onDeleteCharacter(id)}
|
|
onCreate={() => {
|
|
setEditingPlayer(undefined);
|
|
setCreateOpen(true);
|
|
setManagementOpen(false);
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
};
|