diff --git a/src/api/getChallengeLeaderboard.js b/src/api/getChallengeLeaderboard.js index 75c7612..6b7db90 100644 --- a/src/api/getChallengeLeaderboard.js +++ b/src/api/getChallengeLeaderboard.js @@ -5,8 +5,11 @@ const getChallengeLeaderboard = (setDataState, challengeName, setLoading) => { .then(response => response.json()) .then(data => { setDataState(data.entries); - if (setLoading) - setLoading(false); + if (setLoading) { + setTimeout(() => { + setLoading(false); + }, 3000); + } }); }; diff --git a/src/components/elements/Table.js b/src/components/elements/Table.js index 9ccb6f6..d0d588c 100644 --- a/src/components/elements/Table.js +++ b/src/components/elements/Table.js @@ -1,23 +1,103 @@ import React from 'react'; -import {FlexColumn} from '../../utils/containers'; +import {FlexColumn, FlexRow, Grid, Svg} from '../../utils/containers'; import Media from 'react-media'; import theme from '../../utils/theme'; import Loading from './Loading'; 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 [, updateState] = React.useState(); + const forceUpdate = React.useCallback(() => updateState({}), []); + const mobileRender = () => { return ( - {props.renderElements('10px', props.headerElements)} + {/*{props.renderElements('10px', props.headerElements)}*/} ); }; const desktopRender = () => { + const n = (props.pageNr - 1) * ELEMENTS_PER_PAGE; + let submissionToMap = props.submissions.slice(n, n + ELEMENTS_PER_PAGE); return ( - {props.renderElements('32px', props.headerElements)} + + {submissionToMap.map(({ + submitter, + when, + evaluations, + times + }, index) => { + return ( + + {index === 0 ? props.headerElements.map((elem, i) => { + return ( + { + props.sortByUpdate(elem); + forceUpdate(); + }}> + + {elem} + + {elem !== '#' ? + <> + + + : ''} + + ); + }) : ''} + {index === 0 ? : ''} + + {index + n} + + + {submitter ? submitter : '[anonymous]'} + + {!IS_MOBILE() ? evaluations.map((metric, i) => { + return ( + + {metric.score.slice(0, 7)} + + ); + }) : + {evaluations[0] ? evaluations[0].score.slice(0, 7) : 'xxx'} + } + + {times ? times : 1} + + + {when ? `${when.slice(11, 16)} ${when.slice(0, 10)}` + : 'xxx'} + + {index !== 0 ? : ''} + + ); + })} + ); }; diff --git a/src/components/sections/Leaderboard/Leaderboard.js b/src/components/sections/Leaderboard/Leaderboard.js index 27938bd..88c9159 100644 --- a/src/components/sections/Leaderboard/Leaderboard.js +++ b/src/components/sections/Leaderboard/Leaderboard.js @@ -1,27 +1,25 @@ import React from 'react'; import Media from 'react-media'; import theme from '../../../utils/theme'; -import {FlexColumn, FlexRow} from '../../../utils/containers'; -import {H2, H3} from '../../../utils/fonts'; +import {FlexColumn} from '../../../utils/containers'; +import {H2} from '../../../utils/fonts'; import Table from '../../elements/Table'; import PropsTypes from 'prop-types'; import getChallengeLeaderboard from '../../../api/getChallengeLeaderboard'; -import _renderSubmissions from './_renderSubmissions'; import _tableSearchQueryHandler from './_tableSearchQueryHandler'; import {CALC_PAGES} from '../../../utils/globals'; import Search from '../../elements/Search'; import Pager from '../../elements/Pager'; -import Filter from '../../elements/Filter'; -import FilterBy from '../FilterBy'; -import sortOptions from './sortOptions'; const Leaderboard = (props) => { const [entriesFromApi, setEntriesFromApi] = React.useState([]); const [entries, setEntries] = React.useState([]); const [pageNr, setPageNr] = React.useState(1); const [loading, setLoading] = React.useState(true); - const [metricChoose, setMetricChoose] = React.useState(null); - const [sortBy, setSortBy] = React.useState(5); + const [submitterSorted, setSubmitterSorted] = React.useState(false); + const [entriesSorted, setEntriesSorted] = React.useState(false); + const [whenSorted, setWhenSorted] = React.useState(false); + const [scoreSorted, setScoreSorted] = React.useState(false); React.useEffect(() => { challengeDataRequest(props.challengeName); @@ -32,21 +30,16 @@ const Leaderboard = (props) => { getChallengeLeaderboard(setEntries, challengeName, setLoading); }; - const getMainMetricIndex = () => { + const getMetricIndex = (metricName) => { let i = 0; for (let evaluation of entriesFromApi[0].evaluations) { - if (evaluation.test.metric === props.mainMetric) { + if (evaluation.test.metric === metricName) { return i; } i++; } }; - const renderSubmissions = (gridGap, headerElements) => { - return _renderSubmissions(pageNr, entries - ? entries : [], gridGap, (metricChoose ? metricChoose : getMainMetricIndex()), sortBy, headerElements); - }; - const tableSearchQueryHandler = (event) => { _tableSearchQueryHandler(event, entriesFromApi, setPageNr, setEntries); }; @@ -88,12 +81,50 @@ const Leaderboard = (props) => { return header; }; - const metricChooseHandler = (value) => { - setMetricChoose(value); - }; - - const sortByHandler = (value) => { - setSortBy(value); + const sortByUpdate = (elem) => { + let newEntries = entries; + console.log(elem); + switch (elem) { + case 'submitter': + 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 = () => { @@ -103,22 +134,9 @@ const Leaderboard = (props) => { Leaderboard - {!loading ? -

- Metric: -

- {getPossibleMetrics() ? getPossibleMetrics().map((metric, index) => { - return ( - - {metric} - ); - }) : ''} -
: ''} + headerElements={['#', 'submitter', 'result', 'entries', 'when']} + pageNr={pageNr} submissions={entries} sortByUpdate={sortByUpdate}/> { Leaderboard - -
+
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 ( - - {submissions.map(({ - submitter, - when, - evaluations, - times - }, index) => { - return ( - - {index === 0 ? headerElements.map((elem, i) => { - return ( - - - {elem} - - {elem !== '#' ? - <> - - - : ''} - - ); - }) : ''} - {index === 0 ? : ''} - - {index + n} - - - {submitter ? submitter : '[anonymous]'} - - {!IS_MOBILE() ? evaluations.map((metric, i) => { - return ( - - {metric.score.slice(0, 7)} - - ); - }) : - {evaluations[metricChoose] ? evaluations[metricChoose].score.slice(0, 7) : 'xxx'} - } - - {times ? times : 1} - - - {when ? `${when.slice(11, 16)} ${when.slice(0, 10)}` - : 'xxx'} - - {index !== 0 ? : ''} - - ); - })} - - ); - } -}; - -export default _renderSubmissions; \ No newline at end of file