New source found from dndbeyond.com
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user