frontend/src/common/Tour.tsx

156 lines
4.1 KiB
TypeScript

import { useTheme, makeStyles, createStyles, Theme } from "@material-ui/core/styles";
import React from "react";
import Joyride, { Step, CallBackProps, STATUS, TooltipRenderProps, Locale } from "react-joyride";
import {
Button,
Card,
CardContent,
CardHeader,
CardActions,
Grid,
MobileStepper,
Tooltip,
IconButton
} from "@material-ui/core";
import { KeyboardArrowLeft, KeyboardArrowRight, Close as CloseIcon } from "@material-ui/icons";
import classNames from "classnames";
import { grey } from "@material-ui/core/colors";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
stepContainer: {
width: "60vw",
[theme.breakpoints.only("sm")]: {
width: "50vw"
},
[theme.breakpoints.only("md")]: {
width: "40vw"
},
[theme.breakpoints.only("lg")]: {
width: "30vw"
},
[theme.breakpoints.only("xl")]: {
width: "20vw"
}
},
spacing: {
padding: theme.spacing(1),
[theme.breakpoints.up("sm")]: {
padding: theme.spacing(2)
}
},
stepper: {
width: "100%"
}
})
);
const StepContainer = (props: TooltipRenderProps, numSteps: number, skip: () => void) => {
const {
continuous,
index,
step,
backProps,
isLastStep,
closeProps,
primaryProps,
tooltipProps
} = props;
const theme = useTheme();
const classes = useStyles();
return (
<Card {...tooltipProps} className={classes.stepContainer}>
<CardHeader
title={step.title}
action={
<Tooltip title="Skip Tutorial">
<IconButton aria-label="Skip Tutorial" onClick={skip}>
<CloseIcon />
</IconButton>
</Tooltip>
}
className={classes.spacing}
/>
{step.content && <CardContent className={classes.spacing}>{step.content}</CardContent>}
{!step.hideFooter &&
(continuous ? (
<MobileStepper
className={classNames(classes.stepper, classes.spacing)}
variant="text"
steps={numSteps}
position="static"
activeStep={index}
backButton={
<Button size="small" {...backProps} disabled={index === 0}>
{theme.direction === "rtl" ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
Back
</Button>
}
nextButton={
<Button size="small" {...primaryProps}>
{isLastStep ? "Finish" : "Next"}
{theme.direction === "rtl" ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</Button>
}
/>
) : (
!step.hideCloseButton && (
<CardActions>
<Grid container justify="flex-end">
<Button size="small" {...closeProps}>
Close
</Button>
</Grid>
</CardActions>
)
))}
</Card>
);
};
interface Props {
run: boolean;
steps: Step[];
endTourCallback: () => void;
}
export default function Tour(props: Props) {
const { run, steps, endTourCallback } = props;
const theme = useTheme();
const handleTourCallback = (data: CallBackProps) => {
const { status } = data;
const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED];
if (finishedStatuses.includes(status)) {
endTourCallback();
}
};
return (
<Joyride
run={run}
steps={steps}
continuous
scrollToFirstStep={true}
showProgress={true}
showSkipButton={true}
callback={handleTourCallback}
tooltipComponent={props => StepContainer(props, steps.length, endTourCallback)}
locale={{ back: "Back", close: "Close", last: "Done", next: "Next", skip: "Skip" } as Locale}
styles={{
options: {
arrowColor: theme.palette.type === "light" ? grey["100"] : grey["800"],
backgroundColor: theme.palette.background.default,
overlayColor: "rgba(0, 0, 0, 0.5)",
primaryColor: theme.palette.primary.main,
textColor: theme.palette.text.primary,
zIndex: theme.zIndex.modal
}
}}
/>
);
}