238 lines
7.0 KiB
TypeScript
238 lines
7.0 KiB
TypeScript
import clsx from "clsx";
|
|
import React, { FC } from "react";
|
|
import { connect } from "react-redux";
|
|
import SwipeableViews from "react-swipeable-views";
|
|
|
|
import {
|
|
characterSelectors,
|
|
CharacterStatusSlug,
|
|
CharacterTheme,
|
|
FormatUtils,
|
|
rulesEngineSelectors,
|
|
} from "@dndbeyond/character-rules-engine/es";
|
|
import CharacterSheetSvg from "@dndbeyond/fontawesome-cache/svgs/light/address-card.svg";
|
|
import { GameLogNotificationWrapper } from "@dndbeyond/game-log-components";
|
|
|
|
import { Link } from "~/components/Link";
|
|
import { PremadeCharacterEditStatus } from "~/components/PremadeCharacterEditStatus";
|
|
import { Tooltip } from "~/components/Tooltip";
|
|
|
|
import { appEnvSelectors } from "../../../Shared/selectors";
|
|
import { MobileMessengerUtils } from "../../../Shared/utils";
|
|
import { navigationConfig } from "../../config";
|
|
import { builderEnvSelectors, builderSelectors } from "../../selectors";
|
|
import { BuilderAppState } from "../../typings";
|
|
import HelpTextManager from "../HelpTextManager";
|
|
import styles from "./styles.module.css";
|
|
|
|
interface Props {
|
|
characterId: number | null;
|
|
builderMethod: string | null;
|
|
sections: Array<any>;
|
|
firstAvailableSectionRoutes: any;
|
|
isCharacterSheetReady: boolean;
|
|
characterSheetUrl: string;
|
|
activeSectionIdx: number;
|
|
isMobile: boolean;
|
|
characterStatus: CharacterStatusSlug | null;
|
|
isReadonly: boolean;
|
|
theme: CharacterTheme;
|
|
}
|
|
const NavigationSections: FC<Props> = ({
|
|
characterId,
|
|
isCharacterSheetReady,
|
|
characterSheetUrl,
|
|
theme,
|
|
sections,
|
|
firstAvailableSectionRoutes,
|
|
activeSectionIdx,
|
|
builderMethod,
|
|
isMobile,
|
|
characterStatus,
|
|
isReadonly,
|
|
}) => {
|
|
const handleSheetShowClick = () => {
|
|
if (characterId !== null) {
|
|
MobileMessengerUtils.sendMessage(
|
|
MobileMessengerUtils.createShowCharacterSheetMessage(characterId)
|
|
);
|
|
}
|
|
};
|
|
const renderCharacterSheetLink = () => {
|
|
//trading out a Router Link for a div if not ready for accessibility
|
|
const Component = isCharacterSheetReady ? Link : "div";
|
|
const CharacterSheetLink = () => (
|
|
<>
|
|
<Component
|
|
className={clsx([
|
|
styles.characterSheetIcon,
|
|
!isCharacterSheetReady && styles.disabled,
|
|
])}
|
|
href={isCharacterSheetReady ? characterSheetUrl : undefined}
|
|
onClick={handleSheetShowClick}
|
|
userouter={isCharacterSheetReady ? true : undefined}
|
|
data-tooltip-place="bottom"
|
|
data-tooltip-id={"character-sheet-tooltip"}
|
|
data-tooltip-content={
|
|
isCharacterSheetReady
|
|
? "Go to Character Sheet"
|
|
: "Character is incomplete"
|
|
}
|
|
>
|
|
<CharacterSheetSvg
|
|
className={clsx([
|
|
styles.characterSheetIcon,
|
|
!isCharacterSheetReady && styles.disabled,
|
|
])}
|
|
/>
|
|
</Component>
|
|
<Tooltip id="character-sheet-tooltip" />
|
|
</>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className={clsx([
|
|
"builder-sections-sheet",
|
|
!isCharacterSheetReady && "builder-sections-sheet-disabled",
|
|
])}
|
|
>
|
|
<GameLogNotificationWrapper
|
|
themeColor={theme.themeColor}
|
|
gameLogIsOpen={false}
|
|
notificationOnClick={() => {}}
|
|
isCharacterBuilder
|
|
>
|
|
<CharacterSheetLink />
|
|
</GameLogNotificationWrapper>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const renderNonMobileUi = () => (
|
|
<div className="builder-sections builder-sections-large">
|
|
<HelpTextManager />
|
|
{renderCharacterSheetLink()}
|
|
<div className="builder-sections-large-routes">
|
|
{sections.map((section) => {
|
|
const firstRoute = firstAvailableSectionRoutes[section.key];
|
|
let clsNames: Array<string> = [
|
|
"builder-sections-link",
|
|
`builder-sections-${FormatUtils.slugify(section.key)}`,
|
|
];
|
|
if (section.active) {
|
|
clsNames.push("builder-sections-link-active");
|
|
}
|
|
return (
|
|
<div className="builder-sections-view" key={section.key}>
|
|
<Link
|
|
href={firstRoute.path.replace(":characterId", characterId)}
|
|
className={clsNames.join(" ")}
|
|
userouter
|
|
>
|
|
{section.getLabel()}
|
|
</Link>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
const renderMobileUi = () => {
|
|
const scrollbarStyles: React.CSSProperties = {
|
|
padding: "0 35%",
|
|
};
|
|
|
|
return (
|
|
<div className="builder-sections builder-sections-small">
|
|
<HelpTextManager />
|
|
{renderCharacterSheetLink()}
|
|
<SwipeableViews
|
|
index={activeSectionIdx}
|
|
style={scrollbarStyles}
|
|
className="builder-sections-views"
|
|
ignoreNativeScroll={true}
|
|
>
|
|
{sections.map((section) => {
|
|
const firstRoute = firstAvailableSectionRoutes[section.key];
|
|
let clsNames: Array<string> = [
|
|
"builder-sections-link",
|
|
`builder-sections-${FormatUtils.slugify(section.key)}`,
|
|
];
|
|
if (section.active) {
|
|
clsNames.push("builder-sections-link-active");
|
|
}
|
|
return (
|
|
<div className="builder-sections-view" key={section.key}>
|
|
<Link
|
|
href={firstRoute.path.replace(":characterId", characterId)}
|
|
className={clsNames.join(" ")}
|
|
userouter
|
|
>
|
|
{section.getLabel()}
|
|
</Link>
|
|
</div>
|
|
);
|
|
})}
|
|
</SwipeableViews>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
if (builderMethod === null) {
|
|
return null;
|
|
}
|
|
|
|
return isMobile ? (
|
|
<>
|
|
{renderMobileUi()}
|
|
<PremadeCharacterEditStatus
|
|
characterStatus={characterStatus}
|
|
isReadonly={isReadonly}
|
|
isBuilderView
|
|
/>
|
|
</>
|
|
) : (
|
|
<>
|
|
{renderNonMobileUi()}
|
|
<PremadeCharacterEditStatus
|
|
characterStatus={characterStatus}
|
|
isReadonly={isReadonly}
|
|
isBuilderView
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
function mapStateToProps(state: BuilderAppState, ownProps) {
|
|
const currentPath = ownProps.pathname;
|
|
const sections = navigationConfig.getNavigationSections(
|
|
builderSelectors.getBuilderMethod(state),
|
|
navigationConfig.getCurrentRouteDef(currentPath)
|
|
);
|
|
|
|
let activeSectionIdx: number = 0;
|
|
sections.forEach((section, idx) => {
|
|
if (section.active) {
|
|
activeSectionIdx = idx;
|
|
}
|
|
});
|
|
|
|
return {
|
|
sections,
|
|
firstAvailableSectionRoutes:
|
|
builderSelectors.getFirstAvailableSectionRoutes(state),
|
|
isCharacterSheetReady: builderSelectors.checkIsCharacterSheetReady(state),
|
|
characterSheetUrl: builderEnvSelectors.getCharacterSheetUrl(state),
|
|
builderMethod: builderSelectors.getBuilderMethod(state),
|
|
activeSectionIdx,
|
|
isMobile: appEnvSelectors.getIsMobile(state),
|
|
characterStatus: characterSelectors.getStatusSlug(state),
|
|
isReadonly: appEnvSelectors.getIsReadonly(state),
|
|
theme: rulesEngineSelectors.getCharacterTheme(state),
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps)(NavigationSections);
|