Untitled
unknown
typescript
2 years ago
6.4 kB
4
Indexable
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;
Editor is loading...