212 lines
6.3 KiB
TypeScript
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! ✔</> : "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&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>
|
|
);
|
|
};
|