Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
import clsx from "clsx";
|
||||
import React, { FC } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import ArrowRightIcon from "@dndbeyond/fontawesome-cache/svgs/solid/arrow-right.svg";
|
||||
|
||||
import { Button } from "~/components/Button";
|
||||
import { ConfirmModal, ConfirmModalProps } from "~/components/ConfirmModal";
|
||||
import { Reference } from "~/components/Reference";
|
||||
import { SummaryList } from "~/components/SummaryList";
|
||||
import { AppContextTypeEnum, DisplayConfigurationTypeEnum } from "~/constants";
|
||||
import { isNotNullOrUndefined } from "~/helpers/validation";
|
||||
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
|
||||
import { Feat, RacialTraitContract as RacialTrait } from "~/types";
|
||||
|
||||
import { useSpeciesContext } from "../../contexts/Species";
|
||||
import { ConfirmSpeciesContent } from "./ConfirmSpeciesContent";
|
||||
import { ConfirmSpeciesHeader } from "./ConfirmSpeciesHeader";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface ConfirmSpeciesModalProps
|
||||
extends Omit<ConfirmModalProps, "onConfirm"> {
|
||||
feats?: Feat[];
|
||||
}
|
||||
|
||||
export const ConfirmSpeciesModal: FC<ConfirmSpeciesModalProps> = ({
|
||||
className,
|
||||
feats,
|
||||
onClose,
|
||||
...props
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
characterActions: { raceChoose },
|
||||
definitionUtils: { hack__generateDefinitionKey: generateDefinitionKey },
|
||||
featUtils: { getId: getFeatId, getName: getFeatName },
|
||||
raceUtils: {
|
||||
deriveCalledOutRacialTraits,
|
||||
deriveOrderedRacialTraits,
|
||||
deriveVisibleRacialTraits: deriveVisibleTraits,
|
||||
getDefinitionRacialTraits,
|
||||
getEntityRaceId,
|
||||
getEntityRaceTypeId,
|
||||
getFeatIds,
|
||||
getMoreDetailsUrl,
|
||||
},
|
||||
racialTraitUtils: {
|
||||
filterRacialTraitsByDisplayConfigurationType: filterRacialTraits,
|
||||
getName: getRacialTraitName,
|
||||
getDescription: getRacialTraitDescription,
|
||||
simulateRacialTraitFromContract,
|
||||
},
|
||||
ruleData,
|
||||
ruleDataUtils: {
|
||||
getBuilderHelperTextByDefinitionKeys: getHelperText,
|
||||
getSourceDataInfo,
|
||||
},
|
||||
race: species,
|
||||
} = useCharacterEngine();
|
||||
const { defaultSpeciesImageUrl: defaultImageUrl, selectedSpecies } =
|
||||
useSpeciesContext();
|
||||
|
||||
const { description, fullName, isLegacy, portraitAvatarUrl, sources } =
|
||||
selectedSpecies || {};
|
||||
|
||||
const previewUrl = portraitAvatarUrl || defaultImageUrl;
|
||||
|
||||
let missingFeatDependencies: Feat[] = [];
|
||||
|
||||
if (feats && species && selectedSpecies) {
|
||||
let speciesFeatIds = getFeatIds(species);
|
||||
let confirmSpeciesFeatIds = getFeatIds(selectedSpecies);
|
||||
feats.forEach((feat) => {
|
||||
if (
|
||||
speciesFeatIds.includes(getFeatId(feat)) &&
|
||||
!confirmSpeciesFeatIds.includes(getFeatId(feat))
|
||||
) {
|
||||
missingFeatDependencies.push(feat);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get listing url for species
|
||||
const moreDetailsUrl = selectedSpecies
|
||||
? getMoreDetailsUrl(selectedSpecies)
|
||||
: "";
|
||||
|
||||
// Get species traits
|
||||
const speciesTraits =
|
||||
selectedSpecies && getDefinitionRacialTraits(selectedSpecies);
|
||||
|
||||
const simulatedSpeciesTraits = speciesTraits?.map((speciesTrait) =>
|
||||
simulateRacialTraitFromContract(speciesTrait)
|
||||
);
|
||||
|
||||
const calledOutSpeciesTraits =
|
||||
simulatedSpeciesTraits &&
|
||||
deriveCalledOutRacialTraits(simulatedSpeciesTraits, ruleData);
|
||||
|
||||
const onConfirm = () => {
|
||||
if (selectedSpecies) dispatch(raceChoose(selectedSpecies));
|
||||
onClose();
|
||||
};
|
||||
|
||||
const definitionKey =
|
||||
(selectedSpecies &&
|
||||
generateDefinitionKey(
|
||||
getEntityRaceTypeId(selectedSpecies),
|
||||
getEntityRaceId(selectedSpecies)
|
||||
)) ||
|
||||
"";
|
||||
|
||||
const builderText = getHelperText(
|
||||
[definitionKey],
|
||||
ruleData,
|
||||
DisplayConfigurationTypeEnum.RACIAL_TRAIT
|
||||
);
|
||||
|
||||
const orderedSpeciesTraits: RacialTrait[] = speciesTraits
|
||||
? deriveOrderedRacialTraits(speciesTraits)
|
||||
: [];
|
||||
|
||||
let visibleSpeciesTraits: RacialTrait[] = deriveVisibleTraits(
|
||||
orderedSpeciesTraits,
|
||||
AppContextTypeEnum.BUILDER
|
||||
);
|
||||
|
||||
visibleSpeciesTraits = filterRacialTraits(visibleSpeciesTraits, [
|
||||
DisplayConfigurationTypeEnum.RACIAL_TRAIT,
|
||||
]);
|
||||
|
||||
const sourceList = sources
|
||||
?.map((sourceMapping) =>
|
||||
getSourceDataInfo(sourceMapping.sourceId, ruleData)
|
||||
)
|
||||
.filter(isNotNullOrUndefined)
|
||||
.map((source, idx) => (
|
||||
<React.Fragment key={`${source}-${idx}`}>
|
||||
{idx > 0 ? " / " : " "}
|
||||
<Reference name={source.description} />
|
||||
</React.Fragment>
|
||||
));
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
className={clsx([styles.confirmSpeciesModal, className])}
|
||||
onClose={onClose}
|
||||
heading={`${species ? "Confirm Change" : "Confirm"} Species`}
|
||||
onConfirm={onConfirm}
|
||||
useMobileFullScreen
|
||||
{...props}
|
||||
>
|
||||
{missingFeatDependencies.length > 0 && (
|
||||
<div className="builder-message builder-message-warning">
|
||||
By changing your species, you will have invalid feat selection(s):
|
||||
{" " +
|
||||
missingFeatDependencies.map((feat) => getFeatName(feat)).join(", ")}
|
||||
</div>
|
||||
)}
|
||||
{selectedSpecies && (
|
||||
<div className={styles.content}>
|
||||
<ConfirmSpeciesHeader
|
||||
heading={fullName || ""}
|
||||
content={description || ""}
|
||||
imageUrl={previewUrl}
|
||||
isLegacy={isLegacy}
|
||||
sources={sourceList}
|
||||
/>
|
||||
{calledOutSpeciesTraits && calledOutSpeciesTraits.length > 0 && (
|
||||
<SummaryList
|
||||
list={calledOutSpeciesTraits}
|
||||
title="Species Traits"
|
||||
className={styles.summaryList}
|
||||
/>
|
||||
)}
|
||||
{moreDetailsUrl && (
|
||||
<div className={styles.detailsLink}>
|
||||
<Button
|
||||
href={moreDetailsUrl}
|
||||
variant="builder-text"
|
||||
size="x-small"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{fullName} Details Page <ArrowRightIcon />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<ConfirmSpeciesContent
|
||||
heading={`${fullName} Traits`}
|
||||
helpItems={builderText}
|
||||
speciesTraits={visibleSpeciesTraits.map((trait) => ({
|
||||
name: getRacialTraitName(trait),
|
||||
description: getRacialTraitDescription(trait),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</ConfirmModal>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user