Source

src/components/Panels/ReportBuilder/Report/Report.jsx

import { useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import ReportPage from '../ReportPage/ReportPage'
import { LayoutContainer, PrintModalStyle } from './LayoutContainer'
import {
    Alert,
    Box,
    Button,
    Stack,
    Modal,
    Snackbar,
    Typography,
    LinearProgress,
} from '@mui/material'
import { usePrintReport } from '../../../../hooks/usePrintReport'
import { reportSelectors, reportActions } from '../../../../stores/reportStore'
import { paramsActions } from '../../../../stores/paramsStore'
const { togglePanel } = paramsActions
const { setItemLoaded, addReportPage, clearError } = reportActions
const { selectCurrentPage, selectPrintStatus, selectReportError } =
    reportSelectors

/**
 * Inner report component for report builder
 *
 * @category Components/ReportBuilder
 * @param {Object} props
 * @param {string} props.reportName Name of report
 * @param {number} props.activeStep Current step in report process
 * @param {number} props.zoomMultiplier Zoom multiplier for report pages
 * @param {function} props.handleStep Function to change activeStep (step:
 *   number) => void
 * @component
 */
function Report({
    reportName = '',
    activeStep,
    zoomMultiplier = 1,
    handleStep = () => {},
}) {
    const dispatch = useDispatch()
    const currPage = useSelector(selectCurrentPage)
    const gridContext = useRef({})
    const containerRef = useRef(null)
    const pageWidth = containerRef?.current?.clientWidth

    const handleItemLoad = (itemId, isLoaded) => {
        dispatch(
            setItemLoaded({
                itemId,
                isLoaded,
            })
        )
    }

    const handleGridContext = (grid, pageIdx) => {
        gridContext.current = {
            ...gridContext.current,
            [pageIdx]: grid,
        }
    }

    const { handlePrint, handleRef } = usePrintReport({
        handleStep,
    })

    return (
        <LayoutContainer ref={containerRef}>
            <ReportPage
                onMount={handleRef}
                key={`report-page-${reportName}-${currPage}`}
                pageIdx={currPage}
                {...{
                    handleGridContext,
                    reportName,
                    pageWidth,
                    zoomMultiplier,
                    handleItemLoad,
                }}
            />
            <ErrorToast />
            <PrintModal {...{ handleStep, activeStep, handlePrint }} />
        </LayoutContainer>
    )
}

export default Report

/**
 * Print modal menu for report builder to export different formats.
 *
 * @category Components/ReportBuilder
 * @param {Object} props
 * @param {number} props.activeStep Current step in report process,
 * @param {function} props.handleStep Function to change activeStep (step:
 *   number) => void
 * @param {function} props.handlePrint Function to initiate print report
 * @component
 */
function PrintModal({ handleStep, activeStep, handlePrint }) {
    const dispatch = useDispatch()
    const pageIdx = useSelector(selectCurrentPage)
    const isPrinting = useSelector(selectPrintStatus)
    const pageLength = useSelector(
        ({ report }) => report.reports?.[report.currentReport]?.layout?.length
    )

    const currPage = pageIdx === -1 ? pageIdx + 2 : pageIdx + 1
    const progress = (currPage / pageLength) * 100
    const handleCloseModal = () => {
        handleStep(activeStep - 1)
    }

    const handleCloseReport = () => dispatch(togglePanel('reportBuilder'))
    // const report = useSelector(
    //   ({ report }) => report.reports?.[report.currentReport]);
    // cleanLayout(report).then(r => console.log(r))

    return (
        <Modal
            open={activeStep === 3}
            onClose={handleCloseModal}
            aria-labelledby="modal-modal-title"
            aria-describedby="modal-modal-description"
        >
            <Box sx={PrintModalStyle}>
                {isPrinting ? (
                    <>
                        <LinearProgressWithLabel
                            progress={progress}
                            text={`Exporting ${currPage} of ${pageLength}`}
                        />
                        <Typography>
                            <i>Please wait...</i>
                        </Typography>
                    </>
                ) : (
                    <>
                        <Typography>
                            <i>
                                Your report has been saved on this device.
                                <br />
                                <br />
                                Click below to export your report as a PDF
                                document or as images.
                            </i>
                        </Typography>
                        <Stack gap={4} alignItems="center" sx={{ py: 4 }}>
                            <Stack
                                direction="row"
                                gap={1}
                                justifyContent="left"
                            >
                                <Typography>Export Document</Typography>
                                <Button
                                    variant="contained"
                                    onClick={() => handlePrint('PDF')}
                                >
                                    PDF
                                </Button>
                            </Stack>
                            <Stack direction="row" gap={1}>
                                <Typography>Export Images</Typography>
                                <Button
                                    variant="contained"
                                    onClick={() => handlePrint('JPG')}
                                >
                                    JPG
                                </Button>
                                <Button
                                    variant="contained"
                                    onClick={() => handlePrint('PNG')}
                                >
                                    PNG
                                </Button>
                                <Button
                                    variant="contained"
                                    onClick={() => handlePrint('SVG')}
                                >
                                    SVG
                                </Button>
                            </Stack>
                            {/* <Button
              variant="contained"
              onClick={exportReport}>
              Share Report
            </Button> */}
                        </Stack>
                        <hr />
                        <Stack gap={2} alignItems="center" sx={{ py: 2 }}>
                            <Typography>
                                <i>
                                    Click below to keep editing your report or
                                    close the report builder.
                                </i>
                            </Typography>
                            <Button
                                onClick={handleCloseModal}
                                variant="outlined"
                            >
                                Return to Report Builder
                            </Button>
                            <Button
                                onClick={handleCloseReport}
                                variant="outlined"
                            >
                                Return to the Atlas
                            </Button>
                        </Stack>
                    </>
                )}
            </Box>
        </Modal>
    )
}

/**
 * Progress placeholder
 *
 * @category Components/ReportBuilder
 * @param {Object} props
 * @param {number} props.progress 0-100 value to display on linear progress bar
 * @param {string} props.text Text to display on linear progress bar
 * @component
 */
function LinearProgressWithLabel({ progress, text }) {
    return (
        <Stack direction="column" gap={2} width="100%">
            <LinearProgress variant="determinate" value={progress} />
            <Typography variant="body2">{text}</Typography>
        </Stack>
    )
}

/**
 * Toast component for displaying report builder errors. See selectReportError
 * selector in reportSlice.
 *
 * @category Components/ReportBuilder
 * @component
 */
function ErrorToast() {
    const dispatch = useDispatch()
    const error = useSelector(selectReportError)
    const { type, reportName, pageIdx } = error || {}

    const handleClose = () => dispatch(clearError())
    const handleAddPage = () => dispatch(addReportPage(reportName))

    if (!error) return null
    const messages = {
        'Invalid layout': `Page ${
            pageIdx + 1
        } is full! Resize, remove items, or add a new page.`,
    }
    const text = messages[type]

    return (
        <Snackbar open={true} autoHideDuration={6000} onClose={handleClose}>
            <Alert
                onClose={handleClose}
                severity="warning"
                sx={{ width: '100%' }}
                action={
                    <Button
                        color="inherit"
                        size="small"
                        onClick={handleAddPage}
                    >
                        Add Page
                    </Button>
                }
            >
                {text}
            </Alert>
        </Snackbar>
    )
}