Загрузка данных


import React from 'react';

import { Icon } from '@uikit/Icon';
import { BUTTON_MORE_ROW_KEY } from '@widgets/TradingResult/components/Repo/constants';
import { LoadMoreButton } from '@widgets/TradingResult/components/Repo/repo-table/component/loadMoreButton';
import { DataInfoByGroup } from '@widgets/TradingResult/components/Repo/repo-table/logic/table/useLoadGroupSubRowsData';
import { GroupFiltersStruct } from '@widgets/TradingResult/components/Repo/types/group';

import { Group } from 'types/MonitorRepo';

import repoTableStyles from '../styles/repoTable.module.scss';

interface InitialGroupFilterRecord {
  key: string;
  rowData: Record<string, unknown>;
}

interface GroupFilterValue {
  value: string;
}

interface ExpandIconProps {
  onExpand: (
    record: Record<string, unknown>,
    event: React.MouseEvent<HTMLElement>,
  ) => void;
  record: Record<string, unknown>;
}

const VALUES_TO_REFRESH = [
  'aggPrice',
  'aggQuantity',
  'aggAccint',
  'aggValue',
  'aggRepoRate',
  'aggRepoValue',
] as const satisfies readonly (keyof Group)[];

const isGroupFilterValue = (
  value: unknown,
): value is GroupFilterValue => {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return false;
  }

  return 'value' in value && typeof value.value === 'string';
};

export const createInitialGroupFilters = (
  record: InitialGroupFilterRecord,
): GroupFiltersStruct =>
  Object.entries(record.rowData).reduce<GroupFiltersStruct>(
    (acc, [filterName, dataValue]) => {
      if (!isGroupFilterValue(dataValue)) {
        return acc;
      }

      const groupValue = record.key;

      return {
        ...acc,
        [groupValue]: {
          ...acc[groupValue],
          [filterName]: dataValue.value,
        },
      };
    },
    {},
  );

export const ExpandIcon = ({
  onExpand,
  record,
}: ExpandIconProps) =>
  record.children ? (
    <div
      className={repoTableStyles.expandIconWrapper}
      onClick={(event: React.MouseEvent<HTMLElement>) =>
        onExpand(record, event)
      }
    >
      <Icon variant="chevron-down" />
    </div>
  ) : null;

export const unifyGroupAndChildrenRows = <
  T extends Record<string, unknown>,
>(
  groupSubRowsData: Record<string, DataInfoByGroup>,
  groupsData: T[],
  buttonMargin: number,
  loadMore: (groupValue: string) => Promise<void>,
): T[] => {
  // ищем значения групп по которым существуют данные подстрок
  const groupValues = Object.keys(groupSubRowsData);

  if (groupValues.length === 0) {
    return groupsData;
  }

  groupValues.forEach((groupValue) => {
    const groupData = groupSubRowsData[groupValue];

    if (!groupData) {
      return;
    }

    const searchedGroup = groupsData.find(
      (item) => item.key === groupValue,
    );

    if (!searchedGroup) {
      return;
    }

    const data = groupData.data ?? [];
    const page = groupData.page ?? 0;
    const size = groupData.size ?? 0;
    const totalValues = groupData.total ?? 0;
    const itemsCount = data.length;
    const isEmptyChildrenRows = itemsCount === 0;
    const loadedRowsNumber = (page + 1) * size;

    // подгруженные данные репо по группировке заносим в общую структуру групп как children
    searchedGroup.children = [
      ...data,
      {
        key: `${BUTTON_MORE_ROW_KEY}${groupValue}`,
        forceToSort: true,
        secId: (
          <LoadMoreButton
            styles={{ marginLeft: buttonMargin }}
            onClick={() => loadMore(groupValue)}
            loaded={
              !isEmptyChildrenRows
                ? Math.min(
                    loadedRowsNumber,
                    totalValues,
                    itemsCount,
                  )
                : 0
            }
            shouldDisplayButton={
              itemsCount === loadedRowsNumber
            }
            total={
              !isEmptyChildrenRows
                ? totalValues || loadedRowsNumber
                : 0
            }
          />
        ),
      },
    ];
  });

  return [...groupsData];
};

/** Обновляем только пересчитываемые значения */
export const refreshRowAggValues = (
  oldGroup: Group,
  newGroup: Group,
): Group =>
  VALUES_TO_REFRESH.reduce(
    (group, key) => ({
      ...group,
      [key]: newGroup[key],
    }),
    oldGroup,
  );