Files

212 lines
6.3 KiB
TypeScript

import { clsx } from "clsx";
import { FC, useEffect, useRef, useState } from "react";
import { useSelector } from "react-redux";
import { useSearchParams } from "react-router-dom";
import CharacterSheetSvg from "@dndbeyond/fontawesome-cache/svgs/light/address-card.svg";
import CheckMark from "@dndbeyond/fontawesome-cache/svgs/light/circle-check.svg";
import PdfSvg from "@dndbeyond/fontawesome-cache/svgs/light/file-pdf.svg";
import { Button } from "~/components/Button";
import { usePdfExport } from "~/hooks/usePdfExport";
import pageStyles from "~/subApps/builder/styles/page.module.css";
import {
builderEnvSelectors,
builderSelectors,
} from "~/tools/js/CharacterBuilder/selectors";
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
import { ClipboardUtils, MobileMessengerUtils } from "~/tools/js/Shared/utils";
import styles from "./styles.module.css";
export const WhatsNext: FC = () => {
const characterId = useSelector(appEnvSelectors.getCharacterId);
const characterListingUrl = useSelector(
builderEnvSelectors.getProfileCharacterListingUrl
);
const characterSheetUrl = useSelector(
builderEnvSelectors.getCharacterSheetUrl
);
const isCharacterSheetReady = useSelector(
builderSelectors.checkIsCharacterSheetReady
);
const [searchParams] = useSearchParams();
const isVttView = searchParams.get("view") === "vtt";
const urlInput = useRef<HTMLInputElement>(null);
const { exportPdf, isLoading, isFinished, pdfUrl } = usePdfExport();
const [hasCopied, setHasCopied] = useState(false);
useEffect(() => {
if (pdfUrl !== null && isFinished) {
urlInput.current?.focus();
urlInput.current?.setSelectionRange(0, urlInput.current.value.length);
}
}, [isFinished, pdfUrl]);
const handleExportPdf = (evt: React.MouseEvent): void => {
if (isCharacterSheetReady && !isLoading && !isFinished) {
exportPdf();
}
};
const handleClick = (evt: React.MouseEvent): void => {
ClipboardUtils.copyTextToClipboard(pdfUrl === null ? "" : pdfUrl);
setHasCopied(true);
};
const handleMobileSheetShowClick = () => {
if (characterId !== null && isCharacterSheetReady) {
MobileMessengerUtils.sendMessage(
MobileMessengerUtils.createShowCharacterSheetMessage(characterId)
);
}
};
const renderPdfData = (): React.ReactNode => {
if (!isFinished || pdfUrl === null) {
return null;
}
return (
<div className={styles.pdfSection}>
<div className={styles.pdfInputWrapper}>
<label className={styles.pdfDataLabel}>
<PdfSvg /> PDF Generated
</label>
<input
type="text"
value={pdfUrl ? pdfUrl.replace(/https*:\/\//, "") : ""}
className={styles.pdfDataInput}
ref={urlInput}
/>
</div>
<Button
className={styles.pdfDataClipboard}
size="small"
variant="text"
onClick={handleClick}
>
{hasCopied ? <>Copied! &#x2714;</> : "Click to Copy"}
</Button>
{pdfUrl !== null && (
<Button
className={styles.button}
href={pdfUrl}
size={"large"}
download={true}
variant="builder"
>
Click to Download
</Button>
)}
</div>
);
};
const getPdfButtonText = (): string => {
if (isLoading) {
return "Exporting PDF...";
} else if (isFinished) {
return "PDF Generated";
}
return "Export to PDF";
};
const ButtonLinkProps = {
href: characterSheetUrl,
};
return (
<div className={pageStyles.page}>
<p>
Once you have completed creating your character, you can view your
statistics on the digital character sheet or export it for printing.
</p>
<div className={styles.buttonWrapper}>
<Button
className={styles.button}
size="large"
variant="builder"
disabled={!isCharacterSheetReady}
onClick={handleMobileSheetShowClick}
{...(isCharacterSheetReady ? ButtonLinkProps : {})}
>
<CharacterSheetSvg />
<span className={styles.buttonText}>
View Character Sheet
{!isCharacterSheetReady && (
<span className={styles.buttonSubText}>
Unavailable - Character Incomplete
</span>
)}
</span>
</Button>
{!isVttView && (
<Button
className={clsx([
styles.button,
isFinished && styles.buttonComplete,
])}
size="large"
variant="builder"
disabled={!isCharacterSheetReady}
onClick={handleExportPdf}
>
{!isFinished ? <PdfSvg /> : <CheckMark />}
{getPdfButtonText()}
</Button>
)}
</div>
{renderPdfData()}
{!isCharacterSheetReady && (
<p className={styles.returnToHomeText}>
If you are unable to create a character due to missing options, return
to the <strong>Home</strong> tab and change your source settings.
</p>
)}
<div className={styles.section}>
{!isVttView && (
<Button
className={styles.button}
variant="builder-text"
href={characterListingUrl}
>
View all my characters
</Button>
)}
<h2 className={pageStyles.title}>Come Together</h2>
<p>
Most D&amp;D characters don't work alone. Each character plays a role
within a party, a group of adventurers working together for a common
purpose. Talk to your fellow players and your DM to decide whether
your characters know one another, how they met, and what sorts of
quests the group might undertake.
</p>
<p>
A campaign is a series of adventures undertaken by your group's
characters. If your DM has a campaign, you can join it by visiting the
invite link for the campaign. You can also start your own.
</p>
{!isVttView && (
<Button
variant="builder-text"
href="/campaigns/create"
className={styles.button}
>
Start a new campaign
</Button>
)}
</div>
</div>
);
};