import Joyride, { Step, CallBackProps, STATUS, TooltipRenderProps, Locale, ACTIONS, EVENTS } from "react-joyride"; import { Button, Card, CardContent, CardHeader, CardActions, Grid2 as Grid, MobileStepper, Tooltip, IconButton, Theme, useTheme, } from "@mui/material"; import { KeyboardArrowLeft, KeyboardArrowRight, Close as CloseIcon } from "@mui/icons-material"; import classNames from "classnames"; import { grey } from "@mui/material/colors"; import { makeStyles } from "@mui/styles"; import { CSSProperties } from "react"; const useStyles = makeStyles((theme: Theme) => { return ({ 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%" } }) }); export interface TourStep extends Step { onNext?: () => void; // Define onNext as an optional function } 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 ( } className={classes.spacing} /> {step.content && {step.content}} {!step.hideFooter && (continuous ? ( {theme.direction === "rtl" ? : } Back } nextButton={ } /> ) : ( !step.hideCloseButton && ( ) ))} ); }; interface Props { run: boolean; steps: TourStep[]; endTourCallback: () => void; spotlightStyle?: CSSProperties, setStepIndex?: React.Dispatch>, } export default function Tour(props: Props) { const { run, steps, endTourCallback, setStepIndex, spotlightStyle } = props; const theme = useTheme(); const handleTourCallback = (data: CallBackProps) => { const { action, index, status, type } = data; const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED]; if (setStepIndex) setStepIndex(index) if (action === ACTIONS.NEXT && type === EVENTS.STEP_AFTER) { // Safely access the step and call onNext if it exists const currentStep = steps[index]; if (currentStep.onNext) { currentStep.onNext(); } } if (finishedStatuses.includes(status)) { endTourCallback(); } }; return ( StepContainer(props, steps.length, endTourCallback)} locale={{ back: "Back", close: "Close", last: "Done", next: "Next", skip: "Skip" } as Locale} styles={{ options: { arrowColor: theme.palette.mode === "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 }, spotlight: { ...spotlightStyle } }} /> ); }