refactor Table, Leaderboard and MyEntries
This commit is contained in:
parent
b8dcd62da9
commit
f02c071fd7
@ -2,9 +2,7 @@ import React from 'react';
|
||||
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 {ELEMENTS_PER_PAGE} from '../../utils/globals';
|
||||
import {Body, Medium} from '../../utils/fonts';
|
||||
import arrow from '../../assets/arrow.svg';
|
||||
import styled from 'styled-components';
|
||||
@ -32,68 +30,71 @@ const Table = (props) => {
|
||||
};
|
||||
|
||||
const desktopRender = () => {
|
||||
const n = (props.pageNr - 1) * ELEMENTS_PER_PAGE;
|
||||
let submissionToMap = props.submissions.slice(n, n + ELEMENTS_PER_PAGE);
|
||||
const n = (props.pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
|
||||
console.log(props.elements);
|
||||
let elementsToMap = props.elements.slice(n, n + (ELEMENTS_PER_PAGE * 2));
|
||||
return (
|
||||
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
|
||||
<FlexColumn as='tbody' width='100%'>
|
||||
{submissionToMap.map(({
|
||||
submitter,
|
||||
when,
|
||||
evaluations,
|
||||
times
|
||||
}, index) => {
|
||||
<Grid
|
||||
gridGap='20px' position='relative' width='100%' padding='4px' margin='0 0 6px 0'
|
||||
gridTemplateColumns={props.gridTemplateColumns}>
|
||||
{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'}>
|
||||
{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>
|
||||
);
|
||||
})}
|
||||
<Line height='2px' top='32px' shadow={theme.shadow}/>
|
||||
</Grid>
|
||||
{elementsToMap.map((elem, 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'}
|
||||
gridTemplateColumns={props.gridTemplateColumns}
|
||||
gridGap='20px' position='relative' width='100%' padding='4px'>
|
||||
{index === 0 ? props.headerElements.map((elem, i) => {
|
||||
{props.staticColumnElements.map((elemName, 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 key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`} as='td'
|
||||
order={elemName.order} textAlign={elemName.align}>
|
||||
{elemName.format ? elemName.format(elem[elemName.name]) : elem[elemName.name]}
|
||||
</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'/> : ''}
|
||||
})}
|
||||
{props.iterableColumnElement ? elem[props.iterableColumnElement.name].map((iterableElem, i) => {
|
||||
return (
|
||||
<Body key={`metric-result-${i}`} as='td'
|
||||
order={props.iterableColumnElement.order}
|
||||
textAlign={props.iterableColumnElement.align} minWidth='72px'>
|
||||
{props.iterableColumnElement.format ?
|
||||
props.iterableColumnElement.format(iterableElem) : iterableElem}
|
||||
</Body>
|
||||
);
|
||||
}) : ''}
|
||||
{props.myEntries ? props.myEntries.tests.map((test, i) => {
|
||||
return (
|
||||
<Body key={`eval-result-${i}`} width='80px' as='td' textAlign='left'
|
||||
minWidth='72px' order={2}>
|
||||
{props.renderEvalResult(elem.evaluations, test)}
|
||||
</Body>
|
||||
);
|
||||
}) : ''}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
@ -104,29 +105,14 @@ const Table = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Loading visible={props.loading}/>
|
||||
<Media query={theme.mobile}>
|
||||
{!props.loading ? mobileRender() : ''}
|
||||
{mobileRender()}
|
||||
</Media>
|
||||
<Media query={theme.desktop}>
|
||||
{!props.loading ? desktopRender() : ''}
|
||||
{desktopRender()}
|
||||
</Media>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Table.propTypes = {
|
||||
challengeName: PropsTypes.string,
|
||||
loading: PropsTypes.bool,
|
||||
renderElements: PropsTypes.func,
|
||||
headerElements: PropsTypes.arrayOf(PropsTypes.string),
|
||||
};
|
||||
|
||||
Table.defaultProps = {
|
||||
challengeName: '',
|
||||
loading: true,
|
||||
renderElements: null,
|
||||
headerElements: [],
|
||||
};
|
||||
|
||||
export default Table;
|
@ -7,9 +7,10 @@ import Table from '../../elements/Table';
|
||||
import PropsTypes from 'prop-types';
|
||||
import getChallengeLeaderboard from '../../../api/getChallengeLeaderboard';
|
||||
import _tableSearchQueryHandler from './_tableSearchQueryHandler';
|
||||
import {CALC_PAGES} from '../../../utils/globals';
|
||||
import {CALC_PAGES, RENDER_WHEN} from '../../../utils/globals';
|
||||
import Search from '../../elements/Search';
|
||||
import Pager from '../../elements/Pager';
|
||||
import Loading from '../../elements/Loading';
|
||||
|
||||
const Leaderboard = (props) => {
|
||||
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
|
||||
@ -82,6 +83,7 @@ const Leaderboard = (props) => {
|
||||
};
|
||||
|
||||
const sortByUpdate = (elem) => {
|
||||
let metricIndex = 0;
|
||||
let newEntries = entries;
|
||||
console.log(elem);
|
||||
switch (elem) {
|
||||
@ -113,8 +115,7 @@ const Leaderboard = (props) => {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
let metricIndex = getMetricIndex(elem);
|
||||
metricIndex = getMetricIndex(elem);
|
||||
if (scoreSorted) {
|
||||
newEntries = newEntries.sort((a, b) => b.evaluations[metricIndex].score - a.evaluations[metricIndex].score);
|
||||
setScoreSorted(false);
|
||||
@ -145,19 +146,43 @@ const Leaderboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const evaluationsFormat = (evaluate) => {
|
||||
return evaluate.score.slice(0, 7);
|
||||
};
|
||||
|
||||
const desktopRender = () => {
|
||||
return (
|
||||
<FlexColumn padding='24px' as='section' width='100%' maxWidth='1200px'>
|
||||
<H2 as='h2' margin='0 0 32px 0'>
|
||||
Leaderboard
|
||||
</H2>
|
||||
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
||||
<Table challengeName={props.challengeName} loading={loading} headerElements={getLeaderboardHeader()}
|
||||
pageNr={pageNr} submissions={entries} sortByUpdate={sortByUpdate}/>
|
||||
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
||||
pages={CALC_PAGES(entries ? entries : [])}
|
||||
nextPage={nextPage} previousPage={previousPage}
|
||||
number={`${pageNr} / ${CALC_PAGES(entries ? entries : [])}`}/>
|
||||
{!loading ?
|
||||
<>
|
||||
<Search searchQueryHandler={tableSearchQueryHandler}/>
|
||||
<Table challengeName={props.challengeName} headerElements={getLeaderboardHeader()}
|
||||
gridTemplateColumns={entries[0] ? '1fr 3fr ' + '2fr '.repeat(entries[0].evaluations.length) + '1fr 2fr' : ''}
|
||||
staticColumnElements={
|
||||
[
|
||||
{name: 'id', format: null, order: 1, align: 'left'},
|
||||
{name: 'submitter', format: null, order: 2, align: 'left'},
|
||||
{name: 'times', format: null, order: 4, align: 'left'},
|
||||
{name: 'when', format: RENDER_WHEN, order: 5, align: 'right'}
|
||||
]
|
||||
}
|
||||
metrics={getPossibleMetrics()}
|
||||
iterableColumnElement={{
|
||||
name: 'evaluations',
|
||||
format: evaluationsFormat,
|
||||
order: 3,
|
||||
align: 'left'
|
||||
}}
|
||||
pageNr={pageNr} elements={entries} sortByUpdate={sortByUpdate}/>
|
||||
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
||||
pages={CALC_PAGES(entries, 2)}
|
||||
nextPage={nextPage} previousPage={previousPage}
|
||||
number={`${pageNr} / ${CALC_PAGES(entries, 2)}`}/>
|
||||
</>
|
||||
: <Loading/>}
|
||||
</FlexColumn>
|
||||
);
|
||||
};
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import {FlexColumn} from '../../../utils/containers';
|
||||
import {H2} from '../../../utils/fonts';
|
||||
import getMyEntries from '../../../api/getMyEntries';
|
||||
import Pager from '../../elements/Pager';
|
||||
import {CALC_PAGES} from '../../../utils/globals';
|
||||
import {FlexColumn} from '../../utils/containers';
|
||||
import {H2} from '../../utils/fonts';
|
||||
import getMyEntries from '../../api/getMyEntries';
|
||||
import Pager from '../elements/Pager';
|
||||
import {CALC_PAGES, RENDER_WHEN} from '../../utils/globals';
|
||||
import Media from 'react-media';
|
||||
import theme from '../../../utils/theme';
|
||||
import _tableSearchQueryHandler from '../Leaderboard/_tableSearchQueryHandler';
|
||||
import Loading from '../../elements/Loading';
|
||||
import _renderMySubmissions from './_renderMySubmissions';
|
||||
import theme from '../../utils/theme';
|
||||
import _tableSearchQueryHandler from './Leaderboard/_tableSearchQueryHandler';
|
||||
import Loading from '../elements/Loading';
|
||||
import Table from '../elements/Table';
|
||||
|
||||
const MyEntries = (props) => {
|
||||
const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({});
|
||||
@ -23,11 +23,6 @@ const MyEntries = (props) => {
|
||||
challengesRequest();
|
||||
}, []);
|
||||
|
||||
const renderSubmissions = (gridGap, headerElements) => {
|
||||
return _renderMySubmissions(pageNr, myEntries
|
||||
? myEntries : [], gridGap, metricChoose, sortBy, headerElements);
|
||||
};
|
||||
|
||||
const tableSearchQueryHandler = (event) => {
|
||||
_tableSearchQueryHandler(event, myEntriesFromAPI, setPageNr, setMyEntries);
|
||||
};
|
||||
@ -67,18 +62,28 @@ const MyEntries = (props) => {
|
||||
};
|
||||
|
||||
const challengesRequest = () => {
|
||||
getMyEntries(props.challengeName, setMyEntriesFromAPI);
|
||||
getMyEntries(props.challengeName, setMyEntriesFromAPI, setLoading);
|
||||
getMyEntries(props.challengeName, setMyEntries, setLoading);
|
||||
};
|
||||
|
||||
const sortByHandler = (value) => {
|
||||
setSortBy(value);
|
||||
};
|
||||
|
||||
const mobileRender = () => {
|
||||
|
||||
}
|
||||
|
||||
const renderEvalResult = (evaluations, test) => {
|
||||
for (let myEval of evaluations) {
|
||||
if (myEval.test.name === test.name && myEval.test.metric === test.metric) {
|
||||
return myEval.score.slice(0, 7);
|
||||
}
|
||||
}
|
||||
return 'xxx';
|
||||
};
|
||||
|
||||
const sortByUpdate = (elem) => {
|
||||
let newEntries = myEntries;
|
||||
return myEntries;
|
||||
};
|
||||
|
||||
const desktopRender = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
@ -90,16 +95,27 @@ const MyEntries = (props) => {
|
||||
<H2 as='h2' margin='0 0 32px 0'>
|
||||
My entries
|
||||
</H2>
|
||||
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
|
||||
{renderSubmissions('32px', getMyEntriesHeader())}
|
||||
</FlexColumn>
|
||||
{/*<Table challengeName={props.challengeName} loading={loading}*/}
|
||||
{/* renderElements={renderSubmissions}*/}
|
||||
{/* headerElements={getMyEntriesHeader()}/>*/}
|
||||
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
||||
pages={CALC_PAGES(myEntries.submissions ? myEntries.submissions : [])}
|
||||
nextPage={nextPage} previousPage={previousPage}
|
||||
number={`${pageNr} / ${CALC_PAGES(myEntries.submissions ? myEntries.submissions : [])}`}/>
|
||||
{myEntries.submissions ?
|
||||
<>
|
||||
<Table challengeName={props.challengeName} loading={loading}
|
||||
headerElements={getMyEntriesHeader()}
|
||||
gridTemplateColumns={'1fr ' + '4fr '.repeat(getMyEntriesHeader().length - 1)}
|
||||
staticColumnElements={
|
||||
[
|
||||
{name: 'id', format: null, order: 1, align: 'left'},
|
||||
{name: 'when', format: RENDER_WHEN, order: 3, align: 'right'}
|
||||
]
|
||||
}
|
||||
metrics={getPossibleMetrics()} myEntries={myEntries}
|
||||
renderEvalResult={renderEvalResult}
|
||||
pageNr={pageNr} elements={myEntries.submissions}
|
||||
sortByUpdate={sortByUpdate}/>
|
||||
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
|
||||
pages={CALC_PAGES(myEntries.submissions, 2)}
|
||||
nextPage={nextPage} previousPage={previousPage}
|
||||
number={`${pageNr} / ${CALC_PAGES(myEntries.submissions, 2)}`}/>
|
||||
</>
|
||||
: <Loading/>}
|
||||
</FlexColumn>
|
||||
);
|
||||
}
|
@ -1,91 +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 React from 'react';
|
||||
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 renderEvalResult = (evaluations, test) => {
|
||||
for (let myEval of evaluations) {
|
||||
if (myEval.test.name === test.name && myEval.test.metric === test.metric) {
|
||||
return myEval.score.slice(0, 7);
|
||||
}
|
||||
}
|
||||
return 'xxx';
|
||||
};
|
||||
|
||||
const _renderMySubmissions = (pageNr, myEntries, gridGap, metricChoose, sortBy, headerElements) => {
|
||||
const n = (pageNr - 1) * ELEMENTS_PER_PAGE;
|
||||
|
||||
if (myEntries) {
|
||||
// submissions = sortBySwitch(submissions, metricChoose, sortBy);
|
||||
let submissions = myEntries.submissions.slice(n, n + ELEMENTS_PER_PAGE);
|
||||
return (
|
||||
<FlexColumn as='tbody' width='100%'>
|
||||
{submissions.map(({
|
||||
submitter,
|
||||
when,
|
||||
evaluations,
|
||||
times,
|
||||
description
|
||||
}, index) => {
|
||||
return (
|
||||
<Grid as='tr' key={`leaderboard-row-${index}`}
|
||||
backgroundColor={index % 2 === 1 ? theme.colors.dark01 : 'transparent'}
|
||||
gridTemplateColumns={!IS_MOBILE() ? '1fr ' + '4fr '.repeat(headerElements.length - 1) : '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}`} fontSize='16px' as='td'
|
||||
textAlign={elem === 'when' ? 'right' : 'left'}
|
||||
width={elem === 'when' ? '100%' : 'auto'} padding='0 6px 0 0'>
|
||||
{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='50%' shadow={theme.shadow}/> : ''}
|
||||
<Body as='td'>
|
||||
{index + n + 1}
|
||||
</Body>
|
||||
{myEntries.tests.map((test, i) => {
|
||||
return (
|
||||
<Body key={`eval-result-${i}`} width='80px' as='td' textAlign='left'
|
||||
minWidth='72px'>
|
||||
{renderEvalResult(evaluations, test)}
|
||||
</Body>
|
||||
);
|
||||
})}
|
||||
<Body as='td' textAlign='right'>
|
||||
{when ? `${when.slice(11, 16)} ${when.slice(0, 10)}`
|
||||
: 'xxx'}
|
||||
</Body>
|
||||
{index !== 0 ? <Line as='td'/> : ''}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</FlexColumn>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default _renderMySubmissions;
|
@ -7,7 +7,7 @@ import MobileChallengeMenu from '../components/elements/MobileChallengeMenu';
|
||||
import Leaderboard from '../components/sections/Leaderboard/Leaderboard';
|
||||
import Readme from '../components/sections/Readme';
|
||||
import HowTo from '../components/sections/HowTo';
|
||||
import MyEntries from '../components/sections/MyEntries/MyEntries';
|
||||
import MyEntries from '../components/sections/MyEntries';
|
||||
import Submit from '../components/sections/Submit';
|
||||
import Media from 'react-media';
|
||||
import DesktopChallengeMenu from '../components/elements/DesktopChallengeMenu';
|
||||
|
@ -46,9 +46,9 @@ const RENDER_ICO = (type) => {
|
||||
}
|
||||
};
|
||||
|
||||
const CALC_PAGES = (objects) => {
|
||||
const CALC_PAGES = (objects, n = 1) => {
|
||||
if (objects.length === 0) return 1;
|
||||
return Math.ceil(objects.length / ELEMENTS_PER_PAGE);
|
||||
return Math.ceil(objects.length / (ELEMENTS_PER_PAGE * n));
|
||||
};
|
||||
|
||||
const RENDER_DEADLINE_TIME = (time) => {
|
||||
@ -60,6 +60,10 @@ const RENDER_DEADLINE_TIME = (time) => {
|
||||
return '';
|
||||
};
|
||||
|
||||
const RENDER_WHEN = (when) => {
|
||||
return `${when.slice(0, 10)} ${when.slice(11, 16)}`;
|
||||
};
|
||||
|
||||
const IS_MOBILE = () => {
|
||||
return document.body.clientWidth <= 768;
|
||||
};
|
||||
@ -75,5 +79,6 @@ export {
|
||||
RENDER_ICO,
|
||||
CALC_PAGES,
|
||||
RENDER_DEADLINE_TIME,
|
||||
IS_MOBILE
|
||||
IS_MOBILE,
|
||||
RENDER_WHEN
|
||||
};
|
Loading…
Reference in New Issue
Block a user