import React, { Component } from 'react'; import styles from './styles.module.scss'; type ReportComponentPairedWithDomId = { id: string, report: React.ReactElement, } type DashboardReportGridProps = { reports: ReportComponentPairedWithDomId[], mobileBreakpoint?: number } type DashboardReportGridState = { reportHeights: { [id: string]: number, } } export default class DashboardReportGrid extends Component { reportElements: { [id: string]: HTMLDivElement } constructor(props: DashboardReportGridProps) { super(props); this.reportElements = {}; this.state = { reportHeights: {} }; } render() { const { reports } = this.props; const singleColumn = document.body.clientWidth <= (this.props.mobileBreakpoint || 768); const reportComponents = reports.map(({id, report}) => { return (
{ if (!elem) return; this.reportElements[id] = elem; if (this.state.reportHeights[id] !== elem.clientHeight) { this.setState({ reportHeights: Object.assign(this.state.reportHeights, {[id]: elem.clientHeight}) }); } }} > {report}
); }); // Filter out all reports that don't have a height. Render them outside of the columns to a // height can be stored. const reportsWithoutHeights = reportComponents.filter((_, index) => { return !this.state.reportHeights[reports[index].id]; }); if (singleColumn) { const reportsWithHeights = reportComponents.filter((_, index) => { return this.state.reportHeights[reports[index].id]; }); return (
{reportsWithoutHeights}
{reportsWithHeights}
); } else { // For all reports that have heights, sort them into columns. const { columnA, columnB } = reportComponents.filter((_, index) => { return this.state.reportHeights[reports[index].id]; }).reduce<{ columnA: JSX.Element[], columnATotalHeight: number, columnB: JSX.Element[], columnBTotalHeight: number, }>( ({columnA, columnATotalHeight, columnB, columnBTotalHeight}, reportComponent, index) => { const reportId = reports[index].id; // Option one: arrange such that higher numbered reports are higher up the list if (columnATotalHeight <= columnBTotalHeight) { // Option two: always arrange from left to right // if (index % 2 === 0) { // Add to column a return { columnA: [...columnA, reportComponent], columnATotalHeight: columnATotalHeight + this.state.reportHeights[reportId], columnB, columnBTotalHeight, }; } else { // Add to column b return { columnA, columnATotalHeight, columnB: [...columnB, reportComponent], columnBTotalHeight: columnBTotalHeight + this.state.reportHeights[reportId], }; } }, {columnA: [], columnB: [], columnATotalHeight: 0, columnBTotalHeight: 0} ); return (
{reportsWithoutHeights}
{columnA}
{columnB}
); } } }