Files
dndbeyond_src/ddb_main/subApps/sheet/components/WatchTourDialog/WatchTourDialog.tsx
T

145 lines
4.5 KiB
TypeScript

import clsx from "clsx";
import { FC, HTMLAttributes, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import VideoIcon from "@dndbeyond/fontawesome-cache/svgs/solid/video.svg";
import CloseIcon from "@dndbeyond/fontawesome-cache/svgs/solid/x.svg";
import { Button } from "~/components/Button";
import { Dialog } from "~/components/Dialog";
import { MaxCharactersDialog } from "~/components/MaxCharactersDialog";
import { useAuth } from "~/contexts/Authentication";
import { useClaimCharacter } from "~/hooks/useClaimCharacter";
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
import { ClaimConfirmationDialog } from "../ClaimConfirmationDialog";
import styles from "./styles.module.css";
export interface WatchTourDialogProps extends HTMLAttributes<HTMLDivElement> {}
export const WatchTourDialog: FC<WatchTourDialogProps> = ({
className,
...props
}) => {
const [isOpen, setIsOpen] = useState(false);
const [isMaxCharacterMessageOpen, setIsMaxCharacterMessageOpen] =
useState(false);
const user = useAuth();
const { characterSlotLimit, activeCharacterCount } = useSelector(
appEnvSelectors.getCharacterSlots
);
// Character slot limit is null for admin accounts
const hasOpenSlot =
characterSlotLimit === null || activeCharacterCount < characterSlotLimit;
const signedIn = !!user;
const signupLink = `/create-account?returnUrl=${window.location.pathname}`;
const params = new URLSearchParams(globalThis.location.search);
const campaignJoinCode = params.get("campaignJoinCode");
const isAssigned = params.get("isAssigned") !== "false";
const [
claimCharacter,
isClaimingCharacter,
isFinishedClaimingCharacter,
newCharacterId,
campaignId,
] = useClaimCharacter({
campaignJoinCode,
isAssigned,
});
const handleOpen = () => setIsOpen(true);
const handleClose = () => setIsOpen(false);
const handleClaim = () => {
if (hasOpenSlot) {
claimCharacter();
} else {
setIsMaxCharacterMessageOpen(true);
setIsOpen(false);
}
};
useEffect(() => {
if (isFinishedClaimingCharacter) {
setIsOpen(false);
}
}, [isFinishedClaimingCharacter]);
return (
<>
<div className={clsx([styles.watchTourDialog, className])} {...props}>
<Button
className={styles.trigger}
onClick={handleOpen}
color="secondary"
size="x-small"
>
<VideoIcon />
Watch Tour
</Button>
<Dialog
className={styles.dialog}
open={isOpen}
onClose={handleClose}
modal
>
<header className={styles.header}>
<h2 className={styles.title}>D&D Beyond Character Sheet Tour</h2>
<Button
className={styles.closeButton}
variant="tool"
onClick={handleClose}
aria-label="Close Modal"
>
<CloseIcon />
</Button>
</header>
<div className={styles.content}>
<div className={styles.videoWrapper}>
<iframe
className={styles.video}
src="https://www.youtube-nocookie.com/embed/ChYPIdCrBdE"
title="D&D Beyond Sheet Tour"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
/>
</div>
<p>
For a complete guide to getting your game started, see{" "}
<a href="https://www.dndbeyond.com/posts/754-how-to-play-dungeons-dragons-using-d-d-beyond">
How to Play Dungeons & Dragons Using D&D Beyond
</a>
.
</p>
</div>
<footer className={styles.footer}>
<Button
className={styles.claimButton}
{...(!signedIn && { href: signupLink })}
{...(signedIn && { onClick: handleClaim })}
disabled={isClaimingCharacter}
color="info"
size="x-small"
>
Claim Character
</Button>
</footer>
</Dialog>
</div>
<MaxCharactersDialog
open={isMaxCharacterMessageOpen}
onClose={() => setIsMaxCharacterMessageOpen(false)}
useMyCharactersLink
/>
{isFinishedClaimingCharacter && !!newCharacterId && (
<ClaimConfirmationDialog
characterId={newCharacterId ?? 0}
campaignId={campaignId}
/>
)}
</>
);
};