Untitled

 avatar
unknown
plain_text
a month ago
6.6 kB
2
Indexable
/* eslint-disable no-shadow, react/jsx-props-no-spreading */
import React, { useEffect, useRef } from 'react';
import _, { noop } from 'lodash';
import { Scrollbars } from 'react-custom-scrollbars';
import classNames from 'classnames';
import { ContextMenuTrigger, connectMenu } from 'react-contextmenu';
import ReactTooltip from '../../general/reactTooltip';
import { GetDynamicContexOptions } from '../contextMenu';
import { ReactTableScrollPropTypes, ReactTableScrollDefaultProps } from './reactTableScroll.props';

/**
 * Ensures 2D scrolling when table width is larger than browser width
 * Moves table header and filter horizontally to be synced with table body
 * Only supports react-custom-scrollbars component
 */

const worklistItemMenuId = 'grid-context-menu';

const ReactTableScroll = function (props) {
  const {
    children,
    className,
    dataCy,
    getContextMenuOptions,
    hasFilter,
    heightStyle,
    horizontalScroll,
    isColResizing,
    onRowDoubleClicked,
    pageIndex,
    scrollEvents,
    style,
    tableHeader,
    onHide,
    viewId,
    ref
  } = props;

  const tbody = useRef();
  const verticalScrollPosition = useRef();
  const { scroll, start: scrollStart, stop: scrollStop } = scrollEvents;
  const { confirmation } = getContextMenuOptions || {};
  const _className = classNames(className, {
    'rt-tbody': true,
  });
  const headHeight = hasFilter ? 72 : 36;

  useEffect(() => {
    // Reset scroll position to top-left when pagination change
    if (tbody && tbody.current) {
      tbody.current.scrollToTop();
      tbody.current.scrollToLeft();
      verticalScrollPosition.current = tbody.current.getScrollTop();
    }
    return () => {};
  }, [pageIndex, viewId]);

  useEffect(() => {
    /* If we just stopped resizing the columns ->
       Reset vertical scroll position to where it was before we started the resizing */
    if (!isColResizing) tbody.current.scrollTop(verticalScrollPosition.current);
  }, [isColResizing]);

  useEffect(() => {
    if (verticalScrollPosition.current) tbody.current.scrollTop(verticalScrollPosition.current);
  }, [children]);

  function saveScrollPositionAndStop() {
    // if we are NOT currently resizing the columns -> Save the current vertical scroll position
    if (!isColResizing) verticalScrollPosition.current = tbody.current.getScrollTop();
    scrollStop();
  }

  function renderContextMenu() {
    if (!getContextMenuOptions) return null;

    const ConnectedContextMenu = connectMenu(worklistItemMenuId)(GetDynamicContexOptions);
    return (
      <ConnectedContextMenu
        getOptions={getContextMenuOptions.getOption}
        getSelectedEntities={getContextMenuOptions.getSelectedEntities}
        launchMenu={getContextMenuOptions.launchMenu}
        setSelectedEntityIds={getContextMenuOptions.setSelectedEntityIds}
      />
    );
  }

  function getWorklistEntityRowOfChild(child) {
    const tableProps = child.props;
    const columnsProps = tableProps.children[0].props;
    if (columnsProps.entity) return columnsProps.entity;

    const columnCell = columnsProps.children[0].props.children;

    return columnCell?.props?.original;
  }
  // eslint-disable-next-line max-len
  const renderContent = () =>
    confirmation && !_.isEmpty(confirmation) ? confirmation.renderContent : noop;
  const getArrowProps = arrowProps => ({ ...arrowProps, style: { left: 180 } });

  function getEntities() {
    if (!getContextMenuOptions && !onRowDoubleClicked) return children;
    if (!children) return;

    const rows = children;
    const container = document.getElementsByClassName('-worklist-table')[0];

    return rows.map(child => {
      const entityOfChild = getWorklistEntityRowOfChild(child);
      return (
        <div
          key={`child-${entityOfChild ? entityOfChild.id : ''}-${child.key}`}
          onDoubleClick={evt => onRowDoubleClicked && onRowDoubleClicked(evt, child)}>
          {getContextMenuOptions ? (
            <ContextMenuTrigger
              collect={prop => prop}
              data={entityOfChild}
              holdToDisplay={-1}
              id={worklistItemMenuId}>
              <ReactTooltip
                onCloseClick={onHide}
                boundariesElement={container}
                container={container}
                customStyle={{ width: 'auto' }}
                forceShow={confirmation && entityOfChild.id === confirmation?.entityId}
                getArrowProps={getArrowProps}
                hasCloseIcon={confirmation ? confirmation.hasCloseIcon : false}
                key="confirmation-popup"
                offset={450}
                placement="bottom-start"
                renderContent={popup => renderContent()(popup)}
                title={confirmation?.title}
                trigger="none">
                {({ getTriggerProps, triggerRef }) => (
                  // eslint-disable-next-line react/jsx-props-no-spreading
                  <div className="tooltip-div" {...getTriggerProps({ ref: triggerRef })}>
                    {child}
                  </div>
                )}
              </ReactTooltip>
            </ContextMenuTrigger>
          ) : (
            <div>{child}</div>
          )}
        </div>
      );
    });
  }
  return (
    <div ref={ref}>
    <Scrollbars
      data-cy={dataCy}
      onScroll={scroll}
      onScrollStart={scrollStart}
      onScrollStop={saveScrollPositionAndStop}
      ref={tbody}
      renderTrackHorizontal={
        horizontalScroll
          ? ({ style, ...props }) => (
              <div
                {...props}
                className="scrollbarTrackHorizontal"
                style={{ ...style, height: '10px' }}
              />
            )
          : () => <div />
      }
      renderTrackVertical={({ style, ...props }) => (
        <div
          {...props}
          className="scrollbarTrackVertical"
          style={{ ...style, width: '10px', top: `${headHeight}px` }}
        />
      )}
      className={classNames('tbodyScroll', `tbodyScroll--${_className}`)}
      style={{ height: heightStyle }}>
      {tableHeader()}
      <div className={_className} style={{ ...style }}>
        {getEntities()}
        {renderContextMenu()}
      </div>
    </Scrollbars>
    </div>
  );
};

ReactTableScroll.propTypes = ReactTableScrollPropTypes;

ReactTableScroll.defaultProps = ReactTableScrollDefaultProps;

export default ReactTableScroll;
Leave a Comment