diff --git a/src/actions/auth.js b/src/actions/auth.js deleted file mode 100644 index 18e177a..0000000 --- a/src/actions/auth.js +++ /dev/null @@ -1,8 +0,0 @@ -import { createActions } from "redux-actions"; -import service from "../services/lookup"; - -async function getMemberGroups() {} - -export default createActions({ - GET_MEMBER_GROUPS: getMemberGroups, -}); diff --git a/src/actions/challenges.js b/src/actions/challenges.js index 304fa5c..4f4914c 100644 --- a/src/actions/challenges.js +++ b/src/actions/challenges.js @@ -7,28 +7,71 @@ async function doGetChallenges(filter) { return service.getChallenges(filter); } -async function getActiveChallenges(filter) { - const activeFilter = { +async function getAllActiveChallenges(filter) { + const BUCKET_ALL_ACTIVE_CHALLENGES = constants.FILTER_BUCKETS[0]; + let page; + + if (util.isDisplayingBucket(filter, BUCKET_ALL_ACTIVE_CHALLENGES)) { + page = filter.page; + } else { + page = 1; + } + + const allActiveFilter = { ...util.createChallengeCriteria(filter), - ...util.createActiveChallengeCriteria(), + ...util.createAllActiveChallengeCriteria(), + page, }; - return doGetChallenges(activeFilter); + return doGetChallenges(allActiveFilter); } async function getOpenForRegistrationChallenges(filter) { + const BUCKET_OPEN_FOR_REGISTRATION = constants.FILTER_BUCKETS[1]; + let page; + + if (util.isDisplayingBucket(filter, BUCKET_OPEN_FOR_REGISTRATION)) { + page = filter.page; + } else { + page = 1; + } + const openForRegistrationFilter = { ...util.createChallengeCriteria(filter), ...util.createOpenForRegistrationChallengeCriteria(), + page, }; return doGetChallenges(openForRegistrationFilter); } -async function getPastChallenges(filter) { - const pastFilter = { +async function getClosedChallenges(filter) { + const BUCKET_CLOSED_CHALLENGES = constants.FILTER_BUCKETS[1]; + let page; + + if (util.isDisplayingBucket(filter, BUCKET_CLOSED_CHALLENGES)) { + page = filter.page; + } else { + page = 1; + } + + const closedFilter = { ...util.createChallengeCriteria(filter), - ...util.createPastChallengeCriteria(), + ...util.createClosedChallengeCriteria(), + page, }; - return doGetChallenges(pastFilter); + return doGetChallenges(closedFilter); +} + +async function getRecommendedChallenges(filter) { + let result = []; + result.meta = { total: 0 }; + + if (result.length === 0) { + const failbackFilter = { ...filter }; + result = await getOpenForRegistrationChallenges(failbackFilter); + result.loadingRecommendedChallengesError = true; + } + + return result; } function doFilterBySubSommunities(challenges) { @@ -43,46 +86,113 @@ function doFilterByPrizeTo(challenges) { async function getChallenges(filter, change) { const FILTER_BUCKETS = constants.FILTER_BUCKETS; - let challenges; - let challengesFiltered; - let total; - let filterChange = change; - - const getChallengesByBucket = async (f) => { - switch (f.bucket) { - case FILTER_BUCKETS[0]: - return getActiveChallenges(f); - case FILTER_BUCKETS[1]: - return getOpenForRegistrationChallenges(f); - case FILTER_BUCKETS[2]: - return getPastChallenges(f); - default: - return []; - } + const BUCKET_ALL_ACTIVE_CHALLENGES = FILTER_BUCKETS[0]; + const BUCKET_OPEN_FOR_REGISTRATION = FILTER_BUCKETS[1]; + const BUCKET_CLOSED_CHALLENGES = FILTER_BUCKETS[2]; + const filterChange = change; + const bucket = filter.bucket; + + const getChallengesByBuckets = async (f) => { + return FILTER_BUCKETS.includes(f.bucket) + ? Promise.all([ + getAllActiveChallenges(f), + f.recommended + ? getRecommendedChallenges(f) + : getOpenForRegistrationChallenges(f), + getClosedChallenges(f), + ]) + : [[], [], []]; }; + if (!filterChange) { + let [ + allActiveChallenges, + openForRegistrationChallenges, + closedChallenges, + ] = await getChallengesByBuckets(filter); + let challenges; + let openForRegistrationCount; + let total; + let loadingRecommendedChallengesError; + + switch (bucket) { + case BUCKET_ALL_ACTIVE_CHALLENGES: + challenges = allActiveChallenges; + break; + case BUCKET_OPEN_FOR_REGISTRATION: + challenges = openForRegistrationChallenges; + break; + case BUCKET_CLOSED_CHALLENGES: + challenges = closedChallenges; + break; + } + openForRegistrationCount = openForRegistrationChallenges.meta.total; + total = challenges.meta.total; + loadingRecommendedChallengesError = + challenges.loadingRecommendedChallengesError; + + return { + challenges, + total, + openForRegistrationCount, + loadingRecommendedChallengesError, + allActiveChallenges, + openForRegistrationChallenges, + closedChallenges, + }; + } + if (!util.checkRequiredFilterAttributes(filter)) { return { challenges: [], challengesFiltered: [], total: 0 }; } - if (!filterChange) { - const chs = await getChallengesByBucket(filter); - return { challenges: chs, challengesFiltered: chs, total: chs.meta.total }; - } + let allActiveChallenges; + let openForRegistrationChallenges; + let closedChallenges; + let challenges; + let openForRegistrationCount; + let total; + let loadingRecommendedChallengesError; if (util.shouldFetchChallenges(filterChange)) { - challenges = await getChallengesByBucket(filter); + [ + allActiveChallenges, + openForRegistrationChallenges, + closedChallenges, + ] = await getChallengesByBuckets(filter); + switch (bucket) { + case BUCKET_ALL_ACTIVE_CHALLENGES: + challenges = allActiveChallenges; + break; + case BUCKET_OPEN_FOR_REGISTRATION: + challenges = openForRegistrationChallenges; + break; + case BUCKET_CLOSED_CHALLENGES: + challenges = closedChallenges; + break; + } } - challengesFiltered = challenges; + openForRegistrationCount = openForRegistrationChallenges.meta.total; total = challenges.meta.total; + loadingRecommendedChallengesError = + challenges.loadingRecommendedChallengesError; + if (util.shouldFilterChallenges(filterChange)) { - challengesFiltered = doFilterBySubSommunities(challengesFiltered); - challengesFiltered = doFilterByPrizeFrom(challengesFiltered); - challengesFiltered = doFilterByPrizeTo(challengesFiltered); + challenges = doFilterBySubSommunities(challenges); + challenges = doFilterByPrizeFrom(challenges); + challenges = doFilterByPrizeTo(challenges); } - return { challenges, challengesFiltered, total }; + return { + challenges, + total, + openForRegistrationCount, + loadingRecommendedChallengesError, + allActiveChallenges, + openForRegistrationChallenges, + closedChallenges, + }; } export default createActions({ diff --git a/src/actions/filter.js b/src/actions/filter.js index 5d3944b..d24ba3e 100644 --- a/src/actions/filter.js +++ b/src/actions/filter.js @@ -1,9 +1,14 @@ import { createActions } from "redux-actions"; +function restoreFilter(filter) { + return filter; +} + function updateFilter(partialUpdate) { return partialUpdate; } export default createActions({ + RESTORE_FILTER: restoreFilter, UPDATE_FILTER: updateFilter, }); diff --git a/src/assets/icons/card-view.svg b/src/assets/icons/card-view.svg new file mode 100644 index 0000000..a25ef80 --- /dev/null +++ b/src/assets/icons/card-view.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/list-view.svg b/src/assets/icons/list-view.svg new file mode 100644 index 0000000..ea5bd21 --- /dev/null +++ b/src/assets/icons/list-view.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/not-found-recommended.png b/src/assets/icons/not-found-recommended.png new file mode 100644 index 0000000..728a77b Binary files /dev/null and b/src/assets/icons/not-found-recommended.png differ diff --git a/src/components/Button/index.jsx b/src/components/Button/index.jsx index 2d28836..f30e79e 100644 --- a/src/components/Button/index.jsx +++ b/src/components/Button/index.jsx @@ -4,7 +4,7 @@ import PT from "prop-types"; import "./styles.scss"; const Button = ({ children, onClick }) => ( - ); @@ -14,4 +14,17 @@ Button.propTypes = { onClick: PT.func, }; +const ButtonIcon = ({ children, onClick }) => ( + +); + +ButtonIcon.propTypes = { + children: PT.node, + onClick: PT.func, +}; + +export { Button, ButtonIcon }; + export default Button; diff --git a/src/components/Button/styles.scss b/src/components/Button/styles.scss index 88f1d74..608f1ec 100644 --- a/src/components/Button/styles.scss +++ b/src/components/Button/styles.scss @@ -22,5 +22,15 @@ background-color: $green; } -.button-lg {} -.button-sm {} +.button-icon { + width: 32px; + height: 32px; + padding: 0; + line-height: 0; + text-align: center; + vertical-align: middle; + appearance: none; + background: none; + border: 0; + border-radius: 50%; +} diff --git a/src/components/Checkbox/index.jsx b/src/components/Checkbox/index.jsx index 10343de..3ad7a08 100644 --- a/src/components/Checkbox/index.jsx +++ b/src/components/Checkbox/index.jsx @@ -1,7 +1,7 @@ /** * Checkbox component. */ -import React, { useRef, useState } from "react"; +import React, { useRef, useState, useEffect } from "react"; import PT from "prop-types"; import _ from "lodash"; import "./styles.scss"; @@ -22,6 +22,10 @@ function Checkbox({ checked, onChange, size, errorMsg }) { _.debounce((q, cb) => cb(q), process.env.GUIKIT.DEBOUNCE_ON_CHANGE_TIME) // eslint-disable-line no-undef ).current; + useEffect(() => { + setCheckedInternal(checked); + }, [checked]); + return (