Merge branch 'master' into pagination-refactor

This commit is contained in:
Mateusz Tylka 2023-04-14 13:51:27 +02:00 committed by GitHub
commit 8b82ddb36c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 347 additions and 239 deletions

View File

@ -1,89 +1,92 @@
const filterOptions = [
[
{
name: 'Closing',
sort: true,
rotate: ''
},
{
name: 'Closing',
sort: true,
rotate: '180deg'
},
{
name: 'Hotness',
sort: true,
rotate: ''
},
{
name: 'Hotness',
sort: true,
rotate: '180deg'
},
{
name: 'Reward',
sort: true,
rotate: ''
},
{
name: 'Reward',
sort: true,
rotate: '180deg'
}
], [
{
name: 'Both',
sort: false,
rotate: ''
},
{
name: 'Completed',
sort: false,
rotate: ''
},
{
name: 'Active',
sort: false,
rotate: ''
},
], [
{
name: 'All',
sort: false,
rotate: ''
},
{
name: 'Tabular',
sort: false,
rotate: ''
},
{
name: 'Text',
sort: false,
rotate: ''
},
{
name: 'Image',
sort: false,
rotate: ''
},
], [
{
name: 'Both',
sort: false,
rotate: ''
},
{
name: 'Yes',
sort: false,
rotate: ''
},
{
name: 'No',
sort: false,
rotate: ''
},
]
[
{
name: 'Closing',
sort: true,
rotate: '0',
},
{
name: 'Closing',
sort: true,
rotate: '180deg',
},
{
name: 'Hotness',
sort: true,
rotate: '0',
},
{
name: 'Hotness',
sort: true,
rotate: '180deg',
},
{
name: 'Reward',
sort: true,
rotate: '0',
},
{
name: 'Reward',
sort: true,
rotate: '180deg',
},
],
[
{
name: 'Both',
sort: false,
rotate: '0',
},
{
name: 'Closed',
sort: false,
rotate: '0',
},
{
name: 'Active',
sort: false,
rotate: '0',
},
],
[
{
name: 'All',
sort: false,
rotate: '0',
},
{
name: 'Tabular',
sort: false,
rotate: '0',
},
{
name: 'Text',
sort: false,
rotate: '0',
},
{
name: 'Image',
sort: false,
rotate: '0',
},
],
[
{
name: 'Both',
sort: false,
rotate: '0',
},
{
name: 'Yes',
sort: false,
rotate: '0',
},
{
name: 'No',
sort: false,
rotate: '0',
},
],
];
export default filterOptions;
export default filterOptions;

View File

