import React, { useContext } from "react"; import { connect } from "react-redux"; import { rulesEngineSelectors, AbilityLookup, DataOriginRefData, InventoryManager, Item, ItemUtils, LimitedUseUtils, Spell, SpellUtils, RuleData, ItemManager, } from "@dndbeyond/character-rules-engine/es"; import { SpellName } from "~/components/SpellName"; import { useSidebar } from "~/contexts/Sidebar"; import { PaneInfo } from "~/contexts/Sidebar/Sidebar"; import { PaneComponentEnum } from "~/subApps/sheet/components/Sidebar/types"; import SlotManager from "../../components/SlotManager"; import SlotManagerLarge from "../../components/SlotManagerLarge"; import { InventoryManagerContext } from "../../managers/InventoryManagerContext"; import { appEnvSelectors } from "../../selectors"; import { SharedAppState } from "../../stores/typings"; import { PaneIdentifierUtils } from "../../utils"; interface Props { item: Item; largePoolMinAmount: number; abilityLookup: AbilityLookup; ruleData: RuleData; dataOriginRefData: DataOriginRefData; isReadonly: boolean; proficiencyBonus: number; inventoryManager: InventoryManager; paneHistoryPush: PaneInfo["paneHistoryPush"]; } class ItemDetailAbilities extends React.PureComponent { static defaultProps = { largePoolMinAmount: 11, }; handleSlotUseSet = (uses: number): void => { const { item: itemData } = this.props; const item = ItemManager.getItem(ItemUtils.getMappingId(itemData)); item.handleItemLimitedUseSet(uses); }; handleSpellDetailClick = (id: number): void => { const { paneHistoryPush } = this.props; paneHistoryPush( PaneComponentEnum.CHARACTER_SPELL_DETAIL, PaneIdentifierUtils.generateCharacterSpell(id) ); }; renderSmallAmountSlotPool = (): React.ReactNode => { const { ruleData, abilityLookup, item, proficiencyBonus } = this.props; let limitedUse = ItemUtils.getLimitedUse(item); if (limitedUse === null) { return null; } const numberUsed = LimitedUseUtils.getNumberUsed(limitedUse); const maxUses = LimitedUseUtils.deriveMaxUses( limitedUse, abilityLookup, ruleData, proficiencyBonus ); return ( ); }; renderLargeAmountSlotPool = (): React.ReactNode => { const { ruleData, abilityLookup, item, isReadonly, proficiencyBonus } = this.props; let limitedUse = ItemUtils.getLimitedUse(item); if (limitedUse === null) { return null; } const numberUsed = LimitedUseUtils.getNumberUsed(limitedUse); const maxUses = LimitedUseUtils.deriveMaxUses( limitedUse, abilityLookup, ruleData, proficiencyBonus ); return ( ); }; renderLimitedUses = (): React.ReactNode => { const { item, largePoolMinAmount, abilityLookup, ruleData, proficiencyBonus, inventoryManager, } = this.props; let limitedUse = ItemUtils.getLimitedUse(item); if (!limitedUse) { return null; } let initialMaxUses = LimitedUseUtils.getInitialMaxUses(limitedUse); if (initialMaxUses === 0) { return null; } let maxUses = LimitedUseUtils.deriveMaxUses( limitedUse, abilityLookup, ruleData, proficiencyBonus ); if (!maxUses) { return null; } const canUseCharges = inventoryManager.canUseItemCharges(item); return canUseCharges ? (
Charges
{maxUses >= largePoolMinAmount ? this.renderLargeAmountSlotPool() : this.renderSmallAmountSlotPool()}
) : null; }; renderSpell = (spell: Spell): React.ReactNode => { const { dataOriginRefData } = this.props; let limitedUse = SpellUtils.getLimitedUse(spell); let limitedUseNode: React.ReactNode = "At Will"; if (limitedUse) { let minConsumed = LimitedUseUtils.getMinNumberConsumed(limitedUse); let maxConsumed = LimitedUseUtils.getMaxNumberConsumed(limitedUse); if (minConsumed === maxConsumed || minConsumed === null) { limitedUseNode = `${maxConsumed} Charge${maxConsumed === 1 ? "" : "s"}`; } else { limitedUseNode = `${minConsumed}-${maxConsumed} Charges`; } } return (
{limitedUseNode}
); }; renderSpells = (): React.ReactNode => { const { item } = this.props; const spells = ItemUtils.getSpells(item); if (!spells || !spells.length) { return null; } return (
{spells.map((spell) => this.renderSpell(spell))}
); }; render() { let limitedUseNode = this.renderLimitedUses(); let spellsNode = this.renderSpells(); if (!limitedUseNode && !spellsNode) { return null; } return (
{limitedUseNode} {spellsNode}
); } } function mapStateToProps(state: SharedAppState) { return { abilityLookup: rulesEngineSelectors.getAbilityLookup(state), ruleData: rulesEngineSelectors.getRuleData(state), isReadonly: appEnvSelectors.getIsReadonly(state), dataOriginRefData: rulesEngineSelectors.getDataOriginRefData(state), proficiencyBonus: rulesEngineSelectors.getProficiencyBonus(state), }; } const ItemDetailAbilitiesWrapper = (props) => { const { inventoryManager } = useContext(InventoryManagerContext); const { pane: { paneHistoryPush }, } = useSidebar(); return ( ); }; export default connect(mapStateToProps)(ItemDetailAbilitiesWrapper);