sort method correction on desktop
This commit is contained in:
parent
5bc8831824
commit
a653176baf
@ -5,8 +5,11 @@ const getChallengeLeaderboard = (setDataState, challengeName, setLoading) => {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
setDataState(data.entries);
|
setDataState(data.entries);
|
||||||
if (setLoading)
|
if (setLoading) {
|
||||||
|
setTimeout(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,23 +1,103 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FlexColumn} from '../../utils/containers';
|
import {FlexColumn, FlexRow, Grid, Svg} from '../../utils/containers';
|
||||||
import Media from 'react-media';
|
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 {ELEMENTS_PER_PAGE, IS_MOBILE} from '../../utils/globals';
|
||||||
|
import {Body, Medium} from '../../utils/fonts';
|
||||||
|
import arrow from '../../assets/arrow.svg';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Line = styled(FlexRow)`
|
||||||
|
position: absolute;
|
||||||
|
top: ${({top}) => top ? top : 'auto'};
|
||||||
|
bottom: ${({bottom}) => bottom ? bottom : 'auto'};
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: ${({theme}) => theme.colors.dark04};
|
||||||
|
height: ${({height}) => height ? height : '1px'};
|
||||||
|
`;
|
||||||
|
|
||||||
const Table = (props) => {
|
const Table = (props) => {
|
||||||
|
const [, updateState] = React.useState();
|
||||||
|
const forceUpdate = React.useCallback(() => updateState({}), []);
|
||||||
|
|
||||||
const mobileRender = () => {
|
const mobileRender = () => {
|
||||||
return (
|
return (
|
||||||
<FlexColumn as='table' margin='20px 0 32px 0' minHeight='380px'>
|
<FlexColumn as='table' margin='20px 0 32px 0' minHeight='380px'>
|
||||||
{props.renderElements('10px', props.headerElements)}
|
{/*{props.renderElements('10px', props.headerElements)}*/}
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const desktopRender = () => {
|
const desktopRender = () => {
|
||||||
|
const n = (props.pageNr - 1) * ELEMENTS_PER_PAGE;
|
||||||
|
let submissionToMap = props.submissions.slice(n, n + ELEMENTS_PER_PAGE);
|
||||||
return (
|
return (
|
||||||
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
|
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
|
||||||
{props.renderElements('32px', props.headerElements)}
|
<FlexColumn as='tbody' width='100%'>
|
||||||
|
{submissionToMap.map(({
|
||||||
|
submitter,
|
||||||
|
when,
|
||||||
|
evaluations,
|
||||||
|
times
|
||||||
|
}, index) => {
|
||||||
|
return (
|
||||||
|
<Grid as='tr' key={`leaderboard-row-${index}`}
|
||||||
|
backgroundColor={index % 2 === 1 ? theme.colors.dark01 : 'transparent'}
|
||||||
|
gridTemplateColumns={!IS_MOBILE() ? '1fr 3fr ' + '2fr '.repeat(evaluations.length) + '1fr 2fr' : '1fr 3fr 1fr 1fr 2fr'}
|
||||||
|
gridGap='20px' position='relative' width='100%' padding='4px'>
|
||||||
|
{index === 0 ? props.headerElements.map((elem, i) => {
|
||||||
|
return (
|
||||||
|
<FlexRow key={`leaderboard-header-${i}`} alignmentX='flex-start' as='td'
|
||||||
|
onClick={() => {
|
||||||
|
props.sortByUpdate(elem);
|
||||||
|
forceUpdate();
|
||||||
|
}}>
|
||||||
|
<Medium textAlign={elem === 'submitter' ? 'left' : 'right'}
|
||||||
|
width={elem === 'when' ? '100%' : 'auto'} padding='0 6px 0 0'
|
||||||
|
minWidth={elem === 'result' ? '72px' : 'none'} fontSize='18px'>
|
||||||
|
{elem}
|
||||||
|
</Medium>
|
||||||
|
{elem !== '#' ?
|
||||||
|
<>
|
||||||
|
<Svg width='8px' rotate='180deg' src={arrow}
|
||||||
|
backgroundColor={theme.colors.dark} margin='2px 0 0 0'/>
|
||||||
|
<Svg width='8px' src={arrow} backgroundColor={theme.colors.dark}
|
||||||
|
margin='0 0 2px 0'/>
|
||||||
|
</> : ''}
|
||||||
|
</FlexRow>
|
||||||
|
);
|
||||||
|
}) : ''}
|
||||||
|
{index === 0 ? <Line as='td' height='2px' top='38px' shadow={theme.shadow}/> : ''}
|
||||||
|
<Body as='td'>
|
||||||
|
{index + n}
|
||||||
|
</Body>
|
||||||
|
<Body as='td'>
|
||||||
|
{submitter ? submitter : '[anonymous]'}
|
||||||
|
</Body>
|
||||||
|
{!IS_MOBILE() ? evaluations.map((metric, i) => {
|
||||||
|
return (
|
||||||
|
<Body key={`metric-result-${i}`} as='td' textAlign='left' minWidth='72px'>
|
||||||
|
{metric.score.slice(0, 7)}
|
||||||
|
</Body>
|
||||||
|
);
|
||||||
|
}) : <Body as='td' textAlign='left' minWidth='72px'>
|
||||||
|
{evaluations[0] ? evaluations[0].score.slice(0, 7) : 'xxx'}
|
||||||
|
</Body>}
|
||||||
|
<Body as='td' padding='0 2px 0 0' textAlign='left'>
|
||||||
|
{times ? times : 1}
|
||||||
|
</Body>
|
||||||
|
<Body as='td' textAlign='right'>
|
||||||
|
{when ? `${when.slice(11, 16)} ${when.slice(0, 10)}`
|
||||||
|
: 'xxx'}
|
||||||
|
</Body>
|
||||||
|
{index !== 0 ? <Line top='0' as='td'/> : ''}
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</FlexColumn>
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Media from 'react-media';
|
import Media from 'react-media';
|
||||||
import theme from '../../../utils/theme';
|
import theme from '../../../utils/theme';
|
||||||
import {FlexColumn, FlexRow} from '../../../utils/containers';
|
import {FlexColumn} from '../../../utils/containers';
|
||||||
import {H2, H3} from '../../../utils/fonts';
|
import {H2} from '../../../utils/fonts';
|
||||||
import Table from '../../elements/Table';
|
import Table from '../../elements/Table';
|
||||||
import PropsTypes from 'prop-types';
|
import PropsTypes from 'prop-types';
|
||||||
import getChallengeLeaderboard from '../../../api/getChallengeLeaderboard';
|
import getChallengeLeaderboard from '../../../api/getChallengeLeaderboard';
|
||||||
import _renderSubmissions from './_renderSubmissions';
|
|
||||||
import _tableSearchQueryHandler from './_tableSearchQueryHandler';
|
import _tableSearchQueryHandler from './_tableSearchQueryHandler';
|
||||||
import {CALC_PAGES} from '../../../utils/globals';
|
import {CALC_PAGES} from '../../../utils/globals';
|
||||||
import Search from '../../elements/Search';
|
import Search from '../../elements/Search';
|
||||||
import Pager from '../../elements/Pager';
|
import Pager from '../../elements/Pager';
|
||||||
import Filter from '../../elements/Filter';
|
|
||||||
import FilterBy from '../FilterBy';
|
|
||||||
import sortOptions from './sortOptions';
|
|
||||||
|
|
||||||
const Leaderboard = (props) => {
|
const Leaderboard = (props) => {
|
||||||
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
|
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
|
||||||
const [entries, setEntries] = 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);
|
||||||
const [metricChoose, setMetricChoose] = React.useState(null);
|
const [submitterSorted, setSubmitterSorted] = React.useState(false);
|
||||||
const [sortBy, setSortBy] = React.useState(5);
|
const [entriesSorted, setEntriesSorted] = React.useState(false);
|
||||||
|
const [whenSorted, setWhenSorted] = React.useState(false);
|
||||||
|
const [scoreSorted, setScoreSorted] = React.useState(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
challengeDataRequest(props.challengeName);
|
challengeDataRequest(props.challengeName);
|
||||||
@ -32,21 +30,16 @@ const Leaderboard = (props) => {
|
|||||||
getChallengeLeaderboard(setEntries, challengeName, setLoading);
|
getChallengeLeaderboard(setEntries, challengeName, setLoading);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMainMetricIndex = () => {
|
const getMetricIndex = (metricName) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (let evaluation of entriesFromApi[0].evaluations) {
|
for (let evaluation of entriesFromApi[0].evaluations) {
|
||||||
if (evaluation.test.metric === props.mainMetric) {
|
if (evaluation.test.metric === metricName) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderSubmissions = (gridGap, headerElements) => {
|
|
||||||
return _renderSubmissions(pageNr, entries
|
|
||||||
? entries : [], gridGap, (metricChoose ? metricChoose : getMainMetricIndex()), sortBy, headerElements);
|
|
||||||
};
|
|
||||||
|
|
||||||
const tableSearchQueryHandler = (event) => {
|
const tableSearchQueryHandler = (event) => {
|
||||||
_tableSearchQueryHandler(event, entriesFromApi, setPageNr, setEntries);
|
_tableSearchQueryHandler(event, entriesFromApi, setPageNr, setEntries);
|
||||||
};
|
};
|
||||||
@ -88,12 +81,50 @@ const Leaderboard = (props) => {
|
|||||||
return header;
|
return header;
|
||||||
};
|
};
|
||||||
|
|
||||||
const metricChooseHandler = (value) => {
|
const sortByUpdate = (elem) => {
|
||||||
setMetricChoose(value);
|
let newEntries = entries;
|
||||||
};
|
console.log(elem);
|
||||||
|
switch (elem) {
|
||||||
const sortByHandler = (value) => {
|
case 'submitter':
|
||||||
setSortBy(value);
|
if (submitterSorted) {
|
||||||
|
newEntries = newEntries.sort((a, b) => (a.submitter > b.submitter) ? 1 : ((b.submitter > a.submitter) ? -1 : 0));
|
||||||
|
setSubmitterSorted(false);
|
||||||
|
} else {
|
||||||
|
newEntries = newEntries.sort((a, b) => (a.submitter < b.submitter) ? 1 : ((b.submitter < a.submitter) ? -1 : 0));
|
||||||
|
setSubmitterSorted(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'entries':
|
||||||
|
if (entriesSorted) {
|
||||||
|
newEntries = newEntries.sort((a, b) => a.times - b.times);
|
||||||
|
setEntriesSorted(false);
|
||||||
|
} else {
|
||||||
|
newEntries = newEntries.sort((a, b) => b.times - a.times);
|
||||||
|
setEntriesSorted(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'when':
|
||||||
|
if (whenSorted) {
|
||||||
|
newEntries = newEntries.sort((a, b) => (a.when > b.when) ? 1 : ((b.when > a.when) ? -1 : 0));
|
||||||
|
setWhenSorted(false);
|
||||||
|
} else {
|
||||||
|
newEntries = newEntries.sort((a, b) => (a.when < b.when) ? 1 : ((b.when < a.when) ? -1 : 0));
|
||||||
|
setWhenSorted(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-case-declarations
|
||||||
|
let metricIndex = getMetricIndex(elem);
|
||||||
|
if (scoreSorted) {
|
||||||
|
newEntries = newEntries.sort((a, b) => b.evaluations[metricIndex].score - a.evaluations[metricIndex].score);
|
||||||
|
setScoreSorted(false);
|
||||||
|
} else {
|
||||||
|
newEntries = newEntries.sort((a, b) => a.evaluations[metricIndex].score - b.evaluations[metricIndex].score);
|
||||||
|
setScoreSorted(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setEntries(newEntries);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mobileRender = () => {
|
const mobileRender = () => {
|
||||||
@ -103,22 +134,9 @@ const Leaderboard = (props) => {
|
|||||||
Leaderboard
|
Leaderboard
|
||||||
</H2>
|
</H2>
|
||||||
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
||||||
{!loading ? <FlexRow width='100%' gap='16px' as='section' margin='16px 0'>
|
|
||||||
<H3>
|
|
||||||
Metric:
|
|
||||||
</H3>
|
|
||||||
{getPossibleMetrics() ? getPossibleMetrics().map((metric, index) => {
|
|
||||||
return (
|
|
||||||
<Filter option={metricChoose} index={index} borderRadius='4px'
|
|
||||||
key={`metric-${index}`} handler={metricChooseHandler}
|
|
||||||
id={`metric-${index}`} name={`metric-${index}`}>
|
|
||||||
{metric}
|
|
||||||
</Filter>);
|
|
||||||
}) : ''}
|
|
||||||
</FlexRow> : ''}
|
|
||||||
<Table challengeName={props.challengeName} loading={loading}
|
<Table challengeName={props.challengeName} loading={loading}
|
||||||
renderElements={renderSubmissions}
|
headerElements={['#', 'submitter', 'result', 'entries', 'when']}
|
||||||
headerElements={['#', 'submitter', 'result', 'entries', 'when']}/>
|
pageNr={pageNr} submissions={entries} sortByUpdate={sortByUpdate}/>
|
||||||
<Pager pageNr={pageNr} width='48px' borderRadius='64px'
|
<Pager pageNr={pageNr} width='48px' borderRadius='64px'
|
||||||
pages={CALC_PAGES(entries ? entries : [])}
|
pages={CALC_PAGES(entries ? entries : [])}
|
||||||
nextPage={nextPage} previousPage={previousPage}
|
nextPage={nextPage} previousPage={previousPage}
|
||||||
@ -134,12 +152,8 @@ const Leaderboard = (props) => {
|
|||||||
Leaderboard
|
Leaderboard
|
||||||
</H2>
|
</H2>
|
||||||
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
||||||
<FilterBy header='Sort by' options={sortOptions} gridTemplateColumns='auto auto auto auto'
|
<Table challengeName={props.challengeName} loading={loading} headerElements={getLeaderboardHeader()}
|
||||||
option={sortBy} textAlign='center' margin='32px 0 0 0'
|
pageNr={pageNr} submissions={entries} sortByUpdate={sortByUpdate}/>
|
||||||
alignmentX='center' handler={sortByHandler}/>
|
|
||||||
<Table challengeName={props.challengeName} loading={loading}
|
|
||||||
renderElements={renderSubmissions}
|
|
||||||
headerElements={getLeaderboardHeader()}/>
|
|
||||||
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
||||||
pages={CALC_PAGES(entries ? entries : [])}
|
pages={CALC_PAGES(entries ? entries : [])}
|
||||||
nextPage={nextPage} previousPage={previousPage}
|
nextPage={nextPage} previousPage={previousPage}
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
import {ELEMENTS_PER_PAGE, IS_MOBILE} from '../../../utils/globals';
|
|
||||||
import {FlexColumn, FlexRow, Grid, Svg} from '../../../utils/containers';
|
|
||||||
import {Body, Medium} from '../../../utils/fonts';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import theme from '../../../utils/theme';
|
|
||||||
import arrow from '../../../assets/arrow.svg';
|
|
||||||
|
|
||||||
|
|
||||||
const Line = styled(FlexRow)`
|
|
||||||
position: absolute;
|
|
||||||
top: ${({top}) => top ? top : 'auto'};
|
|
||||||
bottom: ${({bottom}) => bottom ? bottom : 'auto'};
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background-color: ${({theme}) => theme.colors.dark04};
|
|
||||||
height: ${({height}) => height ? height : '1px'};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const sortBySwitch = (submissions, metricChoose, sortBy) => {
|
|
||||||
switch (sortBy) {
|
|
||||||
case 0:
|
|
||||||
return submissions.sort((a, b) => (a.submitter < b.submitter) ? 1 : ((b.submitter < a.submitter) ? -1 : 0));
|
|
||||||
case 1:
|
|
||||||
if (metricChoose)
|
|
||||||
return submissions.sort((a, b) => a.evaluations[metricChoose].score - b.evaluations[metricChoose].score);
|
|
||||||
return submissions;
|
|
||||||
case 2:
|
|
||||||
return submissions.sort((a, b) => a.times - b.times);
|
|
||||||
case 3:
|
|
||||||
return submissions.sort((a, b) => (a.when > b.when) ? 1 : ((b.when > a.when) ? -1 : 0));
|
|
||||||
case 4:
|
|
||||||
return submissions.sort((a, b) => (a.submitter > b.submitter) ? 1 : ((b.submitter > a.submitter) ? -1 : 0));
|
|
||||||
case 5:
|
|
||||||
if (metricChoose)
|
|
||||||
return submissions.sort((a, b) => b.evaluations[metricChoose].score - a.evaluations[metricChoose].score);
|
|
||||||
return submissions;
|
|
||||||
case 6:
|
|
||||||
return submissions.sort((a, b) => b.times - a.times);
|
|
||||||
case 7:
|
|
||||||
return submissions.sort((a, b) => (a.when < b.when) ? 1 : ((b.when < a.when) ? -1 : 0));
|
|
||||||
default:
|
|
||||||
return submissions.sort((a, b) => b.evaluations[metricChoose].score - a.evaluations[metricChoose].score);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const _renderSubmissions = (pageNr, submissions, gridGap, metricChoose, sortBy, headerElements) => {
|
|
||||||
const n = (pageNr - 1) * ELEMENTS_PER_PAGE;
|
|
||||||
|
|
||||||
if (submissions) {
|
|
||||||
submissions = sortBySwitch(submissions, metricChoose, sortBy);
|
|
||||||
submissions = submissions.slice(n, n + ELEMENTS_PER_PAGE);
|
|
||||||
return (
|
|
||||||
<FlexColumn as='tbody' width='100%'>
|
|
||||||
{submissions.map(({
|
|
||||||
submitter,
|
|
||||||
when,
|
|
||||||
evaluations,
|
|
||||||
times
|
|
||||||
}, index) => {
|
|
||||||
return (
|
|
||||||
<Grid as='tr' key={`leaderboard-row-${index}`}
|
|
||||||
backgroundColor={index % 2 === 1 ? theme.colors.dark01 : 'transparent'}
|
|
||||||
gridTemplateColumns={!IS_MOBILE() ? '1fr 3fr ' + '2fr '.repeat(evaluations.length) + '1fr 2fr' : '1fr 3fr 1fr 1fr 2fr'}
|
|
||||||
gridGap='20px' position='relative' width='100%' padding='4px'>
|
|
||||||
{index === 0 ? headerElements.map((elem, i) => {
|
|
||||||
return (
|
|
||||||
<FlexRow alignmentX='flex-start'>
|
|
||||||
<Medium key={`leaderboard-header-${i}`}
|
|
||||||
textAlign={elem === 'submitter' ? 'left' : 'right'}
|
|
||||||
width={elem === 'when' ? '100%' : 'auto'} padding='0 6px 0 0'
|
|
||||||
minWidth={elem === 'result' ? '72px' : 'none'} fontSize='18px' as='td'>
|
|
||||||
{elem}
|
|
||||||
</Medium>
|
|
||||||
{elem !== '#' ?
|
|
||||||
<>
|
|
||||||
<Svg width='8px' rotate='180deg' src={arrow}
|
|
||||||
backgroundColor={theme.colors.dark} margin='2px 0 0 0'/>
|
|
||||||
<Svg width='8px' src={arrow} backgroundColor={theme.colors.dark}
|
|
||||||
margin='0 0 2px 0'/>
|
|
||||||
</> : ''}
|
|
||||||
</FlexRow>
|
|
||||||
);
|
|
||||||
}) : ''}
|
|
||||||
{index === 0 ? <Line height='2px' top='38px' shadow={theme.shadow}/> : ''}
|
|
||||||
<Body as='td'>
|
|
||||||
{index + n}
|
|
||||||
</Body>
|
|
||||||
<Body as='td'>
|
|
||||||
{submitter ? submitter : '[anonymous]'}
|
|
||||||
</Body>
|
|
||||||
{!IS_MOBILE() ? evaluations.map((metric, i) => {
|
|
||||||
return (
|
|
||||||
<Body key={`metric-result-${i}`} as='td' textAlign='left' minWidth='72px'>
|
|
||||||
{metric.score.slice(0, 7)}
|
|
||||||
</Body>
|
|
||||||
);
|
|
||||||
}) : <Body as='td' textAlign='left' minWidth='72px'>
|
|
||||||
{evaluations[metricChoose] ? evaluations[metricChoose].score.slice(0, 7) : 'xxx'}
|
|
||||||
</Body>}
|
|
||||||
<Body as='td' padding='0 2px 0 0' textAlign='left'>
|
|
||||||
{times ? times : 1}
|
|
||||||
</Body>
|
|
||||||
<Body as='td' textAlign='right'>
|
|
||||||
{when ? `${when.slice(11, 16)} ${when.slice(0, 10)}`
|
|
||||||
: 'xxx'}
|
|
||||||
</Body>
|
|
||||||
{index !== 0 ? <Line top='0' as='td'/> : ''}
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</FlexColumn>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default _renderSubmissions;
|
|
Loading…
Reference in New Issue
Block a user