All files / src/form/dashboard Dashboard.tsx

2.08% Statements 1/48
0% Branches 0/30
0% Functions 0/11
2.08% Lines 1/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                                    6x                                                                                                                                                                                                                                            
import { DashboardProps, DashboardWidgetProps } from '@props/RecordProps';
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { getDashboardWidgets } from "@utils/FetchUtils";
import DashboardWidget from "./DashboardWidget";
import { LargeSpin } from "../../components";
import { Button, Col, Result, Row } from 'antd';
import "./css/dashboard.less";
import { useMediaQuery } from '@utils/hooks';
 
interface DashboardComponentProps {
  meta: DashboardProps;
  display: boolean;
  triggerRefresh?: boolean | number;
  addWidgetCallback: () => void;
  refreshInterval?: number;
}
 
const Dashboard = (props: DashboardComponentProps): ReactElement => {
  const { meta, display, triggerRefresh, addWidgetCallback, refreshInterval } = props;
  const { t } = useTranslation();
  const { canCreateWidget } = meta;
  const [groupedWidgets, setGroupedWidgets] = useState<Array<Array<DashboardWidgetProps>>>([]);
  const [loading, setLoading] = useState<boolean>(false);
 
  const isMobile = useMediaQuery('(max-width: 480px)');
  const isTabletOrSmallLaptop = useMediaQuery('(min-width: 481px) and (max-width: 1024px)');
  const isLargeScreen = useMediaQuery('(min-width: 1025px) and (max-width: 1200px)');
  const isExtraLarge = useMediaQuery('(min-width: 1201px)');
 
  const getWidgetCol = (widget: DashboardWidgetProps): number => {
    // Fetch user's config from options
    const optionJson = widget.options;
    const option = JSON.parse(optionJson);
    const userConfigCol = option?.position?.col;
 
    // If it's a laptop/desktop, use the configured column span or default
    if (isExtraLarge) {
      return userConfigCol ?? 8;  // 24 / 3 = 8 (for 3 per row)
    }
 
    if (isLargeScreen) {
      return 12; // 24 / 2 = 12 (for 2 per row)
    }
 
    // If it's a tablet or small laptop, 2 per row
    if (isTabletOrSmallLaptop || isMobile) {
      return 24;  // 24 / 2 = 12 (for 2 per row)
    }
 
    return 24;  // Default case (unlikely, but as a fallback)
  };
 
 
  const loadDashboardWidgetsMeta = useCallback(() => {
    setLoading(true);
    getDashboardWidgets(meta.id).then(widgets => {
      const newGroupedWidgets = [] as Array<Array<DashboardWidgetProps>>;
      let currentNumOfCols = 0;
      let currentIdx = 0;
      widgets.forEach(widget => {
        //Default display as 12 cols if not set in options
        const myCol = getWidgetCol(widget);
 
        if (newGroupedWidgets.length === 0) {
          newGroupedWidgets[0] = [widget];
          currentNumOfCols += myCol;
        } else {
          if ((currentNumOfCols + myCol) > 24) {
            newGroupedWidgets.push([widget]);
            currentIdx++;
            currentNumOfCols = myCol;
          } else {
            newGroupedWidgets[currentIdx].push(widget);
            currentNumOfCols += myCol;
          }
        }
      });
      setGroupedWidgets(newGroupedWidgets);
    }).finally(() => setLoading(false));
    // include triggerRefresh to refresh the widget list
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [meta.id, triggerRefresh]);
 
  useEffect(() => {
    loadDashboardWidgetsMeta();
  }, [loadDashboardWidgetsMeta]);
 
  const emptyDashboardMessage = <>{groupedWidgets.length === 0 && <Result
    title={t("No widget defined(or you don't have access to any)")}
    extra={
      canCreateWidget && (
        <Button
          type="primary"
          onClick={() => addWidgetCallback()}
        >
          {t('Create new dashboard widget')}
        </Button>
      )}
  />}</>;
 
  return (display && !loading) ? (
    <div>
      {emptyDashboardMessage}
      {groupedWidgets.length > 0 && groupedWidgets.map((row: Array<DashboardWidgetProps>, idx: number) => {
        return (
          <Row key={idx}>
            {row.map((widget: DashboardWidgetProps, widgetIdx: number) => {
              return (
                <Col
                  span={getWidgetCol(widget)}
                  key={widget.id}
                  className={`dashboard-col ${(widgetIdx === row.length - 1) ? 'dashboard-col-last' : ''}`}
                  //Follow style is to make widget in one row all same height
                  //https://github.com/ant-design/ant-design/issues/9154
                  style={{ display: 'inline-flex', alignSelf: "stretch" }}
                >
                  <DashboardWidget
                    meta={widget}
                    key={widget.id}
                    refreshCallback={() => loadDashboardWidgetsMeta()}
                    refreshInterval={(widget.refreshInterval == 0 || widget.refreshInterval == null) ?
                      refreshInterval : widget.refreshInterval}
                  />
                </Col>
              );
            })}
          </Row>
        );
      })}
    </div>
  ) : <LargeSpin />;
};
 
export default Dashboard;