import { observer } from "mobx-react";
import type { ReactNode } from "react";
import { ChangeEvent, Component, Fragment } from "react";
import {
Translation,
WithTranslation,
withTranslation,
TFunction
} from "react-i18next";
import styled, { DefaultTheme, withTheme } from "styled-components";
import {
HelpContentItem,
PaneMode,
StepItem,
TrainerItem
} from "../../../ReactViewModels/defaultHelpContent";
import ViewState from "../../../ReactViewModels/ViewState";
import Box from "../../../Styled/Box";
import Button, { RawButton } from "../../../Styled/Button";
import { GLYPHS, StyledIcon } from "../../../Styled/Icon";
import Select from "../../../Styled/Select";
import Spacing from "../../../Styled/Spacing";
import Text, { TextSpan } from "../../../Styled/Text";
import measureElement, { MeasureElementProps } from "../../HOCs/measureElement";
import { WithViewState, withViewState } from "../../Context";
import { applyTranslationIfExists } from "../../../Language/languageHelpers";
import StyledHtml from "../../Map/Panels/HelpPanel/StyledHtml";
import CloseButton from "../../Generic/CloseButton";
const TrainerBarWrapper = styled(Box)<{ isMapFullScreen: boolean }>`
top: 0;
left: ${(p) =>
p.isMapFullScreen
? 0
: Number(p.theme.workbenchWidth) + Number(p.theme.workbenchMargin) * 2}px;
z-index: ${(p) => Number(p.theme.frontComponentZIndex) + 100};
`;
// Help with discoverability
const BoxTrainerExpandedSteps = styled(Box)``;
const getSelectedTrainerFromHelpContent = (
viewState: ViewState,
helpContent: HelpContentItem[]
) => {
const selected = viewState.selectedTrainerItem;
const found = helpContent.find((item) => item.itemName === selected);
// Try and find the item that we selected, otherwise find the first trainer pane
return (
found || helpContent.find((item) => item.paneMode === PaneMode.trainer)
);
};
// Ripped from StyledHtml.jsx
const Numbers = styled(Text)<{ darkBg: boolean }>`
width: 22px;
height: 22px;
line-height: 22px;
border-radius: 50%;
background-color: ${(props) => props.theme.textLight};
`;
const StepText = styled(Text).attrs({})`
ol,
ul {
padding: 0;
margin: 0;
// Dislike these arbitrary aligned numbers but leaving it in for now
padding-left: 17px;
}
li {
padding-left: 8px;
}
`;
const renderStep = (
step: StepItem,
number: number,
viewState: ViewState,
options: {
renderDescription: boolean;
comfortable: boolean;
footerComponent?: () => ReactNode;
} = {
renderDescription: true,
comfortable: false,
footerComponent: undefined
}
) => {
return (
{number}
{(_t, { i18n }) => (
{applyTranslationIfExists(step.title, i18n)}
)}
{options.renderDescription && step?.markdownDescription && (
<>
{/* {options.comfortable && } */}
>
)}
{options.footerComponent?.()}
);
};
const renderOrderedStepList = function (
steps: StepItem[],
viewState: ViewState
) {
return steps.map((step: StepItem, index: number) => (
{renderStep(step, index + 1, viewState)}
{index + 1 !== steps.length && }
));
};
interface StepAccordionProps {
selectedTrainerSteps: StepItem[];
t: TFunction;
theme: DefaultTheme;
selectedTrainer: TrainerItem;
isShowingAllSteps: boolean;
setIsShowingAllSteps: (bool: boolean) => void;
isExpanded: boolean;
setIsExpanded: (bool: boolean) => void;
}
interface StepAccordionState {
isExpanded: boolean;
}
// Originally written as a SFC but measureElement only supports class components at the moment
class StepAccordionRaw extends Component<
StepAccordionProps & MeasureElementProps & WithTranslation & WithViewState,
StepAccordionState
> {
refToMeasure: any;
render() {
const {
viewState,
selectedTrainerSteps,
t,
theme,
selectedTrainer,
isShowingAllSteps,
setIsShowingAllSteps,
isExpanded,
setIsExpanded,
heightFromMeasureElementHOC
} = this.props;
return (
setIsPeeking(true)}
>
{/* Non-expanded step */}
{
if (!isExpanded) this.refToMeasure = component;
}}
>
{renderStep(
selectedTrainerSteps[viewState.currentTrainerStepIndex],
viewState.currentTrainerStepIndex + 1,
viewState,
{ renderDescription: false, comfortable: true }
)}
{/* expanded version of the box step */}
{isExpanded && (
(this.refToMeasure = component)}
>
{renderStep(
selectedTrainerSteps[viewState.currentTrainerStepIndex],
viewState.currentTrainerStepIndex + 1,
viewState,
{
renderDescription: true,
comfortable: true,
footerComponent: () => (
<>
setIsShowingAllSteps(!isShowingAllSteps)}
title={
isShowingAllSteps
? t("trainer.hideAllSteps")
: t("trainer.showAllSteps")
}
>
{isShowingAllSteps
? t("trainer.hideAllSteps")
: t("trainer.showAllSteps")}
>
)
}
)}
)}
setIsExpanded(!isExpanded)}
// onMouseOver={() => setIsPeeking(true)}
// onFocus={() => setIsPeeking(true)}
title={
isExpanded
? t("trainer.collapseTrainer")
: t("trainer.expandTrainer")
}
// onBlur={() => {
// if (!isExpanded) setIsPeeking(false);
// }}
css={"z-index:2;"}
>
{/* Accordion / child steps? */}
{isShowingAllSteps && (
{renderOrderedStepList(selectedTrainerSteps, viewState)}
{selectedTrainer.footnote ? (
<>
>
) : (
)}
)}
);
}
}
const StepAccordion = withTranslation()(
withViewState(measureElement(StepAccordionRaw))
);
interface TrainerBarProps extends WithTranslation, WithViewState {
t: TFunction;
theme: DefaultTheme;
}
export const TrainerBar = observer((props: TrainerBarProps) => {
const { i18n, t, theme, viewState } = props;
const terria = viewState.terria;
const { helpContent } = terria.configParameters;
// All these null guards are because we are rendering based on nested
// map-owner defined (helpContent)content which could be malformed
if (!viewState.trainerBarVisible || !helpContent) {
return null;
}
const selectedTrainer = getSelectedTrainerFromHelpContent(
viewState,
helpContent
);
const selectedTrainerItems = selectedTrainer?.trainerItems;
if (!selectedTrainerItems) {
return null;
}
const trainerItemIndex =
viewState.currentTrainerItemIndex <= selectedTrainerItems.length
? viewState.currentTrainerItemIndex
: 0;
const selectedTrainerItem = selectedTrainerItems[trainerItemIndex];
const selectedTrainerSteps = selectedTrainerItem?.steps;
if (!selectedTrainerSteps) {
return null;
}
const isMapFullScreen = viewState.isMapFullScreen;
return (
viewState.setTopElement("TrainerBar")}
>
{/* Trainer Items Dropdown */}
{/* */}
{/* */}
{/* Trainer Steps within a Trainer Item */}
viewState.setTrainerBarShowingAllSteps(bool)
}
isExpanded={viewState.trainerBarExpanded}
setIsExpanded={(bool: boolean) =>
viewState.setTrainerBarExpanded(bool)
}
selectedTrainer={selectedTrainerItem}
theme={theme}
/>
{/* Navigation & Close */}
viewState.setTrainerBarVisible(false)}
/>
);
});
export default withTranslation()(withViewState(withTheme(TrainerBar)));