New source found from dndbeyond.com
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import { FC, HTMLAttributes } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
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";
|
||||
|
||||
@@ -15,6 +16,7 @@ export interface FeatureChoiceProps extends HTMLAttributes<HTMLDivElement> {
|
||||
charClass?: CharClass;
|
||||
featsData: Feat[];
|
||||
subclassData?: ClassDefinitionContract[];
|
||||
itemShoppe?: ContainerManager | null;
|
||||
onChoiceChange: (
|
||||
choiceId: string,
|
||||
type: number,
|
||||
@@ -33,6 +35,7 @@ export const FeatureChoice: FC<FeatureChoiceProps> = ({
|
||||
choice,
|
||||
featsData,
|
||||
subclassData,
|
||||
itemShoppe,
|
||||
onChoiceChange,
|
||||
className,
|
||||
collapseDescription,
|
||||
@@ -69,13 +72,14 @@ export const FeatureChoice: FC<FeatureChoiceProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const { description, options, featSubChoices } =
|
||||
const { description, options, featSubChoices, introDescription } =
|
||||
ChoiceUtils.getSortedChoiceOptionsForFeaturesInfo(
|
||||
choice,
|
||||
featsData,
|
||||
featLookup,
|
||||
charClass || null,
|
||||
subclassData || [],
|
||||
itemShoppe || null,
|
||||
preferences,
|
||||
prerequisiteData,
|
||||
ruleData,
|
||||
@@ -90,6 +94,7 @@ export const FeatureChoice: FC<FeatureChoiceProps> = ({
|
||||
options={options}
|
||||
onChange={handleChoiceChange}
|
||||
description={description || ""}
|
||||
descriptionIntro={introDescription || ""}
|
||||
choiceInfo={choiceInfo}
|
||||
classId={charClass && classUtils.getId(charClass)}
|
||||
showBackgroundProficiencyOptions={true}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clsx from "clsx";
|
||||
import { FC, HTMLAttributes, useEffect, useState } from "react";
|
||||
import { FC, HTMLAttributes, useContext, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import {
|
||||
@@ -9,13 +9,17 @@ import {
|
||||
Choice,
|
||||
ChoiceUtils,
|
||||
ClassDefinitionContract,
|
||||
ClassFeature,
|
||||
ClassFeatureUtils,
|
||||
ClassUtils,
|
||||
Constants,
|
||||
ContainerManager,
|
||||
Feat,
|
||||
FeatUtils,
|
||||
} from "@dndbeyond/character-rules-engine";
|
||||
|
||||
import { Heading } from "~/subApps/sheet/components/Sidebar/components/Heading";
|
||||
import { InventoryManagerContext } from "~/tools/js/Shared/managers/InventoryManagerContext";
|
||||
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
|
||||
import { AppLoggerUtils } from "~/tools/js/Shared/utils";
|
||||
import LoadingPlaceholder from "~/tools/js/smartComponents/LoadingPlaceholder";
|
||||
@@ -35,7 +39,9 @@ export interface FeatureChoicesProps extends HTMLAttributes<HTMLDivElement> {
|
||||
) => void;
|
||||
collapseDescription?: boolean;
|
||||
charClass?: CharClass;
|
||||
classFeature?: ClassFeature;
|
||||
shouldFetch?: boolean; // Optional prop to control fetching behavior
|
||||
itemShoppe?: ContainerManager | null; // Optional prop for cases where the itemShoppe is fetched from the parent component (only used if the Feature Choices component is rendered multiple times in the same parent - e.g. in the Item Plans Manage Pane)
|
||||
}
|
||||
|
||||
export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
@@ -45,7 +51,9 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
onChoiceChange,
|
||||
collapseDescription,
|
||||
charClass,
|
||||
classFeature,
|
||||
shouldFetch = true, // Default to true if not provided
|
||||
itemShoppe = null,
|
||||
...props
|
||||
}) => {
|
||||
const isReadonly = useSelector(appEnvSelectors.getIsReadonly);
|
||||
@@ -56,14 +64,20 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
apiCreatorSelectors.makeLoadAvailableSubclasses
|
||||
);
|
||||
|
||||
const { inventoryManager } = useContext(InventoryManagerContext);
|
||||
|
||||
const [subclassData, setSubclassData] = useState<
|
||||
Array<ClassDefinitionContract>
|
||||
>([]);
|
||||
const [featsData, setFeatsData] = useState<Array<Feat>>([]);
|
||||
const [localItemShoppe, setLocalItemShoppe] =
|
||||
useState<ContainerManager | null>(itemShoppe);
|
||||
const [featLoadingStatus, setFeatLoadingStatus] =
|
||||
useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);
|
||||
const [subclassLoadingStatus, setSubclassLoadingStatus] =
|
||||
useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);
|
||||
const [itemsLoadingStatus, setItemsLoadingStatus] =
|
||||
useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);
|
||||
|
||||
const hasFeatChoice = choices.some(
|
||||
(choice) =>
|
||||
@@ -77,15 +91,23 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
Constants.BuilderChoiceTypeEnum.SUB_CLASS_OPTION
|
||||
);
|
||||
|
||||
const hasItemMappings = classFeature
|
||||
? ClassFeatureUtils.getHasItemMappings(classFeature)
|
||||
: false;
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
|
||||
if (
|
||||
hasFeatChoice &&
|
||||
shouldFetch &&
|
||||
featLoadingStatus === DataLoadingStatusEnum.NOT_INITIALIZED
|
||||
featLoadingStatus !== DataLoadingStatusEnum.LOADED
|
||||
) {
|
||||
setFeatLoadingStatus(DataLoadingStatusEnum.LOADING);
|
||||
|
||||
loadAvailableFeats()
|
||||
loadAvailableFeats({
|
||||
signal: abortController.signal,
|
||||
})
|
||||
.then((response) => {
|
||||
let featsData: Array<Feat> = [];
|
||||
|
||||
@@ -99,17 +121,22 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
setFeatsData(featsData);
|
||||
setFeatLoadingStatus(DataLoadingStatusEnum.LOADED);
|
||||
})
|
||||
.catch(AppLoggerUtils.handleAdhocApiError);
|
||||
.catch((e) => {
|
||||
if (abortController.signal.aborted) return;
|
||||
AppLoggerUtils.handleAdhocApiError(e);
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
charClass &&
|
||||
hasSubclassChoice &&
|
||||
shouldFetch &&
|
||||
subclassLoadingStatus === DataLoadingStatusEnum.NOT_INITIALIZED
|
||||
subclassLoadingStatus !== DataLoadingStatusEnum.LOADED
|
||||
) {
|
||||
setSubclassLoadingStatus(DataLoadingStatusEnum.LOADING);
|
||||
loadAvailableSubclasses(ClassUtils.getId(charClass))
|
||||
loadAvailableSubclasses(ClassUtils.getId(charClass), {
|
||||
signal: abortController.signal,
|
||||
})
|
||||
.then((response) => {
|
||||
let subclassData: Array<ClassDefinitionContract> = [];
|
||||
|
||||
@@ -121,17 +148,55 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
setSubclassData(subclassData);
|
||||
setSubclassLoadingStatus(DataLoadingStatusEnum.LOADED);
|
||||
})
|
||||
.catch(AppLoggerUtils.handleAdhocApiError);
|
||||
.catch((e) => {
|
||||
if (abortController.signal.aborted) return;
|
||||
AppLoggerUtils.handleAdhocApiError(e);
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
localItemShoppe === null &&
|
||||
hasItemMappings &&
|
||||
shouldFetch &&
|
||||
itemsLoadingStatus !== DataLoadingStatusEnum.LOADED
|
||||
) {
|
||||
if (inventoryManager) {
|
||||
setItemsLoadingStatus(DataLoadingStatusEnum.LOADING);
|
||||
|
||||
inventoryManager
|
||||
.getInventoryShoppe({
|
||||
onSuccess: (shoppeContainer: ContainerManager) => {
|
||||
setLocalItemShoppe(shoppeContainer);
|
||||
setItemsLoadingStatus(DataLoadingStatusEnum.LOADED);
|
||||
},
|
||||
additionalApiConfig: {
|
||||
signal: abortController.signal,
|
||||
},
|
||||
})
|
||||
.catch((e) => {
|
||||
if (abortController.signal.aborted) return;
|
||||
AppLoggerUtils.handleAdhocApiError(e);
|
||||
});
|
||||
} else {
|
||||
setItemsLoadingStatus(DataLoadingStatusEnum.LOADED);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
};
|
||||
}, [
|
||||
hasFeatChoice,
|
||||
hasSubclassChoice,
|
||||
hasItemMappings,
|
||||
subclassLoadingStatus,
|
||||
featLoadingStatus,
|
||||
itemsLoadingStatus,
|
||||
charClass,
|
||||
loadAvailableFeats,
|
||||
loadAvailableSubclasses,
|
||||
shouldFetch,
|
||||
inventoryManager,
|
||||
]);
|
||||
|
||||
const isDataLoaded = (): boolean => {
|
||||
@@ -145,6 +210,13 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (itemShoppe !== null) {
|
||||
return true;
|
||||
} else if (hasItemMappings) {
|
||||
if (itemsLoadingStatus !== DataLoadingStatusEnum.LOADED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -163,6 +235,7 @@ export const FeatureChoices: FC<FeatureChoicesProps> = ({
|
||||
charClass={charClass}
|
||||
choice={choice}
|
||||
featsData={featsData}
|
||||
itemShoppe={localItemShoppe}
|
||||
subclassData={subclassData}
|
||||
className={styles.choice}
|
||||
key={ChoiceUtils.getId(choice)}
|
||||
|
||||
Reference in New Issue
Block a user