terriajs
Version:
Geospatial data visualization platform.
368 lines (353 loc) • 13.1 kB
JSX
import { runInAction } from "mobx";
import { observer } from "mobx-react";
import PropTypes from "prop-types";
import { Component, useState, useRef } from "react";
import { Trans, useTranslation, withTranslation } from "react-i18next";
import styled, { withTheme } from "styled-components";
import Box from "../../Styled/Box";
import Button, { RawButton } from "../../Styled/Button";
import Icon, { StyledIcon } from "../../Styled/Icon";
import Spacing from "../../Styled/Spacing";
import Text, { TextSpan } from "../../Styled/Text";
import { ExplorerWindowElementName } from "../ExplorerWindow/ExplorerWindow";
import { useKeyPress } from "../Hooks/useKeyPress.js";
import VideoGuide from "../Map/Panels/HelpPanel/VideoGuide";
import { withViewState } from "../Context";
import { TourPortalDisplayName } from "../Tour/TourPortal";
import FadeIn from "../Transitions/FadeIn/FadeIn";
import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn";
export const WELCOME_MESSAGE_NAME = "welcomeMessage";
export const LOCAL_PROPERTY_KEY = `${WELCOME_MESSAGE_NAME}Prompted`;
const WELCOME_MESSAGE_VIDEO = "welcomeMessageVideo";
const WelcomeModalWrapper = styled(Box)`
z-index: 99999;
background-color: rgba(0, 0, 0, 0.75);
`;
function WelcomeMessageButton(props) {
return (
<Button primary rounded fullWidth onClick={props.onClick}>
<Box centered>
{props.buttonIcon && (
<StyledIcon light styledWidth={"22px"} glyph={props.buttonIcon} />
)}
<Spacing right={2} />
{props.buttonText && (
<TextSpan textLight extraLarge>
{props.buttonText}
</TextSpan>
)}
</Box>
</Button>
);
}
WelcomeMessageButton.propTypes = {
buttonText: PropTypes.string,
buttonIcon: PropTypes.object,
onClick: PropTypes.func
};
@observer
class WelcomeMessage extends Component {
static displayName = "WelcomeMessage";
static propTypes = {
viewState: PropTypes.object,
theme: PropTypes.object,
t: PropTypes.func.isRequired
};
constructor(props) {
super(props);
const viewState = this.props.viewState;
const shouldShow =
(viewState.terria.configParameters.showWelcomeMessage &&
!viewState.terria.getLocalProperty(LOCAL_PROPERTY_KEY)) ||
false;
this.props.viewState.setShowWelcomeMessage(shouldShow);
}
render() {
const viewState = this.props.viewState || {};
return (
<WelcomeMessagePure
showWelcomeMessage={viewState.showWelcomeMessage}
setShowWelcomeMessage={(bool) =>
this.props.viewState.setShowWelcomeMessage(bool)
}
isTopElement={this.props.viewState.topElement === "WelcomeMessage"}
viewState={this.props.viewState}
/>
);
}
}
export const WelcomeMessagePure = (props) => {
const { showWelcomeMessage, setShowWelcomeMessage, viewState } = props;
const { t } = useTranslation();
// This is required so we can do nested animations
const [welcomeVisible, setWelcomeVisible] = useState(showWelcomeMessage);
const [shouldTakeTour, setShouldTakeTour] = useState(false);
const [shouldExploreData, setShouldExploreData] = useState(false);
const [shouldOpenHelp, setShouldOpenHelp] = useState(false);
const [shouldOpenSearch, setShouldOpenSearch] = useState(false);
const modalRef = useRef(null);
const welcomeMessageRef = useRef(null);
// const {
// WelcomeMessagePrimaryBtnClick,
// WelcomeMessageSecondaryBtnClick
// } = viewState.terria.overrides;
const handleClose = (persist = false) => {
setShowWelcomeMessage(false);
setShouldOpenHelp(false);
setShouldOpenSearch(false);
if (persist) {
viewState.terria.setLocalProperty(LOCAL_PROPERTY_KEY, true);
}
};
useKeyPress("Escape", () => {
if (showWelcomeMessage && viewState.videoGuideVisible === "") {
handleClose(false);
}
});
return (
<FadeIn
isVisible={showWelcomeMessage}
onEnter={() => setWelcomeVisible(true)}
nodeRef={modalRef}
transitionProps={{
onExiting: () => setWelcomeVisible(false),
onExited: () => {
if (shouldTakeTour) {
setShouldTakeTour(false);
viewState.setTourIndex(0);
viewState.setShowTour(true);
viewState.setTopElement(TourPortalDisplayName);
}
if (shouldExploreData) {
setShouldExploreData(false);
viewState.openAddData();
viewState.setTopElement(ExplorerWindowElementName);
}
if (shouldOpenHelp) {
setShouldOpenHelp(false);
viewState.showHelpPanel();
}
if (shouldOpenSearch) {
setShouldOpenSearch(false);
runInAction(
() => (viewState.searchState.showMobileLocationSearch = true)
);
}
// Show where help is when never previously prompted
if (!viewState.terria.getLocalProperty("helpPrompted")) {
runInAction(() => {
viewState.toggleFeaturePrompt("help", true, false);
});
}
}
}}
>
<WelcomeModalWrapper
fullWidth
fullHeight
position="absolute"
right
onClick={() => handleClose(false)}
>
<Box
styledWidth={
viewState.isMapFullScreen || viewState.useSmallScreenInterface
? "100%"
: "calc(100% - 350px)"
} // TODO: use variable $work-bench-width
fullHeight
centered
>
<VideoGuide
viewState={viewState}
videoLink={
viewState.terria.configParameters.welcomeMessageVideo.videoUrl
}
background={
viewState.terria.configParameters.welcomeMessageVideo
.placeholderImage
}
videoName={WELCOME_MESSAGE_VIDEO}
/>
<SlideUpFadeIn isVisible={welcomeVisible} nodeRef={welcomeMessageRef}>
<Box
ref={welcomeMessageRef}
styledWidth={"667px"}
styledMinHeight={"504px"}
displayInlineBlock
paddedRatio={viewState.useSmallScreenInterface ? 2 : 6}
onClick={(e) => {
viewState.setTopElement("WelcomeMessage");
e.stopPropagation();
}}
>
<RawButton
onClick={handleClose.bind(null, false)}
css={`
float: right;
`}
>
<StyledIcon
styledWidth={"24px"}
light
glyph={Icon.GLYPHS.closeLight}
/>
</RawButton>
<Spacing bottom={7} />
<Box
displayInlineBlock
styledWidth={
viewState.useSmallScreenInterface ? "100%" : "83.33333%"
}
>
<Text
bold
textLight
styledFontSize={
viewState.useSmallScreenInterface ? "26px" : "36px"
}
textAlignCenter={viewState.useSmallScreenInterface}
styledLineHeight={"49px"}
>
{t("welcomeMessage.title")}
</Text>
<Spacing bottom={3} />
<Text
textLight
medium
textAlignCenter={viewState.useSmallScreenInterface}
>
{viewState.useSmallScreenInterface === false && (
<Trans i18nKey="welcomeMessage.welcomeMessage">
Interested in data discovery and exploration?
<br />
Dive right in and get started or check the following help
guide options.
</Trans>
)}
{viewState.useSmallScreenInterface === true && (
<Trans i18nKey="welcomeMessage.welcomeMessageOnMobile">
Interested in data discovery and exploration?
</Trans>
)}
</Text>
</Box>
<Spacing bottom={6} />
{!viewState.useSmallScreenInterface && (
<>
<Text bold textLight extraLarge>
{
viewState.terria.configParameters.welcomeMessageVideo
.videoTitle
}
</Text>
<Spacing bottom={2} />
</>
)}
<Box fullWidth styledMinHeight={"160px"}>
{!viewState.useSmallScreenInterface && (
<>
<Box
col6
centered
backgroundImage={
viewState.terria.configParameters.welcomeMessageVideo
.placeholderImage
}
backgroundBlackOverlay={0.5}
>
<RawButton
fullWidth
fullHeight
onClick={() =>
viewState.setVideoGuideVisible(WELCOME_MESSAGE_VIDEO)
}
>
<StyledIcon
styledWidth={"48px"}
light
glyph={Icon.GLYPHS.playInverted}
css={`
margin: auto;
`}
/>
</RawButton>
</Box>
<Spacing right={5} />
</>
)}
<Box styledMargin={"0 auto"} displayInlineBlock>
{!viewState.useSmallScreenInterface && (
<>
<WelcomeMessageButton
onClick={() => {
handleClose(false);
// not sure if we should wait for the exit animation,
// if we don't, we have a flicker due to the difference
// in overlay darkness - but if we wait, it goes
// dark -> light -> dark anyway..
setShouldTakeTour(true);
viewState.setTourIndex(0);
viewState.setShowTour(true);
viewState.setTopElement(TourPortalDisplayName);
}}
buttonText={t("welcomeMessage.tourBtnText")}
buttonIcon={Icon.GLYPHS.tour}
/>
<Spacing bottom={4} />
<WelcomeMessageButton
buttonText={t("welcomeMessage.helpBtnText")}
buttonIcon={Icon.GLYPHS.newHelp}
onClick={() => {
handleClose(false);
setShouldOpenHelp(true);
}}
/>
</>
)}
<Spacing bottom={4} />
<WelcomeMessageButton
buttonText={t("welcomeMessage.exploreDataBtnText")}
buttonIcon={Icon.GLYPHS.add}
onClick={() => {
handleClose(false);
setShouldExploreData(true);
}}
/>
{viewState.useSmallScreenInterface && (
<>
<Spacing bottom={4} />
<WelcomeMessageButton
buttonText={t("welcomeMessage.searchBtnText")}
buttonIcon={Icon.GLYPHS.search}
onClick={() => {
handleClose(false);
setShouldOpenSearch(true);
}}
/>
</>
)}
</Box>
</Box>
{!viewState.useSmallScreenInterface && <Spacing bottom={13} />}
<Box fullWidth centered>
<RawButton onClick={handleClose.bind(null, true)}>
<TextSpan textLight isLink>
{t("welcomeMessage.dismissText")}
</TextSpan>
</RawButton>
</Box>
</Box>
</SlideUpFadeIn>
</Box>
</WelcomeModalWrapper>
</FadeIn>
);
};
WelcomeMessagePure.propTypes = {
showWelcomeMessage: PropTypes.bool.isRequired,
setShowWelcomeMessage: PropTypes.func.isRequired,
isTopElement: PropTypes.bool.isRequired,
viewState: PropTypes.object.isRequired
};
export default withTranslation()(withViewState(withTheme(WelcomeMessage)));