Untitled
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;