Source

src/components/Panels/ReportBuilder/ReportPage/ReportPage.jsx

import React, { useRef, useEffect } from 'react'
import ReportComponentMapping from '../PageComponents/PageComponents'
import { useDispatch } from 'react-redux'
import { Responsive, WidthProvider } from 'react-grid-layout'
import {
    LayoutPageContainer,
    DateWaterMark,
    AtlasWaterMark,
    Attribution,
} from './ReportPageLayout'
import { useSelector } from 'react-redux'
import { NoInteractionGate } from '../PageComponents/MapReport'
import { Box } from '@mui/material'
import styled from 'styled-components'
import LinearProgress from '@mui/material/LinearProgress'
import { reportSelectors, reportActions } from '../../../../stores/reportStore'
const { selectPrintStatus, selectIsLoaded } = reportSelectors
const { updateReportLayout } = reportActions
const ResponsiveGridLayout = WidthProvider(Responsive)

const OuterContainer = styled.div`
    position: relative;
    pointer-events: ${({ loading }) => (loading ? 'none' : 'auto')};
`

const Loader = () => (
    <div
        style={{
            position: 'absolute',
            width: '100%',
            height: '100%',
            top: 0,
            left: 0,
            background: 'rgba(255,255,255,0.9)',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            backdropFilter: 'blur(10px)',
            zIndex: 1000,
        }}
    >
        <Box sx={{ maxWidth: '100px' }}>
            <LinearProgress />
            <p>Loading...</p>
        </Box>
    </div>
)

/**
 * Renderer for single page of report. See usage {@linkcode src/components/Panels/ReportBuilder/Report/Report.jsx}
 *
 * @category Components/ReportBuilder
 * @param {Object} props
 * @param {number} props.pageIdx - Index of page in report
 * @param {number} props.pageWidth - Width of page in pixels
 * @param {number} props.zoomMultiplier Multiplier for zoom level of the report
 * @param {string} props.reportName Name of the report
 * @param {function} props.onMount - Callback for when page is mounted (pageRef:
 *   React.RefObject<HTMLDivElement>) => void
 * @param {function} props.handleItemLoad - Callback for when item is loaded
 *   (itemId: string,isLoaded: boolean) => void
 * @component
 */
function ReportPage({
    pageIdx,
    pageWidth,
    zoomMultiplier,
    reportName,
    onMount,
    handleItemLoad,
}) {
    const dispatch = useDispatch()
    const layout = useSelector(
        ({ report }) => report.reports?.[reportName]?.layout?.[pageIdx]
    )
    const isPrinting = useSelector(selectPrintStatus)
    const pageIsLoaded = useSelector(selectIsLoaded)
    const pageRef = useRef(null)

    useEffect(() => {
        !!pageRef?.current && onMount(pageRef.current)
    }, [!!pageRef?.current, pageIdx])

    if (!layout) {
        return null
    }

    const handleLayoutChange = (layout) => {
        dispatch(
            updateReportLayout({
                reportName,
                pageIdx,
                layout,
            })
        )
    }

    return (
        <OuterContainer loading={!pageIsLoaded}>
            <LayoutPageContainer
                ref={pageRef}
                pageWidth={pageWidth}
                zoomMultiplier={zoomMultiplier}
                isPrinting={isPrinting}
            >
                {!pageIsLoaded && <Loader />}
                <ResponsiveGridLayout
                    className="layout"
                    layouts={{
                        lg: layout,
                        md: layout,
                        sm: layout,
                        xs: layout,
                        xxs: layout,
                    }}
                    layout={layout}
                    breakpoints={{
                        lg: 1200,
                        md: 996,
                        sm: 768,
                        xs: 480,
                        xxs: 0,
                    }}
                    cols={{ lg: 8, md: 8, sm: 8, xs: 8, xxs: 8 }}
                    rowHeight={16}
                    draggableHandle={'.content-header'}
                    autoSize={true}
                    onLayoutChange={handleLayoutChange}
                    isDraggable
                    compactType="vertical"
                    isRearrangeable
                    isResizable
                    resizeHandles={['se']}
                >
                    {layout.map(({ i }) => (
                        <div key={i}>
                            <ReportComponentMapping
                                key={i}
                                itemId={i}
                                handleItemLoad={handleItemLoad}
                                {...{ pageIdx, reportName }}
                            />
                        </div>
                    ))}
                </ResponsiveGridLayout>
                <NoInteractionGate style={{ height: 'auto' }}>
                    <DateWaterMark />
                    <AtlasWaterMark />
                    <Attribution />
                </NoInteractionGate>
            </LayoutPageContainer>
        </OuterContainer>
    )
}

export default ReportPage