diff --git a/src/App.js b/src/App.js
index b0eb553..546dc83 100644
--- a/src/App.js
+++ b/src/App.js
@@ -21,7 +21,7 @@ import Loading from './components/generic/Loading';
import { FlexColumn } from './utils/containers';
import PopupMessage from './components/generic/PopupMessage';
import PolicyPrivacy from './pages/PolicyPrivacy';
-import Challenge from './components/specific_challenge/Challenge';
+import Challenge from './pages/Challenge';
const App = () => {
const [loggedBarVisible, setLoggedBarVisible] = React.useState('100vw');
diff --git a/src/api/challengeSubmissionPost.js b/src/api/challengeSubmissionPost.js
index b0d5d10..a9df22f 100644
--- a/src/api/challengeSubmissionPost.js
+++ b/src/api/challengeSubmissionPost.js
@@ -1,15 +1,18 @@
import KeyCloakService from '../services/KeyCloakService';
import { API } from '../utils/globals';
+import SUBMIT_ACTION from '../pages/Submit/model/SubmitActionEnum';
const challengeSubmission = (
challengeName,
repoUrl,
repoBranch,
description,
- setLoading
+ submissionTags,
+ dispatch
) => {
const details = {
f1: description,
+ f2: submissionTags,
f3: repoUrl,
f4: repoBranch,
};
@@ -30,7 +33,7 @@ const challengeSubmission = (
})
.then((resp) => resp.json())
.then((data) => {
- setLoading(true);
+ dispatch({ type: SUBMIT_ACTION.TOGGLE_SUBMISSION_LOADING });
const processUrl = API.replace('/api', '');
window.location.replace(`${processUrl}/open-view-progress/${data}#form`);
// console.log(data);
diff --git a/src/api/getChallenges.js b/src/api/getChallenges.js
index a5c790a..26d8a3f 100644
--- a/src/api/getChallenges.js
+++ b/src/api/getChallenges.js
@@ -1,4 +1,4 @@
-import CHALLENGES_ACTION from '../pages/Challanges/model/ChallengesActionEnum';
+import CHALLENGES_ACTION from '../pages/Challanges/model/ChallengesActions';
import { API } from '../utils/globals';
const getChallenges = (dispatch) => {
diff --git a/src/api/getTags.js b/src/api/getTags.js
index 4ed6e76..fc1f959 100644
--- a/src/api/getTags.js
+++ b/src/api/getTags.js
@@ -1,10 +1,11 @@
+import SUBMIT_ACTION from '../pages/Submit/model/SubmitActionEnum';
import { API } from '../utils/globals';
-const getTags = (setTags) => {
+const getTags = (dispatch) => {
fetch(`${API}/list-tags`)
.then((response) => response.json())
.then((data) => {
- setTags(data);
+ dispatch({ type: SUBMIT_ACTION.LOAD_TAGS, payload: data });
});
};
diff --git a/src/assets/remove_ico.svg b/src/assets/remove_ico.svg
new file mode 100644
index 0000000..8246ed8
--- /dev/null
+++ b/src/assets/remove_ico.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/challenges_list/MiniChallenge.js b/src/components/challenges_list/MiniChallenge.js
deleted file mode 100644
index d8505a0..0000000
--- a/src/components/challenges_list/MiniChallenge.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import React from 'react';
-import {Container, FlexColumn, FlexRow, Grid} from '../../utils/containers';
-import {Body, H3} from '../../utils/fonts';
-import styled from 'styled-components';
-import IconLabel from '../generic/IconLabel';
-import {Link} from 'react-router-dom';
-import {CHALLENGE_PAGE, MINI_DESCRIPTION_RENDER} from '../../utils/globals';
-import theme from '../../utils/theme';
-import PropsTypes from 'prop-types';
-
-const ChallengeStyle = styled(FlexColumn)`
- padding: 12px;
- border: 1px solid ${({theme}) => theme.colors.dark05};
- cursor: pointer;
- transition: transform 0.3s ease-in-out;
- position: relative;
- max-width: 420px;
-
- * {
- cursor: pointer;
- }
-
- &:hover {
- transform: scale(1.05);
- }
-
- article {
- width: 100%;
- align-items: flex-start;
-
- p {
- width: 80%;
- }
- }
-
- @media (min-width: ${({theme}) => theme.overMobile}) {
- width: 360px;
- padding: 20px;
- justify-content: flex-start;
- }
-`;
-
-const IconsGrid = styled(Grid)`
- width: 100%;
- grid-gap: 14px;
- grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr 1fr;
-
- @media (min-width: 500px) {
- grid-template-columns: auto auto auto;
- }
-`;
-
-const MiniChallenge = (props) => {
- const deadlineRender = () => {
- if (props.deadline) {
- return (
-
- {props.deadline.slice(0, 10)}
-
- );
- }
- };
-
- return (
-
-
-
-
- {props.title}
-
- {props.type ? : 'xxx'}
-
-
-
- {props.description ? MINI_DESCRIPTION_RENDER(props.description) : 'xxx'}
-
-
-
- {props.metric ? props.metric : 'xxx'}
-
-
- {props.bestScore ? props.bestScore : 'xxx'}
-
- {deadlineRender()}
-
- {props.baseline ? props.baseline : 'xxx'}
-
- {props.prize ?
- {props.prize}
- : ''}
-
-
-
- );
-};
-
-MiniChallenge.propTypes = {
- name: PropsTypes.string,
- title: PropsTypes.string,
- type: PropsTypes.string,
- description: PropsTypes.string,
- metric: PropsTypes.string,
- bestScore: PropsTypes.string,
- deadline: PropsTypes.string,
- baseline: PropsTypes.string,
- prize: PropsTypes.string
-};
-
-MiniChallenge.defaultProps = {
- name: 'xxx',
- title: 'xxx',
- type: 'xxx',
- description: 'xxx',
- metric: 'xxx',
- bestScore: 'xxx',
- deadline: 'xxx',
- baseline: 'xxx',
- prize: 'xxx'
-};
-
-export default MiniChallenge;
\ No newline at end of file
diff --git a/src/components/generic/Button.js b/src/components/generic/Button.js
index 706c4a8..30ea679 100644
--- a/src/components/generic/Button.js
+++ b/src/components/generic/Button.js
@@ -33,6 +33,7 @@ const Button = (props) => {
onClick={() => props.handler()}
width={props.width}
height={props.height}
+ margin={props.margin}
color={props.color}
backgroundColor={props.backgroundColor}
to={props.to}
diff --git a/src/components/specific_challenge/ColumnFilterIcon.js b/src/components/generic/ColumnFilterIcon.js
similarity index 100%
rename from src/components/specific_challenge/ColumnFilterIcon.js
rename to src/components/generic/ColumnFilterIcon.js
diff --git a/src/components/generic/DropdownWithPopup.js b/src/components/generic/DropdownWithPopup.js
deleted file mode 100644
index cca1014..0000000
--- a/src/components/generic/DropdownWithPopup.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import { FlexColumn, FlexRow, Grid } from '../../utils/containers';
-import { Medium } from '../../utils/fonts';
-import theme from '../../utils/theme';
-import ImageButton from './ImageButton';
-import pencilIco from '../../assets/pencil_ico.svg';
-
-const DropdownWithPopup = (props) => {
- return (
-
-
- {props.label}
-
- props.handler(e.target.value)}
- padding="12px"
- gridTemplateColumns="1fr auto"
- >
-
- dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa
- dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa
- dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa
- dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa dsa
-
-
-
-
- );
-};
-
-export default DropdownWithPopup;
diff --git a/src/components/generic/ImageButton.js b/src/components/generic/ImageButton.js
index 91ca906..fd02d9e 100644
--- a/src/components/generic/ImageButton.js
+++ b/src/components/generic/ImageButton.js
@@ -5,6 +5,9 @@ const ImageButtonStyle = styled(FlexRow)`
cursor: pointer;
transition: transform ease-in-out 0.3s;
transform: rotate(${({ rotate }) => (rotate ? rotate : '0')});
+ * {
+ cursor: pointer;
+ }
&:hover {
transform: rotate(${({ rotate }) => (rotate ? rotate : '0')}), scale(1.2);
}
diff --git a/src/components/generic/PopUp.js b/src/components/generic/PopUp.js
new file mode 100644
index 0000000..fee1adc
--- /dev/null
+++ b/src/components/generic/PopUp.js
@@ -0,0 +1,53 @@
+import React from 'react';
+import { FlexColumn } from '../../utils/containers';
+import styled from 'styled-components';
+
+const PopUpStyle = styled(FlexColumn)`
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 100;
+ width: 100%;
+ height: 100vh;
+ background-color: ${({ theme }) => theme.colors.dark01};
+
+ .PopUpStyle__body {
+ width: ${({ width }) => (width ? width : '60%')};
+ height: ${({ height }) => (height ? height : '50%')};
+ min-height: ${({ minHeight }) => (minHeight ? minHeight : '50%')};
+ padding: ${({ padding }) => (padding ? padding : '48px')};
+ margin: ${({ margin }) => (margin ? margin : '0')};
+ border-radius: 12px;
+ background-color: ${({ theme }) => theme.colors.white};
+ justify-content: flex-start;
+ }
+`;
+
+const PopUp = (props) => {
+ const [onHover, setOnHover] = React.useState(false);
+
+ const closePopUp = () => {
+ if (!onHover) props.closeHandler();
+ };
+
+ return (
+
+ setOnHover(true)}
+ onMouseLeave={() => setOnHover(false)}
+ className="PopUpStyle__body"
+ >
+ {props.children}
+
+
+ );
+};
+
+export default PopUp;
diff --git a/src/components/specific_challenge/Table.js b/src/components/generic/Table.js
similarity index 100%
rename from src/components/specific_challenge/Table.js
rename to src/components/generic/Table.js
diff --git a/src/components/specific_challenge/Submit.js b/src/components/specific_challenge/Submit.js
deleted file mode 100644
index 04feace..0000000
--- a/src/components/specific_challenge/Submit.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import React from 'react';
-import { createPortal } from 'react-dom';
-import { FlexColumn } from '../../utils/containers';
-import { H2, Menu } from '../../utils/fonts';
-import SubmitInput from '../generic/SubmitInput';
-import Button from '../generic/Button';
-import theme from '../../utils/theme';
-import challengeSubmission from '../../api/challengeSubmissionPost';
-import Loading from '../generic/Loading';
-import getTags from '../../api/getTags';
-import DropdownWithPopup from '../generic/DropdownWithPopup';
-
-const Submit = (props) => {
- const [description, setDescription] = React.useState('');
- const [repoUrl, setRepoUrl] = React.useState('');
- const [repoBranch, setRepoBranch] = React.useState('');
- const [loading, setLoading] = React.useState(false);
- const [tags, setTags] = React.useState([]);
- // eslint-disable-next-line no-unused-vars
- const [submissionTags, setSubmissionTags] = React.useState([]);
-
- React.useMemo(() => {
- getTags(setTags);
- }, []);
-
- const challengeSubmissionSubmit = () => {
- setLoading(true);
- challengeSubmission(
- props.challengeName,
- repoUrl,
- repoBranch,
- description,
- setLoading
- );
- };
-
- if (!loading) {
- console.log(tags);
- return (
-
-
- Submit a solution to the challenge
-
-
-
-
-
-
-
-
-
- );
- } else {
- return createPortal(
-
- Submission processing...
-
- ,
- document.body
- );
- }
-};
-
-export default Submit;
diff --git a/src/index.js b/src/index.js
index fad2077..a4f9fd8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -8,13 +8,9 @@ import HttpService from './services/HttpService';
const root = ReactDOM.createRoot(document.getElementById('root'));
-const renderApp = () => root.render(
-
-
-
-);
+const renderApp = () => root.render();
KeyCloakService.initKeycloak(renderApp);
HttpService.configure();
-renderApp();
\ No newline at end of file
+renderApp();
diff --git a/src/components/specific_challenge/AllEntries/AllEntries.js b/src/pages/AllEntries/AllEntries.js
similarity index 94%
rename from src/components/specific_challenge/AllEntries/AllEntries.js
rename to src/pages/AllEntries/AllEntries.js
index cb5d7a7..eddcdd1 100644
--- a/src/components/specific_challenge/AllEntries/AllEntries.js
+++ b/src/pages/AllEntries/AllEntries.js
@@ -1,20 +1,20 @@
import React from 'react';
-import theme from '../../../utils/theme';
+import theme from '../../utils/theme';
import Media from 'react-media';
-import { FlexColumn } from '../../../utils/containers';
-import { H2 } from '../../../utils/fonts';
+import { FlexColumn } from '../../utils/containers';
+import { H2 } from '../../utils/fonts';
import {
CALC_PAGES,
EVALUATIONS_FORMAT,
RENDER_WHEN,
IS_MOBILE,
-} from '../../../utils/globals';
-import Loading from '../../generic/Loading';
-import Pager from '../../generic/Pager';
-import Table from '../Table';
-import Search from '../../generic/Search';
+} from '../../utils/globals';
+import Loading from '../../components/generic/Loading';
+import Pager from '../../components/generic/Pager';
+import Table from '../../components/generic/Table';
+import Search from '../../components/generic/Search';
import allEntriesSearchQueryHandler from './allEntriesSearchQueryHandler';
-import getAllEntries from '../../../api/getAllEntries';
+import getAllEntries from '../../api/getAllEntries';
const AllEntries = (props) => {
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
diff --git a/src/components/specific_challenge/AllEntries/allEntriesSearchQueryHandler.js b/src/pages/AllEntries/allEntriesSearchQueryHandler.js
similarity index 100%
rename from src/components/specific_challenge/AllEntries/allEntriesSearchQueryHandler.js
rename to src/pages/AllEntries/allEntriesSearchQueryHandler.js
diff --git a/src/components/specific_challenge/AllEntries/index.js b/src/pages/AllEntries/index.js
similarity index 100%
rename from src/components/specific_challenge/AllEntries/index.js
rename to src/pages/AllEntries/index.js
diff --git a/src/pages/Challanges/Challenges.js b/src/pages/Challanges/Challenges.js
index c4f7186..ae98353 100644
--- a/src/pages/Challanges/Challenges.js
+++ b/src/pages/Challanges/Challenges.js
@@ -3,13 +3,13 @@ import Media from 'react-media';
import theme from '../../utils/theme';
import getChallenges from '../../api/getChallenges';
import { CHALLENGES_STATUS_FILTER } from '../../utils/globals';
-import FiltersMenu from '../../components/challenges_list/FiltersMenu';
+import FiltersMenu from './components/FiltersMenu';
import statusFilterHandle from './functions/statusFilterHandle';
import ChallengesMobile from './components/ChallengesMobile';
import ChallengesDesktop from './components/ChallengesDesktop';
import challengeSearchQueryHandler from './functions/challengeSearchQueryHandler';
import ChallengesReducer from './model/ChallengesReducer';
-import CHALLENGES_ACTION from './model/ChallengesActionEnum';
+import CHALLENGES_ACTION from './model/ChallengesActions';
const Challenges = () => {
const [state, dispatch] = React.useReducer(ChallengesReducer, {
diff --git a/src/pages/Challanges/components/ChallengesMobile.js b/src/pages/Challanges/components/ChallengesMobile.js
index 63cceaa..939da5f 100644
--- a/src/pages/Challanges/components/ChallengesMobile.js
+++ b/src/pages/Challanges/components/ChallengesMobile.js
@@ -7,7 +7,7 @@ import Search from '../../../components/generic/Search';
import { CALC_PAGES } from '../../../utils/globals';
import renderChallenges from '../functions/renderChallenges';
import Loading from '../../../components/generic/Loading';
-import CHALLENGES_ACTION from '../model/ChallengesActionEnum';
+import CHALLENGES_ACTION from '../model/ChallengesActions';
const ChallengesMobile = (props) => {
return (
diff --git a/src/components/challenges_list/FilterBy.js b/src/pages/Challanges/components/FilterBy.js
similarity index 87%
rename from src/components/challenges_list/FilterBy.js
rename to src/pages/Challanges/components/FilterBy.js
index f198cc6..93ea726 100644
--- a/src/components/challenges_list/FilterBy.js
+++ b/src/pages/Challanges/components/FilterBy.js
@@ -1,10 +1,10 @@
import React from 'react';
-import { FlexColumn, Grid, Svg } from '../../utils/containers';
-import Filter from '../generic/Filter';
-import { Body, H3, Medium } from '../../utils/fonts';
-import arrow from '../../assets/arrow.svg';
+import { FlexColumn, Grid, Svg } from '../../../utils/containers';
+import Filter from '../../../components/generic/Filter';
+import { Body, H3, Medium } from '../../../utils/fonts';
+import arrow from '../../../assets/arrow.svg';
import Media from 'react-media';
-import theme from '../../utils/theme';
+import theme from '../../../utils/theme';
const FilterBy = (props) => {
const renderFilterOptions = () => {
diff --git a/src/components/challenges_list/FiltersMenu/FiltersMenu.js b/src/pages/Challanges/components/FiltersMenu/FiltersMenu.js
similarity index 93%
rename from src/components/challenges_list/FiltersMenu/FiltersMenu.js
rename to src/pages/Challanges/components/FiltersMenu/FiltersMenu.js
index acef5ef..7f76e7c 100644
--- a/src/components/challenges_list/FiltersMenu/FiltersMenu.js
+++ b/src/pages/Challanges/components/FiltersMenu/FiltersMenu.js
@@ -1,12 +1,12 @@
import React from 'react';
-import { FlexColumn, FlexRow, TransBack } from '../../../utils/containers';
-import Button from '../../generic/Button';
-import theme from '../../../utils/theme';
+import { FlexColumn, FlexRow, TransBack } from '../../../../utils/containers';
+import Button from '../../../../components/generic/Button';
+import theme from '../../../../utils/theme';
import styled from 'styled-components';
import FilterBy from '../FilterBy';
import filterOptions from './filterOptions';
import Media from 'react-media';
-import CHALLENGES_ACTION from '../../../pages/Challanges/model/ChallengesActionEnum';
+import CHALLENGES_ACTION from '../../model/ChallengesActions';
const FiltersMenuStyle = styled(FlexColumn)`
position: fixed;
diff --git a/src/components/challenges_list/FiltersMenu/filterOptions.js b/src/pages/Challanges/components/FiltersMenu/filterOptions.js
similarity index 100%
rename from src/components/challenges_list/FiltersMenu/filterOptions.js
rename to src/pages/Challanges/components/FiltersMenu/filterOptions.js
diff --git a/src/components/challenges_list/FiltersMenu/index.js b/src/pages/Challanges/components/FiltersMenu/index.js
similarity index 100%
rename from src/components/challenges_list/FiltersMenu/index.js
rename to src/pages/Challanges/components/FiltersMenu/index.js
diff --git a/src/pages/Challanges/components/MiniChallenge.js b/src/pages/Challanges/components/MiniChallenge.js
new file mode 100644
index 0000000..33ad4ec
--- /dev/null
+++ b/src/pages/Challanges/components/MiniChallenge.js
@@ -0,0 +1,121 @@
+import React from 'react';
+import {
+ Container,
+ FlexColumn,
+ FlexRow,
+ Grid,
+} from '../../../utils/containers';
+import { Body, H3 } from '../../../utils/fonts';
+import styled from 'styled-components';
+import IconLabel from '../../../components/generic/IconLabel';
+import { Link } from 'react-router-dom';
+import {
+ CHALLENGE_PAGE,
+ MINI_DESCRIPTION_RENDER,
+} from '../../../utils/globals';
+import theme from '../../../utils/theme';
+
+const ChallengeStyle = styled(FlexColumn)`
+ padding: 12px;
+ border: 1px solid ${({ theme }) => theme.colors.dark05};
+ cursor: pointer;
+ transition: transform 0.3s ease-in-out;
+ position: relative;
+ max-width: 420px;
+
+ * {
+ cursor: pointer;
+ }
+
+ &:hover {
+ transform: scale(1.05);
+ }
+
+ article {
+ width: 100%;
+ align-items: flex-start;
+
+ p {
+ width: 80%;
+ }
+ }
+
+ @media (min-width: ${({ theme }) => theme.overMobile}) {
+ width: 360px;
+ padding: 20px;
+ justify-content: flex-start;
+ }
+`;
+
+const IconsGrid = styled(Grid)`
+ width: 100%;
+ grid-gap: 14px;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: 1fr 1fr;
+
+ @media (min-width: 500px) {
+ grid-template-columns: auto auto auto;
+ }
+`;
+
+const MiniChallenge = (props) => {
+ const deadlineRender = () => {
+ if (props.deadline) {
+ return (
+
+ {props.deadline.slice(0, 10)}
+
+ );
+ }
+ };
+
+ return (
+
+
+
+
+ {props.title}
+
+ {props.type ? : 'xxx'}
+
+
+
+ {props.description
+ ? MINI_DESCRIPTION_RENDER(props.description)
+ : 'xxx'}
+
+
+
+ {props.metric ? props.metric : 'xxx'}
+
+
+ {props.bestScore ? props.bestScore : 'xxx'}
+
+ {deadlineRender()}
+
+ {props.baseline ? props.baseline : 'xxx'}
+
+ {props.prize ? (
+
+ {props.prize}
+
+ ) : (
+ ''
+ )}
+
+
+
+ );
+};
+
+export default MiniChallenge;
diff --git a/src/pages/Challanges/functions/challengeSearchQueryHandler.js b/src/pages/Challanges/functions/challengeSearchQueryHandler.js
index 90f279e..7cc4a90 100644
--- a/src/pages/Challanges/functions/challengeSearchQueryHandler.js
+++ b/src/pages/Challanges/functions/challengeSearchQueryHandler.js
@@ -1,4 +1,4 @@
-import CHALLENGES_ACTION from '../model/ChallengesActionEnum';
+import CHALLENGES_ACTION from '../model/ChallengesActions';
const challengeSearchQueryHandler = (event, challengesFromAPI, dispatch) => {
let searchQuery = event.target.value;
diff --git a/src/pages/Challanges/functions/renderChallenges.js b/src/pages/Challanges/functions/renderChallenges.js
index bf2f530..5f83f06 100644
--- a/src/pages/Challanges/functions/renderChallenges.js
+++ b/src/pages/Challanges/functions/renderChallenges.js
@@ -1,5 +1,5 @@
import { ELEMENTS_PER_PAGE } from '../../../utils/globals';
-import MiniChallenge from '../../../components/challenges_list/MiniChallenge';
+import MiniChallenge from '../components/MiniChallenge';
import { Grid } from '../../../utils/containers';
import styled from 'styled-components';
diff --git a/src/pages/Challanges/functions/statusFilterHandle.js b/src/pages/Challanges/functions/statusFilterHandle.js
index 4e3bfef..48af319 100644
--- a/src/pages/Challanges/functions/statusFilterHandle.js
+++ b/src/pages/Challanges/functions/statusFilterHandle.js
@@ -1,5 +1,5 @@
import { CHALLENGES_STATUS_FILTER } from '../../../utils/globals';
-import CHALLENGES_ACTION from '../model/ChallengesActionEnum';
+import CHALLENGES_ACTION from '../model/ChallengesActions';
const dateIsOlder = (newerDate, olderDate) => {
if (newerDate.year > olderDate.year) return true;
diff --git a/src/pages/Challanges/model/ChallengesActionEnum.js b/src/pages/Challanges/model/ChallengesActions.js
similarity index 100%
rename from src/pages/Challanges/model/ChallengesActionEnum.js
rename to src/pages/Challanges/model/ChallengesActions.js
diff --git a/src/pages/Challanges/model/ChallengesReducer.js b/src/pages/Challanges/model/ChallengesReducer.js
index 6b42f7a..99ac043 100644
--- a/src/pages/Challanges/model/ChallengesReducer.js
+++ b/src/pages/Challanges/model/ChallengesReducer.js
@@ -1,4 +1,4 @@
-import CHALLENGES_ACTION from './ChallengesActionEnum';
+import CHALLENGES_ACTION from './ChallengesActions';
const ChallengesReducer = (state, action) => {
switch (action.type) {
diff --git a/src/components/specific_challenge/Challenge.js b/src/pages/Challenge/Challenge.js
similarity index 90%
rename from src/components/specific_challenge/Challenge.js
rename to src/pages/Challenge/Challenge.js
index f739a5d..5f58272 100644
--- a/src/components/specific_challenge/Challenge.js
+++ b/src/pages/Challenge/Challenge.js
@@ -3,20 +3,20 @@ import { Container, FlexColumn, FlexRow, Svg } from '../../utils/containers';
import { useParams } from 'react-router-dom';
import { H1, Medium } from '../../utils/fonts';
import theme from '../../utils/theme';
-import MobileChallengeMenu from './MobileChallengeMenu';
-import Leaderboard from './Leaderboard/Leaderboard';
-import Readme from './Readme';
-import HowTo from './HowTo/HowTo';
-import MyEntries from './MyEntries/MyEntries';
-import Submit from './Submit';
+import MobileChallengeMenu from './components/MobileChallengeMenu';
+import Leaderboard from '../Leaderboard/Leaderboard';
+import Readme from '../Readme';
+import HowTo from '../HowTo/HowTo';
+import MyEntries from '../MyEntries/MyEntries';
+import Submit from '../Submit';
import Media from 'react-media';
-import DesktopChallengeMenu from './DesktopChallengeMenu';
+import DesktopChallengeMenu from './components/DesktopChallengeMenu';
import { CHALLENGE_SECTIONS, RENDER_ICO } from '../../utils/globals';
import textIco from '../../assets/text_ico.svg';
import getChallengeInfo from '../../api/getChallengeInfo';
-import Loading from '../generic/Loading';
+import Loading from '../../components/generic/Loading';
import getUser from '../../api/getUser';
-import AllEntries from './AllEntries/AllEntries';
+import AllEntries from '../AllEntries/AllEntries';
const Challenge = (props) => {
const challengeName = useParams().challengeId;
diff --git a/src/components/specific_challenge/DesktopChallengeMenu.js b/src/pages/Challenge/components/DesktopChallengeMenu.js
similarity index 90%
rename from src/components/specific_challenge/DesktopChallengeMenu.js
rename to src/pages/Challenge/components/DesktopChallengeMenu.js
index 6d56525..05d43f6 100644
--- a/src/components/specific_challenge/DesktopChallengeMenu.js
+++ b/src/pages/Challenge/components/DesktopChallengeMenu.js
@@ -1,15 +1,15 @@
import React from 'react';
import styled from 'styled-components';
-import { FlexColumn } from '../../utils/containers';
-import { H3 } from '../../utils/fonts';
+import { FlexColumn } from '../../../utils/containers';
+import { H3 } from '../../../utils/fonts';
import PropsTypes from 'prop-types';
-import KeyCloakService from '../../services/KeyCloakService';
+import KeyCloakService from '../../../services/KeyCloakService';
import { Link } from 'react-router-dom';
import {
MENU_CHALLENGE_SECTIONS_WITH_LOGIN,
MENU_CHALLENGE_SECTIONS_NO_LOGIN,
IS_MOBILE,
-} from '../../utils/globals';
+} from '../../../utils/globals';
const DesktopChallengeMenuStyle = styled(FlexColumn)`
justify-content: flex-start;
diff --git a/src/components/specific_challenge/MobileChallengeMenu.js b/src/pages/Challenge/components/MobileChallengeMenu.js
similarity index 94%
rename from src/components/specific_challenge/MobileChallengeMenu.js
rename to src/pages/Challenge/components/MobileChallengeMenu.js
index c3325a3..4a315fa 100644
--- a/src/components/specific_challenge/MobileChallengeMenu.js
+++ b/src/pages/Challenge/components/MobileChallengeMenu.js
@@ -1,14 +1,14 @@
import React from 'react';
-import { FlexRow } from '../../utils/containers';
+import { FlexRow } from '../../../utils/containers';
import styled from 'styled-components';
-import { Medium } from '../../utils/fonts';
+import { Medium } from '../../../utils/fonts';
import PropsTypes from 'prop-types';
-import KeyCloakService from '../../services/KeyCloakService';
+import KeyCloakService from '../../../services/KeyCloakService';
import {
CHALLENGE_SECTIONS,
MENU_CHALLENGE_SECTIONS_WITH_LOGIN,
MENU_CHALLENGE_SECTIONS_NO_LOGIN,
-} from '../../utils/globals';
+} from '../../../utils/globals';
import { Link } from 'react-router-dom';
const MenuOption = styled(Medium)`
diff --git a/src/pages/Challenge/index.js b/src/pages/Challenge/index.js
new file mode 100644
index 0000000..eeccdd9
--- /dev/null
+++ b/src/pages/Challenge/index.js
@@ -0,0 +1 @@
+export { default } from './Challenge';
diff --git a/src/components/specific_challenge/HowTo/HowTo.js b/src/pages/HowTo/HowTo.js
similarity index 77%
rename from src/components/specific_challenge/HowTo/HowTo.js
rename to src/pages/HowTo/HowTo.js
index d60de4f..07b50ae 100644
--- a/src/components/specific_challenge/HowTo/HowTo.js
+++ b/src/pages/HowTo/HowTo.js
@@ -1,9 +1,9 @@
import React from 'react';
-import getFullUser from '../../../api/getFullUserInfo';
-import KeyCloakService from '../../../services/KeyCloakService';
-import { FlexColumn } from '../../../utils/containers';
-import { IS_MOBILE } from '../../../utils/globals';
-import HowToContent from './sections/HowToContent';
+import getFullUser from '../../api/getFullUserInfo';
+import KeyCloakService from '../../services/KeyCloakService';
+import { FlexColumn } from '../../utils/containers';
+import { IS_MOBILE } from '../../utils/globals';
+import HowToContent from './components/HowToContent';
const HowTo = (props) => {
const [userFullInfo, setUserFullInfo] = React.useState(null);
diff --git a/src/components/specific_challenge/HowTo/sections/HowToContent.js b/src/pages/HowTo/components/HowToContent.js
similarity index 92%
rename from src/components/specific_challenge/HowTo/sections/HowToContent.js
rename to src/pages/HowTo/components/HowToContent.js
index 8472f2e..2394acf 100644
--- a/src/components/specific_challenge/HowTo/sections/HowToContent.js
+++ b/src/pages/HowTo/components/HowToContent.js
@@ -1,9 +1,9 @@
import React from 'react';
-import { IS_MOBILE } from '../../../../utils/globals';
-import { Body, H2, Medium } from '../../../../utils/fonts';
-import { FlexColumn, Grid } from '../../../../utils/containers';
-import CircleNumber from '../../../generic/CircleNumber';
-import CodeShell from '../../../generic/CodeShell';
+import { IS_MOBILE } from '../../../utils/globals';
+import { Body, H2, Medium } from '../../../utils/fonts';
+import { FlexColumn, Grid } from '../../../utils/containers';
+import CircleNumber from '../../../components/generic/CircleNumber';
+import CodeShell from '../../../components/generic/CodeShell';
const HowToContent = (props) => {
const pullCodeLineRender = () => {
diff --git a/src/components/specific_challenge/HowTo/index.js b/src/pages/HowTo/index.js
similarity index 100%
rename from src/components/specific_challenge/HowTo/index.js
rename to src/pages/HowTo/index.js
diff --git a/src/components/specific_challenge/Leaderboard/Leaderboard.js b/src/pages/Leaderboard/Leaderboard.js
similarity index 84%
rename from src/components/specific_challenge/Leaderboard/Leaderboard.js
rename to src/pages/Leaderboard/Leaderboard.js
index 8a67b25..e02cdf2 100644
--- a/src/components/specific_challenge/Leaderboard/Leaderboard.js
+++ b/src/pages/Leaderboard/Leaderboard.js
@@ -1,21 +1,20 @@
import React from 'react';
import Media from 'react-media';
-import theme from '../../../utils/theme';
-import { FlexColumn } from '../../../utils/containers';
-import { H2 } from '../../../utils/fonts';
-import Table from '../Table';
+import theme from '../../utils/theme';
+import { FlexColumn } from '../../utils/containers';
+import { H2 } from '../../utils/fonts';
+import Table from '../../components/generic/Table';
import PropsTypes from 'prop-types';
-import getChallengeLeaderboard from '../../../api/getChallengeLeaderboard';
+import getChallengeLeaderboard from '../../api/getChallengeLeaderboard';
import leaderboardSearchQueryHandler from './leaderboardSearchQueryHandler';
import {
CALC_PAGES,
EVALUATIONS_FORMAT,
RENDER_WHEN,
-
-} from '../../../utils/globals';
-import Search from '../../generic/Search';
-import Pager from '../../generic/Pager';
-import Loading from '../../generic/Loading';
+} from '../../utils/globals';
+import Search from '../../components/generic/Search';
+import Pager from '../../components/generic/Pager';
+import Loading from '../../components/generic/Loading';
const Leaderboard = (props) => {
const [entriesFromApi, setEntriesFromApi] = React.useState([]);
@@ -23,6 +22,7 @@ const Leaderboard = (props) => {
const [pageNr, setPageNr] = React.useState(1);
const [loading, setLoading] = React.useState(true);
const [submitterSorted, setSubmitterSorted] = React.useState(false);
+ const [descriptionSorted, setDescriptionSorted] = React.useState(false);
const [entriesSorted, setEntriesSorted] = React.useState(false);
const [whenSorted, setWhenSorted] = React.useState(false);
const [scoresSorted, setScoresSorted] = React.useState([]);
@@ -65,7 +65,7 @@ const Leaderboard = (props) => {
};
const getLeaderboardHeader = () => {
- let header = ['#', 'submitter'];
+ let header = ['#', 'submitter', 'description'];
for (let metric of getPossibleMetrics()) {
header.push(metric);
}
@@ -75,7 +75,7 @@ const Leaderboard = (props) => {
};
const getLeaderboardHeaderMobile = () => {
- let header = ['#', 'submitter', 'entries', 'when'];
+ let header = ['#', 'submitter', 'description', 'entries', 'when'];
for (let metric of getPossibleMetrics()) {
header.push(metric);
}
@@ -107,6 +107,27 @@ const Leaderboard = (props) => {
setSubmitterSorted(true);
}
break;
+ case 'description':
+ if (descriptionSorted) {
+ newEntries = newEntries.sort((a, b) =>
+ a.description.toLowerCase() < b.description.toLowerCase()
+ ? 1
+ : b.description.toLowerCase() < a.description.toLowerCase()
+ ? -1
+ : 0
+ );
+ setDescriptionSorted(false);
+ } else {
+ newEntries = newEntries.sort((a, b) =>
+ a.description.toLowerCase() > b.description.toLowerCase()
+ ? 1
+ : b.description.toLowerCase() > a.description.toLowerCase()
+ ? -1
+ : 0
+ );
+ setDescriptionSorted(true);
+ }
+ break;
case 'entries':
if (entriesSorted) {
newEntries = newEntries.sort((a, b) => b.times - a.times);
@@ -170,7 +191,7 @@ const Leaderboard = (props) => {
tableType="leaderboard"
gridTemplateColumns={
entries[0]
- ? '1fr 3fr ' +
+ ? '1fr 2fr 3fr ' +
'2fr '.repeat(entries[0].evaluations.length) +
'1fr 2fr'
: ''
@@ -179,6 +200,7 @@ const Leaderboard = (props) => {
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },
{ name: 'submitter', format: null, order: 2, align: 'left' },
+ { name: 'description', format: null, order: 3, align: 'left' },
{ name: 'times', format: null, order: 4, align: 'left' },
{ name: 'when', format: RENDER_WHEN, order: 5, align: 'right' },
]}
@@ -224,7 +246,7 @@ const Leaderboard = (props) => {
headerElements={getLeaderboardHeader()}
gridTemplateColumns={
entries[0]
- ? '1fr 3fr ' +
+ ? '1fr 2fr 3fr ' +
'2fr '.repeat(entries[0].evaluations.length) +
'1fr 2fr'
: ''
@@ -233,6 +255,7 @@ const Leaderboard = (props) => {
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },
{ name: 'submitter', format: null, order: 2, align: 'left' },
+ { name: 'description', format: null, order: 3, align: 'left' },
{ name: 'times', format: null, order: 4, align: 'left' },
{ name: 'when', format: RENDER_WHEN, order: 5, align: 'right' },
]}
@@ -255,7 +278,6 @@ const Leaderboard = (props) => {
width="72px"
borderRadius="64px"
pages={CALC_PAGES(entries, 2)}
-
number={`${pageNr} / ${CALC_PAGES(entries, 2)}`}
/>
>
diff --git a/src/components/specific_challenge/Leaderboard/index.js b/src/pages/Leaderboard/index.js
similarity index 100%
rename from src/components/specific_challenge/Leaderboard/index.js
rename to src/pages/Leaderboard/index.js
diff --git a/src/components/specific_challenge/Leaderboard/leaderboardSearchQueryHandler.js b/src/pages/Leaderboard/leaderboardSearchQueryHandler.js
similarity index 100%
rename from src/components/specific_challenge/Leaderboard/leaderboardSearchQueryHandler.js
rename to src/pages/Leaderboard/leaderboardSearchQueryHandler.js
diff --git a/src/components/specific_challenge/Leaderboard/sortOptions.js b/src/pages/Leaderboard/sortOptions.js
similarity index 100%
rename from src/components/specific_challenge/Leaderboard/sortOptions.js
rename to src/pages/Leaderboard/sortOptions.js
diff --git a/src/components/specific_challenge/MyEntries/MyEntries.js b/src/pages/MyEntries/MyEntries.js
similarity index 93%
rename from src/components/specific_challenge/MyEntries/MyEntries.js
rename to src/pages/MyEntries/MyEntries.js
index 0411c63..a83e867 100644
--- a/src/components/specific_challenge/MyEntries/MyEntries.js
+++ b/src/pages/MyEntries/MyEntries.js
@@ -1,20 +1,20 @@
import React from 'react';
-import { FlexColumn } from '../../../utils/containers';
-import { H2 } from '../../../utils/fonts';
-import getMyEntries from '../../../api/getMyEntries';
-import Pager from '../../generic/Pager';
+import { FlexColumn } from '../../utils/containers';
+import { H2 } from '../../utils/fonts';
+import getMyEntries from '../../api/getMyEntries';
+import Pager from '../../components/generic/Pager';
import {
CALC_PAGES,
EVALUATIONS_FORMAT,
IS_MOBILE,
RENDER_WHEN,
-} from '../../../utils/globals';
+} from '../../utils/globals';
import Media from 'react-media';
-import theme from '../../../utils/theme';
-import Loading from '../../generic/Loading';
-import Table from '../Table';
+import theme from '../../utils/theme';
+import Loading from '../../components/generic/Loading';
+import Table from '../../components/generic/Table';
import myEntriesSearchQueryHandler from './myEntriesSearchQueryHandler';
-import Search from '../../generic/Search';
+import Search from '../../components/generic/Search';
const MyEntries = (props) => {
const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({});
diff --git a/src/components/specific_challenge/MyEntries/index.js b/src/pages/MyEntries/index.js
similarity index 100%
rename from src/components/specific_challenge/MyEntries/index.js
rename to src/pages/MyEntries/index.js
diff --git a/src/components/specific_challenge/MyEntries/myEntriesSearchQueryHandler.js b/src/pages/MyEntries/myEntriesSearchQueryHandler.js
similarity index 100%
rename from src/components/specific_challenge/MyEntries/myEntriesSearchQueryHandler.js
rename to src/pages/MyEntries/myEntriesSearchQueryHandler.js
diff --git a/src/components/specific_challenge/Readme.js b/src/pages/Readme.js
similarity index 86%
rename from src/components/specific_challenge/Readme.js
rename to src/pages/Readme.js
index cac39d9..463d625 100644
--- a/src/components/specific_challenge/Readme.js
+++ b/src/pages/Readme.js
@@ -1,14 +1,12 @@
import React from 'react';
-import { FlexColumn } from '../../utils/containers';
-import { Body, H2 } from '../../utils/fonts';
+import { FlexColumn } from '../utils/containers';
+import { Body, H2 } from '../utils/fonts';
import Media from 'react-media';
-import theme from '../../utils/theme';
-import getChallengeFullDescription from '../../api/getChallengeFullDescription';
+import theme from '../utils/theme';
+import getChallengeFullDescription from '../api/getChallengeFullDescription';
import styled from 'styled-components';
-import InfoList from '../generic/InfoList';
-import Loading from '../generic/Loading';
-import PropsTypes from 'prop-types';
-import MiniChallenge from '../challenges_list/MiniChallenge';
+import InfoList from '../components/generic/InfoList';
+import Loading from '../components/generic/Loading';
import { marked } from 'marked';
const ReadmeStyle = styled(Body)`
@@ -154,14 +152,4 @@ const Readme = (props) => {
);
};
-MiniChallenge.propTypes = {
- challengeName: PropsTypes.string,
- description: PropsTypes.string,
-};
-
-MiniChallenge.defaultProps = {
- challengeName: '',
- description: '',
-};
-
export default Readme;
diff --git a/src/pages/Submit/Submit.js b/src/pages/Submit/Submit.js
new file mode 100644
index 0000000..397c272
--- /dev/null
+++ b/src/pages/Submit/Submit.js
@@ -0,0 +1,114 @@
+import React from 'react';
+import { createPortal } from 'react-dom';
+import { FlexColumn } from '../../utils/containers';
+import { H2, Menu } from '../../utils/fonts';
+import SubmitInput from '../../components/generic/SubmitInput';
+import Button from '../../components/generic/Button';
+import theme from '../../utils/theme';
+import challengeSubmission from '../../api/challengeSubmissionPost';
+import Loading from '../../components/generic/Loading';
+import getTags from '../../api/getTags';
+import TagsChoose from './components/TagsChoose';
+import SubmitReducer from './model/SubmitReducer';
+import SUBMIT_ACTION from './model/SubmitActionEnum';
+import SubmitStyle from './SubmitStyle';
+
+const Submit = (props) => {
+ const [state, dispatch] = React.useReducer(SubmitReducer, {
+ description: '',
+ repoUrl: '',
+ repoBranch: '',
+ submissionLoading: false,
+ tags: [],
+ submissionTags: [],
+ });
+
+ React.useMemo(() => {
+ getTags(dispatch);
+ }, []);
+
+ const challengeSubmissionSubmit = () => {
+ dispatch({ type: SUBMIT_ACTION.TOGGLE_SUBMISSION_LOADING });
+ challengeSubmission(
+ props.challengeName,
+ state.repoUrl,
+ state.repoBranch,
+ state.description,
+ state.submissionTags,
+ dispatch
+ );
+ };
+
+ const setDescription = (value) => {
+ dispatch({ type: SUBMIT_ACTION.SET_DESCRIPTION, payload: value });
+ };
+
+ const setRepoUrl = (value) => {
+ dispatch({ type: SUBMIT_ACTION.SET_REPO_URL, payload: value });
+ };
+
+ const setRepoBranch = (value) => {
+ dispatch({ type: SUBMIT_ACTION.SET_REPO_BRANCH, payload: value });
+ };
+
+ const toggleSubmissionTag = React.useCallback(
+ (tag) => {
+ let actionType = '';
+ if (state.submissionTags.includes(tag))
+ actionType = SUBMIT_ACTION.REMOVE_SUBMISSION_TAG;
+ else actionType = SUBMIT_ACTION.ADD_SUBMISSION_TAG;
+ dispatch({ type: actionType, payload: tag });
+ },
+ [state.submissionTags]
+ );
+
+ const clearSubmissionTags = () => {
+ dispatch({ type: SUBMIT_ACTION.CLEAR_SUBMISSION_TAGS });
+ };
+
+ if (!state.submissionLoading) {
+ return (
+
+
+ Submit a solution to the challenge
+
+
+
+
+
+
+
+
+
+ );
+ } else {
+ return createPortal(
+
+ Submission processing...
+
+ ,
+ document.body
+ );
+ }
+};
+
+export default Submit;
diff --git a/src/pages/Submit/SubmitStyle.js b/src/pages/Submit/SubmitStyle.js
new file mode 100644
index 0000000..a06c8e6
--- /dev/null
+++ b/src/pages/Submit/SubmitStyle.js
@@ -0,0 +1,23 @@
+import styled from 'styled-components';
+import { FlexColumn } from '../../utils/containers';
+
+const SubmitStyle = styled(FlexColumn)`
+ margin: 40px 0 0 0;
+ padding: 24px;
+ gap: 64px;
+ max-width: 624px;
+ width: 100%;
+ align-items: flex-start;
+
+ .SubmitStyle__header {
+ width: 100%;
+ text-align: center;
+ }
+
+ .SubmitStyle__form {
+ width: 100%;
+ gap: 32px;
+ }
+`;
+
+export default SubmitStyle;
diff --git a/src/pages/Submit/components/TagsChoose/TagsChoose.js b/src/pages/Submit/components/TagsChoose/TagsChoose.js
new file mode 100644
index 0000000..2e99c34
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoose/TagsChoose.js
@@ -0,0 +1,53 @@
+import React from 'react';
+import { FlexRow, Grid } from '../../../../utils/containers';
+import { Medium } from '../../../../utils/fonts';
+import ImageButton from '../../../../components/generic/ImageButton';
+import pencilIco from '../../../../assets/pencil_ico.svg';
+import TagsChoosePopUp from '../TagsChoosePopup/TagsChoosePopUp';
+import { createPortal } from 'react-dom';
+import TagsChooseStyle from './TagsChooseStyle';
+
+const TagsChoose = (props) => {
+ const [tagsPopUp, setTagsPopUp] = React.useState(false);
+
+ return (
+ {
+ if (!tagsPopUp) setTagsPopUp(true);
+ }}
+ >
+
+ {props.label}
+
+ props.handler(e.target.value)}
+ >
+
+ {props.submissionTags.map((tag, i) =>
+ i === 0 ? tag.name : `, ${tag.name}`
+ )}
+
+
+
+ {tagsPopUp &&
+ createPortal(
+ ,
+ document.body
+ )}
+
+ );
+};
+
+export default TagsChoose;
diff --git a/src/pages/Submit/components/TagsChoose/TagsChooseStyle.js b/src/pages/Submit/components/TagsChoose/TagsChooseStyle.js
new file mode 100644
index 0000000..7d859c2
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoose/TagsChooseStyle.js
@@ -0,0 +1,31 @@
+import styled from 'styled-components';
+import { FlexColumn } from '../../../../utils/containers';
+
+const TagsChooseStyle = styled(FlexColumn)`
+ cursor: pointer;
+ gap: 8px;
+ width: 100%;
+ align-items: flex-start;
+ * {
+ cursor: pointer;
+ }
+
+ .TagsChooseStyle__grid {
+ border-radius: 4px;
+ width: 100%;
+ height: 100px;
+ border: 1px solid ${({ theme }) => theme.colors.dark};
+ box-shadow: 1px 2px 4px rgba(52, 52, 52, 0.25);
+ padding: 12px;
+ grid-template-columns: 1fr auto;
+ }
+
+ .TagsChooseStyle__tags-container {
+ height: 100%;
+ justify-content: flex-start;
+ align-items: flex-start;
+ overflow-y: scroll;
+ }
+`;
+
+export default TagsChooseStyle;
diff --git a/src/pages/Submit/components/TagsChoose/index.js b/src/pages/Submit/components/TagsChoose/index.js
new file mode 100644
index 0000000..05aa6f3
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoose/index.js
@@ -0,0 +1 @@
+export { default } from './TagsChoose';
diff --git a/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUp.js b/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUp.js
new file mode 100644
index 0000000..9df83b2
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUp.js
@@ -0,0 +1,57 @@
+import React from 'react';
+import PopUp from '../../../../components/generic/PopUp';
+import { FlexColumn, FlexRow } from '../../../../utils/containers';
+import Search from '../../../../components/generic/Search';
+import theme from '../../../../utils/theme';
+import Button from '../../../../components/generic/Button';
+import TagsChoosePopUpStyle from './TagsChoosePopUpStyle';
+import renderTagItems from './functions/renderTagItems';
+
+const TagsChoosePopUp = (props) => {
+ return (
+ props.setTagsPopUp(false)}
+ >
+
+
+
+ {renderTagItems(
+ props.submissionTags,
+ props.toggleSubmissionTag,
+ `1px dotted ${theme.colors.green}`,
+ theme.colors.green03,
+ true
+ )}
+ {renderTagItems(props.tags, props.toggleSubmissionTag, 'none')}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default TagsChoosePopUp;
diff --git a/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUpStyle.js b/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUpStyle.js
new file mode 100644
index 0000000..fce2abf
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoosePopup/TagsChoosePopUpStyle.js
@@ -0,0 +1,31 @@
+import styled from 'styled-components';
+import { FlexColumn } from '../../../../utils/containers';
+
+const TagsChoosePopUpStyle = styled(FlexColumn)`
+ width: 100%;
+ justify-content: flex-start;
+ height: 100%;
+ gap: 24px;
+
+ .TagsChoosePopUpStyle__tags-list {
+ height: 80%;
+ width: 100%;
+ overflow-y: scroll;
+ justify-content: flex-start;
+ }
+
+ .TagsChoosePopUpStyle__tag-item {
+ height: 42px;
+ width: 100%;
+ justify-content: space-between;
+ padding: 12px;
+ cursor: pointer;
+ transition: background-color 0.3s ease-in-out;
+
+ &:hover {
+ background-color: ${({ theme }) => theme.colors.green03};
+ }
+ }
+`;
+
+export default TagsChoosePopUpStyle;
diff --git a/src/pages/Submit/components/TagsChoosePopup/functions/renderTagItems.js b/src/pages/Submit/components/TagsChoosePopup/functions/renderTagItems.js
new file mode 100644
index 0000000..fa83db4
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoosePopup/functions/renderTagItems.js
@@ -0,0 +1,42 @@
+import theme from '../../../../../utils/theme';
+import tagBackgroundColorHandle from './tagBackgroundColorHandle';
+import { FlexRow } from '../../../../../utils/containers';
+import removeIco from '../../../../../assets/remove_ico.svg';
+import { Svg } from '../../../../../utils/containers';
+
+const renderTagItems = (
+ tags,
+ toggleTag,
+ border,
+ backgroundColor,
+ submissionTags = false
+) => {
+ return tags.map((tag, index) => {
+ return (
+ toggleTag(tag)}
+ className="TagsChoosePopUpStyle__tag-item"
+ backgroundColor={
+ backgroundColor
+ ? backgroundColor
+ : tagBackgroundColorHandle(theme, index)
+ }
+ border={border}
+ >
+ {tag.name}
+ {submissionTags && (
+
+ )}
+
+ );
+ });
+};
+
+export default renderTagItems;
diff --git a/src/pages/Submit/components/TagsChoosePopup/functions/tagBackgroundColorHandle.js b/src/pages/Submit/components/TagsChoosePopup/functions/tagBackgroundColorHandle.js
new file mode 100644
index 0000000..aaf118f
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoosePopup/functions/tagBackgroundColorHandle.js
@@ -0,0 +1,6 @@
+const tagBackgroundColorHandle = (theme, index) => {
+ if (index % 2 === 0) return theme.colors.white;
+ return theme.colors.dark01;
+};
+
+export default tagBackgroundColorHandle;
diff --git a/src/pages/Submit/components/TagsChoosePopup/index.js b/src/pages/Submit/components/TagsChoosePopup/index.js
new file mode 100644
index 0000000..a4781d6
--- /dev/null
+++ b/src/pages/Submit/components/TagsChoosePopup/index.js
@@ -0,0 +1 @@
+export { default } from './TagsChoosePopUp';
diff --git a/src/pages/Submit/index.js b/src/pages/Submit/index.js
new file mode 100644
index 0000000..b5be4d5
--- /dev/null
+++ b/src/pages/Submit/index.js
@@ -0,0 +1 @@
+export { default } from './Submit';
diff --git a/src/pages/Submit/model/SubmitActionEnum.js b/src/pages/Submit/model/SubmitActionEnum.js
new file mode 100644
index 0000000..c57bb6e
--- /dev/null
+++ b/src/pages/Submit/model/SubmitActionEnum.js
@@ -0,0 +1,12 @@
+const SUBMIT_ACTION = {
+ SET_DESCRIPTION: 'set_description',
+ SET_REPO_URL: 'set_repo_url',
+ SET_REPO_BRANCH: 'set_repo_branch',
+ TOGGLE_SUBMISSION_LOADING: 'toggle_submission_loading',
+ LOAD_TAGS: 'load_tags',
+ ADD_SUBMISSION_TAG: 'add_submission_tag',
+ REMOVE_SUBMISSION_TAG: 'remove_submission_tag',
+ CLEAR_SUBMISSION_TAGS: 'clear_submission_tags',
+};
+
+export default SUBMIT_ACTION;
diff --git a/src/pages/Submit/model/SubmitReducer.js b/src/pages/Submit/model/SubmitReducer.js
new file mode 100644
index 0000000..803269b
--- /dev/null
+++ b/src/pages/Submit/model/SubmitReducer.js
@@ -0,0 +1,42 @@
+import SUBMIT_ACTION from './SubmitActionEnum';
+
+const SubmitReducer = (state, action) => {
+ console.log(`SubmitReducer: ${action.type}`);
+ let newSubmissionTags = state.submissionTags;
+ let newTags = state.tags;
+ switch (action.type) {
+ case SUBMIT_ACTION.SET_DESCRIPTION:
+ return { ...state, description: action.payload };
+ case SUBMIT_ACTION.SET_REPO_BRANCH:
+ return { ...state, repoBranch: action.payload };
+ case SUBMIT_ACTION.SET_REPO_URL:
+ return { ...state, repoUrl: action.payload };
+ case SUBMIT_ACTION.TOGGLE_SUBMISSION_LOADING:
+ return { ...state, submissionLoading: !state.submissionLoading };
+ case SUBMIT_ACTION.LOAD_TAGS:
+ if (state.tags.length === 0) newTags = action.payload;
+ return { ...state, tags: newTags };
+ case SUBMIT_ACTION.ADD_SUBMISSION_TAG:
+ if (!newSubmissionTags.includes(action.payload)) {
+ newTags = state.tags;
+ newSubmissionTags.push(action.payload);
+ newTags = newTags.filter((tag) => tag.name !== action.payload.name);
+ }
+ return { ...state, submissionTags: newSubmissionTags, tags: newTags };
+ case SUBMIT_ACTION.REMOVE_SUBMISSION_TAG:
+ if (newSubmissionTags.includes(action.payload)) {
+ newSubmissionTags = newSubmissionTags.filter(
+ (tag) => tag.name !== action.payload.name
+ );
+ newTags.push(action.payload);
+ newTags = newTags.sort((a, b) => a.name.localeCompare(b.name));
+ }
+ return { ...state, submissionTags: newSubmissionTags, tags: newTags };
+ case SUBMIT_ACTION.CLEAR_SUBMISSION_TAGS:
+ return { ...state, submissionTags: [] };
+ default:
+ throw new Error('Undefined action in SubmitReducer!');
+ }
+};
+
+export default SubmitReducer;
diff --git a/src/utils/colors.js b/src/utils/colors.js
index 40edebe..841cb3f 100644
--- a/src/utils/colors.js
+++ b/src/utils/colors.js
@@ -1,15 +1,16 @@
const colors = {
- white: '#FCFCFC',
- green: '#1B998B',
- green03: 'rgba(27, 153, 139, 0.3)',
- green05: 'rgba(27, 153, 139, 0.5)',
- dark: '#343434',
- dark01: 'rgba(52, 52, 52, 0.1)',
- dark03: 'rgba(52, 52, 52, 0.3)',
- dark04: 'rgba(52, 52, 52, 0.4)',
- dark05: 'rgba(52, 52, 52, 0.5)',
- dark07: 'rgba(52, 52, 52, 0.7)',
- dark08: 'rgba(52, 52, 52, 0.8)',
+ white: '#FCFCFC',
+ green: '#1B998B',
+ blue: '#4B8FF0',
+ green03: 'rgba(27, 153, 139, 0.3)',
+ green05: 'rgba(27, 153, 139, 0.5)',
+ dark: '#343434',
+ dark01: 'rgba(52, 52, 52, 0.1)',
+ dark03: 'rgba(52, 52, 52, 0.3)',
+ dark04: 'rgba(52, 52, 52, 0.4)',
+ dark05: 'rgba(52, 52, 52, 0.5)',
+ dark07: 'rgba(52, 52, 52, 0.7)',
+ dark08: 'rgba(52, 52, 52, 0.8)',
};
-export default colors;
\ No newline at end of file
+export default colors;
diff --git a/src/utils/containers.js b/src/utils/containers.js
index 24c794a..35ec2dc 100644
--- a/src/utils/containers.js
+++ b/src/utils/containers.js
@@ -37,6 +37,7 @@ const Container = styled.div`
list-style: ${({ listStyle }) => (listStyle ? listStyle : 'none')};
overflow-wrap: ${({ overflowWrap }) =>
overflowWrap ? overflowWrap : 'normal'};
+ overflow-y: ${({ overflowY }) => (overflowY ? overflowY : 'none')};
`;
const FlexRow = styled(Container)`