New source found from dndbeyond.com
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import { useContext } from "react";
|
||||
import { connect, DispatchProp } from "react-redux";
|
||||
import { AnyAction } from "redux";
|
||||
|
||||
import {
|
||||
rulesEngineSelectors,
|
||||
CampaignUtils,
|
||||
serviceDataActions,
|
||||
Constants,
|
||||
Container,
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
GroupedMenuOption,
|
||||
serviceDataSelectors,
|
||||
PartyInfo,
|
||||
ItemPlan,
|
||||
ContainerLookup,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import { Button } from "~/components/Button";
|
||||
@@ -24,29 +26,18 @@ import { Popover } from "~/components/Popover";
|
||||
import { PopoverContent } from "~/components/PopoverContent";
|
||||
import { useSidebar } from "~/contexts/Sidebar";
|
||||
import { PaneInfo } from "~/contexts/Sidebar/Sidebar";
|
||||
import { ButtonWithMenu } from "~/subApps/sheet/components/Sidebar/components/ButtonWithMenu";
|
||||
import { PaneComponentEnum } from "~/subApps/sheet/components/Sidebar/types";
|
||||
|
||||
import SimpleQuantity from "../../components/SimpleQuantity";
|
||||
import {
|
||||
RemoveButton,
|
||||
ThemeButton,
|
||||
ThemeButtonWithMenu,
|
||||
} from "../../components/common/Button";
|
||||
import { InventoryManagerContext } from "../../managers/InventoryManagerContext";
|
||||
import * as appEnvSelectors from "../../selectors/appEnv";
|
||||
import { SharedAppState } from "../../stores/typings";
|
||||
import { PaneIdentifierUtils } from "../../utils";
|
||||
|
||||
interface LabelLookup {
|
||||
consume: string;
|
||||
remove: string;
|
||||
unequip: string;
|
||||
equip: string;
|
||||
attune: string;
|
||||
unattune: string;
|
||||
}
|
||||
|
||||
interface Props extends DispatchProp {
|
||||
// TODO: We are typing with AnyAction here to work around issues with UnknownAction, the type that was introduced in Redux 5.
|
||||
// If we decide to modernize to Redux 5, we will need to refactor much of the Rules Engine redux usage.
|
||||
interface Props extends DispatchProp<AnyAction> {
|
||||
item: Item;
|
||||
hasMaxAttunedItems: boolean;
|
||||
ruleData: RuleData;
|
||||
@@ -56,6 +47,10 @@ interface Props extends DispatchProp {
|
||||
partyInfo: PartyInfo | null;
|
||||
inventoryManager: InventoryManager;
|
||||
paneHistoryStart: PaneInfo["paneHistoryStart"];
|
||||
itemPlans: Array<ItemPlan>;
|
||||
containerLookup: ContainerLookup;
|
||||
isUserDM: boolean;
|
||||
onRemoveItem?: () => void;
|
||||
}
|
||||
interface State {
|
||||
quantity: number;
|
||||
@@ -98,8 +93,17 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
handleRemove = (): void => {
|
||||
const { paneHistoryStart, item, onPostRemoveNavigation, inventoryManager } =
|
||||
this.props;
|
||||
const {
|
||||
paneHistoryStart,
|
||||
item,
|
||||
onPostRemoveNavigation,
|
||||
inventoryManager,
|
||||
onRemoveItem,
|
||||
} = this.props;
|
||||
|
||||
if (onRemoveItem) {
|
||||
onRemoveItem();
|
||||
}
|
||||
|
||||
if (onPostRemoveNavigation) {
|
||||
paneHistoryStart(onPostRemoveNavigation);
|
||||
@@ -113,7 +117,13 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
handleRemoveInfusion = (): void => {
|
||||
const { dispatch, paneHistoryStart, item } = this.props;
|
||||
const {
|
||||
dispatch,
|
||||
paneHistoryStart,
|
||||
item,
|
||||
inventoryManager,
|
||||
containerLookup,
|
||||
} = this.props;
|
||||
|
||||
const infusion = ItemUtils.getInfusion(item);
|
||||
if (infusion) {
|
||||
@@ -137,7 +147,10 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
dispatch(
|
||||
serviceDataActions.infusionMappingDestroy(
|
||||
infusionId,
|
||||
InfusionUtils.getInventoryMappingId(infusion)
|
||||
InfusionUtils.getInventoryMappingId(infusion),
|
||||
inventoryManager.handleAcceptOnSuccess(
|
||||
ItemUtils.isShared(item, containerLookup)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -180,34 +193,30 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
inventoryManager.handleMove({ item, containerDefinitionKey });
|
||||
};
|
||||
|
||||
getLabels = (): LabelLookup => {
|
||||
return {
|
||||
consume: "Consume",
|
||||
remove: "Delete Item",
|
||||
unequip: "Unequip",
|
||||
equip: "Equip",
|
||||
attune: "Attune",
|
||||
unattune: "Unattune",
|
||||
};
|
||||
};
|
||||
|
||||
getContainerOptions = (): Array<GroupedMenuOption> => {
|
||||
const { containers, item, partyInfo } = this.props;
|
||||
const { containers, item } = this.props;
|
||||
|
||||
return ContainerUtils.getGroupedOptions(
|
||||
ItemUtils.getContainerDefinitionKey(item),
|
||||
containers,
|
||||
"Move To:",
|
||||
partyInfo
|
||||
? CampaignUtils.getSharingState(partyInfo)
|
||||
: Constants.PartyInventorySharingStateEnum.OFF
|
||||
"Move To:"
|
||||
);
|
||||
};
|
||||
|
||||
renderRemove = (): React.ReactNode => {
|
||||
const { item, containers, isReadonly, inventoryManager } = this.props;
|
||||
const {
|
||||
item,
|
||||
containers,
|
||||
isReadonly,
|
||||
inventoryManager,
|
||||
itemPlans,
|
||||
isUserDM,
|
||||
} = this.props;
|
||||
|
||||
const canRemoveItem = isUserDM
|
||||
? true
|
||||
: inventoryManager.canRemoveItem(item);
|
||||
|
||||
const canRemoveItem = inventoryManager.canRemoveItem(item);
|
||||
if (isReadonly || !canRemoveItem) {
|
||||
return null;
|
||||
}
|
||||
@@ -216,6 +225,7 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
|
||||
const name = ItemUtils.getName(item);
|
||||
const isContainer = ItemUtils.isContainer(item);
|
||||
const itemPlan = ItemUtils.getItemPlan(item, itemPlans);
|
||||
|
||||
if (isContainer) {
|
||||
const container = containers.find((container) => {
|
||||
@@ -230,13 +240,15 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
if (container) {
|
||||
if (infusion) {
|
||||
return (
|
||||
<RemoveButton
|
||||
<Button
|
||||
onClick={this.handleRemove}
|
||||
className="ct-item-detail__action"
|
||||
variant="outline"
|
||||
size="xx-small"
|
||||
themed
|
||||
data-testid="remove-infusion-button"
|
||||
>
|
||||
Remove Infusion
|
||||
</RemoveButton>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
const hasInfusions = ContainerUtils.hasInfusions(container);
|
||||
@@ -245,7 +257,7 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
<Popover
|
||||
trigger={
|
||||
<Button size="xx-small" variant="outline" themed>
|
||||
Delete
|
||||
Delete{itemPlan ? " Replicated Item" : ""}
|
||||
</Button>
|
||||
}
|
||||
position="bottom"
|
||||
@@ -262,43 +274,34 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
withCancel
|
||||
/>
|
||||
</Popover>
|
||||
// <RemoveButtonWithModal
|
||||
// className="ct-item-detail__action"
|
||||
// style={"outline"}
|
||||
// size="small"
|
||||
// modalTitle={`Delete ${name}?`}
|
||||
// modalContent={`Deleting the ${name} will also delete all of its${
|
||||
// hasInfusions ? " infusions and" : ""
|
||||
// } contents.`}
|
||||
// confirmCallback={() => {
|
||||
// this.handleRemove();
|
||||
// }}
|
||||
// data-testid="delete-item-button"
|
||||
// />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (infusion) {
|
||||
return (
|
||||
<RemoveButton
|
||||
<Button
|
||||
onClick={this.handleRemoveInfusion}
|
||||
className="ct-item-detail__action"
|
||||
variant="outline"
|
||||
size="xx-small"
|
||||
themed
|
||||
data-testid="remove-infusion-button"
|
||||
>
|
||||
Remove Infusion
|
||||
</RemoveButton>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<RemoveButton
|
||||
<Button
|
||||
onClick={this.handleRemove}
|
||||
className="ct-item-detail__action"
|
||||
variant="outline"
|
||||
size="xx-small"
|
||||
themed
|
||||
data-testid="delete-item-button"
|
||||
>
|
||||
Delete
|
||||
</RemoveButton>
|
||||
Delete{itemPlan ? " Replicated Item" : ""}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -310,14 +313,11 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
containers,
|
||||
inventoryManager,
|
||||
} = this.props;
|
||||
|
||||
const labels = this.getLabels();
|
||||
const containerMoveOptions = this.getContainerOptions();
|
||||
const isEquipped = ItemUtils.isEquipped(item);
|
||||
const isAttuned = ItemUtils.isAttuned(item);
|
||||
const isStackable = ItemUtils.isStackable(item);
|
||||
const quantity = ItemUtils.getQuantity(item);
|
||||
const isContainer = ItemUtils.getDefinitionIsContainer(item);
|
||||
const parentContainer = ContainerUtils.getItemParentContainer(
|
||||
containers,
|
||||
ItemUtils.getContainerDefinitionKey(item)
|
||||
@@ -325,16 +325,20 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
if (!parentContainer) {
|
||||
return null;
|
||||
}
|
||||
const canEquip = inventoryManager.canEquipUnequipItem(item);
|
||||
const canAttune = inventoryManager.canAttuneUnattuneItem(item);
|
||||
const canModifyQuantity = inventoryManager.canModifyQuantity(item);
|
||||
const canMoveItem =
|
||||
inventoryManager.canMoveItem(item) &&
|
||||
!isContainer &&
|
||||
!isReadonly &&
|
||||
!!containers.length;
|
||||
const canShareItem = inventoryManager.canShareItem(item) && !isReadonly;
|
||||
const canClaimItem = inventoryManager.canClaimItem(item) && !isReadonly;
|
||||
const canEquip = inventoryManager.canEquipUnequipItem(item) && !isReadonly;
|
||||
const canAttune =
|
||||
inventoryManager.canAttuneUnattuneItem(item) && !isReadonly;
|
||||
const canModifyQuantity =
|
||||
inventoryManager.canModifyQuantity(item) && !isReadonly;
|
||||
const canMoveItem = inventoryManager.canMoveItem(item) && !isReadonly;
|
||||
const canShareContainer =
|
||||
inventoryManager.canShareContainer(item) && !isReadonly;
|
||||
const canClaimContainer =
|
||||
inventoryManager.canClaimContainer(item) && !isReadonly;
|
||||
const partyInventoryDefinitionKey =
|
||||
inventoryManager.getPartyEquipmentContainerDefinitionKey();
|
||||
const characterInventoryDefinitionKey =
|
||||
inventoryManager.getCharacterContainerDefinitionKey();
|
||||
|
||||
return (
|
||||
<div className="ct-item-detail__actions">
|
||||
@@ -342,80 +346,86 @@ class ItemDetailActions extends React.PureComponent<Props, State> {
|
||||
<SimpleQuantity
|
||||
quantity={quantity}
|
||||
onUpdate={this.handleQuantityUpdate}
|
||||
isReadonly={isReadonly || !canModifyQuantity}
|
||||
isReadonly={!canModifyQuantity}
|
||||
/>
|
||||
)}
|
||||
|
||||
{canEquip && !isReadonly && (
|
||||
<ThemeButton
|
||||
{canEquip && (
|
||||
<Button
|
||||
onClick={isEquipped ? this.handleUnequip : this.handleEquip}
|
||||
style={isEquipped ? "" : "outline"}
|
||||
size="small"
|
||||
className="ct-item-detail__action"
|
||||
variant={isEquipped ? "solid" : "outline"}
|
||||
size="xx-small"
|
||||
themed
|
||||
data-testid="equip-item-button"
|
||||
>
|
||||
{isEquipped ? labels.unequip : labels.equip}
|
||||
</ThemeButton>
|
||||
{isEquipped ? "Unequip" : "Equip"}
|
||||
</Button>
|
||||
)}
|
||||
{canAttune && !isReadonly && (
|
||||
<ThemeButton
|
||||
{canAttune && (
|
||||
<Button
|
||||
onClick={isAttuned ? this.handleUnattune : this.handleAttune}
|
||||
style={isAttuned ? "" : "outline"}
|
||||
size="small"
|
||||
variant={isAttuned ? "solid" : "outline"}
|
||||
size="xx-small"
|
||||
themed
|
||||
disabled={hasMaxAttunedItems && !isAttuned}
|
||||
className="ct-item-detail__action"
|
||||
data-testid="attune-item-button"
|
||||
>
|
||||
{isAttuned ? labels.unattune : labels.attune}
|
||||
</ThemeButton>
|
||||
{isAttuned ? "Unattune" : "Attune"}
|
||||
</Button>
|
||||
)}
|
||||
{canShareItem && (
|
||||
<ThemeButton
|
||||
style="outline"
|
||||
onClick={() => {
|
||||
const definitionKey =
|
||||
inventoryManager.getPartyEquipmentContainerDefinitionKey();
|
||||
if (definitionKey) {
|
||||
this.handleMove(definitionKey);
|
||||
}
|
||||
}}
|
||||
size="small"
|
||||
className="ct-item-detail__action"
|
||||
{canShareContainer && partyInventoryDefinitionKey && (
|
||||
<ButtonWithMenu
|
||||
showSingleOption={true}
|
||||
placement="bottom-end"
|
||||
variant="outline"
|
||||
groupedOptions={[
|
||||
{
|
||||
label: "Move To:",
|
||||
options: [
|
||||
{
|
||||
label: "Party Inventory",
|
||||
value: partyInventoryDefinitionKey,
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
onSelect={() => this.handleMove(partyInventoryDefinitionKey)}
|
||||
data-testid="move-item-button"
|
||||
>
|
||||
Move
|
||||
</ThemeButton>
|
||||
</ButtonWithMenu>
|
||||
)}
|
||||
{canClaimItem && (
|
||||
<ThemeButton
|
||||
style="outline"
|
||||
onClick={() => {
|
||||
const definitionKey =
|
||||
inventoryManager.getCharacterContainerDefinitionKey();
|
||||
if (definitionKey) {
|
||||
this.handleMove(definitionKey);
|
||||
}
|
||||
}}
|
||||
size="small"
|
||||
className="ct-item-detail__action"
|
||||
{canClaimContainer && characterInventoryDefinitionKey && (
|
||||
<ButtonWithMenu
|
||||
showSingleOption={true}
|
||||
placement="bottom-end"
|
||||
variant="outline"
|
||||
groupedOptions={[
|
||||
{
|
||||
label: "Move To:",
|
||||
options: [
|
||||
{
|
||||
label: "My Inventory",
|
||||
value: characterInventoryDefinitionKey,
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
onSelect={() => this.handleMove(characterInventoryDefinitionKey)}
|
||||
data-testid="move-item-button"
|
||||
>
|
||||
Move
|
||||
</ThemeButton>
|
||||
</ButtonWithMenu>
|
||||
)}
|
||||
{canMoveItem && (
|
||||
<ThemeButtonWithMenu
|
||||
buttonStyle="outline"
|
||||
containerEl={
|
||||
document.querySelector(".ct-sidebar__portal") as HTMLElement
|
||||
}
|
||||
className="ct-item-detail__action"
|
||||
<ButtonWithMenu
|
||||
variant="outline"
|
||||
groupedOptions={containerMoveOptions}
|
||||
showSingleOption={true}
|
||||
onSelect={this.handleMove}
|
||||
>
|
||||
Move
|
||||
</ThemeButtonWithMenu>
|
||||
</ButtonWithMenu>
|
||||
)}
|
||||
{this.renderRemove()}
|
||||
</div>
|
||||
@@ -430,6 +440,9 @@ function mapStateToProps(state: SharedAppState) {
|
||||
hasMaxAttunedItems: rulesEngineSelectors.hasMaxAttunedItems(state),
|
||||
containers: rulesEngineSelectors.getInventoryContainers(state),
|
||||
partyInfo: serviceDataSelectors.getPartyInfo(state),
|
||||
itemPlans: rulesEngineSelectors.getAvailableItemPlans(state),
|
||||
containerLookup: rulesEngineSelectors.getContainerLookup(state),
|
||||
isUserDM: appEnvSelectors.getIsUserDM(state),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -438,6 +451,7 @@ function ItemDetailActionsContainer(props) {
|
||||
const {
|
||||
pane: { paneHistoryStart },
|
||||
} = useSidebar();
|
||||
|
||||
return (
|
||||
<ItemDetailActions
|
||||
inventoryManager={inventoryManager}
|
||||
|
||||
Reference in New Issue
Block a user