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,302 @@
|
||||
import { keyBy } from "lodash";
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
ItemPreview,
|
||||
Snippet,
|
||||
CreaturePreview,
|
||||
} from "@dndbeyond/character-components/es";
|
||||
import {
|
||||
AccessUtils,
|
||||
ClassUtils,
|
||||
Constants,
|
||||
Creature,
|
||||
CreatureLookup,
|
||||
CreatureUtils,
|
||||
HelperUtils,
|
||||
Infusion,
|
||||
InfusionChoice,
|
||||
InfusionChoiceUtils,
|
||||
InfusionModifierDataContract,
|
||||
InfusionUtils,
|
||||
InventoryLookup,
|
||||
Item,
|
||||
ItemUtils,
|
||||
KnownInfusionUtils,
|
||||
RuleData,
|
||||
SnippetData,
|
||||
Hack__BaseCharClass,
|
||||
CharacterTheme,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
interface Props {
|
||||
inventory: Array<Item>;
|
||||
creatures: Array<Creature>;
|
||||
infusionChoices: Array<InfusionChoice>;
|
||||
proficiencyBonus: number;
|
||||
snippetData: SnippetData;
|
||||
ruleData: RuleData;
|
||||
isReadonly: boolean;
|
||||
isMobile: boolean;
|
||||
theme: CharacterTheme;
|
||||
|
||||
onInfusionChoiceShow?: (infusionChoice: InfusionChoice) => void;
|
||||
onItemShow?: (item: Item) => void;
|
||||
onCreatureShow?: (creature: Creature) => void;
|
||||
}
|
||||
interface State {
|
||||
inventoryLookup: InventoryLookup;
|
||||
creatureLookup: CreatureLookup;
|
||||
}
|
||||
export class Infusions extends React.PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
isReadonly: false,
|
||||
isMobile: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
inventoryLookup: keyBy(props.inventory, (item) =>
|
||||
ItemUtils.getMappingId(item)
|
||||
),
|
||||
creatureLookup: keyBy(props.creatures, (creature) =>
|
||||
CreatureUtils.getMappingId(creature)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (
|
||||
prevProps.inventory !== this.props.inventory ||
|
||||
prevProps.creatures !== this.props.creatures
|
||||
) {
|
||||
this.setState({
|
||||
inventoryLookup: keyBy(this.props.inventory, (item) =>
|
||||
ItemUtils.getMappingId(item)
|
||||
),
|
||||
creatureLookup: keyBy(this.props.creatures, (creature) =>
|
||||
CreatureUtils.getMappingId(creature)
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleItemClick = (item: Item): void => {
|
||||
const { onItemShow } = this.props;
|
||||
|
||||
if (onItemShow) {
|
||||
onItemShow(item);
|
||||
}
|
||||
};
|
||||
|
||||
handleCreatureClick = (creature: Creature): void => {
|
||||
const { onCreatureShow } = this.props;
|
||||
|
||||
if (onCreatureShow) {
|
||||
onCreatureShow(creature);
|
||||
}
|
||||
};
|
||||
|
||||
handleInfusionClick = (
|
||||
infusionChoice: InfusionChoice,
|
||||
evt: React.MouseEvent
|
||||
): void => {
|
||||
const { onInfusionChoiceShow } = this.props;
|
||||
|
||||
evt.stopPropagation();
|
||||
evt.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
if (onInfusionChoiceShow) {
|
||||
onInfusionChoiceShow(infusionChoice);
|
||||
}
|
||||
};
|
||||
|
||||
renderDescription = (
|
||||
simulatedInfusion: Infusion,
|
||||
infusionChoice: InfusionChoice,
|
||||
selectedModifierData: InfusionModifierDataContract | null
|
||||
): React.ReactNode => {
|
||||
const { snippetData, proficiencyBonus } = this.props;
|
||||
|
||||
if (
|
||||
AccessUtils.isAccessible(InfusionUtils.getAccessType(simulatedInfusion))
|
||||
) {
|
||||
let classLevel: number | null = selectedModifierData?.value ?? null;
|
||||
const dataOriginType =
|
||||
InfusionChoiceUtils.getDataOriginType(infusionChoice);
|
||||
|
||||
if (
|
||||
dataOriginType === Constants.DataOriginTypeEnum.CLASS_FEATURE &&
|
||||
!classLevel
|
||||
) {
|
||||
const dataOrigin = InfusionChoiceUtils.getDataOrigin(infusionChoice);
|
||||
classLevel = ClassUtils.getLevel(
|
||||
dataOrigin.parent as Hack__BaseCharClass
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Snippet
|
||||
snippetData={snippetData}
|
||||
classLevel={classLevel}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
>
|
||||
{InfusionUtils.getSnippet(simulatedInfusion)}
|
||||
</Snippet>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ct-infusions__infusion-empty">
|
||||
Check out the Marketplace to unlock this infusion.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
renderInfusions = (): React.ReactNode => {
|
||||
const { inventoryLookup, creatureLookup } = this.state;
|
||||
const { infusionChoices, ruleData, theme } = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{infusionChoices.map((infusionChoice) => {
|
||||
const knownInfusion =
|
||||
InfusionChoiceUtils.getKnownInfusion(infusionChoice);
|
||||
|
||||
if (knownInfusion === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const simulatedInfusion =
|
||||
KnownInfusionUtils.getSimulatedInfusion(knownInfusion);
|
||||
|
||||
if (simulatedInfusion === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const infusion = InfusionChoiceUtils.getInfusion(infusionChoice);
|
||||
const infusionType = InfusionUtils.getType(simulatedInfusion);
|
||||
|
||||
let item: Item | null = null;
|
||||
let creature: Creature | null = null;
|
||||
let selectedModifierData: InfusionModifierDataContract | null = null;
|
||||
if (infusion) {
|
||||
let inventoryMappingId =
|
||||
InfusionUtils.getInventoryMappingId(infusion);
|
||||
item = HelperUtils.lookupDataOrFallback(
|
||||
inventoryLookup,
|
||||
inventoryMappingId
|
||||
);
|
||||
let creatureMappingId =
|
||||
InfusionUtils.getCreatureMappingId(infusion);
|
||||
if (creatureMappingId !== null) {
|
||||
creature = HelperUtils.lookupDataOrFallback(
|
||||
creatureLookup,
|
||||
creatureMappingId
|
||||
);
|
||||
}
|
||||
selectedModifierData =
|
||||
InfusionUtils.getSelectedModifierData(infusion);
|
||||
}
|
||||
|
||||
let itemNode: React.ReactNode;
|
||||
if (item) {
|
||||
itemNode = (
|
||||
<div className="ct-infusions__infusion-item">
|
||||
<ItemPreview
|
||||
theme={theme}
|
||||
item={item}
|
||||
onClick={this.handleItemClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
itemNode = (
|
||||
<div className="ct-infusions__infusion-empty">
|
||||
No item infused
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let creatureNode: React.ReactNode;
|
||||
if (creature) {
|
||||
creatureNode = (
|
||||
<div className="ct-infusions__infusion-item">
|
||||
<CreaturePreview
|
||||
creature={creature}
|
||||
ruleData={ruleData}
|
||||
onClick={this.handleCreatureClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let selectedModifierDataNode: React.ReactNode;
|
||||
if (selectedModifierData && selectedModifierData.name) {
|
||||
selectedModifierDataNode = (
|
||||
<div className="ct-infusions__infusion-item">
|
||||
{selectedModifierData.name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let infusionName = InfusionUtils.getName(simulatedInfusion);
|
||||
let infusionNameExtraNode: React.ReactNode;
|
||||
if (infusionType === Constants.InfusionTypeEnum.REPLICATE) {
|
||||
let itemName = KnownInfusionUtils.getItemName(knownInfusion);
|
||||
if (itemName) {
|
||||
infusionNameExtraNode = `: ${itemName}`;
|
||||
}
|
||||
}
|
||||
|
||||
const choiceKey = InfusionChoiceUtils.getKey(infusionChoice);
|
||||
return (
|
||||
<div
|
||||
className="ct-infusions__infusion"
|
||||
key={choiceKey === null ? "" : choiceKey}
|
||||
onClick={this.handleInfusionClick.bind(this, infusionChoice)}
|
||||
>
|
||||
<div className="ct-infusions__infusion-header">
|
||||
{infusionName}
|
||||
{infusionNameExtraNode}
|
||||
</div>
|
||||
<div className="ct-infusions__infusion-content">
|
||||
<div className="ct-infusions__infusion-description">
|
||||
{this.renderDescription(
|
||||
simulatedInfusion,
|
||||
infusionChoice,
|
||||
selectedModifierData
|
||||
)}
|
||||
</div>
|
||||
<div className="ct-infusions__infusion-items">
|
||||
{itemNode}
|
||||
{creatureNode}
|
||||
{selectedModifierDataNode}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { infusionChoices } = this.props;
|
||||
|
||||
let contentNode: React.ReactNode = (
|
||||
<div className="ct-infusions__empty">
|
||||
No infusions choices have been made for this character
|
||||
</div>
|
||||
);
|
||||
if (infusionChoices.length > 0) {
|
||||
contentNode = this.renderInfusions();
|
||||
}
|
||||
|
||||
return <div className="ct-infusions">{contentNode}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Infusions;
|
||||
Reference in New Issue
Block a user