179 lines
6.2 KiB
TypeScript
179 lines
6.2 KiB
TypeScript
import clsx from "clsx";
|
|
import { useContext, useEffect, useRef, useState } from "react";
|
|
import ReactDOM from "react-dom";
|
|
import { useSelector } from "react-redux";
|
|
|
|
import {
|
|
ConfigUtils,
|
|
Constants,
|
|
CampaignUtils,
|
|
characterEnvSelectors,
|
|
} from "@dndbeyond/character-rules-engine/es";
|
|
import { Platform } from "@dndbeyond/event-pipeline-lib/shared";
|
|
import D20 from "@dndbeyond/fontawesome-cache/svgs/light/dice-d20.svg";
|
|
import { GameLogContext } from "@dndbeyond/game-log-components";
|
|
import { getMessageBroker } from "@dndbeyond/message-broker-lib";
|
|
import {
|
|
CustomDiceRoller,
|
|
rollerImport,
|
|
} from "@dndbeyond/pocket-dimension-dice/components/CustomDiceRoller";
|
|
import "@dndbeyond/pocket-dimension-dice/components/CustomDiceRoller/index.css";
|
|
import { Context as DiceWorkerContext } from "@dndbeyond/pocket-dimension-dice/context";
|
|
import { instrumentDiceClear } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceClear";
|
|
import { instrumentDiceContainerClose } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceContainerClose";
|
|
import { instrumentDiceContainerOpen } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceContainerOpen";
|
|
import { instrumentDiceRoll } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceRoll";
|
|
import { useDiceSets } from "@dndbeyond/pocket-dimension-dice/hooks/useDiceSets";
|
|
import { useUserDiceDataStore } from "@dndbeyond/pocket-dimension-dice/hooks/useUserDiceDataStore";
|
|
import { AnchoredPopover } from "@dndbeyond/ttui/components/AnchoredPopover";
|
|
|
|
import { Button } from "~/components/Button";
|
|
import { useAuth } from "~/contexts/Authentication";
|
|
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
|
|
import { useDispatch } from "~/hooks/useDispatch";
|
|
|
|
import { appEnvSelectors } from "../../selectors";
|
|
import styles from "./DiceContainer.module.css";
|
|
|
|
const location = "characterSheet";
|
|
|
|
export default function DiceContainer({ canShow = true, isVttView = false }) {
|
|
const { nodeEnv, env } = useContext(DiceWorkerContext);
|
|
const dispatch = useDispatch();
|
|
const diceEnabled = useSelector(appEnvSelectors.getDiceEnabled);
|
|
const diceFeatureConfiguration = useSelector(
|
|
appEnvSelectors.getDiceFeatureConfiguration
|
|
);
|
|
const { campaign, characterName } = useCharacterEngine();
|
|
const user = useAuth();
|
|
const [{ entityId }] = useContext(GameLogContext);
|
|
const canvasContainer = useRef<HTMLDivElement | null>(null);
|
|
const [isCustomDiceRollerOpen, setIsCustomDiceRollerOpen] = useState(false);
|
|
const diceSets = useDiceSets(nodeEnv, env);
|
|
const setId = useUserDiceDataStore(
|
|
(state) => state.getUserDiceData(Number(user?.id))?.setId
|
|
);
|
|
const dmId = campaign
|
|
? String(CampaignUtils.getDmUserId(campaign))
|
|
: undefined;
|
|
const isSheet =
|
|
useSelector(characterEnvSelectors.getContext) ===
|
|
Constants.AppContextTypeEnum.SHEET;
|
|
|
|
useEffect(() => {
|
|
getMessageBroker().then((mb) => {
|
|
if (mb && user?.id) {
|
|
if (campaign) {
|
|
mb.gameId = CampaignUtils.getId(campaign).toString();
|
|
} else {
|
|
mb.gameId = undefined;
|
|
}
|
|
|
|
mb.userId = user.id;
|
|
}
|
|
ConfigUtils.configureRulesEngine({ messageBroker: mb });
|
|
});
|
|
}, [
|
|
campaign,
|
|
diceFeatureConfiguration.apiEndpoint,
|
|
diceFeatureConfiguration.assetBaseLocation,
|
|
diceFeatureConfiguration.enabled,
|
|
diceFeatureConfiguration.trackingId,
|
|
dispatch,
|
|
isSheet,
|
|
user?.id,
|
|
]);
|
|
|
|
if (isVttView) return null;
|
|
|
|
return ReactDOM.createPortal(
|
|
<div className={"dice-rolling-panel"} ref={canvasContainer}>
|
|
{canShow && diceEnabled && (
|
|
<AnchoredPopover
|
|
offset={16}
|
|
open={isCustomDiceRollerOpen}
|
|
allowedPlacements={["top-start"]}
|
|
referenceComponent={
|
|
<Button
|
|
className={clsx([
|
|
styles.button,
|
|
isCustomDiceRollerOpen && styles.customDiceRollOpen,
|
|
])}
|
|
onClick={() => {
|
|
setIsCustomDiceRollerOpen(!isCustomDiceRollerOpen);
|
|
|
|
// isCustomDiceRollerOpen is the previous state here
|
|
if (isCustomDiceRollerOpen) {
|
|
instrumentDiceContainerClose(
|
|
user,
|
|
Platform.Web,
|
|
location,
|
|
campaign?.id,
|
|
undefined,
|
|
env
|
|
);
|
|
} else {
|
|
instrumentDiceContainerOpen(
|
|
user,
|
|
Platform.Web,
|
|
location,
|
|
campaign?.id,
|
|
undefined,
|
|
env
|
|
);
|
|
}
|
|
}}
|
|
themed
|
|
onMouseEnter={rollerImport}
|
|
>
|
|
<D20 />
|
|
</Button>
|
|
}
|
|
floatingArrow
|
|
floatingArrowClassName={styles.floatingArrow}
|
|
>
|
|
{diceSets && (
|
|
<CustomDiceRoller
|
|
rollCallback={() => setIsCustomDiceRollerOpen(false)}
|
|
onClose={() => setIsCustomDiceRollerOpen(false)}
|
|
diceSets={diceSets}
|
|
gameId={campaign?.id}
|
|
visible={isCustomDiceRollerOpen}
|
|
setId={setId}
|
|
entityType="character"
|
|
entityId={entityId}
|
|
name={characterName ?? undefined}
|
|
rollInstrumentationCallback={(eventPayload) =>
|
|
instrumentDiceRoll(
|
|
user,
|
|
eventPayload,
|
|
Platform.Web,
|
|
location,
|
|
campaign?.id,
|
|
undefined,
|
|
env
|
|
)
|
|
}
|
|
clearDiceCallback={() =>
|
|
instrumentDiceClear(
|
|
user,
|
|
Platform.Web,
|
|
location,
|
|
campaign?.id,
|
|
undefined,
|
|
env
|
|
)
|
|
}
|
|
dmId={dmId}
|
|
/>
|
|
)}
|
|
</AnchoredPopover>
|
|
)}
|
|
{/* We want this one so it is sticking around,
|
|
also this is where the canvas goes when we append */}
|
|
{/* <canvas className={'dice-rolling-panel__container'} ref={canvas} /> */}
|
|
</div>,
|
|
document.body
|
|
);
|
|
}
|