Files
dndbeyond_src/ddb_main/components/FeatureChoices/FeatureChoice/FeatureChoice.tsx
T

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>
);
};