@ -7,6 +7,8 @@ import {
CALC_PAGES,
EVALUATIONS_FORMAT,
RENDER_WHEN
IS_MOBILE,
RENDER_WHEN,
} from '../../../utils/globals';
import Loading from '../../generic/Loading';
import Pager from '../../generic/Pager';
@ -55,10 +57,11 @@ const AllEntries = (props) => {
const getAllEntriesHeader = () => {
let header = ['#', 'submitter'];
if (IS_MOBILE()) header.push('when');
for (let metric of getPossibleMetrics()) {
header.push(metric);
}
header.push('when');
if (!IS_MOBILE()) header.push('when');
return header;
};
@ -135,12 +138,57 @@ const AllEntries = (props) => {
};
const mobileRender = () => {
return <></>;
return (
<FlexColumn padding="24px 12px" width="70%" as="section" id="start">
<H2 as="h2" margin="0 0 12px 0">
All Entries
</H2>
{!loading ? (
<>
<Search searchQueryHandler={searchQueryHandler} />
<Table
challengeName={props.challengeName}
headerElements={getAllEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
tableType="allEntries"
gridTemplateColumns={
'1fr ' + '4fr '.repeat(getAllEntriesHeader().length - 1)
}
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' },
]}
iterableColumnElement={{
name: 'evaluations',
format: EVALUATIONS_FORMAT,
order: 3,
align: 'left',
}}
pageNr={pageNr}
elements={entries}
sortByUpdate={sortByUpdate}
/>
<Pager
pageNr={pageNr}
width="48px"
borderRadius="64px"
pages={CALC_PAGES(entries)}
nextPage={nextPage}
previousPage={previousPage}
number={`${pageNr} / ${CALC_PAGES(entries)}`}
/>
</>
) : (
<Loading />
)}
</FlexColumn>
);
};
const desktopRender = () => {
return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1400px">
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1600px">
<H2 as="h2" margin="0 0 32px 0">
All Entries
</H2>

View File

@ -115,7 +115,7 @@ const Challenge = (props) => {
<FlexColumn
minHeight="100vh"
alignmentY="flex-start"
padding="64px 24px 64px 310px"
padding="64px 24px 64px 280px"
id="start"
>
<FlexRow gap="32px" margin="0 0 32px 0" padding="16px">

View File

@ -9,7 +9,8 @@ const ColumnFilterIcon = (props) => {
if (props.index === props.active) {
return (
<Svg
width="8px"
minWidth="8px"
maxWidth="8px"
src={filterIco}
cursor={props.cursor}
backgroundColor={theme.colors.dark}
@ -20,7 +21,8 @@ const ColumnFilterIcon = (props) => {
} else {
return (
<Svg
width="8px"
minWidth="8px"
maxWidth="8px"
src={arrow}
cursor={props.cursor}
backgroundColor={theme.colors.dark}
@ -33,7 +35,8 @@ const ColumnFilterIcon = (props) => {
return (
<>
<Svg
width="8px"
minWidth="8px"
maxWidth="8px"
rotate="180deg"
src={arrow}
cursor={props.cursor}

View File

@ -8,6 +8,7 @@ import { Link } from 'react-router-dom';
import {
MENU_CHALLENGE_SECTIONS_WITH_LOGIN,
MENU_CHALLENGE_SECTIONS_NO_LOGIN,
IS_MOBILE,
} from '../../utils/globals';
const DesktopChallengeMenuStyle = styled(FlexColumn)`
@ -15,7 +16,7 @@ const DesktopChallengeMenuStyle = styled(FlexColumn)`
position: fixed;
left: 0;
overflow-y: auto;
width: 280px;
width: 240px;
height: 100vh;
top: 50px;
padding: 64px 0 0 0;
@ -58,7 +59,12 @@ const DesktopChallengeMenu = (props) => {
.toLowerCase()
.replace(' ', '')}`}
>
<H3 textTransform="uppercase">{option}</H3>
<H3
fontSize={IS_MOBILE() ? '18px' : '22px'}
textTransform="uppercase"
>
{option}
</H3>
</Option>
);
})}

View File

@ -167,7 +167,7 @@ const Leaderboard = (props) => {
<Table
challengeName={props.challengeName}
headerElements={getLeaderboardHeaderMobile()}
tableType="Leaderboard"
tableType="leaderboard"
gridTemplateColumns={
entries[0]
? '1fr 3fr ' +
@ -212,7 +212,7 @@ const Leaderboard = (props) => {
const desktopRender = () => {
return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1200px">
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1600px">
<H2 as="h2" margin="0 0 32px 0">
Leaderboard
</H2>

View File

@ -161,9 +161,9 @@ const MyEntries = (props) => {
const desktopRender = () => {
return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1400px">
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1600px">
<FlexColumn padding="24px 12px" width="70%" as="section" id="start">
<H2 as="h2" margin="0 0 12px 0">
<H2 as="h2" margin="0 0 32px 0">
My Entries
</H2>
</FlexColumn>
@ -175,7 +175,7 @@ const MyEntries = (props) => {
headerElements={getMyEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
gridTemplateColumns={
'1fr ' + '4fr '.repeat(getMyEntriesHeader().length - 1)
'1fr ' + '3fr '.repeat(getMyEntriesHeader().length - 2) + ' 4fr'
}
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },

View File

@ -95,7 +95,9 @@ const Table = (props) => {
elem = newElem;
}
let indexModificator = 2;
if (props.tableType === 'Leaderboard') indexModificator = 4;
if (props.tableType === 'leaderboard') indexModificator = 4;
if (props.tableType === 'allEntries') indexModificator = 3;
return elem.map((iterableElem, i) => {
return (
<Body
@ -104,6 +106,8 @@ const Table = (props) => {
order={props.iterableColumnElement.order}
textAlign={props.iterableColumnElement.align}
minWidth="72px"
margin="auto 0"
overflowWrap="anywhere"
>
{IS_MOBILE() && (
<Container className="mobile-table-header">
@ -128,6 +132,8 @@ const Table = (props) => {
as="td"
order={elemName.order}
textAlign={elemName.align}
margin="auto 0"
overflowWrap="anywhere"
>
{IS_MOBILE() && (
<Container className="mobile-table-header">
@ -154,7 +160,8 @@ const Table = (props) => {
gridGap="20px"
position="relative"
width="100%"
padding="4px"
padding="0 6px"
minHeight="44px"
margin="0 0 6px 0"
gridTemplateColumns={props.gridTemplateColumns}
>
@ -181,8 +188,8 @@ const Table = (props) => {
cursor={elem !== '#' ? 'pointer' : ''}
textAlign={elem === 'when' ? 'right' : 'left'}
width={elem === 'when' ? '100%' : 'auto'}
padding="0 6px 0 0"
overflowWrap="break-word"
padding="0 4px 0 0"
overflowWrap="anywhere"
minWidth={elem === 'result' ? '72px' : 'none'}
>
{elem.replace('.', ' ')}
@ -198,7 +205,12 @@ const Table = (props) => {
</FlexRow>
);
})}
<Line height="2px" top="100%" as="td" shadow={theme.shadow} />
<Line
height="2px"
top="calc(100% + 2px)"
as="td"
shadow={theme.shadow}
/>
</Grid>
{elementsToMap.map((elem, index) => {
return (
@ -213,6 +225,7 @@ const Table = (props) => {
position="relative"
width="100%"
padding="4px"
minHeight="48px"
>
{rowRender(elem)}
{props.headerElements ? metricsRender(elem) : ''}

View File

@ -5,13 +5,14 @@ import Search from '../../components/generic/Search';
import Pager from '../../components/generic/Pager';
import FiltersMenu from '../../components/challenges_list/FiltersMenu';
import challengeSearchQueryHandler from './challengeSearchQueryHandler';
import _renderChallenges from './_renderChallenges';
import renderChallenges from './renderChallenges';
import Media from 'react-media';
import theme from '../../utils/theme';
import cupIco from '../../assets/cup_ico.svg';
import getChallenges from '../../api/getChallenges';
import { CALC_PAGES } from '../../utils/globals';
import { CALC_PAGES, CHALLENGES_STATUS_FILTER } from '../../utils/globals';
import Loading from '../../components/generic/Loading';
import ChallengesStyle from './ChallengesStyle';
const Challenges = () => {
const [pageNr, setPageNr] = React.useState(1);
@ -19,7 +20,7 @@ const Challenges = () => {
const [challenges, setChallenges] = React.useState([]);
const [filtersMenu, setFiltersMenu] = React.useState(false);
const [sortBy, setSortBy] = React.useState(0);
const [status, setStatus] = React.useState(0);
const [status, setStatus] = React.useState(CHALLENGES_STATUS_FILTER.BOTH);
const [challengeType, setChallengeType] = React.useState(0);
const [commercial, setCommercial] = React.useState(0);
const [loading, setLoading] = React.useState(true);
@ -33,22 +34,6 @@ const Challenges = () => {
getChallenges(setChallenges, setLoading);
};
const sortByHandler = (value) => {
setSortBy(value);
};
const statusHandler = (value) => {
setStatus(value);
};
const challengeTypeHandler = (value) => {
setChallengeType(value);
};
const commercialHandler = (value) => {
setCommercial(value);
};
const searchQueryHandler = (event) => {
challengeSearchQueryHandler(
event,
@ -58,10 +43,6 @@ const Challenges = () => {
);
};
const renderChallenges = () => {
return _renderChallenges(pageNr, challenges);
};
const toggleFiltersMenu = () => {
let newFiltersMenu = !filtersMenu;
setFiltersMenu(newFiltersMenu);
@ -74,27 +55,18 @@ const Challenges = () => {
translateX={filtersMenu ? '0' : '100vw'}
opacity={filtersMenu ? '1' : '0'}
toggleFiltersMenu={toggleFiltersMenu}
sortByHandler={sortByHandler}
statusHandler={statusHandler}
challengeTypeHandler={challengeTypeHandler}
commercialHandler={commercialHandler}
sortByHandler={setSortBy}
statusHandler={setStatus}
challengeTypeHandler={setChallengeType}
commercialHandler={setCommercial}
sortBy={sortBy}
status={status}
challengeType={challengeType}
commercial={commercial}
/>
<FlexColumn
as="main"
alignmentY="flex-start"
width="100%"
id="start"
minHeight="100vh"
padding="90px 0 32px 0"
>
<FlexColumn alignmentX="flex-start" width="80%">
<H1 as="h1" margin="0 0 20px 0">
Challenges
</H1>
<ChallengesStyle as="main" id="start">
<FlexColumn className="ChallengesStyle__page-container">
<H1 as="h1">Challenges</H1>
<Search
searchQueryHandler={searchQueryHandler}
filterButton
@ -102,10 +74,10 @@ const Challenges = () => {
/>
<FlexColumn width="100%">
<Loading visible={loading} />
{renderChallenges()}
{renderChallenges(pageNr, challenges)}
</FlexColumn>
</FlexColumn>
{!loading ? (
{!loading && (
<Pager
elements={challenges}
pageNr={pageNr}
@ -115,10 +87,8 @@ const Challenges = () => {
borderRadius="64px"
number={`${pageNr} / ${CALC_PAGES(challenges)}`}
/>
) : (
''
)}
</FlexColumn>
</ChallengesStyle>
</>
);
};
@ -129,65 +99,45 @@ const Challenges = () => {
<FiltersMenu
toggleFiltersMenu={toggleFiltersMenu}
transBackDisplay="none"
sortByHandler={sortByHandler}
statusHandler={statusHandler}
challengeTypeHandler={challengeTypeHandler}
commercialHandler={commercialHandler}
sortByHandler={setSortBy}
statusHandler={setStatus}
challengeTypeHandler={setChallengeType}
commercialHandler={setCommercial}
sortBy={sortBy}
status={status}
challengeType={challengeType}
commercial={commercial}
/>
<FlexColumn
as="main"
alignmentY="flex-start"
width="100%"
id="start"
minHeight="100vh"
padding="112px 0 82px 310px"
>
<FlexColumn alignmentX="flex-start" width="80%">
<FlexRow width="100%" gap="32px">
<FlexColumn
alignmentX="flex-start"
gap="32px"
width="75%"
maxWidth="720px"
>
<ChallengesStyle as="main" id="start">
<FlexColumn className="ChallengesStyle__page-container">
<FlexRow className="ChallengesStyle__page-header-container">
<FlexColumn className="ChallengesStyle__page-header">
<H1 as="h1">Challenges</H1>
<Body margin="0 0 12px 0" maxWidth="400px">
<Body className="ChallengesStyle__header-content">
Increase your machine learning skills by competing in our
exciting challenges.
</Body>
<Search searchQueryHandler={searchQueryHandler} />
</FlexColumn>
<Svg
src={cupIco}
size="contain"
width="25%"
height="160px"
backgroundColor={theme.colors.green}
/>
<Svg src={cupIco} className="ChallengesStyle__main-image" />
</FlexRow>
<FlexColumn width="100%">
<Loading visible={loading} />
{renderChallenges()}
{renderChallenges(pageNr, challenges)}
</FlexColumn>
</FlexColumn>
{!loading ? (
{!loading && (
<Pager
pageNr={pageNr}
setPageNr={setPageNr}
elements={challenges}
pages={CALC_PAGES(challenges)}
borderRadius="64px"
width="72px"
borderRadius="64px"
number={`${pageNr} / ${CALC_PAGES(challenges)}`}
/>
) : (
''
)}
</FlexColumn>
</ChallengesStyle>
</>
);
};

View File

@ -0,0 +1,50 @@
import styled from 'styled-components';
import { FlexColumn } from '../../utils/containers';
const ChallengesStyle = styled(FlexColumn)`
justify-content: flex-start;
width: 100%;
min-height: 100vh;
padding: 90px 0 32px 0;
@media (min-width: ${({ theme }) => theme.overMobile}) {
padding: 112px 0 82px 310px;
}
.ChallengesStyle__page-container {
align-items: flex-start;
width: 80%;
h1 {
margin: 0 0 20px 0;
@media (min-width: ${({ theme }) => theme.overMobile}) {
margin: 0;
}
}
}
.ChallengesStyle__page-header-container {
width: 100%;
gap: 32px;
}
.ChallengesStyle__page-header {
align-items: flex-start;
gap: 32px;
width: 75%;
max-width: 720px;
}
.ChallengesStyle__header-content {
margin: 0 0 12px 0;
max-width: 600px;
}
.ChallengesStyle__main-image {
width: 25%;
height: 160px;
background-color: ${({ theme }) => theme.colors.green};
mask-size: contain;
}
`;
export default ChallengesStyle;

View File

@ -1,40 +0,0 @@
import {ELEMENTS_PER_PAGE} from '../../utils/globals';
import MiniChallenge from '../../components/challenges_list/MiniChallenge';
import {Grid} from '../../utils/containers';
import styled from 'styled-components';
const ChallengesGrid = styled(Grid)`
margin: 32px 0;
grid-gap: 32px 0;
@media (min-width: 1200px) {
margin: 96px 0;
grid-gap: 64px;
grid-template-columns: 1fr 1fr;
}
@media (min-width: 1600px) {
grid-template-columns: 1fr 1fr 1fr;
}
`;
const _renderChallenges = (pageNr, challenges) => {
const n = (pageNr - 1) * ELEMENTS_PER_PAGE;
if (challenges && challenges !== []) {
return (
<ChallengesGrid margin='32px 0' gridGap='32px 0'>
{challenges.slice(n, n + ELEMENTS_PER_PAGE).map(
({title, type, description, mainMetric, bestScore, baseline, prize, deadline, name}, index) => {
return (
<MiniChallenge key={`challenge-${index}`} title={title} type={type}
description={description} metric={mainMetric} bestScore={bestScore}
baseline={baseline} prize={prize} deadline={deadline} name={name}/>
);
})}
</ChallengesGrid>
);
}
return '';
};
export default _renderChallenges;

View File

@ -0,0 +1,65 @@
import { ELEMENTS_PER_PAGE } from '../../utils/globals';
import MiniChallenge from '../../components/challenges_list/MiniChallenge';
import { Grid } from '../../utils/containers';
import styled from 'styled-components';
const ChallengesGrid = styled(Grid)`
margin: 32px 0;
grid-gap: 32px 0;
@media (min-width: 1200px) {
margin: 96px 0;
grid-gap: 64px;
grid-template-columns: 1fr 1fr;
}
@media (min-width: 1600px) {
grid-template-columns: 1fr 1fr 1fr;
}
`;
const renderChallenges = (pageNr, challenges) => {
const n = (pageNr - 1) * ELEMENTS_PER_PAGE;
if (challenges && challenges !== []) {
return (
<ChallengesGrid margin="32px 0" gridGap="32px 0">
{challenges
.slice(n, n + ELEMENTS_PER_PAGE)
.map(
(
{
title,
type,
description,
mainMetric,
bestScore,
baseline,
prize,
deadline,
name,
},
index
) => {
return (
<MiniChallenge
key={`challenge-${index}`}
title={title}
type={type}
description={description}
metric={mainMetric}
bestScore={bestScore}
baseline={baseline}
prize={prize}
deadline={deadline}
name={name}
/>
);
}
)}
</ChallengesGrid>
);
}
return '';
};
export default renderChallenges;

View File

@ -1,5 +1,5 @@
import styled from 'styled-components';
import {Container} from './containers';
import { Container } from './containers';
const H1 = styled(Container)`
display: inline-block;
@ -8,7 +8,7 @@ const H1 = styled(Container)`
font-size: 24px;
line-height: 24px;
letter-spacing: 0.1px;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 48px;
line-height: 52px;
}
@ -16,7 +16,7 @@ const H1 = styled(Container)`
const H2 = styled(H1)`
font-size: 20px;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 32px;
line-height: 36px;
}
@ -25,9 +25,12 @@ const H2 = styled(H1)`
const H3 = styled(H1)`
font-size: 18px;
line-height: 22px;
@media (min-width: ${({theme}) => theme.overMobile}) {
font-size: ${({ fontSize }) => (fontSize ? fontSize : '18px')};
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 24px;
line-height: 26px;
font-size: ${({ fontSize }) => (fontSize ? fontSize : '24px')};
}
`;
@ -37,7 +40,7 @@ const Body = styled(Container)`
font-weight: 300;
font-size: 14px;
line-height: 20px;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-weight: 400;
font-size: 16px;
line-height: 22px;
@ -46,9 +49,9 @@ const Body = styled(Container)`
const Medium = styled(Body)`
font-weight: 400;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-weight: 500;
font-size: ${({fontSize}) => fontSize ? fontSize : '16px'}
font-size: ${({ fontSize }) => (fontSize ? fontSize : '16px')};
}
`;
@ -63,7 +66,7 @@ const Menu = styled(Container)`
const Label = styled(Menu)`
display: inline-block;
font-weight: 300;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 22px;
line-height: 24px;
}
@ -75,22 +78,22 @@ const Code = styled(Container)`
font-size: 12px;
line-height: 18px;
font-weight: 300;
color: ${({theme}) => theme.colors.white};
color: ${({ theme }) => theme.colors.white};
max-width: 600px;
overflow-wrap: break-word;
&:before {
display: ${({before}) => before ? 'inline-block' : 'none'};
display: ${({ before }) => (before ? 'inline-block' : 'none')};
content: '~$';
color: ${({theme}) => theme.colors.green};
color: ${({ theme }) => theme.colors.green};
font-weight: 400;
margin: 0 4px 0 0;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-weight: 500;
}
}
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 16px;
line-height: 24px;
font-weight: 400;
@ -98,11 +101,11 @@ const Code = styled(Container)`
`;
const CodeMedium = styled(Code)`
color: ${({theme}) => theme.colors.green};
color: ${({ theme }) => theme.colors.green};
font-weight: 400;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-weight: 500;
}
`;
export {H1, H2, H3, Body, Medium, Menu, Label, Code, CodeMedium};
export { H1, H2, H3, Body, Medium, Menu, Label, Code, CodeMedium };

View File

@ -42,6 +42,12 @@ const CHALLENGE_SECTIONS = {
SUBMIT: 5,
};
const CHALLENGES_STATUS_FILTER = {
BOTH: 0,
CLOSED: 1,
ACTIVE: 2,
};
const MINI_DESCRIPTION_RENDER = (description) => {
if (description) {
if (description.length <= MINI_DESCRIPTION_LENGTH) return description;
@ -127,6 +133,7 @@ export {
CHALLENGE_SECTIONS,
MENU_CHALLENGE_SECTIONS_NO_LOGIN,
MENU_CHALLENGE_SECTIONS_WITH_LOGIN,
CHALLENGES_STATUS_FILTER,
MINI_DESCRIPTION_RENDER,
RENDER_ICO,
CALC_PAGES,