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:
+482
@@ -0,0 +1,482 @@
|
||||
import React from "react";
|
||||
import { useContext } from "react";
|
||||
import { DispatchProp } from "react-redux";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleHeaderContent,
|
||||
CollapsibleHeading,
|
||||
} from "@dndbeyond/character-components/es";
|
||||
import {
|
||||
characterActions,
|
||||
CharacterConfiguration,
|
||||
CharacterCurrencyContract,
|
||||
CharacterNotes,
|
||||
CharacterTheme,
|
||||
Constants,
|
||||
ContainerLookup,
|
||||
ContainerUtils,
|
||||
InventoryManager,
|
||||
FormatUtils,
|
||||
Item,
|
||||
ItemUtils,
|
||||
Modifier,
|
||||
RuleData,
|
||||
rulesEngineSelectors,
|
||||
TypeValueLookup,
|
||||
CoinManager,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import { EditorWithDialog } from "~/subApps/builder/components/EditorWithDialog";
|
||||
import { RouteKey } from "~/subApps/builder/constants";
|
||||
import {
|
||||
ModalData,
|
||||
useModalManager,
|
||||
} from "~/subApps/builder/contexts/ModalManager";
|
||||
|
||||
import * as toastActions from "../../../../Shared/actions/toastMessage/actions";
|
||||
import { ArmorListItem } from "../../../../Shared/components/legacy/ArmorList";
|
||||
import { CurrencyList } from "../../../../Shared/components/legacy/CurrencyList";
|
||||
import { EquipmentManagerShop } from "../../../../Shared/components/legacy/EquipmentManagerShop";
|
||||
import { GearListItem } from "../../../../Shared/components/legacy/GearList";
|
||||
import { WeaponListItem } from "../../../../Shared/components/legacy/WeaponList";
|
||||
import { CURRENCY_VALUE } from "../../../../Shared/constants/App";
|
||||
import StartingEquipment from "../../../../Shared/containers/StartingEquipment";
|
||||
import { CurrencyErrorTypeEnum } from "../../../../Shared/containers/panes/CurrencyPane/CurrencyPaneConstants";
|
||||
import { CoinManagerContext } from "../../../../Shared/managers/CoinManagerContext";
|
||||
import { InventoryManagerContext } from "../../../../Shared/managers/InventoryManagerContext";
|
||||
import { AppNotificationUtils } from "../../../../Shared/utils";
|
||||
import Page from "../../../components/Page";
|
||||
import { PageBody } from "../../../components/PageBody";
|
||||
import { PageHeader } from "../../../components/PageHeader";
|
||||
import { BuilderAppState } from "../../../typings";
|
||||
import ConnectedBuilderPage from "../ConnectedBuilderPage";
|
||||
|
||||
interface Props extends DispatchProp {
|
||||
configuration: CharacterConfiguration;
|
||||
inventory: Array<Item>;
|
||||
containerLookup: ContainerLookup;
|
||||
totalWeight: number;
|
||||
notes: CharacterNotes;
|
||||
ruleData: RuleData;
|
||||
hasMaxAttunedItems: boolean;
|
||||
characterId: number;
|
||||
theme: CharacterTheme;
|
||||
globalModifiers: Array<Modifier>;
|
||||
valueLookupByType: TypeValueLookup;
|
||||
proficiencyBonus: number;
|
||||
inventoryManager: InventoryManager;
|
||||
coinManager: CoinManager;
|
||||
activeSourceCategories: Array<number>;
|
||||
createModal: (modalData: ModalData) => void;
|
||||
}
|
||||
interface State {
|
||||
showStartingEquipment: boolean;
|
||||
}
|
||||
class EquipmentManage extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showStartingEquipment: props.configuration.startingEquipmentType === null,
|
||||
};
|
||||
}
|
||||
|
||||
textareaInput = React.createRef<HTMLDivElement>();
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>,
|
||||
snapshot?: any
|
||||
): void {
|
||||
const { configuration } = this.props;
|
||||
|
||||
if (configuration !== prevProps.configuration) {
|
||||
this.setState({
|
||||
showStartingEquipment: configuration.startingEquipmentType === null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleItemAdd = (
|
||||
item: Item,
|
||||
amount: number,
|
||||
containerDefinitionKey: string
|
||||
): void => {
|
||||
const { inventoryManager } = this.props;
|
||||
|
||||
inventoryManager.handleAdd(
|
||||
{ item, amount, containerDefinitionKey },
|
||||
AppNotificationUtils.handleItemAddAccepted.bind(this, item, amount)
|
||||
);
|
||||
};
|
||||
|
||||
handleCurrencyChange = (coin: CharacterCurrencyContract): void => {
|
||||
const { coinManager } = this.props;
|
||||
|
||||
coinManager.handleCoinSet({
|
||||
coin,
|
||||
containerDefinitionKey: coinManager.getCharacterContainerDefinitionKey(),
|
||||
});
|
||||
};
|
||||
|
||||
handleCurrencyError = (
|
||||
currencyName: string,
|
||||
errorType: CurrencyErrorTypeEnum
|
||||
): void => {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
let message: string = "";
|
||||
if (errorType === CurrencyErrorTypeEnum.MIN) {
|
||||
message =
|
||||
"Cannot set currency to a negative value, the previous amount has been set instead.";
|
||||
}
|
||||
|
||||
if (errorType === CurrencyErrorTypeEnum.MAX) {
|
||||
message = `The max amount allowed for each currency type is ${FormatUtils.renderLocaleNumber(
|
||||
CURRENCY_VALUE.MAX
|
||||
)}, the previous value has been set instead.`;
|
||||
}
|
||||
|
||||
if (errorType !== null) {
|
||||
dispatch(
|
||||
toastActions.toastError(
|
||||
`Unable to Set Currency: ${currencyName}`,
|
||||
message
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderStartingEquipment = (): React.ReactNode => {
|
||||
const { showStartingEquipment } = this.state;
|
||||
|
||||
let headingNode: React.ReactNode = (
|
||||
<CollapsibleHeading>Starting Equipment</CollapsibleHeading>
|
||||
);
|
||||
|
||||
let headerNode: React.ReactNode = (
|
||||
<CollapsibleHeaderContent heading={headingNode} />
|
||||
);
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
header={headerNode}
|
||||
className="equipment-manage__starting"
|
||||
useBuilderStyles={true}
|
||||
initiallyCollapsed={!showStartingEquipment}
|
||||
collapsed={!showStartingEquipment}
|
||||
onChangeHandler={(isCollapsed) => {
|
||||
this.setState({
|
||||
showStartingEquipment: !isCollapsed,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<StartingEquipment
|
||||
onStartingEquipmentChoose={() => {
|
||||
this.setState({
|
||||
showStartingEquipment: false,
|
||||
});
|
||||
}}
|
||||
isInitialView={true}
|
||||
/>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
renderItem = (
|
||||
item: Item,
|
||||
itemParams,
|
||||
weaponLabels,
|
||||
armorLabels,
|
||||
gearLabels
|
||||
): React.ReactNode => {
|
||||
if (ItemUtils.isWeaponContract(item)) {
|
||||
let finalWeaponLabels = weaponLabels;
|
||||
if (ItemUtils.isAmmunition(item)) {
|
||||
//TODO fix this to be cleaner
|
||||
finalWeaponLabels = {
|
||||
...weaponLabels,
|
||||
equipLabel: "Use",
|
||||
unequipLabel:
|
||||
weaponLabels.unequipLabel === "Stow"
|
||||
? weaponLabels.unequipLabel
|
||||
: "In Use",
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<WeaponListItem
|
||||
key={uuidv4()}
|
||||
item={item}
|
||||
{...finalWeaponLabels}
|
||||
{...itemParams}
|
||||
/>
|
||||
);
|
||||
} else if (ItemUtils.isArmorContract(item)) {
|
||||
return (
|
||||
<ArmorListItem
|
||||
key={uuidv4()}
|
||||
item={item}
|
||||
{...armorLabels}
|
||||
{...itemParams}
|
||||
/>
|
||||
);
|
||||
} else if (ItemUtils.isGearContract(item)) {
|
||||
return (
|
||||
<GearListItem
|
||||
key={uuidv4()}
|
||||
item={item}
|
||||
{...gearLabels}
|
||||
{...itemParams}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
renderItemList = (): React.ReactNode => {
|
||||
const { inventory } = this.props;
|
||||
|
||||
const weaponLabels = {
|
||||
equipLabel: "Wield",
|
||||
unequipLabel: "Wielding",
|
||||
};
|
||||
const armorLabels = {
|
||||
equipLabel: "Wear",
|
||||
unequipLabel: "Wearing",
|
||||
};
|
||||
const gearLabels = {
|
||||
equipLabel: "Use",
|
||||
unequipLabel: "In Use",
|
||||
};
|
||||
const itemParams = {
|
||||
showRemove: true,
|
||||
showEquip: true,
|
||||
showUnequip: true,
|
||||
showHeaderAction: true,
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{ItemUtils.sortInventoryItems(inventory).map((item) =>
|
||||
this.renderItem(
|
||||
item,
|
||||
itemParams,
|
||||
weaponLabels,
|
||||
armorLabels,
|
||||
gearLabels
|
||||
)
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
renderInventory = (): React.ReactNode => {
|
||||
const { inventory, totalWeight } = this.props;
|
||||
|
||||
const itemTotal: number = inventory.length;
|
||||
|
||||
let headerNode: React.ReactNode = (
|
||||
<CollapsibleHeaderContent
|
||||
heading={
|
||||
<CollapsibleHeading>
|
||||
Current Inventory ({itemTotal})
|
||||
</CollapsibleHeading>
|
||||
}
|
||||
callout={
|
||||
<div className="equipment-manage__callout">
|
||||
Total Weight: {FormatUtils.renderWeight(totalWeight)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
header={headerNode}
|
||||
className="equipment-manage__inventory"
|
||||
useBuilderStyles={true}
|
||||
initiallyCollapsed={itemTotal === 0}
|
||||
collapsed={itemTotal === 0}
|
||||
>
|
||||
{itemTotal === 0 ? (
|
||||
<div className="equipment-manager__inventory-empty">
|
||||
You currently have no items in your inventory. Add Starting
|
||||
Equipment above or Add Items from the list of available items below.
|
||||
</div>
|
||||
) : (
|
||||
this.renderItemList()
|
||||
)}
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
renderOtherPossessions = (): React.ReactNode => {
|
||||
const { notes, dispatch } = this.props;
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
header={"Other Possessions"}
|
||||
className="equipment-manage__possessions"
|
||||
useBuilderStyles={true}
|
||||
>
|
||||
<EditorWithDialog
|
||||
heading={<h3>Personal Possessions</h3>}
|
||||
editButtonLabel="Edit Possessions"
|
||||
addButtonLabel="Add Possessions"
|
||||
placeholder="Add personal possessions here..."
|
||||
content={notes[Constants.NoteKeyEnum.PERSONAL_POSSESSIONS] ?? ""}
|
||||
onSave={(content) => {
|
||||
dispatch(
|
||||
characterActions.noteSet(
|
||||
Constants.NoteKeyEnum.PERSONAL_POSSESSIONS,
|
||||
content
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
renderAddItems = (): React.ReactNode => {
|
||||
const {
|
||||
ruleData,
|
||||
characterId,
|
||||
theme,
|
||||
globalModifiers,
|
||||
valueLookupByType,
|
||||
proficiencyBonus,
|
||||
activeSourceCategories,
|
||||
inventoryManager,
|
||||
} = this.props;
|
||||
|
||||
const characterContainerKey =
|
||||
ContainerUtils.getCharacterContainerDefinitionKey(characterId);
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
header={"Add Items"}
|
||||
className="equipment-manage__add-items"
|
||||
useBuilderStyles={true}
|
||||
>
|
||||
<EquipmentManagerShop
|
||||
theme={theme}
|
||||
globalModifiers={globalModifiers}
|
||||
valueLookupByType={valueLookupByType}
|
||||
onItemAdd={this.handleItemAdd}
|
||||
ruleData={ruleData}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
containerDefinitionKey={characterContainerKey}
|
||||
activeSourceCategories={activeSourceCategories}
|
||||
inventoryManager={inventoryManager}
|
||||
/>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
renderCurrency = (): React.ReactNode => {
|
||||
const { coinManager } = this.props;
|
||||
|
||||
const coin = coinManager.getContainerCoin(
|
||||
coinManager.getCharacterContainerDefinitionKey()
|
||||
);
|
||||
|
||||
if (!coin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let headerNode: React.ReactNode = (
|
||||
<CollapsibleHeaderContent
|
||||
heading={<CollapsibleHeading>Currency</CollapsibleHeading>}
|
||||
callout={
|
||||
<div className="equipment-manage__callout">
|
||||
Total in GP:{" "}
|
||||
{FormatUtils.renderLocaleNumber(
|
||||
coinManager.getTotalContainerCoinInGold(
|
||||
coinManager.getCharacterContainerDefinitionKey()
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
header={headerNode}
|
||||
className="equipment-manage__currency"
|
||||
useBuilderStyles={true}
|
||||
>
|
||||
<CurrencyList
|
||||
{...coin}
|
||||
onChange={this.handleCurrencyChange}
|
||||
onError={this.handleCurrencyError}
|
||||
totalGp={coinManager.getTotalContainerCoinInGold(
|
||||
coinManager.getCharacterContainerDefinitionKey()
|
||||
)}
|
||||
/>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Page>
|
||||
<PageBody>
|
||||
<PageHeader>Choose Equipment</PageHeader>
|
||||
<div className="equipment-manage">
|
||||
{this.renderStartingEquipment()}
|
||||
{this.renderInventory()}
|
||||
{this.renderOtherPossessions()}
|
||||
{this.renderAddItems()}
|
||||
{this.renderCurrency()}
|
||||
</div>
|
||||
</PageBody>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function EquipmentManageContainer(props) {
|
||||
const { inventoryManager } = useContext(InventoryManagerContext);
|
||||
const { coinManager } = useContext(CoinManagerContext);
|
||||
const { createModal } = useModalManager();
|
||||
|
||||
return (
|
||||
<EquipmentManage
|
||||
coinManager={coinManager}
|
||||
inventoryManager={inventoryManager}
|
||||
createModal={createModal}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConnectedBuilderPage(
|
||||
EquipmentManageContainer,
|
||||
RouteKey.EQUIPMENT_MANAGE,
|
||||
(state: BuilderAppState) => {
|
||||
return {
|
||||
configuration: rulesEngineSelectors.getCharacterConfiguration(state),
|
||||
inventory: rulesEngineSelectors.getInventory(state),
|
||||
containerLookup: rulesEngineSelectors.getContainerLookup(state),
|
||||
totalWeight: rulesEngineSelectors.getTotalCarriedWeight(state),
|
||||
notes: rulesEngineSelectors.getCharacterNotes(state),
|
||||
currencies: rulesEngineSelectors.getCurrencies(state),
|
||||
ruleData: rulesEngineSelectors.getRuleData(state),
|
||||
hasMaxAttunedItems: rulesEngineSelectors.hasMaxAttunedItems(state),
|
||||
proficiencyBonus: rulesEngineSelectors.getProficiencyBonus(state),
|
||||
characterId: rulesEngineSelectors.getId(state),
|
||||
globalModifiers: rulesEngineSelectors.getValidGlobalModifiers(state),
|
||||
valueLookupByType:
|
||||
rulesEngineSelectors.getCharacterValueLookupByType(state),
|
||||
theme: rulesEngineSelectors.getCharacterTheme(state),
|
||||
activeSourceCategories:
|
||||
rulesEngineSelectors.getActiveSourceCategories(state),
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,4 @@
|
||||
import EquipmentManage from "./EquipmentManage";
|
||||
|
||||
export default EquipmentManage;
|
||||
export { EquipmentManage };
|
||||
Reference in New Issue
Block a user