teableio/teable

View on GitHub
packages/sdk/src/components/grid-enhancements/hooks/use-grid-column-statistics.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { NoneFunc, StatisticsFunc } from '@teable/core';
import type { IAggregationVo } from '@teable/openapi';
import { isEmpty, keyBy } from 'lodash';
import { useCallback, useEffect, useMemo, useState } from 'react';
import type { IColumnStatistics, IGridColumn } from '../..';
import { useTranslation } from '../../../context/app/i18n';
import { useAggregation } from '../../../hooks/use-aggregation';
import { useFields } from '../../../hooks/use-fields';
import { useViewId } from '../../../hooks/use-view-id';
import { statisticsValue2DisplayValue } from '../../../utils';

export const useStatisticFunc2NameMap = () => {
  const { t } = useTranslation();
  return useMemo(
    () => ({
      [NoneFunc.None]: t('statisticFunc.none'),
      [StatisticsFunc.Count]: t('statisticFunc.count'),
      [StatisticsFunc.Empty]: t('statisticFunc.empty'),
      [StatisticsFunc.Filled]: t('statisticFunc.filled'),
      [StatisticsFunc.Unique]: t('statisticFunc.unique'),
      [StatisticsFunc.Max]: t('statisticFunc.max'),
      [StatisticsFunc.Min]: t('statisticFunc.min'),
      [StatisticsFunc.Sum]: t('statisticFunc.sum'),
      [StatisticsFunc.Average]: t('statisticFunc.average'),
      [StatisticsFunc.Checked]: t('statisticFunc.checked'),
      [StatisticsFunc.UnChecked]: t('statisticFunc.unChecked'),
      [StatisticsFunc.PercentEmpty]: t('statisticFunc.percentEmpty'),
      [StatisticsFunc.PercentFilled]: t('statisticFunc.percentFilled'),
      [StatisticsFunc.PercentUnique]: t('statisticFunc.percentUnique'),
      [StatisticsFunc.PercentChecked]: t('statisticFunc.percentChecked'),
      [StatisticsFunc.PercentUnChecked]: t('statisticFunc.percentUnChecked'),
      [StatisticsFunc.EarliestDate]: t('statisticFunc.earliestDate'),
      [StatisticsFunc.LatestDate]: t('statisticFunc.latestDate'),
      [StatisticsFunc.DateRangeOfDays]: t('statisticFunc.dateRangeOfDays'),
      [StatisticsFunc.DateRangeOfMonths]: t('statisticFunc.dateRangeOfMonths'),
      [StatisticsFunc.TotalAttachmentSize]: t('statisticFunc.totalAttachmentSize'),
    }),
    [t]
  );
};

export function useGridColumnStatistics(columns: (IGridColumn & { id: string })[]) {
  const viewId = useViewId();
  const fields = useFields({ withHidden: true, withDenied: true });
  const remoteStatistics = useAggregation();
  const [columnStatistics, setColumnStatistics] = useState<IColumnStatistics>({});
  const statisticFunc2NameMap = useStatisticFunc2NameMap();
  const getColumnStatistics = useCallback(
    (source: IAggregationVo | null) => {
      if (source == null) return {};
      const { aggregations } = source;
      if (isEmpty(aggregations)) return {};
      const aggregationMap = keyBy(aggregations, 'fieldId');
      const fieldMap = keyBy(fields, 'id');

      return columns.reduce((acc, column) => {
        const { id: columnId } = column;

        const columnAggregations = aggregationMap[columnId];

        const { total, group } = columnAggregations ?? {};

        if (columnAggregations === null || total === null) {
          acc[columnId] = null;
          return acc;
        }

        const field = fieldMap[columnId];
        const groupAggregations: Record<string, string> = {};

        if (group) {
          Object.entries(group).forEach(([groupId, item]) => {
            const { aggFunc, value } = item;
            const displayValue = statisticsValue2DisplayValue(aggFunc, value, field);
            groupAggregations[groupId] = `${statisticFunc2NameMap[aggFunc]} ${displayValue}`;
          });
        }

        if (total != null && field != null) {
          const { aggFunc, value } = total;

          const displayValue = statisticsValue2DisplayValue(aggFunc, value, field);
          acc[columnId] = {
            ...groupAggregations,
            total: `${statisticFunc2NameMap[aggFunc]} ${displayValue}`,
          };
        }
        return acc;
      }, {} as IColumnStatistics);
    },
    [columns, fields, statisticFunc2NameMap]
  );

  useEffect(() => {
    if (remoteStatistics == null || viewId == null) return;

    const partialColumnStatistics = getColumnStatistics(remoteStatistics);
    if (partialColumnStatistics == null) return;

    setColumnStatistics(partialColumnStatistics);
  }, [getColumnStatistics, remoteStatistics, viewId]);

  return { columnStatistics };
}