Search in Leaderboard

This commit is contained in:
mattyl006 2022-08-01 14:25:27 +02:00
parent 033ef57bbe
commit 6b183ad5bb
9 changed files with 111 additions and 88 deletions

View File

@ -1,10 +1,10 @@
import {API} from '../utils/globals'; import {API} from '../utils/globals';
const getChallengeLeaderboard = (setDataState, setLoading, challengeName) => { const getChallengeLeaderboard = (setDataState, challengeName, setLoading) => {
fetch(`${API}/leaderboard/${challengeName}`) fetch(`${API}/leaderboard/${challengeName}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
setDataState(data); setDataState(data.entries);
if (setLoading) if (setLoading)
setLoading(false); setLoading(false);
}); });

View File

@ -71,7 +71,7 @@ const FiltersMenu = (props) => {
</FlexRow> </FlexRow>
</Media> </Media>
<Media query={theme.desktop}> <Media query={theme.desktop}>
<FlexRow margin='20px 0 0 0' width='94%' alignmentX='flex-start'> <FlexRow margin='8px 0 0 0' width='94%' alignmentX='flex-start'>
<Button width='72px' height='34px' backgroundColor={theme.colors.green} handler={resetHandler}> <Button width='72px' height='34px' backgroundColor={theme.colors.green} handler={resetHandler}>
Reset Reset
</Button> </Button>

View File

@ -50,23 +50,19 @@ const RightArrow = styled(Svg)`
`; `;
const Pager = (props) => { const Pager = (props) => {
if (props.visible) { return (
return ( <PagerStyle>
<PagerStyle> <LeftArrow as='button' src={polygon} onClick={props.previousPage} size='cover'
<LeftArrow as='button' src={polygon} onClick={props.previousPage} size='cover' backgroundColor={(props.pageNr === 1) ? 'transparent' : theme.colors.dark}/>
backgroundColor={(props.pageNr === 1) ? 'transparent' : theme.colors.dark}/> <CircleNumber number={props.number} width={props.width} borderRadius={props.borderRadius}/>
<CircleNumber number={props.number} width={props.width} borderRadius={props.borderRadius}/> <RightArrow as='button' src={polygon} onClick={props.nextPage} size='cover'
<RightArrow as='button' src={polygon} onClick={props.nextPage} size='cover' backgroundColor={(props.pageNr === props.pages)
backgroundColor={(props.pageNr === props.pages) ? 'transparent' : theme.colors.dark}/>
? 'transparent' : theme.colors.dark}/> </PagerStyle>
</PagerStyle> );
);
}
return '';
}; };
Pager.propTypes = { Pager.propTypes = {
visible: PropsTypes.bool,
previousPage: PropsTypes.func, previousPage: PropsTypes.func,
pageNr: PropsTypes.number, pageNr: PropsTypes.number,
nextPage: PropsTypes.func, nextPage: PropsTypes.func,
@ -77,7 +73,6 @@ Pager.propTypes = {
}; };
Pager.defaultProps = { Pager.defaultProps = {
visible: false,
previousPage: null, previousPage: null,
pageNr: 1, pageNr: 1,
nextPage: null, nextPage: null,

View File

@ -29,10 +29,6 @@ const SearchStyle = styled(FlexRow)`
&:hover { &:hover {
transform: scale(1.25); transform: scale(1.25);
} }
@media (min-width: ${({theme}) => theme.overMobile}) {
display: none;
}
} }
input { input {
@ -46,7 +42,8 @@ const Search = (props) => {
<SearchStyle> <SearchStyle>
<Svg src={loopIco}/> <Svg src={loopIco}/>
<Body as='input' onChange={(event) => props.searchQueryHandler(event)}/> <Body as='input' onChange={(event) => props.searchQueryHandler(event)}/>
<Svg as='button' src={filtersIco} onClick={props.toggleFiltersMenu}/> <Svg as='button' src={filtersIco} onClick={props.toggleFiltersMenu}
display={props.filterButton ? 'block' : 'none'}/>
</SearchStyle> </SearchStyle>
); );
}; };
@ -54,11 +51,13 @@ const Search = (props) => {
Search.propTypes = { Search.propTypes = {
searchQueryHandler: PropsTypes.func, searchQueryHandler: PropsTypes.func,
toggleFiltersMenu: PropsTypes.func, toggleFiltersMenu: PropsTypes.func,
filterButton: PropsTypes.bool
}; };
Search.defaultProps = { Search.defaultProps = {
searchQueryHandler: null, searchQueryHandler: null,
toggleFiltersMenu: null, toggleFiltersMenu: null,
filterButton: false,
}; };
export default Search; export default Search;

View File

@ -9,28 +9,36 @@ import Media from 'react-media';
import theme from '../../../utils/theme'; import theme from '../../../utils/theme';
import Loading from '../Loading'; import Loading from '../Loading';
import PropsTypes from 'prop-types'; import PropsTypes from 'prop-types';
import _tableSearchQueryHandler from './_tableSearchQueryHandler';
import Search from '../Search';
const Table = (props) => { const Table = (props) => {
const headerElements = ['#', 'submitter', 'when', 'result', 'entries']; const headerElements = ['#', 'submitter', 'when', 'result', 'entries'];
const [leaderboardData, setLeaderboardData] = React.useState({}); const [entriesFromApi, setEntriesFromApi] = React.useState([]);
const [entries, setEntries] = React.useState([]);
const [pageNr, setPageNr] = React.useState(1); const [pageNr, setPageNr] = React.useState(1);
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
React.useEffect(() => { React.useEffect(() => {
challengeDataRequest(); challengeDataRequest(props.challengeName);
}); }, [props.challengeName]);
const challengeDataRequest = () => { const challengeDataRequest = (challengeName) => {
getChallengeLeaderboard(setLeaderboardData, setLoading, props.challengeName); getChallengeLeaderboard(setEntriesFromApi, challengeName);
getChallengeLeaderboard(setEntries, challengeName, setLoading);
}; };
const renderSubmissions = () => { const renderSubmissions = () => {
return _renderSubmissions(pageNr, leaderboardData.entries return _renderSubmissions(pageNr, entries
? leaderboardData.entries : []); ? entries : []);
};
const tableSearchQueryHandler = (event) => {
_tableSearchQueryHandler(event, entriesFromApi, setPageNr, setEntries);
}; };
const nextPage = () => { const nextPage = () => {
if (pageNr !== CALC_PAGES(leaderboardData.entries ? leaderboardData.entries : [])) { if (pageNr !== CALC_PAGES(entries ? entries : [])) {
let newPage = pageNr + 1; let newPage = pageNr + 1;
setPageNr(newPage); setPageNr(newPage);
} }
@ -45,40 +53,54 @@ const Table = (props) => {
const mobileRender = () => { const mobileRender = () => {
return ( return (
<FlexColumn as='table' margin='0 0 32px 0' minHeight='380px'> <>
<Grid as='thead' gridTemplateColumns='1fr 3fr 3fr 1fr 1fr' <Search searchQueryHandler={tableSearchQueryHandler}/>
gridGap='10px' width='100%'> <FlexColumn as='table' margin='20px 0 32px 0' minHeight='380px'>
{headerElements.map((elem, index) => { <Grid as='thead' gridTemplateColumns='1fr 3fr 3fr 1fr 1fr'
return ( gridGap='10px' width='100%'>
<FlexRow as='tr' key={`leaderboard-header-${index}`} {headerElements.map((elem, index) => {
alignmentX={elem === 'entries' ? 'flex-end' : 'flex-start'}> return (
<Medium as='th'>{elem}</Medium> <FlexRow as='tr' key={`leaderboard-header-${index}`}
</FlexRow> alignmentX={elem === 'entries' ? 'flex-end' : 'flex-start'}>
); <Medium as='th'>{elem}</Medium>
})} </FlexRow>
</Grid> );
{renderSubmissions()} })}
</FlexColumn> </Grid>
{renderSubmissions()}
</FlexColumn>
<Pager pageNr={pageNr} width='48px' borderRadius='64px'
pages={CALC_PAGES(entries ? entries : [])}
nextPage={nextPage} previousPage={previousPage}
number={`${pageNr} / ${CALC_PAGES(entries ? entries : [])}`}/>
</>
); );
}; };
const desktopRender = () => { const desktopRender = () => {
return ( return (
<FlexColumn as='table' margin='0 0 72px 0' minHeight='438px'> <>
<Grid as='thead' gridTemplateColumns='1fr 3fr 3fr 1fr 1fr' <Search searchQueryHandler={tableSearchQueryHandler}/>
gridGap='10px' width='100%' margin='0 0 28px 0'> <FlexColumn as='table' margin='32px 0 72px 0' minHeight='438px'>
{headerElements.map((elem, index) => { <Grid as='thead' gridTemplateColumns='1fr 3fr 3fr 1fr 1fr'
return ( gridGap='10px' width='100%' margin='0 0 28px 0'>
<FlexRow as='tr' key={`leaderboard-header-${index}`} {headerElements.map((elem, index) => {
alignmentX={elem === 'entries' ? 'flex-end' : 'flex-start'}> return (
<H3 as='th'>{elem}</H3> <FlexRow as='tr' key={`leaderboard-header-${index}`}
</FlexRow> alignmentX={elem === 'entries' ? 'flex-end' : 'flex-start'}>
); <H3 as='th'>{elem}</H3>
})} </FlexRow>
</Grid> );
{renderSubmissions()} })}
</FlexColumn> </Grid>
{renderSubmissions()}
</FlexColumn>
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
pages={CALC_PAGES(entries ? entries : [])}
nextPage={nextPage} previousPage={previousPage}
number={`${pageNr} / ${CALC_PAGES(entries ? entries : [])}`}/>
</>
); );
}; };
@ -86,24 +108,11 @@ const Table = (props) => {
<> <>
<Loading visible={loading}/> <Loading visible={loading}/>
<Media query={theme.mobile}> <Media query={theme.mobile}>
<> {!loading ? mobileRender() : ''}
{!loading ? mobileRender() : ''}
<Pager visible={!loading} pageNr={pageNr}
pages={CALC_PAGES(leaderboardData.entries ? leaderboardData.entries : [])}
nextPage={nextPage} previousPage={previousPage} width='48px' borderRadius='64px'
number={`${pageNr} / ${CALC_PAGES(leaderboardData.entries ?
leaderboardData.entries : [])}`}/>
</>
</Media> </Media>
<Media query={theme.desktop}> <Media query={theme.desktop}>
<> {!loading ? desktopRender() : ''}
{!loading ? desktopRender() : ''}
<Pager visible={!loading} pageNr={pageNr}
pages={CALC_PAGES(leaderboardData.entries ? leaderboardData.entries : [])}
nextPage={nextPage} previousPage={previousPage} width='72px' borderRadius='64px'
number={`${pageNr} / ${CALC_PAGES(leaderboardData.entries ?
leaderboardData.entries : [])}`}/>
</>
</Media> </Media>
</> </>
); );

View File

@ -0,0 +1,18 @@
const _tableSearchQueryHandler = (event, entriesFromApi, setPageNr, setEntries) => {
let searchQuery = event.target.value;
let submissionsToRender = [];
setPageNr(1);
if (searchQuery === '')
setEntries(entriesFromApi);
else {
for (let entry of entriesFromApi) {
const {submitter, when, evaluations, times} = entry;
const str = `${submitter} ${when.slice(11, 16)} ${when.slice(0, 10)} ${evaluations} ${times}`;
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry);
}
setEntries(submissionsToRender);
}
};
export default _tableSearchQueryHandler;

View File

@ -53,7 +53,7 @@ const Leaderboard = (props) => {
<H2 as='h2' margin='0 0 12px 0'> <H2 as='h2' margin='0 0 12px 0'>
Leaderboard Leaderboard
</H2> </H2>
<FlexRow gap='12px' margin='0 0 20px 0'> <FlexRow gap='12px' margin='0 0 24px 0'>
<BoardVariantMobile as='button' active={0 === variant} onClick={() => setVariant(0)}> <BoardVariantMobile as='button' active={0 === variant} onClick={() => setVariant(0)}>
By user By user
</BoardVariantMobile> </BoardVariantMobile>
@ -72,7 +72,7 @@ const Leaderboard = (props) => {
<H2 as='h2' margin='0 0 32px 0'> <H2 as='h2' margin='0 0 32px 0'>
Leaderboard Leaderboard
</H2> </H2>
<FlexRow border={`1px solid ${theme.colors.green05}`} margin='0 0 76px 0'> <FlexRow border={`1px solid ${theme.colors.green05}`} margin='0 0 48px 0'>
<BoardVariantDesktop as='button' width='150px' height='48px' <BoardVariantDesktop as='button' width='150px' height='48px'
active={0 === variant} onClick={() => setVariant(0)}> active={0 === variant} onClick={() => setVariant(0)}>
<H3 as='span'> <H3 as='span'>

View File

@ -90,15 +90,16 @@ const Challenges = () => {
<H1 as='h1' margin='0 0 20px 0'> <H1 as='h1' margin='0 0 20px 0'>
Challenges Challenges
</H1> </H1>
<Search searchQueryHandler={searchQueryHandler} toggleFiltersMenu={toggleFiltersMenu}/> <Search searchQueryHandler={searchQueryHandler} filterButton
toggleFiltersMenu={toggleFiltersMenu}/>
<FlexColumn width='100%'> <FlexColumn width='100%'>
<Loading visible={loading}/> <Loading visible={loading}/>
{renderChallenges()} {renderChallenges()}
</FlexColumn> </FlexColumn>
</FlexColumn> </FlexColumn>
<Pager visible={!loading} pageNr={pageNr} pages={CALC_PAGES(challenges)} {!loading ? <Pager pageNr={pageNr} pages={CALC_PAGES(challenges)}
nextPage={nextPage} previousPage={previousPage} width='48px' borderRadius='64px' nextPage={nextPage} previousPage={previousPage} width='48px' borderRadius='64px'
number={`${pageNr} / ${CALC_PAGES(challenges)}`}/> number={`${pageNr} / ${CALC_PAGES(challenges)}`}/> : ''}
</FlexColumn> </FlexColumn>
</> </>
); );
@ -122,7 +123,7 @@ const Challenges = () => {
<Body margin='0 0 12px 0' maxWidth='400px'> <Body margin='0 0 12px 0' maxWidth='400px'>
Increase your machine learning skills by competing in our exciting challenges. Increase your machine learning skills by competing in our exciting challenges.
</Body> </Body>
<Search searchQueryHandler={searchQueryHandler} toggleFiltersMenu={toggleFiltersMenu}/> <Search searchQueryHandler={searchQueryHandler}/>
</FlexColumn> </FlexColumn>
<Svg src={cupIco} size='contain' width='25%' <Svg src={cupIco} size='contain' width='25%'
height='160px' backgroundColor={theme.colors.green}/> height='160px' backgroundColor={theme.colors.green}/>
@ -132,9 +133,9 @@ const Challenges = () => {
{renderChallenges()} {renderChallenges()}
</FlexColumn> </FlexColumn>
</FlexColumn> </FlexColumn>
<Pager visible={!loading} pageNr={pageNr} pages={CALC_PAGES(challenges)} {!loading ? <Pager pageNr={pageNr} pages={CALC_PAGES(challenges)}
nextPage={nextPage} previousPage={previousPage} width='72px' borderRadius='64px' nextPage={nextPage} previousPage={previousPage} width='72px' borderRadius='64px'
number={`${pageNr} / ${CALC_PAGES(challenges)}`}/> number={`${pageNr} / ${CALC_PAGES(challenges)}`}/> : ''}
</FlexColumn> </FlexColumn>
</> </>
); );

View File

@ -6,8 +6,9 @@ const _searchQueryHandler = (event, challengesFromAPI, setPageNr, setChallenges)
setChallenges(challengesFromAPI); setChallenges(challengesFromAPI);
else { else {
for (let challenge of challengesFromAPI) { for (let challenge of challengesFromAPI) {
let str = `${challenge.title} ${challenge.description} ${challenge.type} ${challenge.mainMetric} const {title, description, type, mainMetric, bestScore, deadline, baseline, prize} = challenge;
${challenge.bestScore} ${challenge.deadline} ${challenge.baseline} ${challenge.prize}`; const str = `${title} ${description} ${type} ${mainMetric} ${bestScore}
${deadline.slice(11, 16)} ${deadline.slice(0, 10)} ${baseline} ${prize}`;
if (str.toLowerCase().includes(searchQuery.toLowerCase())) if (str.toLowerCase().includes(searchQuery.toLowerCase()))
challengesToRender.push(challenge); challengesToRender.push(challenge);
} }