Compare commits
2 Commits
45601ce05c
...
3e66cfa3a9
Author | SHA1 | Date | |
---|---|---|---|
3e66cfa3a9 | |||
27bbe74dd0 |
12
src/App.js
12
src/App.js
@ -128,25 +128,29 @@ 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} />}
|
element={<Challenge section={4} />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={`${CHALLENGE_PAGE}/:challengeId/submit`}
|
path={`${CHALLENGE_PAGE}/:challengeId/submit`}
|
||||||
element={<Challenge section={4} />}
|
element={<Challenge section={5} />}
|
||||||
/>
|
/>
|
||||||
<Route path={CHALLENGES_PAGE} element={<Challenges />} />
|
<Route path={CHALLENGES_PAGE} element={<Challenges />} />
|
||||||
<Route
|
<Route
|
||||||
|
66
src/api/getAllEntries.js
Normal file
66
src/api/getAllEntries.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { API } from '../utils/globals';
|
||||||
|
import KeyCloakService from '../services/KeyCloakService';
|
||||||
|
|
||||||
|
const getAllEntries = (
|
||||||
|
challengeName,
|
||||||
|
setDataOriginalState,
|
||||||
|
setDataState,
|
||||||
|
setLoadingState,
|
||||||
|
setScoreSorted
|
||||||
|
) => {
|
||||||
|
fetch(`${API}/challenge-all-submissions/${challengeName}`, {
|
||||||
|
headers: { Authorization: `Bearer ${KeyCloakService.getToken()}` },
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (setDataOriginalState) setDataOriginalState(data);
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getAllEntries;
|
210
src/components/specific_challenge/AllEntries/AllEntries.js
Normal file
210
src/components/specific_challenge/AllEntries/AllEntries.js
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import theme from '../../../utils/theme';
|
||||||
|
import Media from 'react-media';
|
||||||
|
import { FlexColumn } from '../../../utils/containers';
|
||||||
|
import { H2 } from '../../../utils/fonts';
|
||||||
|
import {
|
||||||
|
CALC_PAGES,
|
||||||
|
EVALUATIONS_FORMAT,
|
||||||
|
RENDER_WHEN,
|
||||||
|
} from '../../../utils/globals';
|
||||||
|
import Loading from '../../generic/Loading';
|
||||||
|
import Pager from '../../generic/Pager';
|
||||||
|
import Table from '../Table';
|
||||||
|
import Search from '../../generic/Search';
|
||||||
|
import allEntriesSearchQueryHandler from './allEntriesSearchQueryHandler';
|
||||||
|
import getAllEntries from '../../../api/getAllEntries';
|
||||||
|
|
||||||
|
const AllEntries = (props) => {
|
||||||
|
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
|
||||||
|
const [entriesAll, setEntriesAll] = React.useState([]);
|
||||||
|
const [entries, setEntries] = React.useState([]);
|
||||||
|
const [pageNr, setPageNr] = React.useState(1);
|
||||||
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
const [scoresSorted, setScoresSorted] = React.useState([]);
|
||||||
|
const [submitterSorted, setSubmitterSorted] = React.useState(false);
|
||||||
|
const [whenSorted, setWhenSorted] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (props.challengeName) challengeDataRequest(props.challengeName);
|
||||||
|
}, [props.challengeName]);
|
||||||
|
|
||||||
|
const challengeDataRequest = (challengeName) => {
|
||||||
|
getAllEntries(challengeName, setEntriesFromApi, setEntriesAll);
|
||||||
|
getAllEntries(
|
||||||
|
challengeName,
|
||||||
|
undefined,
|
||||||
|
setEntries,
|
||||||
|
setLoading,
|
||||||
|
setScoresSorted
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPossibleMetrics = () => {
|
||||||
|
let metrics = [];
|
||||||
|
if (entriesFromApi.tests) {
|
||||||
|
for (let test of entriesFromApi.tests) {
|
||||||
|
let myEval = `${test.metric}.${test.name}`;
|
||||||
|
if (myEval && !metrics.includes(myEval)) {
|
||||||
|
metrics.push(myEval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metrics;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllEntriesHeader = () => {
|
||||||
|
let header = ['#', 'submitter'];
|
||||||
|
for (let metric of getPossibleMetrics()) {
|
||||||
|
header.push(metric);
|
||||||
|
}
|
||||||
|
header.push('when');
|
||||||
|
return header;
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchQueryHandler = (event) => {
|
||||||
|
allEntriesSearchQueryHandler(event, entriesAll, setPageNr, setEntries);
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextPage = () => {
|
||||||
|
if (pageNr !== CALC_PAGES(entries ? entries : [])) {
|
||||||
|
let newPage = pageNr + 1;
|
||||||
|
setPageNr(newPage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const previousPage = () => {
|
||||||
|
if (pageNr !== 1) {
|
||||||
|
let newPage = pageNr - 1;
|
||||||
|
setPageNr(newPage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sortByUpdate = (elem, i) => {
|
||||||
|
let newEntries = entries;
|
||||||
|
switch (elem) {
|
||||||
|
case '#':
|
||||||
|
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':
|
||||||
|
if (whenSorted) {
|
||||||
|
setWhenSorted(false);
|
||||||
|
newEntries = newEntries.sort((a, b) =>
|
||||||
|
a.when < b.when ? 1 : b.when < a.when ? -1 : 0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setWhenSorted(true);
|
||||||
|
newEntries = newEntries.sort((a, b) =>
|
||||||
|
a.when > b.when ? 1 : b.when > a.when ? -1 : 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-case-declarations
|
||||||
|
let metricIndex = getPossibleMetrics().indexOf(elem);
|
||||||
|
// eslint-disable-next-line no-case-declarations
|
||||||
|
let newScoresSorted = scoresSorted;
|
||||||
|
if (scoresSorted[metricIndex]) {
|
||||||
|
newEntries = newEntries.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(b.evaluations ? b.evaluations[elem] : -1) -
|
||||||
|
(a.evaluations ? a.evaluations[elem] : -1)
|
||||||
|
);
|
||||||
|
newScoresSorted[metricIndex] = false;
|
||||||
|
setScoresSorted(newScoresSorted);
|
||||||
|
} else {
|
||||||
|
newEntries = newEntries.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(a.evaluations ? a.evaluations[elem] : -1) -
|
||||||
|
(b.evaluations ? b.evaluations[elem] : -1)
|
||||||
|
);
|
||||||
|
newScoresSorted[metricIndex] = true;
|
||||||
|
setScoresSorted(newScoresSorted);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setEntries(newEntries);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobileRender = () => {
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktopRender = () => {
|
||||||
|
return (
|
||||||
|
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1400px">
|
||||||
|
<H2 as="h2" margin="0 0 32px 0">
|
||||||
|
All Entries
|
||||||
|
</H2>
|
||||||
|
{!loading ? (
|
||||||
|
<>
|
||||||
|
<Search searchQueryHandler={searchQueryHandler} />
|
||||||
|
<Table
|
||||||
|
challengeName={props.challengeName}
|
||||||
|
headerElements={getAllEntriesHeader()}
|
||||||
|
possibleMetrics={getPossibleMetrics()}
|
||||||
|
gridTemplateColumns={
|
||||||
|
'1fr 3fr ' + '3fr '.repeat(getPossibleMetrics().length) + ' 3fr'
|
||||||
|
}
|
||||||
|
user={props.user}
|
||||||
|
staticColumnElements={[
|
||||||
|
{ name: 'id', format: null, order: 1, align: 'left' },
|
||||||
|
{ name: 'submitter', format: null, order: 2, align: 'left' },
|
||||||
|
{ name: 'when', format: RENDER_WHEN, order: 5, align: 'right' },
|
||||||
|
]}
|
||||||
|
metrics={getPossibleMetrics()}
|
||||||
|
iterableColumnElement={{
|
||||||
|
name: 'evaluations',
|
||||||
|
format: EVALUATIONS_FORMAT,
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Media query={theme.mobile}>{mobileRender()}</Media>
|
||||||
|
<Media query={theme.desktop}>{desktopRender()}</Media>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AllEntries;
|
@ -0,0 +1,32 @@
|
|||||||
|
const allEntriesSearchQueryHandler = (
|
||||||
|
event,
|
||||||
|
entriesFromApi,
|
||||||
|
setPageNr,
|
||||||
|
setEntries
|
||||||
|
) => {
|
||||||
|
let searchQuery = event.target.value;
|
||||||
|
let submissionsToRender = [];
|
||||||
|
setPageNr(1);
|
||||||
|
if (searchQuery === '') setEntries(entriesFromApi);
|
||||||
|
else {
|
||||||
|
for (let entry of entriesFromApi) {
|
||||||
|
const { id, when, submitter } = entry;
|
||||||
|
console.log(entry);
|
||||||
|
let evaluations = '';
|
||||||
|
if (entry.evaluations) {
|
||||||
|
for (let evaluation of Object.values(entry.evaluations)) {
|
||||||
|
evaluations += ` ${evaluation}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const str = `${id} ${submitter} ${when.slice(11, 16)} ${when.slice(
|
||||||
|
0,
|
||||||
|
10
|
||||||
|
)} ${evaluations}`;
|
||||||
|
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||||
|
submissionsToRender.push(entry);
|
||||||
|
}
|
||||||
|
setEntries(submissionsToRender);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default allEntriesSearchQueryHandler;
|
1
src/components/specific_challenge/AllEntries/index.js
Normal file
1
src/components/specific_challenge/AllEntries/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './AllEntries';
|
@ -16,6 +16,7 @@ import textIco from '../../assets/text_ico.svg';
|
|||||||
import getChallengeInfo from '../../api/getChallengeInfo';
|
import getChallengeInfo from '../../api/getChallengeInfo';
|
||||||
import Loading from '../generic/Loading';
|
import Loading from '../generic/Loading';
|
||||||
import getUser from '../../api/getUser';
|
import getUser from '../../api/getUser';
|
||||||
|
import AllEntries from './AllEntries/AllEntries';
|
||||||
|
|
||||||
const Challenge = (props) => {
|
const Challenge = (props) => {
|
||||||
const challengeName = useParams().challengeId;
|
const challengeName = useParams().challengeId;
|
||||||
@ -39,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}
|
||||||
@ -47,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}
|
||||||
@ -55,9 +60,9 @@ const Challenge = (props) => {
|
|||||||
user={user}
|
user={user}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 3:
|
|
||||||
return <MyEntries challengeName={challengeName} />;
|
|
||||||
case 4:
|
case 4:
|
||||||
|
return <MyEntries challengeName={challengeName} />;
|
||||||
|
case 5:
|
||||||
return <Submit challengeName={challengeName} setLoading={setLoading} />;
|
return <Submit challengeName={challengeName} setLoading={setLoading} />;
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
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';
|
||||||
@ -8,21 +8,38 @@ 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}
|
||||||
|
cursor={props.cursor}
|
||||||
|
backgroundColor={theme.colors.dark}
|
||||||
|
margin="0 0 0 2px"
|
||||||
|
rotate={props.rotateIcon ? '0' : '180deg'}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Svg width='8px' src={arrow} backgroundColor={theme.colors.dark}
|
<Svg
|
||||||
margin='0 0 2px 0'/>
|
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"
|
||||||
|
rotate="180deg"
|
||||||
|
src={arrow}
|
||||||
|
cursor={props.cursor}
|
||||||
|
backgroundColor={theme.colors.dark}
|
||||||
|
margin="2px 0 0 0"
|
||||||
|
/>
|
||||||
{renderSecondIcon()}
|
{renderSecondIcon()}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -38,9 +38,16 @@ 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 = ['Leaderboard', 'Readme', 'How to', 'My entries', 'Submit'];
|
options = [
|
||||||
|
'Leaderboard',
|
||||||
|
'All entries',
|
||||||
|
'Readme',
|
||||||
|
'How to',
|
||||||
|
'My entries',
|
||||||
|
'Submit',
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<DesktopChallengeMenuStyle>
|
<DesktopChallengeMenuStyle>
|
||||||
{options.map((option, index) => {
|
{options.map((option, index) => {
|
||||||
|
@ -1,17 +1,26 @@
|
|||||||
const myEntriesSearchQueryHandler = (event, entriesFromApi, setPageNr, setEntries) => {
|
const myEntriesSearchQueryHandler = (
|
||||||
|
event,
|
||||||
|
entriesFromApi,
|
||||||
|
setPageNr,
|
||||||
|
setEntries
|
||||||
|
) => {
|
||||||
let searchQuery = event.target.value;
|
let searchQuery = event.target.value;
|
||||||
let submissionsToRender = [];
|
let submissionsToRender = [];
|
||||||
setPageNr(1);
|
setPageNr(1);
|
||||||
if (searchQuery === '')
|
if (searchQuery === '') setEntries(entriesFromApi);
|
||||||
setEntries(entriesFromApi);
|
|
||||||
else {
|
else {
|
||||||
for (let entry of entriesFromApi) {
|
for (let entry of entriesFromApi) {
|
||||||
const {id, when} = entry;
|
const { id, when } = entry;
|
||||||
let evaluations = '';
|
let evaluations = '';
|
||||||
|
if (entry.evaluations) {
|
||||||
for (let evaluation of Object.values(entry.evaluations)) {
|
for (let evaluation of Object.values(entry.evaluations)) {
|
||||||
evaluations += ` ${evaluation}`;
|
evaluations += ` ${evaluation}`;
|
||||||
}
|
}
|
||||||
const str = `${id} ${when.slice(11, 16)} ${when.slice(0, 10)} ${evaluations}`;
|
}
|
||||||
|
const str = `${id} ${when.slice(11, 16)} ${when.slice(
|
||||||
|
0,
|
||||||
|
10
|
||||||
|
)} ${evaluations}`;
|
||||||
console.log(entry);
|
console.log(entry);
|
||||||
console.log(str);
|
console.log(str);
|
||||||
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
|
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||||
|
@ -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,43 +71,53 @@ 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]}'` : ''};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -114,8 +128,7 @@ const Table = (props) => {
|
|||||||
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 {
|
||||||
@ -124,68 +137,86 @@ const Table = (props) => {
|
|||||||
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
|
else newElem.push(elem[props.iterableColumnElement.name][metric]);
|
||||||
newElem.push(elem[props.iterableColumnElement.name][metric]);
|
|
||||||
} else {
|
} else {
|
||||||
newElem.push('N/A');
|
newElem.push('N/A');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem = newElem;
|
elem = newElem;
|
||||||
}
|
}
|
||||||
|
return elem.map((iterableElem, i) => {
|
||||||
return (
|
return (
|
||||||
elem.map((iterableElem, i) => {
|
<Body
|
||||||
return (
|
key={`metric-result-${i}`}
|
||||||
<Body key={`metric-result-${i}`} as='td'
|
as="td"
|
||||||
order={props.iterableColumnElement.order}
|
order={props.iterableColumnElement.order}
|
||||||
textAlign={props.iterableColumnElement.align} minWidth='72px'>
|
textAlign={props.iterableColumnElement.align}
|
||||||
{props.iterableColumnElement.format ?
|
minWidth="72px"
|
||||||
props.iterableColumnElement.format(iterableElem) : iterableElem}
|
>
|
||||||
|
{props.iterableColumnElement.format
|
||||||
|
? props.iterableColumnElement.format(iterableElem)
|
||||||
|
: iterableElem}
|
||||||
</Body>
|
</Body>
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowRender = (elem) => {
|
const rowRender = (elem) => {
|
||||||
if (elem.submitter === props.user) {
|
if (elem.submitter === props.user) {
|
||||||
|
return props.staticColumnElements.map((elemName, i) => {
|
||||||
return (
|
return (
|
||||||
props.staticColumnElements.map((elemName, i) => {
|
<Medium
|
||||||
return (
|
key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
|
||||||
<Medium key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
|
as="td"
|
||||||
as='td'
|
order={elemName.order}
|
||||||
order={elemName.order} textAlign={elemName.align}>
|
textAlign={elemName.align}
|
||||||
{elemName.format ? elemName.format(elem[elemName.name]) : elem[elemName.name]}
|
>
|
||||||
|
{elemName.format
|
||||||
|
? elemName.format(elem[elemName.name])
|
||||||
|
: elem[elemName.name]}
|
||||||
</Medium>
|
</Medium>
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return props.staticColumnElements.map((elemName, i) => {
|
||||||
return (
|
return (
|
||||||
props.staticColumnElements.map((elemName, i) => {
|
<Body
|
||||||
return (
|
key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
|
||||||
<Body key={`leaderboard-static-elemName-${i}-${elem[elemName.name]}`}
|
as="td"
|
||||||
as='td'
|
order={elemName.order}
|
||||||
order={elemName.order} textAlign={elemName.align}>
|
textAlign={elemName.align}
|
||||||
{elemName.format ? elemName.format(elem[elemName.name]) : elem[elemName.name]}
|
>
|
||||||
|
{elemName.format
|
||||||
|
? elemName.format(elem[elemName.name])
|
||||||
|
: elem[elemName.name]}
|
||||||
</Body>
|
</Body>
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const desktopRender = () => {
|
const desktopRender = () => {
|
||||||
const n = (props.pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
|
const n = (props.pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
|
||||||
let elementsToMap = props.elements.slice(n, n + (ELEMENTS_PER_PAGE * 2));
|
let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE * 2);
|
||||||
if (elementsToMap.length > 0) {
|
if (elementsToMap.length > 0) {
|
||||||
return (
|
return (
|
||||||
<FlexColumn as='table' margin='32px 0 72px 0' width='100%'>
|
<FlexColumn as="table" margin="32px 0 72px 0" width="100%">
|
||||||
<FlexColumn as='tbody' width='100%'>
|
<FlexColumn as="tbody" width="100%">
|
||||||
<Grid as='tr'
|
<Grid
|
||||||
gridGap='20px' position='relative' width='100%' padding='4px' margin='0 0 6px 0'
|
as="tr"
|
||||||
gridTemplateColumns={props.gridTemplateColumns}>
|
gridGap="20px"
|
||||||
|
position="relative"
|
||||||
|
width="100%"
|
||||||
|
padding="4px"
|
||||||
|
margin="0 0 6px 0"
|
||||||
|
gridTemplateColumns={props.gridTemplateColumns}
|
||||||
|
>
|
||||||
{props.headerElements.map((elem, i) => {
|
{props.headerElements.map((elem, i) => {
|
||||||
return (
|
return (
|
||||||
<FlexRow key={`table-header-${i}`} alignmentX='flex-start' as='td'
|
<FlexRow
|
||||||
|
key={`table-header-${i}`}
|
||||||
|
alignmentX="flex-start"
|
||||||
|
as="td"
|
||||||
|
cursor="pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (activeIcon === i) {
|
if (activeIcon === i) {
|
||||||
let newRotateActiveIcon = !rotateActiveIcon;
|
let newRotateActiveIcon = !rotateActiveIcon;
|
||||||
@ -196,27 +227,47 @@ const Table = (props) => {
|
|||||||
setActiveIcon(i);
|
setActiveIcon(i);
|
||||||
props.sortByUpdate(elem, i);
|
props.sortByUpdate(elem, i);
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
}}>
|
}}
|
||||||
<Medium textAlign={elem === 'submitter' ? 'left' : 'right'}
|
>
|
||||||
width={elem === 'when' ? '100%' : 'auto'} padding='0 6px 0 0'
|
<Medium
|
||||||
minWidth={elem === 'result' ? '72px' : 'none'}>
|
cursor={elem !== '#' ? 'pointer' : ''}
|
||||||
{elem}
|
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>
|
</Medium>
|
||||||
{elem !== '#' ?
|
{elem !== '#' ? (
|
||||||
<ColumnFilterIcon index={i} active={activeIcon}
|
<ColumnFilterIcon
|
||||||
rotateIcon={rotateActiveIcon}/>
|
cursor="pointer"
|
||||||
: ''}
|
index={i}
|
||||||
|
active={activeIcon}
|
||||||
|
rotateIcon={rotateActiveIcon}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
</FlexRow>
|
</FlexRow>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Line height='2px' top='32px' as='td' shadow={theme.shadow}/>
|
<Line height="2px" top="100%" as="td" shadow={theme.shadow} />
|
||||||
</Grid>
|
</Grid>
|
||||||
{elementsToMap.map((elem, index) => {
|
{elementsToMap.map((elem, index) => {
|
||||||
return (
|
return (
|
||||||
<Grid as='tr' key={`leaderboard-row-${index}`}
|
<Grid
|
||||||
backgroundColor={index % 2 === 1 ? theme.colors.dark01 : 'transparent'}
|
as="tr"
|
||||||
|
key={`leaderboard-row-${index}`}
|
||||||
|
backgroundColor={
|
||||||
|
index % 2 === 1 ? theme.colors.dark01 : 'transparent'
|
||||||
|
}
|
||||||
gridTemplateColumns={props.gridTemplateColumns}
|
gridTemplateColumns={props.gridTemplateColumns}
|
||||||
gridGap='20px' position='relative' width='100%' padding='4px'>
|
gridGap="20px"
|
||||||
|
position="relative"
|
||||||
|
width="100%"
|
||||||
|
padding="4px"
|
||||||
|
>
|
||||||
{rowRender(elem)}
|
{rowRender(elem)}
|
||||||
{props.headerElements ? metricsRender(elem) : ''}
|
{props.headerElements ? metricsRender(elem) : ''}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -226,11 +277,7 @@ const Table = (props) => {
|
|||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return <Medium margin="72px 0">No results ;c</Medium>;
|
||||||
<Medium margin='72px 0'>
|
|
||||||
No results ;c
|
|
||||||
</Medium>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -239,23 +286,26 @@ const Table = (props) => {
|
|||||||
let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE);
|
let elementsToMap = props.elements.slice(n, n + ELEMENTS_PER_PAGE);
|
||||||
if (elementsToMap.length > 0) {
|
if (elementsToMap.length > 0) {
|
||||||
return (
|
return (
|
||||||
<MobileTableStyle as='table' staticColumnElements={props.staticColumnElements}
|
<MobileTableStyle
|
||||||
headerElements={props.headerElements}>
|
as="table"
|
||||||
<Container as='thead'>
|
staticColumnElements={props.staticColumnElements}
|
||||||
<Container as='tr'>
|
headerElements={props.headerElements}
|
||||||
|
>
|
||||||
|
<Container as="thead">
|
||||||
|
<Container as="tr">
|
||||||
{props.headerElements.map((elem, i) => {
|
{props.headerElements.map((elem, i) => {
|
||||||
return (
|
return (
|
||||||
<Medium key={`table-header-${i}`} as='th'>
|
<Medium key={`table-header-${i}`} as="th">
|
||||||
{elem}
|
{elem}
|
||||||
</Medium>
|
</Medium>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Container>
|
</Container>
|
||||||
</Container>
|
</Container>
|
||||||
<Container as='tbody'>
|
<Container as="tbody">
|
||||||
{elementsToMap.map((elem, index) => {
|
{elementsToMap.map((elem, index) => {
|
||||||
return (
|
return (
|
||||||
<Grid as='tr' key={`leaderboard-row-${index}`}>
|
<Grid as="tr" key={`leaderboard-row-${index}`}>
|
||||||
{rowRender(elem)}
|
{rowRender(elem)}
|
||||||
{props.headerElements ? metricsRender(elem) : ''}
|
{props.headerElements ? metricsRender(elem) : ''}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -265,22 +315,14 @@ const Table = (props) => {
|
|||||||
</MobileTableStyle>
|
</MobileTableStyle>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return <Medium margin="72px 0">No results ;c</Medium>;
|
||||||
<Medium margin='72px 0'>
|
|
||||||
No results ;c
|
|
||||||
</Medium>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Media query={theme.mobile}>
|
<Media query={theme.mobile}>{mobileRender()}</Media>
|
||||||
{mobileRender()}
|
<Media query={theme.desktop}>{desktopRender()}</Media>
|
||||||
</Media>
|
|
||||||
<Media query={theme.desktop}>
|
|
||||||
{desktopRender()}
|
|
||||||
</Media>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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)`
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user