Untitled

mail@pastecode.io avatarunknown
typescript
a month ago
6.4 kB
0
Indexable
Never
import React, { memo, useRef } from 'react';
import CandidateCard from '@components/CandidateCard';
import styles from './styles.module.scss';
import ContentLoader from "react-content-loader";
import { BiLoader } from 'react-icons/bi';
import { useActiveCandidate, useUpdateActiveCandidate } from 'contexts/ActiveCandidateContext';
import { useFilter, useUpdateFilter } from 'contexts/FilterContext';
import { FixedSizeGrid as Grid, shouldComponentUpdate } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import { useMediaQuery } from 'usehooks-ts';

const CandidateCardGrid = memo((props) => {
  const { SMCStage, SMCSlotCandidates } = useFilter();
  const { setActiveCandidateOpen, setActiveCandidateId, setActiveCandidates, getActiveCandidate } = useUpdateActiveCandidate();
  const { activeCandidateOpen, activeCandidate, activeCandidates } = useActiveCandidate();

  const { setSMCSlotCandidates } = useUpdateFilter();

  //? Responsiveness
  const S = useMediaQuery("(min-width:435px)");
  const M = useMediaQuery("(min-width:870px)");
  const L = useMediaQuery("(min-width:1280px)");
  const XL = useMediaQuery("(min-width:1500px)");
  const XXL = useMediaQuery("(min-width:1920px");
  let columnCount;
  if (XXL) {
    columnCount = 9;
  } else if (XL) {
    columnCount = 7;
  } else if (L) {
    columnCount = 6;
  } else if (M) {
    columnCount = 4;
  } else if (S) {
    columnCount = 2;
  } else {
    columnCount = 1;
  }

  //? React Window - Data Virtualization
  const Cell = ({ columnIndex, rowIndex, style }) => {
    //? Calculate the grid candidate placement ((0,0), (0,1), etc...)
    const dataIndex = rowIndex * (columnCount) + columnIndex;
    const candidate = props.data[dataIndex];
    if (!candidate) { return null; }

    //? Apply the custom styling to each div inside the grid
    const cellStyle = {
      ...style, //? styles from react-window
      paddingRight: '10px',
      display: 'block'
    };

    const handleCardClick = (candidate) => {
      if (SMCStage) {
        multipleCandidateSelection(candidate);
      } else {
        handleCandidateActive(candidate);
      }
    };

    return (
      <div
        key={candidate.id}
        className={styles.cardWrapper}
        style={cellStyle}
        onClick={() => {
          handleCardClick(candidate);
        }}
      >
        <CandidateCard
          candidate={candidate}
          // borderColor={activeCandidateOpen}
          showCandidate={props.showCandidate}
          incognito={props.incognito}
          setModalOpen={props.setModalOpen}

        />
      </div>
    )
  }
  const MemoizedCell = React.memo(Cell);
  const ItemCardGrid = memo(() => {
    return (
      <AutoSizer>
        {({ height, width }) => {
          return (
            <Grid
              columnCount={columnCount}
              columnWidth={204}
              height={height > 0 ? height : 110}
              rowCount={Math.round(props.data.length / columnCount)}
              rowHeight={110}
              width={width}
              style={{ overflowX: 'hidden' }}
            >
              {({ columnIndex, rowIndex, style }) => (
                <MemoizedCell
                  columnIndex={columnIndex}
                  rowIndex={rowIndex}
                  style={style}
                />
              )}
            </Grid>
          )
        }}
      </AutoSizer>
    )
  })

  const handleCandidateActive = (candidate) => {
    const isActive = activeCandidate?.id === candidate.id;
    if (isActive) {
      setActiveCandidateOpen(true);
    } else {
      setActiveCandidateId(candidate.id);
      setActiveCandidateOpen(true);
    }
  }

  const multipleCandidateSelection = async (candidate) => {
    const isSlotCandidate = SMCSlotCandidates.some((c) => c.id === candidate.id);
    const isStageCandidate = activeCandidates.some((c) => c.id === candidate.id);
    if (isSlotCandidate) {
      const updatedCandidates = SMCSlotCandidates.filter((c) => c.id !== candidate.id);
      setSMCSlotCandidates(updatedCandidates);
    }
    else if (isStageCandidate) {
      const updatedCandidates = activeCandidates.filter((c) => c.id !== candidate.id);
      setActiveCandidates(updatedCandidates);
    } else {
      const newCandidate = await getActiveCandidate(candidate.id);
      //? First fill Slot candidates (3 max), then fill Active candidates (for Head2Head)
      if (SMCSlotCandidates.length <= 2) {
        setSMCSlotCandidates([...SMCSlotCandidates, newCandidate]);
      } else {
        setActiveCandidates([...activeCandidates, newCandidate]);
      }
    }
  }

  return (
    <>
      <div
        className={SMCStage ? styles.candidateCardsSMCStage : ''}
        style={{
          margin: '0px 5px',
          marginBottom: '18px',
          position: 'relative',
          paddingLeft: '20px'
        }}
      >
        <h2 style={{ fontWeight: 'bold', position: 'fixed', zIndex: '11' }}>
          Candidates ({props.isLoading ? <BiLoader className={styles.spinner} /> : props.data.length})
        </h2>

      </div>
      <div style={{ marginTop: 10, width: '100%', height: SMCStage ? '77vh' : '70vh', padding: '5px 0px 5px 20px ' }}>
        {
          props.isLoading
            ? <MyLoader />
            : <ItemCardGrid />
        }
      </div>
    </>
  );
});

const MyLoader = () => {

  let placeholder = [];
  for (let i = 0; i < 9; i++) {
    placeholder.push(
      <div key={i} className={styles.cardWrapper}>
        <ContentLoader
          speed={2}
          width={188}
          height={105}
          viewBox="0 0 188 105"
          backgroundColor="#f3f3f3"
          foregroundColor="#ecebeb"
        >
          <rect x="4" y="9" rx="3" ry="3" width="88" height="6" />
          <rect x="4" y="27" rx="3" ry="3" width="52" height="6" />
          <rect x="0" y="56" rx="3" ry="3" width="410" height="6" />
          <rect x="0" y="72" rx="3" ry="3" width="380" height="6" />
          <rect x="0" y="88" rx="3" ry="3" width="178" height="6" />
          <circle cx="162" cy="21" r="20" />
        </ContentLoader>
      </div>
    );
  }
  return placeholder;
};

const CandidateCards = (props) => {
  const { SMCStage } = useFilter();
  return (
    <div className={SMCStage ? styles.SMCCandidatesHeight : styles.candidateCards} id="candidate-cards">
      <CandidateCardGrid {...props} />
    </div>
  )
};

export default CandidateCards;