allentries on desktop

This commit is contained in:
Mateusz Tylka 2023-04-04 10:04:09 +02:00
parent 27bbe74dd0
commit 3e66cfa3a9
11 changed files with 446 additions and 299 deletions

View File

@ -128,28 +128,28 @@ const App = () => {
element={<Challenge section={0} />} element={<Challenge section={0} />}
/> />
<Route <Route
path={`${CHALLENGE_PAGE}/:challengeId/readme`} path={`${CHALLENGE_PAGE}/:challengeId/allentries`}
element={<Challenge section={1} />} element={<Challenge section={1} />}
/> />
<Route
path={`${CHALLENGE_PAGE}/:challengeId/readme`}
element={<Challenge section={2} />}
/>
<Route <Route
path={`${CHALLENGE_PAGE}/:challengeId/howto`} path={`${CHALLENGE_PAGE}/:challengeId/howto`}
element={ element={
<Challenge <Challenge
popUpMessageHandler={popUpMessageHandler} popUpMessageHandler={popUpMessageHandler}
section={2} section={3}
/> />
} }
/> />
<Route <Route
path={`${CHALLENGE_PAGE}/:challengeId/myentries`} path={`${CHALLENGE_PAGE}/:challengeId/myentries`}
element={<Challenge section={3} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/submit`}
element={<Challenge section={4} />} element={<Challenge section={4} />}
/> />
<Route <Route
path={`${CHALLENGE_PAGE}/:challengeId/allentries`} path={`${CHALLENGE_PAGE}/:challengeId/submit`}
element={<Challenge section={5} />} element={<Challenge section={5} />}
/> />
<Route path={CHALLENGES_PAGE} element={<Challenges />} /> <Route path={CHALLENGES_PAGE} element={<Challenges />} />

View File

@ -1,16 +1,66 @@
import { API } from '../utils/globals'; import { API } from '../utils/globals';
import KeyCloakService from '../services/KeyCloakService';
const getAllEntries = async (setDataState, challengeName, setLoading) => { const getAllEntries = (
await fetch(`${API}/challenge-all-submissions/${challengeName}`) challengeName,
setDataOriginalState,
setDataState,
setLoadingState,
setScoreSorted
) => {
fetch(`${API}/challenge-all-submissions/${challengeName}`, {
headers: { Authorization: `Bearer ${KeyCloakService.getToken()}` },
})
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
console.log(data); if (setDataOriginalState) setDataOriginalState(data);
setDataState(data.entries); let item = {};
let result = [];
let initSetScoreSorted = [];
let tests = data.tests;
for (let submission of data.submissions) {
for (let evaluation of submission.evaluations) {
item = {
...item,
evaluations: {
...item.evaluations,
[`${evaluation.test.metric}.${evaluation.test.name}`]:
evaluation.score,
},
};
}
for (let test of tests) {
if (item.evaluations) {
if (
!Object.hasOwn(item.evaluations, `${test.metric}.${test.name}`)
) {
item = {
...item,
evaluations: {
...item.evaluations,
[`${test.metric}.${test.name}`]: '-1',
},
};
}
}
}
item = {
...item,
id: submission.id,
submitter: submission.submitter,
when: submission.when,
};
result.push(item);
item = {};
}
// eslint-disable-next-line no-unused-vars
for (let _ of tests) {
initSetScoreSorted.push(false);
}
setDataState(result);
if (setScoreSorted) setScoreSorted(initSetScoreSorted);
if (setLoadingState) setLoadingState(false);
}); });
if (setLoading) {
setLoading(false);
}
}; };
export default getAllEntries; export default getAllEntries;

View File

@ -4,7 +4,7 @@ import Media from 'react-media';
import { FlexColumn } from '../../../utils/containers'; import { FlexColumn } from '../../../utils/containers';
import { H2 } from '../../../utils/fonts'; import { H2 } from '../../../utils/fonts';
import { import {
// CALC_PAGES, CALC_PAGES,
EVALUATIONS_FORMAT, EVALUATIONS_FORMAT,
RENDER_WHEN, RENDER_WHEN,
} from '../../../utils/globals'; } from '../../../utils/globals';
@ -17,31 +17,39 @@ import getAllEntries from '../../../api/getAllEntries';
const AllEntries = (props) => { const AllEntries = (props) => {
const [entriesFromApi, setEntriesFromApi] = React.useState([]); const [entriesFromApi, setEntriesFromApi] = React.useState([]);
const [entriesAll, setEntriesAll] = 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 [submitterSorted, setSubmitterSorted] = React.useState(false);
// const [entriesSorted, setEntriesSorted] = React.useState(false);
const [whenSorted, setWhenSorted] = React.useState(false);
const [scoresSorted, setScoresSorted] = React.useState([]); const [scoresSorted, setScoresSorted] = React.useState([]);
const [submitterSorted, setSubmitterSorted] = React.useState(false);
const [whenSorted, setWhenSorted] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
challengeDataRequest(props.challengeName); if (props.challengeName) challengeDataRequest(props.challengeName);
}, [props.challengeName]); }, [props.challengeName]);
const challengeDataRequest = (challengeName) => { const challengeDataRequest = (challengeName) => {
getAllEntries(setEntriesFromApi, challengeName); getAllEntries(challengeName, setEntriesFromApi, setEntriesAll);
getAllEntries(setEntries, challengeName, setLoading); getAllEntries(
challengeName,
undefined,
setEntries,
setLoading,
setScoresSorted
);
}; };
const getPossibleMetrics = () => { const getPossibleMetrics = () => {
let metrics = []; let metrics = [];
// for (let test of entriesFromApi.tests) { if (entriesFromApi.tests) {
// let myEval = `${test.metric}.${test.name}`; for (let test of entriesFromApi.tests) {
// if (myEval && !metrics.includes(myEval)) { let myEval = `${test.metric}.${test.name}`;
// metrics.push(myEval); if (myEval && !metrics.includes(myEval)) {
// } metrics.push(myEval);
// } }
}
}
return metrics; return metrics;
}; };
@ -50,20 +58,19 @@ const AllEntries = (props) => {
for (let metric of getPossibleMetrics()) { for (let metric of getPossibleMetrics()) {
header.push(metric); header.push(metric);
} }
header.push('entries');
header.push('when'); header.push('when');
return header; return header;
}; };
const searchQueryHandler = (event) => { const searchQueryHandler = (event) => {
allEntriesSearchQueryHandler(event, entriesFromApi, setPageNr, setEntries); allEntriesSearchQueryHandler(event, entriesAll, setPageNr, setEntries);
}; };
const nextPage = () => { const nextPage = () => {
// if (pageNr !== CALC_PAGES(entries ? entries : [])) { if (pageNr !== CALC_PAGES(entries ? entries : [])) {
// let newPage = pageNr + 1; let newPage = pageNr + 1;
// setPageNr(newPage); setPageNr(newPage);
// } }
}; };
const previousPage = () => { const previousPage = () => {
@ -78,17 +85,38 @@ const AllEntries = (props) => {
switch (elem) { switch (elem) {
case '#': case '#':
break; break;
case 'submitter':
if (submitterSorted) {
setSubmitterSorted(false);
newEntries = newEntries.sort((a, b) =>
a.submitter.toLowerCase() < b.submitter.toLowerCase()
? 1
: b.submitter.toLowerCase() < a.submitter.toLowerCase()
? -1
: 0
);
} else {
setSubmitterSorted(true);
newEntries = newEntries.sort((a, b) =>
a.submitter.toLowerCase() > b.submitter.toLowerCase()
? 1
: b.submitter.toLowerCase() > a.submitter.toLowerCase()
? -1
: 0
);
}
break;
case 'when': case 'when':
if (whenSorted) { if (whenSorted) {
setWhenSorted(false);
newEntries = newEntries.sort((a, b) => newEntries = newEntries.sort((a, b) =>
a.when < b.when ? 1 : b.when < a.when ? -1 : 0 a.when < b.when ? 1 : b.when < a.when ? -1 : 0
); );
setWhenSorted(false);
} else { } else {
setWhenSorted(true);
newEntries = newEntries.sort((a, b) => newEntries = newEntries.sort((a, b) =>
a.when > b.when ? 1 : b.when > a.when ? -1 : 0 a.when > b.when ? 1 : b.when > a.when ? -1 : 0
); );
setWhenSorted(true);
} }
break; break;
default: default:
@ -124,7 +152,7 @@ const AllEntries = (props) => {
const desktopRender = () => { const desktopRender = () => {
return ( return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1200px"> <FlexColumn padding="24px" as="section" width="100%" maxWidth="1400px">
<H2 as="h2" margin="0 0 32px 0"> <H2 as="h2" margin="0 0 32px 0">
All Entries All Entries
</H2> </H2>
@ -134,18 +162,14 @@ const AllEntries = (props) => {
<Table <Table
challengeName={props.challengeName} challengeName={props.challengeName}
headerElements={getAllEntriesHeader()} headerElements={getAllEntriesHeader()}
// gridTemplateColumns={ possibleMetrics={getPossibleMetrics()}
// entries[0] gridTemplateColumns={
// ? '1fr 3fr ' + '1fr 3fr ' + '3fr '.repeat(getPossibleMetrics().length) + ' 3fr'
// '2fr '.repeat(entries[0].evaluations.length) + }
// '1fr 2fr'
// : ''
// }
user={props.user} user={props.user}
staticColumnElements={[ staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' }, { name: 'id', format: null, order: 1, align: 'left' },
{ name: 'submitter', format: null, order: 2, 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' }, { name: 'when', format: RENDER_WHEN, order: 5, align: 'right' },
]} ]}
metrics={getPossibleMetrics()} metrics={getPossibleMetrics()}
@ -156,17 +180,17 @@ const AllEntries = (props) => {
align: 'left', align: 'left',
}} }}
pageNr={pageNr} pageNr={pageNr}
elements={[]} elements={entries}
sortByUpdate={sortByUpdate} sortByUpdate={sortByUpdate}
/> />
<Pager <Pager
pageNr={pageNr} pageNr={pageNr}
width="72px" width="72px"
borderRadius="64px" borderRadius="64px"
pages={2} //CALC_PAGES(entries, 2) pages={CALC_PAGES(entries, 2)}
nextPage={nextPage} nextPage={nextPage}
previousPage={previousPage} previousPage={previousPage}
number={1} //`${pageNr} / ${CALC_PAGES(entries, 2)}`} number={`${pageNr} / ${CALC_PAGES(entries, 2)}`}
/> />
</> </>
) : ( ) : (

View File

@ -10,15 +10,18 @@ const allEntriesSearchQueryHandler = (
if (searchQuery === '') setEntries(entriesFromApi); if (searchQuery === '') setEntries(entriesFromApi);
else { else {
for (let entry of entriesFromApi) { for (let entry of entriesFromApi) {
const { id, submitter, when, times } = entry; const { id, when, submitter } = entry;
console.log(entry);
let evaluations = ''; let evaluations = '';
for (let evaluation of entry.evaluations) { if (entry.evaluations) {
evaluations += ` ${evaluation.score}`; for (let evaluation of Object.values(entry.evaluations)) {
evaluations += ` ${evaluation}`;
}
} }
const str = `${id} ${submitter} ${when.slice(11, 16)} ${when.slice( const str = `${id} ${submitter} ${when.slice(11, 16)} ${when.slice(
0, 0,
10 10
)} ${evaluations} ${times}`; )} ${evaluations}`;
if (str.toLowerCase().includes(searchQuery.toLowerCase())) if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry); submissionsToRender.push(entry);
} }

View File

@ -40,6 +40,10 @@ const Challenge = (props) => {
/> />
); );
case 1: case 1:
return (
<AllEntries challengeName={challengeName} setLoading={setLoading} />
);
case 2:
return ( return (
<Readme <Readme
challengeName={challengeName} challengeName={challengeName}
@ -48,7 +52,7 @@ const Challenge = (props) => {
deadline={challenge.deadline} deadline={challenge.deadline}
/> />
); );
case 2: case 3:
return ( return (
<HowTo <HowTo
popUpMessageHandler={props.popUpMessageHandler} popUpMessageHandler={props.popUpMessageHandler}
@ -56,14 +60,10 @@ const Challenge = (props) => {
user={user} user={user}
/> />
); );
case 3:
return <MyEntries challengeName={challengeName} />;
case 4: case 4:
return <Submit challengeName={challengeName} setLoading={setLoading} />; return <MyEntries challengeName={challengeName} />;
case 5: case 5:
return ( return <Submit challengeName={challengeName} setLoading={setLoading} />;
<AllEntries challengeName={challengeName} setLoading={setLoading} />
);
default: default:
return ( return (
<Leaderboard <Leaderboard

View File

@ -1,31 +1,48 @@
import React from 'react'; import React from 'react';
import {Svg} from '../../utils/containers'; import { Svg } from '../../utils/containers';
import arrow from '../../assets/arrow.svg'; import arrow from '../../assets/arrow.svg';
import filterIco from '../../assets/filter_direction.svg'; import filterIco from '../../assets/filter_direction.svg';
import theme from '../../utils/theme'; import theme from '../../utils/theme';
const ColumnFilterIcon = (props) => { const ColumnFilterIcon = (props) => {
const renderSecondIcon = () => { const renderSecondIcon = () => {
if (props.index === props.active) { if (props.index === props.active) {
return ( return (
<Svg width='8px' src={filterIco} backgroundColor={theme.colors.dark} <Svg
margin='0 0 0 2px' rotate={props.rotateIcon ? '0' : '180deg'}/> width="8px"
); src={filterIco}
} else { cursor={props.cursor}
return ( backgroundColor={theme.colors.dark}
<Svg width='8px' src={arrow} backgroundColor={theme.colors.dark} margin="0 0 0 2px"
margin='0 0 2px 0'/> rotate={props.rotateIcon ? '0' : '180deg'}
); />
} );
}; } else {
return (
<Svg
width="8px"
src={arrow}
cursor={props.cursor}
backgroundColor={theme.colors.dark}
margin="0 0 2px 0"
/>
);
}
};
return ( return (
<> <>
<Svg width='8px' rotate='180deg' src={arrow} <Svg
backgroundColor={theme.colors.dark} margin='2px 0 0 0'/> width="8px"
{renderSecondIcon()} rotate="180deg"
</> src={arrow}
); cursor={props.cursor}
backgroundColor={theme.colors.dark}
margin="2px 0 0 0"
/>
{renderSecondIcon()}
</>
);
}; };
export default ColumnFilterIcon; export default ColumnFilterIcon;

View File

@ -38,15 +38,15 @@ const Option = styled(FlexColumn)`
`; `;
const DesktopChallengeMenu = (props) => { const DesktopChallengeMenu = (props) => {
let options = ['Leaderboard', 'Readme', 'How to']; let options = ['Leaderboard', 'All entries', 'Readme', 'How to'];
if (KeyCloakService.isLoggedIn()) if (KeyCloakService.isLoggedIn())
options = [ options = [
'Leaderboard', 'Leaderboard',
'All entries',
'Readme', 'Readme',
'How to', 'How to',
'My entries', 'My entries',
'Submit', 'Submit',
'All entries',
]; ];
return ( return (
<DesktopChallengeMenuStyle> <DesktopChallengeMenuStyle>

View File

@ -1,24 +1,33 @@
const myEntriesSearchQueryHandler = (event, entriesFromApi, setPageNr, setEntries) => { const myEntriesSearchQueryHandler = (
let searchQuery = event.target.value; event,
let submissionsToRender = []; entriesFromApi,
setPageNr(1); setPageNr,
if (searchQuery === '') setEntries
setEntries(entriesFromApi); ) => {
else { let searchQuery = event.target.value;
for (let entry of entriesFromApi) { let submissionsToRender = [];
const {id, when} = entry; setPageNr(1);
let evaluations = ''; if (searchQuery === '') setEntries(entriesFromApi);
for (let evaluation of Object.values(entry.evaluations)) { else {
evaluations += ` ${evaluation}`; for (let entry of entriesFromApi) {
} const { id, when } = entry;
const str = `${id} ${when.slice(11, 16)} ${when.slice(0, 10)} ${evaluations}`; let evaluations = '';
console.log(entry); if (entry.evaluations) {
console.log(str); for (let evaluation of Object.values(entry.evaluations)) {
if (str.toLowerCase().includes(searchQuery.toLowerCase())) evaluations += ` ${evaluation}`;
submissionsToRender.push(entry);
} }
setEntries(submissionsToRender); }
const str = `${id} ${when.slice(11, 16)} ${when.slice(
0,
10
)} ${evaluations}`;
console.log(entry);
console.log(str);
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry);
} }
setEntries(submissionsToRender);
}
}; };
export default myEntriesSearchQueryHandler; export default myEntriesSearchQueryHandler;

View File

@ -1,20 +1,20 @@
import React from 'react'; import React from 'react';
import {Container, FlexColumn, FlexRow, Grid} from '../../utils/containers'; import { Container, FlexColumn, FlexRow, Grid } from '../../utils/containers';
import Media from 'react-media'; import Media from 'react-media';
import theme from '../../utils/theme'; import theme from '../../utils/theme';
import {ELEMENTS_PER_PAGE} from '../../utils/globals'; import { ELEMENTS_PER_PAGE } from '../../utils/globals';
import {Body, Medium} from '../../utils/fonts'; import { Body, Medium } from '../../utils/fonts';
import styled from 'styled-components'; import styled from 'styled-components';
import ColumnFilterIcon from './ColumnFilterIcon'; import ColumnFilterIcon from './ColumnFilterIcon';
const Line = styled(FlexRow)` const Line = styled(FlexRow)`
position: absolute; position: absolute;
top: ${({top}) => top ? top : 'auto'}; top: ${({ top }) => (top ? top : 'auto')};
bottom: ${({bottom}) => bottom ? bottom : 'auto'}; bottom: ${({ bottom }) => (bottom ? bottom : 'auto')};
left: 0; left: 0;
width: 100%; width: 100%;
background-color: ${({theme}) => theme.colors.dark04}; background-color: ${({ theme }) => theme.colors.dark04};
height: ${({height}) => height ? height : '1px'}; height: ${({ height }) => (height ? height : '1px')};
`; `;
const MobileTableStyle = styled(Container)` const MobileTableStyle = styled(Container)`
@ -23,23 +23,27 @@ const MobileTableStyle = styled(Container)`
margin: 32px 0; margin: 32px 0;
tr:nth-of-type(odd) { tr:nth-of-type(odd) {
background: ${({theme}) => theme.colors.dark03}; background: ${({ theme }) => theme.colors.dark03};
} }
th { th {
background: ${({theme}) => theme.colors.dark05}; background: ${({ theme }) => theme.colors.dark05};
color: ${({theme}) => theme.colors.white}; color: ${({ theme }) => theme.colors.white};
} }
td, th { td,
th {
padding: 6px; padding: 6px;
border: 1px solid ${({theme}) => theme.colors.white}; border: 1px solid ${({ theme }) => theme.colors.white};
text-align: left; text-align: left;
} }
display: block; display: block;
thead, tbody, th, td { thead,
tbody,
th,
td {
display: block; display: block;
} }
@ -51,7 +55,7 @@ const MobileTableStyle = styled(Container)`
td { td {
border: none; border: none;
border-bottom: 1px solid ${({theme}) => theme.colors.dark01}; border-bottom: 1px solid ${({ theme }) => theme.colors.dark01};
position: relative; position: relative;
padding-left: 50%; padding-left: 50%;
@ -67,222 +71,260 @@ const MobileTableStyle = styled(Container)`
} }
td:nth-of-type(1):before { td:nth-of-type(1):before {
content: ${({headerElements}) => headerElements[0] ? `'${headerElements[0]}'` : ''}; content: ${({ headerElements }) =>
headerElements[0] ? `'${headerElements[0]}'` : ''};
} }
td:nth-of-type(2):before { td:nth-of-type(2):before {
content: ${({headerElements}) => headerElements[1] ? `'${headerElements[1]}'` : ''}; content: ${({ headerElements }) =>
headerElements[1] ? `'${headerElements[1]}'` : ''};
} }
td:nth-of-type(3):before { td:nth-of-type(3):before {
content: ${({headerElements}) => headerElements[2] ? `'${headerElements[2]}'` : ''}; content: ${({ headerElements }) =>
headerElements[2] ? `'${headerElements[2]}'` : ''};
} }
td:nth-of-type(4):before { td:nth-of-type(4):before {
content: ${({headerElements}) => headerElements[3] ? `'${headerElements[3]}'` : ''}; content: ${({ headerElements }) =>
headerElements[3] ? `'${headerElements[3]}'` : ''};
} }
td:nth-of-type(5):before { td:nth-of-type(5):before {
content: ${({headerElements}) => headerElements[4] ? `'${headerElements[4]}'` : ''}; content: ${({ headerElements }) =>
headerElements[4] ? `'${headerElements[4]}'` : ''};
} }
td:nth-of-type(6):before { td:nth-of-type(6):before {
content: ${({headerElements}) => headerElements[5] ? `'${headerElements[5]}'` : ''}; content: ${({ headerElements }) =>
headerElements[5] ? `'${headerElements[5]}'` : ''};
} }
td:nth-of-type(7):before { td:nth-of-type(7):before {
content: ${({headerElements}) => headerElements[6] ? `'${headerElements[6]}'` : ''}; content: ${({ headerElements }) =>
headerElements[6] ? `'${headerElements[6]}'` : ''};
} }
td:nth-of-type(8):before { td:nth-of-type(8):before {
content: ${({headerElements}) => headerElements[7] ? `'${headerElements[7]}'` : ''}; content: ${({ headerElements }) =>
headerElements[7] ? `'${headerElements[7]}'` : ''};
} }
td:nth-of-type(9):before { td:nth-of-type(9):before {
content: ${({headerElements}) => headerElements[8] ? `'${headerElements[8]}'` : ''}; content: ${({ headerElements }) =>
headerElements[8] ? `'${headerElements[8]}'` : ''};
} }
td:nth-of-type(10):before { td:nth-of-type(10):before {
content: ${({headerElements}) => headerElements[9] ? `'${headerElements[9]}'` : ''}; content: ${({ headerElements }) =>
headerElements[9] ? `'${headerElements[9]}'` : ''};
} }
`; `;
const Table = (props) => { const Table = (props) => {
const [, updateState] = React.useState(); const [, updateState] = React.useState();
const forceUpdate = React.useCallback(() => updateState({}), []); const forceUpdate = React.useCallback(() => updateState({}), []);
const [activeIcon, setActiveIcon] = React.useState(null); const [activeIcon, setActiveIcon] = React.useState(null);
const [rotateActiveIcon, setRotateActiveIcon] = React.useState(false); const [rotateActiveIcon, setRotateActiveIcon] = React.useState(false);
const metricsRender = (elem) => { const metricsRender = (elem) => {
if (!props.iterableColumnElement) if (!props.iterableColumnElement) return <></>;
return <></>; if (Array.isArray(elem[props.iterableColumnElement.name]))
if (Array.isArray(elem[props.iterableColumnElement.name])) elem = elem[props.iterableColumnElement.name];
elem = elem[props.iterableColumnElement.name]; else {
else { let newElem = [];
let newElem = []; for (let metric of props.possibleMetrics) {
for (let metric of props.possibleMetrics) { if (Object.hasOwn(elem, props.iterableColumnElement.name)) {
if (Object.hasOwn(elem, props.iterableColumnElement.name)) { if (elem[props.iterableColumnElement.name][metric] === '-1')
if (elem[props.iterableColumnElement.name][metric] === '-1') newElem.push('N/A');
newElem.push('N/A'); else newElem.push(elem[props.iterableColumnElement.name][metric]);
else
newElem.push(elem[props.iterableColumnElement.name][metric]);
} else {
newElem.push('N/A');
}
}
elem = newElem;
}
return (
elem.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>
);
})
);
};
const rowRender = (elem) => {
if (elem.submitter === props.user) {
return (
props.staticColumnElements.map((elemName, i) => {
return (
<Medium 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]}
</Medium>
);
})
);
}
return (
props.staticColumnElements.map((elemName, i) => {
return (
<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>
);
})
);
};
const desktopRender = () => {
const n = (props.pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
let elementsToMap = props.elements.slice(n, n + (ELEMENTS_PER_PAGE * 2));
if (elementsToMap.length > 0) {
return (
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
<FlexColumn as='tbody' width='100%'>
<Grid as='tr'
gridGap='20px' position='relative' width='100%' padding='4px' margin='0 0 6px 0'
gridTemplateColumns={props.gridTemplateColumns}>
{props.headerElements.map((elem, i) => {
return (
<FlexRow key={`table-header-${i}`} alignmentX='flex-start' as='td'
onClick={() => {
if (activeIcon === i) {
let newRotateActiveIcon = !rotateActiveIcon;
setRotateActiveIcon(newRotateActiveIcon);
} else {
setRotateActiveIcon(false);
}
setActiveIcon(i);
props.sortByUpdate(elem, i);
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 !== '#' ?
<ColumnFilterIcon index={i} active={activeIcon}
rotateIcon={rotateActiveIcon}/>
: ''}
</FlexRow>
);
})}
<Line height='2px' top='32px' as='td' 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={props.gridTemplateColumns}
gridGap='20px' position='relative' width='100%' padding='4px'>
{rowRender(elem)}
{props.headerElements ? metricsRender(elem) : ''}
</Grid>
);
})}
</FlexColumn>
</FlexColumn>
);
} else { } else {
return ( newElem.push('N/A');
<Medium margin='72px 0'>
No results ;c
</Medium>
);
} }
}; }
elem = newElem;
}
return elem.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>
);
});
};
const mobileRender = () => { const rowRender = (elem) => {
const n = (props.pageNr - 1) * ELEMENTS_PER_PAGE; if (elem.submitter === props.user) {
let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE); return props.staticColumnElements.map((elemName, i) => {
if (elementsToMap.length > 0) { return (
return ( <Medium
<MobileTableStyle as='table' staticColumnElements={props.staticColumnElements} key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
headerElements={props.headerElements}> as="td"
<Container as='thead'> order={elemName.order}
<Container as='tr'> textAlign={elemName.align}
{props.headerElements.map((elem, i) => { >
return ( {elemName.format
<Medium key={`table-header-${i}`} as='th'> ? elemName.format(elem[elemName.name])
{elem} : elem[elemName.name]}
</Medium> </Medium>
); );
})} });
</Container> }
</Container> return props.staticColumnElements.map((elemName, i) => {
<Container as='tbody'> return (
{elementsToMap.map((elem, index) => { <Body
return ( key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
<Grid as='tr' key={`leaderboard-row-${index}`}> as="td"
{rowRender(elem)} order={elemName.order}
{props.headerElements ? metricsRender(elem) : ''} textAlign={elemName.align}
</Grid> >
); {elemName.format
})} ? elemName.format(elem[elemName.name])
</Container> : elem[elemName.name]}
</MobileTableStyle> </Body>
); );
} else { });
return ( };
<Medium margin='72px 0'>
No results ;c
</Medium>
);
}
};
return ( const desktopRender = () => {
<> const n = (props.pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
<Media query={theme.mobile}> let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE * 2);
{mobileRender()} if (elementsToMap.length > 0) {
</Media> return (
<Media query={theme.desktop}> <FlexColumn as="table" margin="32px 0 72px 0" width="100%">
{desktopRender()} <FlexColumn as="tbody" width="100%">
</Media> <Grid
</> as="tr"
); gridGap="20px"
position="relative"
width="100%"
padding="4px"
margin="0 0 6px 0"
gridTemplateColumns={props.gridTemplateColumns}
>
{props.headerElements.map((elem, i) => {
return (
<FlexRow
key={`table-header-${i}`}
alignmentX="flex-start"
as="td"
cursor="pointer"
onClick={() => {
if (activeIcon === i) {
let newRotateActiveIcon = !rotateActiveIcon;
setRotateActiveIcon(newRotateActiveIcon);
} else {
setRotateActiveIcon(false);
}
setActiveIcon(i);
props.sortByUpdate(elem, i);
forceUpdate();
}}
>
<Medium
cursor={elem !== '#' ? 'pointer' : ''}
textAlign={elem === 'when' ? 'right' : 'left'}
width={elem === 'when' ? '100%' : 'auto'}
padding="0 6px 0 0"
overflowWrap="break-word"
minWidth={elem === 'result' ? '72px' : 'none'}
>
{elem.replace('.', ' ')}
</Medium>
{elem !== '#' ? (
<ColumnFilterIcon
cursor="pointer"
index={i}
active={activeIcon}
rotateIcon={rotateActiveIcon}
/>
) : (
''
)}
</FlexRow>
);
})}
<Line height="2px" top="100%" as="td" 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={props.gridTemplateColumns}
gridGap="20px"
position="relative"
width="100%"
padding="4px"
>
{rowRender(elem)}
{props.headerElements ? metricsRender(elem) : ''}
</Grid>
);
})}
</FlexColumn>
</FlexColumn>
);
} else {
return <Medium margin="72px 0">No results ;c</Medium>;
}
};
const mobileRender = () => {
const n = (props.pageNr - 1) * ELEMENTS_PER_PAGE;
let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE);
if (elementsToMap.length > 0) {
return (
<MobileTableStyle
as="table"
staticColumnElements={props.staticColumnElements}
headerElements={props.headerElements}
>
<Container as="thead">
<Container as="tr">
{props.headerElements.map((elem, i) => {
return (
<Medium key={`table-header-${i}`} as="th">
{elem}
</Medium>
);
})}
</Container>
</Container>
<Container as="tbody">
{elementsToMap.map((elem, index) => {
return (
<Grid as="tr" key={`leaderboard-row-${index}`}>
{rowRender(elem)}
{props.headerElements ? metricsRender(elem) : ''}
</Grid>
);
})}
</Container>
</MobileTableStyle>
);
} else {
return <Medium margin="72px 0">No results ;c</Medium>;
}
};
return (
<>
<Media query={theme.mobile}>{mobileRender()}</Media>
<Media query={theme.desktop}>{desktopRender()}</Media>
</>
);
}; };
export default Table; export default Table;

View File

@ -35,6 +35,8 @@ const Container = styled.div`
order: ${({ order }) => (order ? order : '0')}; order: ${({ order }) => (order ? order : '0')};
z-index: ${({ zIndex }) => (zIndex ? zIndex : '0')}; z-index: ${({ zIndex }) => (zIndex ? zIndex : '0')};
list-style: ${({ listStyle }) => (listStyle ? listStyle : 'none')}; list-style: ${({ listStyle }) => (listStyle ? listStyle : 'none')};
overflow-wrap: ${({ overflowWrap }) =>
overflowWrap ? overflowWrap : 'normal'};
`; `;
const FlexRow = styled(Container)` const FlexRow = styled(Container)`

View File

@ -16,7 +16,7 @@ const POLICY_PRIVACY_PAGE = '/policy-privacy';
const CSI_LINK = 'https://csi.amu.edu.pl/'; const CSI_LINK = 'https://csi.amu.edu.pl/';
const ROOT_URL = window.location.origin; const ROOT_URL = window.location.origin;
const LOGIN_REQUIRED_PAGES = ['myentries', 'submit', 'howto']; const LOGIN_REQUIRED_PAGES = ['myentries', 'submit'];
const MINI_DESCRIPTION_RENDER = (description) => { const MINI_DESCRIPTION_RENDER = (description) => {
if (description) { if (description) {