125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
import { FC, HTMLAttributes } from "react";
|
|
|
|
import {
|
|
characterActions,
|
|
ChoiceUtils,
|
|
ContainerManager,
|
|
} from "@dndbeyond/character-rules-engine";
|
|
|
|
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
|
|
import { useDispatch } from "~/hooks/useDispatch";
|
|
import { DetailChoice } from "~/tools/js/Shared/containers/DetailChoice";
|
|
import { CharClass, Choice, ClassDefinitionContract, Feat } from "~/types";
|
|
|
|
export interface FeatureChoiceProps extends HTMLAttributes<HTMLDivElement> {
|
|
choice: Choice;
|
|
charClass?: CharClass;
|
|
featsData: Feat[];
|
|
subclassData?: ClassDefinitionContract[];
|
|
itemShoppe?: ContainerManager | null;
|
|
onChoiceChange: (
|
|
choiceId: string,
|
|
type: number,
|
|
value: any,
|
|
parentChoiceId: string | null
|
|
) => void;
|
|
collapseDescription?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Component for rendering a features choice(s) - for species traits and class features - using DetailChoice for the choices and mapping over any feat sub choices if the choice from a species trait or class feature is a feat.
|
|
* It is used in both the builder and character sheet sidebar panes.
|
|
*/
|
|
export const FeatureChoice: FC<FeatureChoiceProps> = ({
|
|
charClass,
|
|
choice,
|
|
featsData,
|
|
subclassData,
|
|
itemShoppe,
|
|
onChoiceChange,
|
|
className,
|
|
collapseDescription,
|
|
...props
|
|
}) => {
|
|
const dispatch = useDispatch();
|
|
const {
|
|
classUtils,
|
|
featLookup,
|
|
preferences,
|
|
prerequisiteData,
|
|
choiceInfo,
|
|
ruleData,
|
|
entityRestrictionData,
|
|
} = useCharacterEngine();
|
|
|
|
const handleChoiceChange = (
|
|
id: string,
|
|
type: number,
|
|
value: any,
|
|
parentChoiceId: string | null
|
|
): void => {
|
|
onChoiceChange(id, type, value, parentChoiceId);
|
|
};
|
|
|
|
const handleFeatChoiceChange = (
|
|
featId: number,
|
|
id: string | null,
|
|
type: number,
|
|
value: any
|
|
): void => {
|
|
if (id !== null) {
|
|
dispatch(characterActions.featChoiceSetRequest(featId, type, id, value));
|
|
}
|
|
};
|
|
|
|
const { description, options, featSubChoices, introDescription } =
|
|
ChoiceUtils.getSortedChoiceOptionsForFeaturesInfo(
|
|
choice,
|
|
featsData,
|
|
featLookup,
|
|
charClass || null,
|
|
subclassData || [],
|
|
itemShoppe || null,
|
|
preferences,
|
|
prerequisiteData,
|
|
ruleData,
|
|
entityRestrictionData
|
|
);
|
|
|
|
return (
|
|
<div className={className} {...props}>
|
|
<DetailChoice
|
|
{...choice}
|
|
choice={choice}
|
|
options={options}
|
|
onChange={handleChoiceChange}
|
|
description={description || ""}
|
|
descriptionIntro={introDescription || ""}
|
|
choiceInfo={choiceInfo}
|
|
classId={charClass && classUtils.getId(charClass)}
|
|
showBackgroundProficiencyOptions={true}
|
|
collapseDescription={collapseDescription}
|
|
/>
|
|
{featSubChoices &&
|
|
featSubChoices.map((subChoice) => {
|
|
const id = ChoiceUtils.getId(subChoice.choice);
|
|
return (
|
|
<DetailChoice
|
|
{...subChoice.choice}
|
|
label={subChoice.choice.label}
|
|
choice={subChoice.choice}
|
|
key={id !== null ? id : ""}
|
|
options={subChoice.options}
|
|
onChange={(id, type, value) =>
|
|
handleFeatChoiceChange(subChoice.featId, id, type, value)
|
|
}
|
|
choiceInfo={choiceInfo}
|
|
showBackgroundProficiencyOptions={true}
|
|
description={subChoice.description}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|