From 2762c3df3535f169fd91c159eb1ae96422ed33d0 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Tue, 16 Nov 2021 14:48:47 +0700 Subject: [PATCH 01/58] issue #145 --- config/dev.js | 4 ++++ config/prod.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/dev.js b/config/dev.js index 5ca5059..632f11b 100644 --- a/config/dev.js +++ b/config/dev.js @@ -139,4 +139,8 @@ module.exports = { process.env.FILESTACK_SUBMISSION_CONTAINER || "topcoder-dev-submissions-dmz", }, + /* Time in MS to wait before refreshing challenge details after register + * and unregister. Used to allow API sufficent time to update. + */ + CHALLENGE_DETAILS_REFRESH_DELAY: 3000, }; diff --git a/config/prod.js b/config/prod.js index ab93169..bb2f09b 100644 --- a/config/prod.js +++ b/config/prod.js @@ -134,4 +134,8 @@ module.exports = { process.env.FILESTACK_SUBMISSION_CONTAINER || "topcoder-dev-submissions-dmz", }, + /* Time in MS to wait before refreshing challenge details after register + * and unregister. Used to allow API sufficent time to update. + */ + CHALLENGE_DETAILS_REFRESH_DELAY: 3000, }; From 91b76771d908238b24dbe452141706adbb38aa98 Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 16 Nov 2021 17:09:59 +0800 Subject: [PATCH 02/58] fix: issue #110 --- src/routers/challenge-list/index.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routers/challenge-list/index.jsx b/src/routers/challenge-list/index.jsx index 49bcaa2..8b28696 100644 --- a/src/routers/challenge-list/index.jsx +++ b/src/routers/challenge-list/index.jsx @@ -36,7 +36,8 @@ const App = () => { return; } - const params = utils.url.parseUrlQuery(location.search); + let search = location.href.split('?').length ? '?' + location.href.split('?')[1]: '' + const params = utils.url.parseUrlQuery(search); const toUpdate = utils.challenge.createChallengeFilter(params); if (!toUpdate.types) toUpdate.types = []; From 6f1061c48733f637f2f42d909e2ba041a71e0aee Mon Sep 17 00:00:00 2001 From: Shivam Kumar Singh Date: Tue, 16 Nov 2021 15:29:58 +0530 Subject: [PATCH 03/58] Fixed #96 --- src/utils/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/index.js b/src/utils/index.js index b3fc4e1..5bda4b7 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -164,10 +164,10 @@ export function parseTotalPrizes(s) { if (valid) { n = +val.replace(/,/g, ""); if (/,/.test(val)) { - valid = valid && n.toLocaleString("en-US") === val; + n = n.toLocaleString("en-US"); } + return n; } - if (valid) return n; } export function triggerDownload(fileName,blob) { From 2556bd6e6e799d9ddc18a66006c31d628f9e157f Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 17:17:43 +0700 Subject: [PATCH 04/58] Reset Pagination to 1 When Choosing Filter --- .../Filter/ChallengeFilter/index.jsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index d28ff5b..bdf2f16 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -90,7 +90,10 @@ const ChallengeFilter = ({ const newTypes = checked ? types.concat(type) : types.filter((i) => i !== type); - const filterChange = { types: newTypes }; + const filterChange = { + types: newTypes, + page: 1, + }; updateFilter(filterChange); }} /> @@ -111,7 +114,10 @@ const ChallengeFilter = ({ const newTracks = checked ? tracks.concat(track) : tracks.filter((i) => i !== track); - const filterChange = { tracks: newTracks }; + const filterChange = { + tracks: newTracks, + page: 1, + }; updateFilter(filterChange); }} /> @@ -132,6 +138,7 @@ const ChallengeFilter = ({ ); const filterChange = { tags: selectedTagOptions.map((tagOption) => tagOption.label), + page: 1, }; updateFilter(filterChange); }} @@ -164,6 +171,7 @@ const ChallengeFilter = ({ } const filterChange = { totalPrizesFrom: value, + page: 1, }; updateFilter(filterChange); }) @@ -196,6 +204,7 @@ const ChallengeFilter = ({ } const filterChange = { totalPrizesTo: value, + page: 1, }; updateFilter(filterChange); }) @@ -237,7 +246,10 @@ const ChallengeFilter = ({ event !== utils.challenge.getCommunityEvent(subCommunity) ); - filterChange = { events: newEvents }; + filterChange = { + events: newEvents, + page: 1, + }; } else { const newGroups = checked ? groups.concat( @@ -248,7 +260,10 @@ const ChallengeFilter = ({ group !== utils.challenge.getCommunityGroup(subCommunity) ); - filterChange = { groups: newGroups }; + filterChange = { + groups: newGroups, + page: 1, + }; } updateFilter(filterChange); From ec5f26ddc71d072679d38605bac3a1f3d76a7468 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 17:19:42 +0700 Subject: [PATCH 05/58] linter --- src/containers/Submission/Submit/Header/index.jsx | 6 ++++-- src/utils/index.js | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/containers/Submission/Submit/Header/index.jsx b/src/containers/Submission/Submit/Header/index.jsx index 946eef2..447268a 100644 --- a/src/containers/Submission/Submit/Header/index.jsx +++ b/src/containers/Submission/Submit/Header/index.jsx @@ -1,14 +1,16 @@ import React from "react"; import PT from "prop-types"; import { Link } from "@reach/router"; -import config from '../../../../../config' +import config from "../../../../../config"; import "./styles.scss"; const Header = ({ title, challengeId }) => { return (
- +

Back to challenge

diff --git a/src/utils/index.js b/src/utils/index.js index b3fc4e1..05f421f 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -170,11 +170,11 @@ export function parseTotalPrizes(s) { if (valid) return n; } -export function triggerDownload(fileName,blob) { +export function triggerDownload(fileName, blob) { const url = window.URL.createObjectURL(new Blob([blob])); - const link = document.createElement('a'); + const link = document.createElement("a"); link.href = url; - link.setAttribute('download', fileName); + link.setAttribute("download", fileName); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); From 9762005b25a13e55921f466efa46af3453081161 Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 16 Nov 2021 18:49:08 +0800 Subject: [PATCH 06/58] fix: issue #126 --- src/services/challenges.js | 2 +- src/utils/url.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/services/challenges.js b/src/services/challenges.js index 7e6728a..2ecbe5d 100644 --- a/src/services/challenges.js +++ b/src/services/challenges.js @@ -17,7 +17,7 @@ import { getService as getSubmissionsService } from "./submissions"; * @return {Array} challenges */ async function getChallenges(filter, cancellationSignal) { - const challengeQuery = util.buildQueryString(filter); + const challengeQuery = util.buildQueryString(filter, true); return api.get( `/challenges/${challengeQuery}`, undefined, diff --git a/src/utils/url.js b/src/utils/url.js index 501c761..bb4a84a 100644 --- a/src/utils/url.js +++ b/src/utils/url.js @@ -15,9 +15,11 @@ import qs from "qs"; * @params {Object<{[key: string]: any}>} params Query string parameters * @return {String} */ -export function buildQueryString(params) { +export function buildQueryString(params, disableEncode) { params = _.omitBy(params, (p) => p == null || p === "" || p.length === 0); - + if (!disableEncode) { + params.tags = _.map(params.tags, (t) => encodeURIComponent(t)) + } let queryString = qs.stringify(params, { encode: false, arrayFormat: "brackets", @@ -28,7 +30,11 @@ export function buildQueryString(params) { } export function parseUrlQuery(queryString) { - return qs.parse(queryString, { ignoreQueryPrefix: true }); + let params = qs.parse(queryString, { ignoreQueryPrefix: true }); + if (params.tags) { + params.tags = _.map(params.tags, (t) => decodeURIComponent(t)) + } + return params } export function updateQuery(params) { From 72165fe0b2355d3eea7ae6a80c5262909f0192a6 Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 16 Nov 2021 19:18:28 +0800 Subject: [PATCH 07/58] fix: issue #106 --- src/containers/Challenges/Listing/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 17a0ec5..b5ee5ad 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -50,7 +50,7 @@ const Listing = ({ size="xs" onChange={(value) => { onSearch.current(() => { - const filterChange = { search: value }; + const filterChange = { search: value, page: 1 }; updateFilter(filterChange); }); }} From 5cca6d3f2788079010d195f497e168586f2e0d40 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Tue, 16 Nov 2021 18:37:42 +0700 Subject: [PATCH 08/58] issue #143 --- src/routers/challenge-list/index.jsx | 19 ++++++++++++++----- src/utils/lifeCycle.js | 14 +++++++++----- src/utils/url.js | 8 ++++++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/routers/challenge-list/index.jsx b/src/routers/challenge-list/index.jsx index 49bcaa2..b0b593d 100644 --- a/src/routers/challenge-list/index.jsx +++ b/src/routers/challenge-list/index.jsx @@ -9,7 +9,7 @@ import { FeedbackButton, showMenu } from "@topcoder/micro-frontends-earn-app"; import actions from "../../actions"; import * as utils from "../../utils"; import store from "../../store"; -import { initialChallengeFilter } from "../..//reducers/filter"; +import { initialChallengeFilter } from "../../reducers/filter"; import _ from "lodash"; import "react-date-range/dist/theme/default.css"; @@ -29,10 +29,19 @@ const App = () => { useEffect(() => { if (!location.search) { - store.dispatch(actions.challenges.getChallengesInit()); - store.dispatch( - actions.challenges.getChallengesDone(initialChallengeFilter) - ); + const currentFilter = store.getState().filter.challenge; + const diff = !_.isEqual(initialChallengeFilter, currentFilter); + + if (diff) { + const params = utils.challenge.createChallengeParams(currentFilter); + utils.url.updateQuery(params, true); + } else { + store.dispatch(actions.challenges.getChallengesInit()); + store.dispatch( + actions.challenges.getChallengesDone(currentFilter) + ); + } + return; } diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index 735a9c3..538b41e 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -5,19 +5,23 @@ import * as utils from "../utils"; export default function appInit() { let initialQuery; let urlPath; + let firstMounted = true; function bootstrap() { return Promise.resolve().then(() => { initialQuery = window.location.search; - urlPath = window.location.pathname; + urlPath = utils.url.removeTrailingSlash(window.location.pathname); }); } function mount() { - if (initialQuery) { - const params = utils.url.parseUrlQuery(initialQuery); - const filter = utils.challenge.createChallengeFilter(params); - store.dispatch(action.initApp(filter)); + if (firstMounted) { + if (initialQuery && urlPath === '/earn/find/challenges') { + const params = utils.url.parseUrlQuery(initialQuery); + const filter = utils.challenge.createChallengeFilter(params); + store.dispatch(action.initApp(filter)); + } + firstMounted = false; } return Promise.resolve(); diff --git a/src/utils/url.js b/src/utils/url.js index 501c761..97844fd 100644 --- a/src/utils/url.js +++ b/src/utils/url.js @@ -31,12 +31,16 @@ export function parseUrlQuery(queryString) { return qs.parse(queryString, { ignoreQueryPrefix: true }); } -export function updateQuery(params) { +export function updateQuery(params, replace = false) { const oldQuery = decodeURIComponent(window.location.search); let query = buildQueryString(params); query = `?${query.substring(1).split("&").sort().join("&")}`; if (query !== oldQuery) { - window.history.pushState(window.history.state, "", query); + if (replace) { + window.history.replaceState(window.history.state, "", query); + } else { + window.history.pushState(window.history.state, "", query); + } } } From c6593d899cd693f0c0c353fa70802ad96d712417 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 19:43:01 +0700 Subject: [PATCH 09/58] Prevent Trigger Change On Date Picker Input --- src/components/DateRangePicker/DateInput/index.jsx | 8 +++++++- src/components/DateRangePicker/index.jsx | 3 ++- src/components/TextInput/index.jsx | 2 +- src/containers/Challenges/Listing/index.jsx | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/DateRangePicker/DateInput/index.jsx b/src/components/DateRangePicker/DateInput/index.jsx index 1d62dfb..1c24b70 100644 --- a/src/components/DateRangePicker/DateInput/index.jsx +++ b/src/components/DateRangePicker/DateInput/index.jsx @@ -20,6 +20,7 @@ const DateInput = ({ onClickCalendarIcon, onStartEndDateChange, placeholder, + enterToSubmit }) => { const ref = useRef(null); const [focused, setFocused] = useState(false); @@ -125,7 +126,12 @@ const DateInput = ({ size="xs" value={rangeText} onChange={(value) => { - onChangeRangeTextDebounced.current(() => onChangeRangeText(value)); + if (!enterToSubmit) { + onChangeRangeTextDebounced.current(() => onChangeRangeText(value)); + } + }} + onEnterKey={(value) => { + onChangeRangeText(value) }} placeholder={placeholder} /> diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 64b5f52..c8f363d 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -16,7 +16,7 @@ import { } from "./helpers"; function DateRangePicker(props) { - const { id, range, onChange, placeholder } = props; + const { id, range, onChange, placeholder, enterToSubmit = false } = props; const [rangeString, setRangeString] = useState({ startDateString: "", @@ -538,6 +538,7 @@ function DateRangePicker(props) { }} onStartEndDateChange={onStartEndDateChange} placeholder={placeholder} + enterToSubmit={enterToSubmit} />
diff --git a/src/components/TextInput/index.jsx b/src/components/TextInput/index.jsx index e543b0a..4ccca63 100644 --- a/src/components/TextInput/index.jsx +++ b/src/components/TextInput/index.jsx @@ -55,7 +55,7 @@ function TextInput({ }} onKeyPress={(e) => { if (e.key === "Enter") { - onEnterKey(); + onEnterKey(e.target.value); } }} /> diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 17a0ec5..6ea0d82 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -83,6 +83,7 @@ const Listing = ({ }`} > { const d = range.endDate ? moment(range.endDate).toISOString() From eb510acaf3d56daaea58c6a7cb2471a3a450a2c6 Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 16 Nov 2021 23:03:06 +0800 Subject: [PATCH 10/58] fix: issue #85 --- src/components/DropdownTerms/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DropdownTerms/index.jsx b/src/components/DropdownTerms/index.jsx index 5b3ced8..c5ca31c 100644 --- a/src/components/DropdownTerms/index.jsx +++ b/src/components/DropdownTerms/index.jsx @@ -52,7 +52,7 @@ function DropdownTerms({ }, [focused, selectedOption]); useEffect(() => { setInternalTerms(terms); - }, [terms]); + }, [terms && terms.length]); const CustomReactSelectRow = React.forwardRef( ({ className, option, children, onSelect }, ref) => From a20e2c88f4b31c88f259cdfac4b791a9092e7d8c Mon Sep 17 00:00:00 2001 From: Shivam Kumar Singh Date: Tue, 16 Nov 2021 20:41:03 +0530 Subject: [PATCH 11/58] Fixes #95 --- src/components/challenge-detail/Submissions/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/challenge-detail/Submissions/index.jsx b/src/components/challenge-detail/Submissions/index.jsx index 7317378..6c17173 100644 --- a/src/components/challenge-detail/Submissions/index.jsx +++ b/src/components/challenge-detail/Submissions/index.jsx @@ -206,8 +206,8 @@ class SubmissionsComponent extends React.Component { valueA = getFinalScore(a); valueB = getFinalScore(b); } else { - valueA = !_.isEmpty(a.review) && a.review[0].score; - valueB = !_.isEmpty(b.review) && b.review[0].score; + valueA = !_.isEmpty(a.review) ? a.review[0].score : 0; + valueB = !_.isEmpty(b.review) ? b.review[0].score : 0; } break; } From 915ff0bee1eb0029412705603bf0534650ff55c7 Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 16 Nov 2021 23:20:22 +0800 Subject: [PATCH 12/58] fix: issue #76 --- src/containers/Challenges/Listing/index.jsx | 58 +++++++++++---------- src/containers/Challenges/index.jsx | 4 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 17a0ec5..05381b4 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -3,6 +3,7 @@ import PT from "prop-types"; import _ from "lodash"; import moment from "moment"; import Panel from "../../../components/Panel"; +import ChallengeError from "../Listing/errors/ChallengeError"; import Pagination from "../../../components/Pagination"; import ChallengeItem from "./ChallengeItem"; import TextInput from "../../../components/TextInput"; @@ -101,38 +102,39 @@ const Listing = ({
- - {challenges.map((challenge, index) => ( -
- { - const filterChange = { tags: [tag] }; - updateFilter(filterChange); - }} - onClickTrack={(track) => { - const filterChange = { tracks: [track] }; + {challenges.length ? + + {challenges.map((challenge, index) => ( +
+ { + const filterChange = { tags: [tag] }; + updateFilter(filterChange); + }} + onClickTrack={(track) => { + const filterChange = { tracks: [track] }; + updateFilter(filterChange); + }} + isLoggedIn={isLoggedIn} + /> +
+ ))} +
+ { + const filterChange = { + page: utils.pagination.pageIndexToPage(event.pageIndex), + perPage: event.pageSize, + }; updateFilter(filterChange); }} - isLoggedIn={isLoggedIn} />
- ))} -
- { - const filterChange = { - page: utils.pagination.pageIndexToPage(event.pageIndex), - perPage: event.pageSize, - }; - updateFilter(filterChange); - }} - /> -
-
+ : } ); }; diff --git a/src/containers/Challenges/index.jsx b/src/containers/Challenges/index.jsx index cb1a484..deb1cfd 100644 --- a/src/containers/Challenges/index.jsx +++ b/src/containers/Challenges/index.jsx @@ -3,7 +3,6 @@ import PT from "prop-types"; import { connect } from "react-redux"; import Listing from "./Listing"; import actions from "../../actions"; -import ChallengeError from "./Listing/errors/ChallengeError"; // import ChallengeRecommendedError from "./Listing/errors/ChallengeRecommendedError"; import * as constants from "../../constants"; import IconListView from "../../assets/icons/list-view.svg"; @@ -70,8 +69,7 @@ const Challenges = ({ - {challenges.length === 0 && initialized && } - {challenges.length > 0 && ( + {initialized && ( <> {/*noRecommendedChallenges && */} Date: Tue, 16 Nov 2021 23:21:44 +0700 Subject: [PATCH 13/58] issue #97 --- .../Submission/Submit/Uploading/index.jsx | 18 ++++++++++++++++-- src/containers/challenge-detail/index.jsx | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/containers/Submission/Submit/Uploading/index.jsx b/src/containers/Submission/Submit/Uploading/index.jsx index 8c712dd..4f77bed 100644 --- a/src/containers/Submission/Submit/Uploading/index.jsx +++ b/src/containers/Submission/Submit/Uploading/index.jsx @@ -1,6 +1,6 @@ -import React from "react"; +import React, { useEffect, useRef } from "react"; import PT from "prop-types"; -import { Link } from "@reach/router"; +import { Link, navigate } from "@reach/router"; import { PrimaryButton, DefaultButton as Button } from "components/Buttons"; import { COMPETITION_TRACKS, CHALLENGES_URL } from "../../../../constants"; import RobotHappy from "assets/icons/robot-happy.svg"; @@ -20,6 +20,20 @@ const Uploading = ({ uploadProgress, back, }) => { + const propsRef = useRef(); + propsRef.current = { submitDone, challengeId }; + + useEffect(() => { + return () => { + if (propsRef.current.submitDone) { + const backUrl = window.location.pathname; + if (backUrl === `${CHALLENGES_URL}/${challengeId}`) { + navigate(`${CHALLENGES_URL}/${propsRef.current.challengeId}?reload=true`); + } + } + } + }, []); + return (
diff --git a/src/containers/challenge-detail/index.jsx b/src/containers/challenge-detail/index.jsx index b2a17b1..8af2c34 100644 --- a/src/containers/challenge-detail/index.jsx +++ b/src/containers/challenge-detail/index.jsx @@ -221,6 +221,10 @@ class ChallengeDetailPageContainer extends React.Component { challenge, // loadingRecommendedChallengesUUID, history, + loadChallengeDetails, + loadFullChallengeDetails, + isLoadingChallenge, + isLoadingTerms, } = this.props; if ( @@ -247,6 +251,15 @@ class ChallengeDetailPageContainer extends React.Component { // getAllRecommendedChallenges(auth.tokenV3, recommendedTechnology); // } + const query = new URLSearchParams(history.location.search); + const isReloading = isLoadingChallenge || isLoadingTerms; + if (query.get('reload') && !isReloading) { + history.replace(history.location.pathname, history.state); + loadChallengeDetails(nextProps.auth, challengeId, loadFullChallengeDetails); + + return; + } + const { thriveArticles } = this.state; const userId = _.get(this, "props.auth.user.userId"); const nextUserId = _.get(nextProps, "auth.user.userId"); From 0a808479681fb5af6e4106f0945ce203646b0808 Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Wed, 17 Nov 2021 01:51:20 +0800 Subject: [PATCH 14/58] ci:deploying --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4be26f9..eddbd3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,7 +77,7 @@ workflows: branches: only: - dev - - submission-page + - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. From da3ec4495d4276805ccfec691c6c9267389a1435 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 01:19:09 +0700 Subject: [PATCH 15/58] Add Close Button in Calendar --- src/components/DateRangePicker/index.jsx | 35 +++++++++++++++-------- src/components/DateRangePicker/style.scss | 13 +++++++-- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 64b5f52..686e158 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -562,18 +562,29 @@ function DateRangePicker(props) { preview={preview} onPreviewChange={onPreviewChange} /> - +
+ + +
)}
diff --git a/src/components/DateRangePicker/style.scss b/src/components/DateRangePicker/style.scss index 8a9caa9..ff8c7c8 100644 --- a/src/components/DateRangePicker/style.scss +++ b/src/components/DateRangePicker/style.scss @@ -391,6 +391,7 @@ $darkGreen: #0AB88A;; z-index: 10; @include phone { + width: 100vw; position: fixed; top: 0; left: 0; @@ -402,7 +403,15 @@ $darkGreen: #0AB88A;; border-radius: 0; } - .reset-button { + .calendar-footer { + width: 100%; + + @include phone { + padding: 0 20px; + } + } + + .calendar-button { @include roboto-bold; width: 71px; @@ -421,7 +430,7 @@ $darkGreen: #0AB88A;; height: 26px; line-height: 27px; font-size: 12px; - margin: 20px 12px 0; + margin: 0 12px 0; } } } From 36f988d891a2caa311cfd99b3b79221e958dc4e3 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 02:09:41 +0700 Subject: [PATCH 16/58] issue #132 --- src/components/DateRangePicker/index.jsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 64b5f52..883eab9 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -344,8 +344,17 @@ function DateRangePicker(props) { const onPreviewChange = (date) => { if (!(date instanceof Date)) { setPreview(null); - setActiveDate(null); - setFocusedRange([0, focusedRange[1]]); + + // --- + // workaround for fixing issue 132: + // - set the active range's background to transparent color + // to prevent the calendar auto focusing on the day of today by default when no + // start date nor end date are set. + // - does not set the end date of the selection range as default when mouse is out. + // --- + + // setActiveDate(null); + // setFocusedRange([0, focusedRange[1]]); return; } @@ -485,7 +494,7 @@ function DateRangePicker(props) { startDate: activeDate, endDate: activeDate, key: "active", - color: "#D8FDD8", + color: preview ? "#D8FDD8" : "#D8FDD800", }, ]; } From 314693a8b1b59cdbf3acf0c8977c87cfb69e9055 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 03:21:22 +0700 Subject: [PATCH 17/58] issue 132: focus selection range when having value --- src/components/DateRangePicker/index.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 883eab9..439808f 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -350,11 +350,13 @@ function DateRangePicker(props) { // - set the active range's background to transparent color // to prevent the calendar auto focusing on the day of today by default when no // start date nor end date are set. - // - does not set the end date of the selection range as default when mouse is out. + // - does not set focus on the empty selection range when mouse leaves. // --- // setActiveDate(null); - // setFocusedRange([0, focusedRange[1]]); + if (range.startDate || range.endDate) { + setFocusedRange([0, focusedRange[1]]); + } return; } From 9a9d96617f0ce5c56187d4604bfe1ed40a81b7cf Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 04:00:34 +0700 Subject: [PATCH 18/58] issue 132: fixed duration of a week having 8 days --- src/components/DateRangePicker/helpers.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/DateRangePicker/helpers.js b/src/components/DateRangePicker/helpers.js index cef8582..73f55d5 100644 --- a/src/components/DateRangePicker/helpers.js +++ b/src/components/DateRangePicker/helpers.js @@ -50,39 +50,40 @@ const staticRangeHandler = { * @return {object[]} list of defined ranges */ export function createStaticRanges() { - const now = moment().utcOffset(0); - const pastWeek = now.clone().subtract(1, "week"); - const pastMonth = now.clone().subtract(1, "month"); - const past6Months = now.clone().subtract(6, "month"); - const pastYear = now.clone().subtract(1, "year"); + const today = moment(); + const endOfToday = today.set({ hour: 23, minute: 59, second: 59, millisecond: 999 }); + const pastWeek = endOfToday.clone().subtract(1, "week"); + const pastMonth = endOfToday.clone().subtract(1, "month"); + const past6Months = endOfToday.clone().subtract(6, "month"); + const pastYear = endOfToday.clone().subtract(1, "year"); const ranges = [ { label: "Past Week", range: () => ({ startDate: pastWeek.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past Month", range: () => ({ startDate: pastMonth.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past 6 Months", range: () => ({ startDate: past6Months.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past Year", range: () => ({ startDate: pastYear.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, ]; From 323c8d4242b71ba38e4ac50d185e5021ec80030b Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 06:13:05 +0700 Subject: [PATCH 19/58] Clear Challenge Filter On Menu Click --- src/routers/challenge-list/index.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routers/challenge-list/index.jsx b/src/routers/challenge-list/index.jsx index 49bcaa2..c14c670 100644 --- a/src/routers/challenge-list/index.jsx +++ b/src/routers/challenge-list/index.jsx @@ -29,6 +29,8 @@ const App = () => { useEffect(() => { if (!location.search) { + const filterChange = utils.challenge.createEmptyChallengeFilter(); + store.dispatch(actions.filter.clearChallengeFilter(filterChange)); store.dispatch(actions.challenges.getChallengesInit()); store.dispatch( actions.challenges.getChallengesDone(initialChallengeFilter) From 3f23d6a2e60b9446ae34366c19b106a875e497a0 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 06:27:22 +0700 Subject: [PATCH 20/58] Reset Pagination to 1 --- src/containers/Challenges/Listing/index.jsx | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 05381b4..1f32274 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -51,7 +51,10 @@ const Listing = ({ size="xs" onChange={(value) => { onSearch.current(() => { - const filterChange = { search: value }; + const filterChange = { + search: value, + page: 1 + }; updateFilter(filterChange); }); }} @@ -73,6 +76,7 @@ const Listing = ({ ); const filterChange = { sortBy: constants.CHALLENGE_SORT_BY[selectedOption.label], + page: 1 }; updateFilter(filterChange); }} @@ -91,7 +95,11 @@ const Listing = ({ const s = range.startDate ? moment(range.startDate).toISOString() : null; - const filterChange = { endDateStart: s, startDateEnd: d }; + const filterChange = { + endDateStart: s, + startDateEnd: d, + page: 1 + }; updateFilter(filterChange); }} range={{ @@ -102,18 +110,24 @@ const Listing = ({
- {challenges.length ? + {challenges.length ? {challenges.map((challenge, index) => (
{ - const filterChange = { tags: [tag] }; + const filterChange = { + tags: [tag], + page: 1 + }; updateFilter(filterChange); }} onClickTrack={(track) => { - const filterChange = { tracks: [track] }; + const filterChange = { + tracks: [track], + page: 1 + }; updateFilter(filterChange); }} isLoggedIn={isLoggedIn} From 6ef504bd9653be3e402e7497f3a36ced969ab6c6 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 06:28:02 +0700 Subject: [PATCH 21/58] linter --- src/containers/Challenges/Listing/index.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 1f32274..68a8530 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -53,7 +53,7 @@ const Listing = ({ onSearch.current(() => { const filterChange = { search: value, - page: 1 + page: 1, }; updateFilter(filterChange); }); @@ -76,7 +76,7 @@ const Listing = ({ ); const filterChange = { sortBy: constants.CHALLENGE_SORT_BY[selectedOption.label], - page: 1 + page: 1, }; updateFilter(filterChange); }} @@ -98,7 +98,7 @@ const Listing = ({ const filterChange = { endDateStart: s, startDateEnd: d, - page: 1 + page: 1, }; updateFilter(filterChange); }} @@ -119,14 +119,14 @@ const Listing = ({ onClickTag={(tag) => { const filterChange = { tags: [tag], - page: 1 + page: 1, }; updateFilter(filterChange); }} onClickTrack={(track) => { const filterChange = { tracks: [track], - page: 1 + page: 1, }; updateFilter(filterChange); }} From ab62178998df8f9ea4f47159a64ffb9be4d12555 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 08:09:59 +0700 Subject: [PATCH 22/58] Implement Not Found Error --- src/components/NotFoundError/index.jsx | 20 ++++++++++++++++++ src/components/NotFoundError/styles.scss | 21 +++++++++++++++++++ ...topcoder-micro-frontends-challenges-app.js | 5 ++++- src/utils/lifeCycle.js | 18 +++++++++------- 4 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/components/NotFoundError/index.jsx create mode 100644 src/components/NotFoundError/styles.scss diff --git a/src/components/NotFoundError/index.jsx b/src/components/NotFoundError/index.jsx new file mode 100644 index 0000000..4803798 --- /dev/null +++ b/src/components/NotFoundError/index.jsx @@ -0,0 +1,20 @@ +import React from "react"; +import IconNotFound from "assets/icons/not-found.png"; + +import "./styles.scss"; + +const NotFoundError = ({ message }) => ( +
+
+ not found +
+

+ 404 Not found +

+

+ Sorry, we couldn’t find that page +

+
+); + +export default NotFoundError; diff --git a/src/components/NotFoundError/styles.scss b/src/components/NotFoundError/styles.scss new file mode 100644 index 0000000..fb8a1d4 --- /dev/null +++ b/src/components/NotFoundError/styles.scss @@ -0,0 +1,21 @@ +@import "styles/variables"; + +.not-found-error { + padding: 16px 24px; + min-height: 136px; + margin-bottom: 35px; + font-size: $font-size-sm; + line-height: 22px; + text-align: center; + background: $white; + border-radius: $border-radius-lg; + + h1 { + padding: 15px 0 10px; + margin-bottom: 20px; + } + + p { + margin-bottom: 8px; + } +} diff --git a/src/topcoder-micro-frontends-challenges-app.js b/src/topcoder-micro-frontends-challenges-app.js index bee6e7e..7d4513e 100644 --- a/src/topcoder-micro-frontends-challenges-app.js +++ b/src/topcoder-micro-frontends-challenges-app.js @@ -4,6 +4,7 @@ import ReactDOM from "react-dom"; import singleSpaReact from "single-spa-react"; import Root from "./root.component"; import appInit from "./utils/lifeCycle"; +import NotFoundError from "./components/NotFoundError"; const appLifecycles = appInit(); @@ -13,7 +14,9 @@ const lifecycles = singleSpaReact({ rootComponent: Root, errorBoundary(err, info, props) { // Customize the root error boundary for your microfrontend here. - return null; + return ( + + ); }, }); diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index 735a9c3..7eed6d4 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -13,14 +13,18 @@ export default function appInit() { }); } - function mount() { - if (initialQuery) { - const params = utils.url.parseUrlQuery(initialQuery); - const filter = utils.challenge.createChallengeFilter(params); - store.dispatch(action.initApp(filter)); + async function mount() { + try { + if (initialQuery) { + const params = utils.url.parseUrlQuery(initialQuery); + const filter = utils.challenge.createChallengeFilter(params); + store.dispatch(action.initApp(filter)); + } + } catch (error) { + console.error(error) + } finally { + return Promise.resolve(); } - - return Promise.resolve(); } function unmount() { From 47d6771045224071470f056853036c92ce0bad39 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 08:34:03 +0700 Subject: [PATCH 23/58] Use debounce function for sort by --- src/containers/Challenges/Listing/index.jsx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 05381b4..0a6e7fd 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -36,6 +36,15 @@ const Listing = ({ ); const onSearch = useRef(_.debounce((f) => f(), 1000)); + const onChangeSortBy = (newSortByOptions) => { + const selectedOption = utils.getSelectedDropdownOption( + newSortByOptions + ); + const filterChange = { + sortBy: constants.CHALLENGE_SORT_BY[selectedOption.label], + }; + updateFilter(filterChange); + } return ( @@ -67,15 +76,7 @@ const Listing = ({ label="Sort by" options={sortByOptions} size="xs" - onChange={(newSortByOptions) => { - const selectedOption = utils.getSelectedDropdownOption( - newSortByOptions - ); - const filterChange = { - sortBy: constants.CHALLENGE_SORT_BY[selectedOption.label], - }; - updateFilter(filterChange); - }} + onChange={_.debounce(onChangeSortBy, 1000)} />
- {challenges.length ? + {challenges.length ? {challenges.map((challenge, index) => (
From 0bb794e8eeac9426efd3f5203cc3e5d971177dbd Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 13:25:24 +0700 Subject: [PATCH 24/58] issue #75 --- src/components/Pagination/index.jsx | 80 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/src/components/Pagination/index.jsx b/src/components/Pagination/index.jsx index 1d7835b..184b815 100644 --- a/src/components/Pagination/index.jsx +++ b/src/components/Pagination/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useMemo, useRef } from "react"; import PT from "prop-types"; import Dropdown from "../Dropdown"; import { @@ -12,6 +12,20 @@ import "./styles.scss"; const N = PAGINATION_MAX_PAGE_DISPLAY; +const createDisplayPages = (p, n) => { + const pages = []; + for ( + let start = utils.clamp(p - N, 0, n), + end = utils.clamp(p + N, 0, n), + i = start; + i < end; + i += 1 + ) { + pages.push(i); + } + return pages.slice(-N); +}; + /** * Pagination with the first page index being as 0 and the last page index being as `total - 1` */ @@ -20,24 +34,6 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { const perPageOptions = utils.createDropdownOptions(PAGINATION_PER_PAGES); utils.setSelectedDropdownOption(perPageOptions, `${pageSize}`); - const createDisplayPages = (p, n) => { - const pages = []; - for ( - let start = utils.clamp(p - N, 0, n), - end = utils.clamp(p + N, 0, n), - i = start; - i < end; - i += 1 - ) { - pages.push(i); - } - return pages.slice(-N); - }; - - const [displayPages, setDisplayPages] = useState( - createDisplayPages(pageIndex, total) - ); - const onChangePageSize = (options) => { const selectedOption = utils.getSelectedDropdownOption(options); const newPageSize = +selectedOption.label; @@ -59,33 +55,35 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { } }; - const latestPropsRef = useRef(null); - latestPropsRef.current = { displayPages, pageIndex }; + const propsRef = useRef(); + propsRef.current = { pageIndex }; - useEffect(() => { + const displayPages = useMemo(() => { const newTotal = Math.ceil(length / pageSize); - const _pageIndex = latestPropsRef.current.pageIndex; - setDisplayPages(createDisplayPages(_pageIndex, newTotal)); + const initDisplayPages = createDisplayPages(propsRef.current.pageIndex, newTotal); + return initDisplayPages; }, [length, pageSize]); - useEffect(() => { - const _displayPages = latestPropsRef.current.displayPages; - const start = _displayPages[0]; - const end = _displayPages[_displayPages.length - 1]; - const updateDisplayPages = []; - if (pageIndex < start) { - for (let i = pageIndex; i < pageIndex + N; i += 1) { - updateDisplayPages.push(i); - } - setDisplayPages(updateDisplayPages); - } else if (pageIndex > end) { - for (let i = pageIndex; i > pageIndex - N; i -= 1) { - updateDisplayPages.unshift(i); + const updateDisplayPages = useMemo(() => { + const start = displayPages[0]; + const end = displayPages[displayPages.length - 1]; + + const _updateDisplayPages = []; + if (pageIndex < start) { + for (let i = pageIndex; i < pageIndex + N; i += 1) { + _updateDisplayPages.push(i); + } + } else if (pageIndex > end) { + for (let i = pageIndex; i > pageIndex - N; i -= 1) { + _updateDisplayPages.unshift(i); + } + } else { + _updateDisplayPages.push(...displayPages); } - setDisplayPages(updateDisplayPages); - } - }, [pageIndex]); + + return _updateDisplayPages; + }, [pageIndex, displayPages]); const formatPage = (p) => `${p + 1}`; @@ -107,7 +105,7 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { PREVIOUS - {displayPages.map((p) => ( + {updateDisplayPages.map((p) => (
  • - {updateDisplayPages.map((p) => ( + {displayPages.map((p) => (
  • - - {challenges.map((challenge, index) => ( -
    - { - const filterChange = { tags: [tag] }; - updateFilter(filterChange); - }} - onClickTrack={(track) => { - const filterChange = { tracks: [track] }; + {challenges.length ? + + {challenges.map((challenge, index) => ( +
    + { + const filterChange = { tags: [tag] }; + updateFilter(filterChange); + }} + onClickTrack={(track) => { + const filterChange = { tracks: [track] }; + updateFilter(filterChange); + }} + isLoggedIn={isLoggedIn} + /> +
    + ))} +
    + { + const filterChange = { + page: utils.pagination.pageIndexToPage(event.pageIndex), + perPage: event.pageSize, + }; updateFilter(filterChange); }} - isLoggedIn={isLoggedIn} />
    - ))} -
    - { - const filterChange = { - page: utils.pagination.pageIndexToPage(event.pageIndex), - perPage: event.pageSize, - }; - updateFilter(filterChange); - }} - /> -
    -
    + : } ); }; diff --git a/src/containers/Challenges/index.jsx b/src/containers/Challenges/index.jsx index cb1a484..deb1cfd 100644 --- a/src/containers/Challenges/index.jsx +++ b/src/containers/Challenges/index.jsx @@ -3,7 +3,6 @@ import PT from "prop-types"; import { connect } from "react-redux"; import Listing from "./Listing"; import actions from "../../actions"; -import ChallengeError from "./Listing/errors/ChallengeError"; // import ChallengeRecommendedError from "./Listing/errors/ChallengeRecommendedError"; import * as constants from "../../constants"; import IconListView from "../../assets/icons/list-view.svg"; @@ -70,8 +69,7 @@ const Challenges = ({ - {challenges.length === 0 && initialized && } - {challenges.length > 0 && ( + {initialized && ( <> {/*noRecommendedChallenges && */} Date: Tue, 16 Nov 2021 23:03:06 +0800 Subject: [PATCH 29/58] fix: issue #85 --- src/components/DropdownTerms/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DropdownTerms/index.jsx b/src/components/DropdownTerms/index.jsx index 5b3ced8..c5ca31c 100644 --- a/src/components/DropdownTerms/index.jsx +++ b/src/components/DropdownTerms/index.jsx @@ -52,7 +52,7 @@ function DropdownTerms({ }, [focused, selectedOption]); useEffect(() => { setInternalTerms(terms); - }, [terms]); + }, [terms && terms.length]); const CustomReactSelectRow = React.forwardRef( ({ className, option, children, onSelect }, ref) => From 9d2b365f2f45bb1701a6c26b6576f6c43b2e72fd Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Wed, 17 Nov 2021 01:51:20 +0800 Subject: [PATCH 30/58] ci:deploying --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4be26f9..eddbd3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,7 +77,7 @@ workflows: branches: only: - dev - - submission-page + - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. From 119c77ece27d81344545a631da8f0bb3b3714fa8 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Singh Date: Tue, 16 Nov 2021 20:41:03 +0530 Subject: [PATCH 31/58] Fixes #95 --- src/components/challenge-detail/Submissions/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/challenge-detail/Submissions/index.jsx b/src/components/challenge-detail/Submissions/index.jsx index 7317378..6c17173 100644 --- a/src/components/challenge-detail/Submissions/index.jsx +++ b/src/components/challenge-detail/Submissions/index.jsx @@ -206,8 +206,8 @@ class SubmissionsComponent extends React.Component { valueA = getFinalScore(a); valueB = getFinalScore(b); } else { - valueA = !_.isEmpty(a.review) && a.review[0].score; - valueB = !_.isEmpty(b.review) && b.review[0].score; + valueA = !_.isEmpty(a.review) ? a.review[0].score : 0; + valueB = !_.isEmpty(b.review) ? b.review[0].score : 0; } break; } From 6a346435580753be9bd71e7e35759dd710c4d23e Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 13:25:24 +0700 Subject: [PATCH 32/58] issue #75 --- src/components/Pagination/index.jsx | 80 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/src/components/Pagination/index.jsx b/src/components/Pagination/index.jsx index 1d7835b..184b815 100644 --- a/src/components/Pagination/index.jsx +++ b/src/components/Pagination/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useMemo, useRef } from "react"; import PT from "prop-types"; import Dropdown from "../Dropdown"; import { @@ -12,6 +12,20 @@ import "./styles.scss"; const N = PAGINATION_MAX_PAGE_DISPLAY; +const createDisplayPages = (p, n) => { + const pages = []; + for ( + let start = utils.clamp(p - N, 0, n), + end = utils.clamp(p + N, 0, n), + i = start; + i < end; + i += 1 + ) { + pages.push(i); + } + return pages.slice(-N); +}; + /** * Pagination with the first page index being as 0 and the last page index being as `total - 1` */ @@ -20,24 +34,6 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { const perPageOptions = utils.createDropdownOptions(PAGINATION_PER_PAGES); utils.setSelectedDropdownOption(perPageOptions, `${pageSize}`); - const createDisplayPages = (p, n) => { - const pages = []; - for ( - let start = utils.clamp(p - N, 0, n), - end = utils.clamp(p + N, 0, n), - i = start; - i < end; - i += 1 - ) { - pages.push(i); - } - return pages.slice(-N); - }; - - const [displayPages, setDisplayPages] = useState( - createDisplayPages(pageIndex, total) - ); - const onChangePageSize = (options) => { const selectedOption = utils.getSelectedDropdownOption(options); const newPageSize = +selectedOption.label; @@ -59,33 +55,35 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { } }; - const latestPropsRef = useRef(null); - latestPropsRef.current = { displayPages, pageIndex }; + const propsRef = useRef(); + propsRef.current = { pageIndex }; - useEffect(() => { + const displayPages = useMemo(() => { const newTotal = Math.ceil(length / pageSize); - const _pageIndex = latestPropsRef.current.pageIndex; - setDisplayPages(createDisplayPages(_pageIndex, newTotal)); + const initDisplayPages = createDisplayPages(propsRef.current.pageIndex, newTotal); + return initDisplayPages; }, [length, pageSize]); - useEffect(() => { - const _displayPages = latestPropsRef.current.displayPages; - const start = _displayPages[0]; - const end = _displayPages[_displayPages.length - 1]; - const updateDisplayPages = []; - if (pageIndex < start) { - for (let i = pageIndex; i < pageIndex + N; i += 1) { - updateDisplayPages.push(i); - } - setDisplayPages(updateDisplayPages); - } else if (pageIndex > end) { - for (let i = pageIndex; i > pageIndex - N; i -= 1) { - updateDisplayPages.unshift(i); + const updateDisplayPages = useMemo(() => { + const start = displayPages[0]; + const end = displayPages[displayPages.length - 1]; + + const _updateDisplayPages = []; + if (pageIndex < start) { + for (let i = pageIndex; i < pageIndex + N; i += 1) { + _updateDisplayPages.push(i); + } + } else if (pageIndex > end) { + for (let i = pageIndex; i > pageIndex - N; i -= 1) { + _updateDisplayPages.unshift(i); + } + } else { + _updateDisplayPages.push(...displayPages); } - setDisplayPages(updateDisplayPages); - } - }, [pageIndex]); + + return _updateDisplayPages; + }, [pageIndex, displayPages]); const formatPage = (p) => `${p + 1}`; @@ -107,7 +105,7 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { PREVIOUS - {displayPages.map((p) => ( + {updateDisplayPages.map((p) => (
  • - {updateDisplayPages.map((p) => ( + {displayPages.map((p) => (
  • - {challenges.length ? + {challenges.length ? {challenges.map((challenge, index) => (
    From 9ee11d156fba0d1cd023bd4ad983aa34609302fd Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Tue, 16 Nov 2021 23:21:44 +0700 Subject: [PATCH 35/58] issue #97 --- .../Submission/Submit/Uploading/index.jsx | 18 ++++++++++++++++-- src/containers/challenge-detail/index.jsx | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/containers/Submission/Submit/Uploading/index.jsx b/src/containers/Submission/Submit/Uploading/index.jsx index 8c712dd..4f77bed 100644 --- a/src/containers/Submission/Submit/Uploading/index.jsx +++ b/src/containers/Submission/Submit/Uploading/index.jsx @@ -1,6 +1,6 @@ -import React from "react"; +import React, { useEffect, useRef } from "react"; import PT from "prop-types"; -import { Link } from "@reach/router"; +import { Link, navigate } from "@reach/router"; import { PrimaryButton, DefaultButton as Button } from "components/Buttons"; import { COMPETITION_TRACKS, CHALLENGES_URL } from "../../../../constants"; import RobotHappy from "assets/icons/robot-happy.svg"; @@ -20,6 +20,20 @@ const Uploading = ({ uploadProgress, back, }) => { + const propsRef = useRef(); + propsRef.current = { submitDone, challengeId }; + + useEffect(() => { + return () => { + if (propsRef.current.submitDone) { + const backUrl = window.location.pathname; + if (backUrl === `${CHALLENGES_URL}/${challengeId}`) { + navigate(`${CHALLENGES_URL}/${propsRef.current.challengeId}?reload=true`); + } + } + } + }, []); + return (
    diff --git a/src/containers/challenge-detail/index.jsx b/src/containers/challenge-detail/index.jsx index b2a17b1..8af2c34 100644 --- a/src/containers/challenge-detail/index.jsx +++ b/src/containers/challenge-detail/index.jsx @@ -221,6 +221,10 @@ class ChallengeDetailPageContainer extends React.Component { challenge, // loadingRecommendedChallengesUUID, history, + loadChallengeDetails, + loadFullChallengeDetails, + isLoadingChallenge, + isLoadingTerms, } = this.props; if ( @@ -247,6 +251,15 @@ class ChallengeDetailPageContainer extends React.Component { // getAllRecommendedChallenges(auth.tokenV3, recommendedTechnology); // } + const query = new URLSearchParams(history.location.search); + const isReloading = isLoadingChallenge || isLoadingTerms; + if (query.get('reload') && !isReloading) { + history.replace(history.location.pathname, history.state); + loadChallengeDetails(nextProps.auth, challengeId, loadFullChallengeDetails); + + return; + } + const { thriveArticles } = this.state; const userId = _.get(this, "props.auth.user.userId"); const nextUserId = _.get(nextProps, "auth.user.userId"); From e43a6cf86c49a3bd6c12a88e3991044858493ad7 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 17:17:43 +0700 Subject: [PATCH 36/58] Reset Pagination to 1 When Choosing Filter --- .../Filter/ChallengeFilter/index.jsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index d28ff5b..bdf2f16 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -90,7 +90,10 @@ const ChallengeFilter = ({ const newTypes = checked ? types.concat(type) : types.filter((i) => i !== type); - const filterChange = { types: newTypes }; + const filterChange = { + types: newTypes, + page: 1, + }; updateFilter(filterChange); }} /> @@ -111,7 +114,10 @@ const ChallengeFilter = ({ const newTracks = checked ? tracks.concat(track) : tracks.filter((i) => i !== track); - const filterChange = { tracks: newTracks }; + const filterChange = { + tracks: newTracks, + page: 1, + }; updateFilter(filterChange); }} /> @@ -132,6 +138,7 @@ const ChallengeFilter = ({ ); const filterChange = { tags: selectedTagOptions.map((tagOption) => tagOption.label), + page: 1, }; updateFilter(filterChange); }} @@ -164,6 +171,7 @@ const ChallengeFilter = ({ } const filterChange = { totalPrizesFrom: value, + page: 1, }; updateFilter(filterChange); }) @@ -196,6 +204,7 @@ const ChallengeFilter = ({ } const filterChange = { totalPrizesTo: value, + page: 1, }; updateFilter(filterChange); }) @@ -237,7 +246,10 @@ const ChallengeFilter = ({ event !== utils.challenge.getCommunityEvent(subCommunity) ); - filterChange = { events: newEvents }; + filterChange = { + events: newEvents, + page: 1, + }; } else { const newGroups = checked ? groups.concat( @@ -248,7 +260,10 @@ const ChallengeFilter = ({ group !== utils.challenge.getCommunityGroup(subCommunity) ); - filterChange = { groups: newGroups }; + filterChange = { + groups: newGroups, + page: 1, + }; } updateFilter(filterChange); From c5a1b0c7f5c65d18e364f526190744e216e1e1e2 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 17:19:42 +0700 Subject: [PATCH 37/58] linter --- src/containers/Submission/Submit/Header/index.jsx | 6 ++++-- src/utils/index.js | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/containers/Submission/Submit/Header/index.jsx b/src/containers/Submission/Submit/Header/index.jsx index 946eef2..447268a 100644 --- a/src/containers/Submission/Submit/Header/index.jsx +++ b/src/containers/Submission/Submit/Header/index.jsx @@ -1,14 +1,16 @@ import React from "react"; import PT from "prop-types"; import { Link } from "@reach/router"; -import config from '../../../../../config' +import config from "../../../../../config"; import "./styles.scss"; const Header = ({ title, challengeId }) => { return (
    - +

    Back to challenge

    diff --git a/src/utils/index.js b/src/utils/index.js index b3fc4e1..05f421f 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -170,11 +170,11 @@ export function parseTotalPrizes(s) { if (valid) return n; } -export function triggerDownload(fileName,blob) { +export function triggerDownload(fileName, blob) { const url = window.URL.createObjectURL(new Blob([blob])); - const link = document.createElement('a'); + const link = document.createElement("a"); link.href = url; - link.setAttribute('download', fileName); + link.setAttribute("download", fileName); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); From 8c3f401afcfb1498480e0a547b972dc3f5dcb37e Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Tue, 16 Nov 2021 14:48:47 +0700 Subject: [PATCH 38/58] issue #145 --- config/dev.js | 4 ++++ config/prod.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/dev.js b/config/dev.js index 5ca5059..632f11b 100644 --- a/config/dev.js +++ b/config/dev.js @@ -139,4 +139,8 @@ module.exports = { process.env.FILESTACK_SUBMISSION_CONTAINER || "topcoder-dev-submissions-dmz", }, + /* Time in MS to wait before refreshing challenge details after register + * and unregister. Used to allow API sufficent time to update. + */ + CHALLENGE_DETAILS_REFRESH_DELAY: 3000, }; diff --git a/config/prod.js b/config/prod.js index ab93169..bb2f09b 100644 --- a/config/prod.js +++ b/config/prod.js @@ -134,4 +134,8 @@ module.exports = { process.env.FILESTACK_SUBMISSION_CONTAINER || "topcoder-dev-submissions-dmz", }, + /* Time in MS to wait before refreshing challenge details after register + * and unregister. Used to allow API sufficent time to update. + */ + CHALLENGE_DETAILS_REFRESH_DELAY: 3000, }; From 0cc1eaf3e7e06104af9365cb6aedd7201366cd70 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Wed, 17 Nov 2021 08:09:59 +0700 Subject: [PATCH 39/58] Implement Not Found Error --- src/components/NotFoundError/index.jsx | 20 ++++++++++++++++++ src/components/NotFoundError/styles.scss | 21 +++++++++++++++++++ ...topcoder-micro-frontends-challenges-app.js | 5 ++++- src/utils/lifeCycle.js | 16 +++++++------- 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 src/components/NotFoundError/index.jsx create mode 100644 src/components/NotFoundError/styles.scss diff --git a/src/components/NotFoundError/index.jsx b/src/components/NotFoundError/index.jsx new file mode 100644 index 0000000..4803798 --- /dev/null +++ b/src/components/NotFoundError/index.jsx @@ -0,0 +1,20 @@ +import React from "react"; +import IconNotFound from "assets/icons/not-found.png"; + +import "./styles.scss"; + +const NotFoundError = ({ message }) => ( +
    +
    + not found +
    +

    + 404 Not found +

    +

    + Sorry, we couldn’t find that page +

    +
    +); + +export default NotFoundError; diff --git a/src/components/NotFoundError/styles.scss b/src/components/NotFoundError/styles.scss new file mode 100644 index 0000000..fb8a1d4 --- /dev/null +++ b/src/components/NotFoundError/styles.scss @@ -0,0 +1,21 @@ +@import "styles/variables"; + +.not-found-error { + padding: 16px 24px; + min-height: 136px; + margin-bottom: 35px; + font-size: $font-size-sm; + line-height: 22px; + text-align: center; + background: $white; + border-radius: $border-radius-lg; + + h1 { + padding: 15px 0 10px; + margin-bottom: 20px; + } + + p { + margin-bottom: 8px; + } +} diff --git a/src/topcoder-micro-frontends-challenges-app.js b/src/topcoder-micro-frontends-challenges-app.js index bee6e7e..7d4513e 100644 --- a/src/topcoder-micro-frontends-challenges-app.js +++ b/src/topcoder-micro-frontends-challenges-app.js @@ -4,6 +4,7 @@ import ReactDOM from "react-dom"; import singleSpaReact from "single-spa-react"; import Root from "./root.component"; import appInit from "./utils/lifeCycle"; +import NotFoundError from "./components/NotFoundError"; const appLifecycles = appInit(); @@ -13,7 +14,9 @@ const lifecycles = singleSpaReact({ rootComponent: Root, errorBoundary(err, info, props) { // Customize the root error boundary for your microfrontend here. - return null; + return ( + + ); }, }); diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index 538b41e..7eed6d4 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -5,26 +5,26 @@ import * as utils from "../utils"; export default function appInit() { let initialQuery; let urlPath; - let firstMounted = true; function bootstrap() { return Promise.resolve().then(() => { initialQuery = window.location.search; - urlPath = utils.url.removeTrailingSlash(window.location.pathname); + urlPath = window.location.pathname; }); } - function mount() { - if (firstMounted) { - if (initialQuery && urlPath === '/earn/find/challenges') { + async function mount() { + try { + if (initialQuery) { const params = utils.url.parseUrlQuery(initialQuery); const filter = utils.challenge.createChallengeFilter(params); store.dispatch(action.initApp(filter)); } - firstMounted = false; + } catch (error) { + console.error(error) + } finally { + return Promise.resolve(); } - - return Promise.resolve(); } function unmount() { From 38c915de9295f9db5d3fb6210fe882429bd0ed6f Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 16 Nov 2021 19:43:01 +0700 Subject: [PATCH 40/58] Prevent Trigger Change On Date Picker Input --- src/components/DateRangePicker/DateInput/index.jsx | 8 +++++++- src/components/DateRangePicker/index.jsx | 3 ++- src/components/TextInput/index.jsx | 2 +- src/containers/Challenges/Listing/index.jsx | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/DateRangePicker/DateInput/index.jsx b/src/components/DateRangePicker/DateInput/index.jsx index 1d62dfb..1c24b70 100644 --- a/src/components/DateRangePicker/DateInput/index.jsx +++ b/src/components/DateRangePicker/DateInput/index.jsx @@ -20,6 +20,7 @@ const DateInput = ({ onClickCalendarIcon, onStartEndDateChange, placeholder, + enterToSubmit }) => { const ref = useRef(null); const [focused, setFocused] = useState(false); @@ -125,7 +126,12 @@ const DateInput = ({ size="xs" value={rangeText} onChange={(value) => { - onChangeRangeTextDebounced.current(() => onChangeRangeText(value)); + if (!enterToSubmit) { + onChangeRangeTextDebounced.current(() => onChangeRangeText(value)); + } + }} + onEnterKey={(value) => { + onChangeRangeText(value) }} placeholder={placeholder} /> diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 64b5f52..c8f363d 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -16,7 +16,7 @@ import { } from "./helpers"; function DateRangePicker(props) { - const { id, range, onChange, placeholder } = props; + const { id, range, onChange, placeholder, enterToSubmit = false } = props; const [rangeString, setRangeString] = useState({ startDateString: "", @@ -538,6 +538,7 @@ function DateRangePicker(props) { }} onStartEndDateChange={onStartEndDateChange} placeholder={placeholder} + enterToSubmit={enterToSubmit} />
    diff --git a/src/components/TextInput/index.jsx b/src/components/TextInput/index.jsx index e543b0a..4ccca63 100644 --- a/src/components/TextInput/index.jsx +++ b/src/components/TextInput/index.jsx @@ -55,7 +55,7 @@ function TextInput({ }} onKeyPress={(e) => { if (e.key === "Enter") { - onEnterKey(); + onEnterKey(e.target.value); } }} /> diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 0a6e7fd..c60ad6e 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -85,6 +85,7 @@ const Listing = ({ }`} > { const d = range.endDate ? moment(range.endDate).toISOString() From 0b6303692ca44065208a16ed4d8d6c5086a18c31 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 02:09:41 +0700 Subject: [PATCH 41/58] issue #132 --- src/components/DateRangePicker/index.jsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index c8f363d..81a86ca 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -344,8 +344,17 @@ function DateRangePicker(props) { const onPreviewChange = (date) => { if (!(date instanceof Date)) { setPreview(null); - setActiveDate(null); - setFocusedRange([0, focusedRange[1]]); + + // --- + // workaround for fixing issue 132: + // - set the active range's background to transparent color + // to prevent the calendar auto focusing on the day of today by default when no + // start date nor end date are set. + // - does not set the end date of the selection range as default when mouse is out. + // --- + + // setActiveDate(null); + // setFocusedRange([0, focusedRange[1]]); return; } @@ -485,7 +494,7 @@ function DateRangePicker(props) { startDate: activeDate, endDate: activeDate, key: "active", - color: "#D8FDD8", + color: preview ? "#D8FDD8" : "#D8FDD800", }, ]; } From 6b3fb8547e06855d1acac94ead7a1deca8e3de39 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 03:21:22 +0700 Subject: [PATCH 42/58] issue 132: focus selection range when having value --- src/components/DateRangePicker/index.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/DateRangePicker/index.jsx b/src/components/DateRangePicker/index.jsx index 81a86ca..2b74d17 100644 --- a/src/components/DateRangePicker/index.jsx +++ b/src/components/DateRangePicker/index.jsx @@ -350,11 +350,13 @@ function DateRangePicker(props) { // - set the active range's background to transparent color // to prevent the calendar auto focusing on the day of today by default when no // start date nor end date are set. - // - does not set the end date of the selection range as default when mouse is out. + // - does not set focus on the empty selection range when mouse leaves. // --- // setActiveDate(null); - // setFocusedRange([0, focusedRange[1]]); + if (range.startDate || range.endDate) { + setFocusedRange([0, focusedRange[1]]); + } return; } From 57e2caf91d0c6e082518a57ecfb92e8f9c13f1fc Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 04:00:34 +0700 Subject: [PATCH 43/58] issue 132: fixed duration of a week having 8 days --- src/components/DateRangePicker/helpers.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/DateRangePicker/helpers.js b/src/components/DateRangePicker/helpers.js index cef8582..73f55d5 100644 --- a/src/components/DateRangePicker/helpers.js +++ b/src/components/DateRangePicker/helpers.js @@ -50,39 +50,40 @@ const staticRangeHandler = { * @return {object[]} list of defined ranges */ export function createStaticRanges() { - const now = moment().utcOffset(0); - const pastWeek = now.clone().subtract(1, "week"); - const pastMonth = now.clone().subtract(1, "month"); - const past6Months = now.clone().subtract(6, "month"); - const pastYear = now.clone().subtract(1, "year"); + const today = moment(); + const endOfToday = today.set({ hour: 23, minute: 59, second: 59, millisecond: 999 }); + const pastWeek = endOfToday.clone().subtract(1, "week"); + const pastMonth = endOfToday.clone().subtract(1, "month"); + const past6Months = endOfToday.clone().subtract(6, "month"); + const pastYear = endOfToday.clone().subtract(1, "year"); const ranges = [ { label: "Past Week", range: () => ({ startDate: pastWeek.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past Month", range: () => ({ startDate: pastMonth.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past 6 Months", range: () => ({ startDate: past6Months.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, { label: "Past Year", range: () => ({ startDate: pastYear.startOf("day").toDate(), - endDate: now.endOf("day").toDate(), + endDate: endOfToday.toDate(), }), }, ]; From 9517217207a5fd0465248672bdc0cba0276a597e Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Wed, 17 Nov 2021 23:35:43 +0700 Subject: [PATCH 44/58] =resolve merge conflict --- src/utils/lifeCycle.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index 7eed6d4..b363e48 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -5,20 +5,24 @@ import * as utils from "../utils"; export default function appInit() { let initialQuery; let urlPath; + let firstMounted = true; function bootstrap() { return Promise.resolve().then(() => { initialQuery = window.location.search; - urlPath = window.location.pathname; + urlPath = utils.url.removeTrailingSlash(window.location.pathname); }); } async function mount() { try { - if (initialQuery) { - const params = utils.url.parseUrlQuery(initialQuery); - const filter = utils.challenge.createChallengeFilter(params); - store.dispatch(action.initApp(filter)); + if (firstMounted) { + if (initialQuery && urlPath === '/earn/find/challenges') { + const params = utils.url.parseUrlQuery(initialQuery); + const filter = utils.challenge.createChallengeFilter(params); + store.dispatch(action.initApp(filter)); + } + firstMounted = false; } } catch (error) { console.error(error) From 8d039680f267065458c1e9f50491c291920d5084 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Thu, 18 Nov 2021 12:20:42 +0700 Subject: [PATCH 45/58] Replace Track QA --- .../Challenges/Listing/ChallengeItem/TrackIcon/styles.scss | 1 + src/containers/Challenges/Listing/index.jsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/containers/Challenges/Listing/ChallengeItem/TrackIcon/styles.scss b/src/containers/Challenges/Listing/ChallengeItem/TrackIcon/styles.scss index 1528470..489052a 100644 --- a/src/containers/Challenges/Listing/ChallengeItem/TrackIcon/styles.scss +++ b/src/containers/Challenges/Listing/ChallengeItem/TrackIcon/styles.scss @@ -6,6 +6,7 @@ height: 36px; vertical-align: middle; line-height: 1; + cursor: pointer; > svg { position: absolute; diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 68a8530..aeb22a8 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -125,7 +125,7 @@ const Listing = ({ }} onClickTrack={(track) => { const filterChange = { - tracks: [track], + tracks: [track.replace('Quality Assurance', 'QA')], page: 1, }; updateFilter(filterChange); From c317cd26bc536fbd2ebc1d497faf8f1b380f8a9d Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Thu, 18 Nov 2021 13:11:21 +0700 Subject: [PATCH 46/58] Reset Pagination --- src/containers/Challenges/index.jsx | 12 ++++++++++++ src/reducers/challenges.js | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/containers/Challenges/index.jsx b/src/containers/Challenges/index.jsx index deb1cfd..86103f4 100644 --- a/src/containers/Challenges/index.jsx +++ b/src/containers/Challenges/index.jsx @@ -14,6 +14,7 @@ import "./styles.scss"; const Challenges = ({ challenges, + challengesMeta, search, page, perPage, @@ -38,6 +39,16 @@ const Challenges = ({ checkIsLoggedIn(); }, []); + // reset pagination + if (page > 1 && challengesMeta.total && challengesMeta.total > 0 && challenges.length === 0) { + updateFilter({ + page: 1 + }) + updateQuery({ + page: 1 + }) + } + const BUCKET_OPEN_FOR_REGISTRATION = constants.FILTER_BUCKETS[1]; const isRecommended = recommended && bucket === BUCKET_OPEN_FOR_REGISTRATION; const sortByValue = isRecommended @@ -124,6 +135,7 @@ const mapStateToProps = (state) => ({ endDateStart: state.filter.challenge.endDateStart, startDateEnd: state.filter.challenge.startDateEnd, challenges: state.challenges.challenges, + challengesMeta: state.challenges.challengesMeta, bucket: state.filter.challenge.bucket, recommended: state.filter.challenge.recommended, recommendedChallenges: state.challenges.recommendedChallenges, diff --git a/src/reducers/challenges.js b/src/reducers/challenges.js index dc8d54c..37fc947 100644 --- a/src/reducers/challenges.js +++ b/src/reducers/challenges.js @@ -4,6 +4,7 @@ const defaultState = { loadingChallenges: false, loadingChallengesError: null, challenges: [], + challengesMeta: {}, total: 0, loadingRecommendedChallenges: false, loadingRecommendedChallengesError: null, @@ -31,6 +32,7 @@ function onGetChallengesDone(state, { payload }) { loadingChallenges: false, loadingChallengesError: null, challenges: payload.challenges, + challengesMeta: payload.challenges?.meta, total: payload.total, openForRegistrationCount: payload.openForRegistrationCount, initialized: true, From ecf2b8d4c9ba15e4191743e8b62cfcca13ddb37f Mon Sep 17 00:00:00 2001 From: Shivam Kumar Singh Date: Thu, 18 Nov 2021 12:14:46 +0530 Subject: [PATCH 47/58] Minor updates done for fixing #96 --- src/containers/Filter/ChallengeFilter/index.jsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index c9942b4..e41cc22 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -60,6 +60,19 @@ const ChallengeFilter = ({ const [totalPrizesFromError, setTotalPrizesFromError] = useState(null); const [totalPrizesToError, setTotalPrizesToError] = useState(null); + const [valTotalPrizesFrom, setValTotalPrizesFrom] = useState(totalPrizesFrom); + const [valTotalPrizesTo, setValTotalPrizesTo] = useState(totalPrizesTo); + + useEffect(() => { + ref.current.totalPrizesFrom = totalPrizesFrom; + setValTotalPrizesFrom(totalPrizesFrom); + }, [totalPrizesFrom]); + + useEffect(() => { + ref.current.totalPrizesTo = totalPrizesTo; + setValTotalPrizesTo(totalPrizesTo); + }, [totalPrizesTo]); + const onInputTotalPrizesFrom = useRef(_.debounce((f) => f(), 500)); const onInputTotalPrizesTo = useRef(_.debounce((f) => f(), 500)); @@ -159,7 +172,7 @@ const ChallengeFilter = ({ } else { setTotalPrizesFromError(null); } - totalPrizesFrom = value.toLocaleString("en-US"); + setValTotalPrizesFrom(value.toLocaleString("en-US")); if (totalPrizesToError) { return; } @@ -192,7 +205,7 @@ const ChallengeFilter = ({ } else { setTotalPrizesToError(null); } - totalPrizesTo = value.toLocaleString("en-US"); + setValTotalPrizesTo(value.toLocaleString("en-US")); if (totalPrizesFromError) { return; } From 6d2715d1df6d73757cbdf6b06a42c4b447d5f2b2 Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Thu, 18 Nov 2021 22:27:07 +0800 Subject: [PATCH 48/58] fix: lint --- .../DateRangePicker/DateInput/index.jsx | 8 ++- src/components/DateRangePicker/helpers.js | 7 ++- src/components/DropdownTerms/index.jsx | 2 +- src/components/NotFoundError/index.jsx | 8 +-- src/components/Pagination/index.jsx | 55 ++++++++++--------- src/containers/Challenges/Listing/index.jsx | 20 ++++--- src/containers/Challenges/index.jsx | 15 +++-- .../Submission/Submit/Uploading/index.jsx | 6 +- src/containers/challenge-detail/index.jsx | 8 ++- src/routers/challenge-list/index.jsx | 10 ++-- ...topcoder-micro-frontends-challenges-app.js | 4 +- src/utils/lifeCycle.js | 4 +- src/utils/url.js | 8 +-- 13 files changed, 88 insertions(+), 67 deletions(-) diff --git a/src/components/DateRangePicker/DateInput/index.jsx b/src/components/DateRangePicker/DateInput/index.jsx index 1c24b70..f543b52 100644 --- a/src/components/DateRangePicker/DateInput/index.jsx +++ b/src/components/DateRangePicker/DateInput/index.jsx @@ -20,7 +20,7 @@ const DateInput = ({ onClickCalendarIcon, onStartEndDateChange, placeholder, - enterToSubmit + enterToSubmit, }) => { const ref = useRef(null); const [focused, setFocused] = useState(false); @@ -127,11 +127,13 @@ const DateInput = ({ value={rangeText} onChange={(value) => { if (!enterToSubmit) { - onChangeRangeTextDebounced.current(() => onChangeRangeText(value)); + onChangeRangeTextDebounced.current(() => + onChangeRangeText(value) + ); } }} onEnterKey={(value) => { - onChangeRangeText(value) + onChangeRangeText(value); }} placeholder={placeholder} /> diff --git a/src/components/DateRangePicker/helpers.js b/src/components/DateRangePicker/helpers.js index 73f55d5..df745c9 100644 --- a/src/components/DateRangePicker/helpers.js +++ b/src/components/DateRangePicker/helpers.js @@ -51,7 +51,12 @@ const staticRangeHandler = { */ export function createStaticRanges() { const today = moment(); - const endOfToday = today.set({ hour: 23, minute: 59, second: 59, millisecond: 999 }); + const endOfToday = today.set({ + hour: 23, + minute: 59, + second: 59, + millisecond: 999, + }); const pastWeek = endOfToday.clone().subtract(1, "week"); const pastMonth = endOfToday.clone().subtract(1, "month"); const past6Months = endOfToday.clone().subtract(6, "month"); diff --git a/src/components/DropdownTerms/index.jsx b/src/components/DropdownTerms/index.jsx index c5ca31c..b605974 100644 --- a/src/components/DropdownTerms/index.jsx +++ b/src/components/DropdownTerms/index.jsx @@ -51,7 +51,7 @@ function DropdownTerms({ } }, [focused, selectedOption]); useEffect(() => { - setInternalTerms(terms); + setInternalTerms(terms); // eslint-disable-next-line react-hooks/exhaustive-deps }, [terms && terms.length]); const CustomReactSelectRow = React.forwardRef( diff --git a/src/components/NotFoundError/index.jsx b/src/components/NotFoundError/index.jsx index 4803798..72c7f02 100644 --- a/src/components/NotFoundError/index.jsx +++ b/src/components/NotFoundError/index.jsx @@ -8,12 +8,8 @@ const NotFoundError = ({ message }) => (
    not found
    -

    - 404 Not found -

    -

    - Sorry, we couldn’t find that page -

    +

    404 Not found

    +

    Sorry, we couldn’t find that page

    ); diff --git a/src/components/Pagination/index.jsx b/src/components/Pagination/index.jsx index 2e9cd68..ee625ef 100644 --- a/src/components/Pagination/index.jsx +++ b/src/components/Pagination/index.jsx @@ -59,35 +59,40 @@ const Pagination = ({ length, pageIndex, pageSize, onChange }) => { const [displayPages, setDisplayPages] = useState([]); useEffect(() => { - let _displayPages = displayPages; - - if (!previousPropsRef.current - || previousPropsRef.current.length !== length - || previousPropsRef.current.pageSize !== pageSize) { - const newTotal = Math.ceil(length / pageSize); - _displayPages = createDisplayPages(pageIndex, newTotal); - setDisplayPages(_displayPages) - } + let _displayPages = displayPages; + + if ( + !previousPropsRef.current || + previousPropsRef.current.length !== length || + previousPropsRef.current.pageSize !== pageSize + ) { + const newTotal = Math.ceil(length / pageSize); + _displayPages = createDisplayPages(pageIndex, newTotal); + setDisplayPages(_displayPages); + } - if (!previousPropsRef.current || previousPropsRef.current.pageIndex !== pageIndex) { - const start = _displayPages[0]; - const end = _displayPages[_displayPages.length - 1]; - - const updateDisplayPages = []; - if (pageIndex < start) { - for (let i = pageIndex; i < pageIndex + N; i += 1) { - updateDisplayPages.push(i); - } - setDisplayPages(updateDisplayPages); - } else if (pageIndex > end) { - for (let i = pageIndex; i > pageIndex - N; i -= 1) { - updateDisplayPages.unshift(i); - } - setDisplayPages(updateDisplayPages); + if ( + !previousPropsRef.current || + previousPropsRef.current.pageIndex !== pageIndex + ) { + const start = _displayPages[0]; + const end = _displayPages[_displayPages.length - 1]; + + const updateDisplayPages = []; + if (pageIndex < start) { + for (let i = pageIndex; i < pageIndex + N; i += 1) { + updateDisplayPages.push(i); } + setDisplayPages(updateDisplayPages); + } else if (pageIndex > end) { + for (let i = pageIndex; i > pageIndex - N; i -= 1) { + updateDisplayPages.unshift(i); + } + setDisplayPages(updateDisplayPages); } + } - previousPropsRef.current = { length, pageSize, pageIndex }; + previousPropsRef.current = { length, pageSize, pageIndex }; }, [length, pageSize, pageIndex, displayPages, setDisplayPages]); const formatPage = (p) => `${p + 1}`; diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 1997d5c..970ba11 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -37,15 +37,13 @@ const Listing = ({ const onSearch = useRef(_.debounce((f) => f(), 1000)); const onChangeSortBy = (newSortByOptions) => { - const selectedOption = utils.getSelectedDropdownOption( - newSortByOptions - ); + const selectedOption = utils.getSelectedDropdownOption(newSortByOptions); const filterChange = { sortBy: constants.CHALLENGE_SORT_BY[selectedOption.label], page: 1, }; updateFilter(filterChange); - } + }; return ( @@ -112,10 +110,13 @@ const Listing = ({
    - {challenges.length ? + {challenges.length ? ( {challenges.map((challenge, index) => ( -
    +
    { @@ -127,7 +128,7 @@ const Listing = ({ }} onClickTrack={(track) => { const filterChange = { - tracks: [track.replace('Quality Assurance', 'QA')], + tracks: [track.replace("Quality Assurance", "QA")], page: 1, }; updateFilter(filterChange); @@ -150,7 +151,10 @@ const Listing = ({ }} />
    - : } + + ) : ( + + )} ); }; diff --git a/src/containers/Challenges/index.jsx b/src/containers/Challenges/index.jsx index 86103f4..9ed26b9 100644 --- a/src/containers/Challenges/index.jsx +++ b/src/containers/Challenges/index.jsx @@ -40,13 +40,18 @@ const Challenges = ({ }, []); // reset pagination - if (page > 1 && challengesMeta.total && challengesMeta.total > 0 && challenges.length === 0) { + if ( + page > 1 && + challengesMeta.total && + challengesMeta.total > 0 && + challenges.length === 0 + ) { updateFilter({ - page: 1 - }) + page: 1, + }); updateQuery({ - page: 1 - }) + page: 1, + }); } const BUCKET_OPEN_FOR_REGISTRATION = constants.FILTER_BUCKETS[1]; diff --git a/src/containers/Submission/Submit/Uploading/index.jsx b/src/containers/Submission/Submit/Uploading/index.jsx index 4f77bed..9f83d8d 100644 --- a/src/containers/Submission/Submit/Uploading/index.jsx +++ b/src/containers/Submission/Submit/Uploading/index.jsx @@ -28,10 +28,12 @@ const Uploading = ({ if (propsRef.current.submitDone) { const backUrl = window.location.pathname; if (backUrl === `${CHALLENGES_URL}/${challengeId}`) { - navigate(`${CHALLENGES_URL}/${propsRef.current.challengeId}?reload=true`); + navigate( + `${CHALLENGES_URL}/${propsRef.current.challengeId}?reload=true` + ); } } - } + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( diff --git a/src/containers/challenge-detail/index.jsx b/src/containers/challenge-detail/index.jsx index 8af2c34..5720f19 100644 --- a/src/containers/challenge-detail/index.jsx +++ b/src/containers/challenge-detail/index.jsx @@ -253,9 +253,13 @@ class ChallengeDetailPageContainer extends React.Component { const query = new URLSearchParams(history.location.search); const isReloading = isLoadingChallenge || isLoadingTerms; - if (query.get('reload') && !isReloading) { + if (query.get("reload") && !isReloading) { history.replace(history.location.pathname, history.state); - loadChallengeDetails(nextProps.auth, challengeId, loadFullChallengeDetails); + loadChallengeDetails( + nextProps.auth, + challengeId, + loadFullChallengeDetails + ); return; } diff --git a/src/routers/challenge-list/index.jsx b/src/routers/challenge-list/index.jsx index a682dbb..6adcfb0 100644 --- a/src/routers/challenge-list/index.jsx +++ b/src/routers/challenge-list/index.jsx @@ -37,15 +37,15 @@ const App = () => { utils.url.updateQuery(params, true); } else { store.dispatch(actions.challenges.getChallengesInit()); - store.dispatch( - actions.challenges.getChallengesDone(currentFilter) - ); + store.dispatch(actions.challenges.getChallengesDone(currentFilter)); } - + return; } - let search = location.href.split('?').length ? '?' + location.href.split('?')[1]: '' + let search = location.href.split("?").length + ? "?" + location.href.split("?")[1] + : ""; const params = utils.url.parseUrlQuery(search); const toUpdate = utils.challenge.createChallengeFilter(params); diff --git a/src/topcoder-micro-frontends-challenges-app.js b/src/topcoder-micro-frontends-challenges-app.js index 7d4513e..1bb7678 100644 --- a/src/topcoder-micro-frontends-challenges-app.js +++ b/src/topcoder-micro-frontends-challenges-app.js @@ -14,9 +14,7 @@ const lifecycles = singleSpaReact({ rootComponent: Root, errorBoundary(err, info, props) { // Customize the root error boundary for your microfrontend here. - return ( - - ); + return ; }, }); diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index b363e48..3ccf7ff 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -17,7 +17,7 @@ export default function appInit() { async function mount() { try { if (firstMounted) { - if (initialQuery && urlPath === '/earn/find/challenges') { + if (initialQuery && urlPath === "/earn/find/challenges") { const params = utils.url.parseUrlQuery(initialQuery); const filter = utils.challenge.createChallengeFilter(params); store.dispatch(action.initApp(filter)); @@ -25,7 +25,7 @@ export default function appInit() { firstMounted = false; } } catch (error) { - console.error(error) + console.error(error); } finally { return Promise.resolve(); } diff --git a/src/utils/url.js b/src/utils/url.js index 1ace7ac..a2598c6 100644 --- a/src/utils/url.js +++ b/src/utils/url.js @@ -18,7 +18,7 @@ import qs from "qs"; export function buildQueryString(params, disableEncode) { params = _.omitBy(params, (p) => p == null || p === "" || p.length === 0); if (!disableEncode) { - params.tags = _.map(params.tags, (t) => encodeURIComponent(t)) + params.tags = _.map(params.tags, (t) => encodeURIComponent(t)); } let queryString = qs.stringify(params, { encode: false, @@ -30,11 +30,11 @@ export function buildQueryString(params, disableEncode) { } export function parseUrlQuery(queryString) { - let params = qs.parse(queryString, { ignoreQueryPrefix: true }); + let params = qs.parse(queryString, { ignoreQueryPrefix: true }); if (params.tags) { - params.tags = _.map(params.tags, (t) => decodeURIComponent(t)) + params.tags = _.map(params.tags, (t) => decodeURIComponent(t)); } - return params + return params; } export function updateQuery(params, replace = false) { From e476c4cbc534287f20c804fdbfb4b4d76ea27b99 Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Thu, 18 Nov 2021 22:57:53 +0800 Subject: [PATCH 49/58] fix: refine --- src/containers/Filter/ChallengeFilter/index.jsx | 15 --------------- src/utils/index.js | 5 ++++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index e6d0ba9..bdf2f16 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -60,19 +60,6 @@ const ChallengeFilter = ({ const [totalPrizesFromError, setTotalPrizesFromError] = useState(null); const [totalPrizesToError, setTotalPrizesToError] = useState(null); - const [valTotalPrizesFrom, setValTotalPrizesFrom] = useState(totalPrizesFrom); - const [valTotalPrizesTo, setValTotalPrizesTo] = useState(totalPrizesTo); - - useEffect(() => { - ref.current.totalPrizesFrom = totalPrizesFrom; - setValTotalPrizesFrom(totalPrizesFrom); - }, [totalPrizesFrom]); - - useEffect(() => { - ref.current.totalPrizesTo = totalPrizesTo; - setValTotalPrizesTo(totalPrizesTo); - }, [totalPrizesTo]); - const onInputTotalPrizesFrom = useRef(_.debounce((f) => f(), 500)); const onInputTotalPrizesTo = useRef(_.debounce((f) => f(), 500)); @@ -179,7 +166,6 @@ const ChallengeFilter = ({ } else { setTotalPrizesFromError(null); } - setValTotalPrizesFrom(value.toLocaleString("en-US")); if (totalPrizesToError) { return; } @@ -213,7 +199,6 @@ const ChallengeFilter = ({ } else { setTotalPrizesToError(null); } - setValTotalPrizesTo(value.toLocaleString("en-US")); if (totalPrizesFromError) { return; } diff --git a/src/utils/index.js b/src/utils/index.js index f389bef..ada0b97 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -163,8 +163,11 @@ export function parseTotalPrizes(s) { let n; if (valid) { n = +val.replace(/,/g, ""); - return n; + if (/,/.test(val)) { + valid = valid && n.toLocaleString("en-US") === val; + } } + return n; } export function triggerDownload(fileName, blob) { From acc82b69043f878255835fa8dda42a04c487f12d Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sat, 20 Nov 2021 00:34:49 +0800 Subject: [PATCH 50/58] restore ci --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eddbd3b..21fcb93 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,7 +77,6 @@ workflows: branches: only: - dev - - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. From 9674b03463c8958fb4202d1a91560bba46445643 Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sat, 20 Nov 2021 13:04:11 +0800 Subject: [PATCH 51/58] deploy bug bash --- .circleci/config.yml | 1 + src/containers/Filter/ChallengeFilter/index.jsx | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 21fcb93..eddbd3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,6 +77,7 @@ workflows: branches: only: - dev + - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index bdf2f16..33301e5 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -35,7 +35,7 @@ const ChallengeFilter = ({ // const BUCKET_OPEN_FOR_REGISTRATION = constants.FILTER_BUCKETS[1]; const tagOptions = utils.createDropdownTermOptions(challengeTags, tags); const bucketOptions = utils.createRadioOptions(challengeBuckets, bucket); - + const maxPrize = 100000; const caseSensitive = false; utils.setSelectedDropdownTermOptions(tagOptions, tags, caseSensitive); @@ -163,6 +163,9 @@ const ChallengeFilter = ({ if (value == null) { setTotalPrizesFromError("Invalid format"); return; + } else if (value > maxPrize) { + setTotalPrizesFromError("Too big"); + return; } else { setTotalPrizesFromError(null); } @@ -196,6 +199,9 @@ const ChallengeFilter = ({ if (value == null) { setTotalPrizesToError("Invalid format"); return; + } else if (value > maxPrize) { + setTotalPrizesFromError("Too big"); + return; } else { setTotalPrizesToError(null); } From 96f8055eb6a5d227b04b0ed1823903cab0fe49b5 Mon Sep 17 00:00:00 2001 From: Gaurav Seta Date: Sat, 20 Nov 2021 10:40:47 +0530 Subject: [PATCH 52/58] issue 91 fix (#169) * issue 91 fix * feedback fix --- src/components/TextInput/index.jsx | 3 +++ src/containers/Challenges/Listing/index.jsx | 1 + 2 files changed, 4 insertions(+) diff --git a/src/components/TextInput/index.jsx b/src/components/TextInput/index.jsx index 4ccca63..149cde7 100644 --- a/src/components/TextInput/index.jsx +++ b/src/components/TextInput/index.jsx @@ -18,6 +18,7 @@ function TextInput({ type, onEnterKey, readonly, + maxLength, }) { const [val, setVal] = useState(value); const delayedOnChange = useRef( @@ -41,6 +42,7 @@ function TextInput({ readOnly={readonly} defaultValue={value} type={type} + maxLength={maxLength} placeholder={`${placeholder}${placeholder && required ? " *" : ""}`} styleName={`${value || val ? "haveValue" : ""} ${ errorMsg ? "haveError" : "" @@ -85,6 +87,7 @@ TextInput.defaultProps = { type: "text", onEnterKey: () => {}, readonly: false, + maxLength: undefined, }; TextInput.propTypes = { diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index 970ba11..d2cd3e4 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -66,6 +66,7 @@ const Listing = ({ updateFilter(filterChange); }); }} + maxLength="100" />
    From 7c18600dc1e80cdd81e80b5bf06248091b89361d Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sat, 20 Nov 2021 13:24:12 +0800 Subject: [PATCH 53/58] adjustment --- src/containers/Filter/ChallengeFilter/index.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index 33301e5..2573dde 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -166,6 +166,9 @@ const ChallengeFilter = ({ } else if (value > maxPrize) { setTotalPrizesFromError("Too big"); return; + } else if (value >= totalPrizesTo) { + setTotalPrizesFromError("Too big"); + return; } else { setTotalPrizesFromError(null); } @@ -200,7 +203,10 @@ const ChallengeFilter = ({ setTotalPrizesToError("Invalid format"); return; } else if (value > maxPrize) { - setTotalPrizesFromError("Too big"); + setTotalPrizesToError("Too big"); + return; + } else if (value <= totalPrizesFrom) { + setTotalPrizesToError("Too small"); return; } else { setTotalPrizesToError(null); From 7ec9bca48b4165130c23f783735f2fa50eb4195a Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sat, 20 Nov 2021 14:27:36 +0800 Subject: [PATCH 54/58] restore ci --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eddbd3b..21fcb93 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,7 +77,6 @@ workflows: branches: only: - dev - - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. From c6766c54fb1662e7e12e35fcd8b876849de4e39b Mon Sep 17 00:00:00 2001 From: Nguyen Viet <36178659+nqviet@users.noreply.github.com> Date: Sun, 21 Nov 2021 19:12:42 +0700 Subject: [PATCH 55/58] issue #115 (#183) --- .../challenge-detail/Header/ChallengeTags.jsx | 19 +++++++++++++++++-- src/containers/challenge-detail/index.jsx | 3 +-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/components/challenge-detail/Header/ChallengeTags.jsx b/src/components/challenge-detail/Header/ChallengeTags.jsx index 7ca45e9..f4f8ef2 100644 --- a/src/components/challenge-detail/Header/ChallengeTags.jsx +++ b/src/components/challenge-detail/Header/ChallengeTags.jsx @@ -26,6 +26,8 @@ import { COMPETITION_TRACKS } from "utils/tc"; import VerifiedTag from "components/challenge-listing/VerifiedTag"; import MatchScore from "components/challenge-listing/ChallengeCard/MatchScore"; import { calculateScore } from "../../../utils/challenge-listing/helper"; +import * as urlUtil from "utils/url"; +import * as constants from "constants"; import "./style.module.scss"; export default function ChallengeTags(props) { @@ -75,6 +77,19 @@ export default function ChallengeTags(props) { const tags = technPlatforms.filter((tag) => !matchSkills.includes(tag)); + const filterByChallengeType = urlUtil.buildQueryString({ + bucket: constants.FILTER_BUCKETS[1], + tracks: _.values(constants.FILTER_CHALLENGE_TRACK_ABBREVIATIONS), + page: 1, + }); + + const filterByTag = urlUtil.buildQueryString({ + bucket: constants.FILTER_BUCKETS[1], + tracks: _.values(constants.FILTER_CHALLENGE_TRACK_ABBREVIATIONS), + page: 1, + types: _.values(constants.FILTER_CHALLENGE_TYPE_ABBREVIATIONS), + }); + return (
    {challengeType && ( @@ -84,7 +99,7 @@ export default function ChallengeTags(props) { setChallengeListingFilter({ types: [challengeType.name] }) ) } - to={`${challengesUrl}?types[]=${encodeURIComponent( + to={`${challengesUrl}${filterByChallengeType}&types[]=${encodeURIComponent( challengeType.abbreviation )}`} > @@ -112,7 +127,7 @@ export default function ChallengeTags(props) { onClick={() => setImmediate(() => setChallengeListingFilter({ tags: [tag] })) } - to={`${challengesUrl}?tags[]=${encodeURIComponent(tag)}`} + to={`${challengesUrl}${filterByTag}&tags[]=${encodeURIComponent(tag)}`} > {tag} diff --git a/src/containers/challenge-detail/index.jsx b/src/containers/challenge-detail/index.jsx index 5720f19..f3f3cfc 100644 --- a/src/containers/challenge-detail/index.jsx +++ b/src/containers/challenge-detail/index.jsx @@ -978,8 +978,7 @@ const mapDispatchToProps = (dispatch) => { } dispatch(updateFilter(change)); dispatch( - updateQuery({ ...stateProps.filter.challenge, ...change }), - change + updateQuery({ ...stateProps.filter.challenge, ...change }) ); }, setSpecsTabState: (state) => From eb3484bf7bf507d2ed5fd9d18c630a8e70c4258f Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sun, 21 Nov 2021 20:15:06 +0800 Subject: [PATCH 56/58] ci: deploying --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 21fcb93..eddbd3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,6 +77,7 @@ workflows: branches: only: - dev + - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch. From 74a668a00a921a63be41e083cf8f9c2ba5a0664d Mon Sep 17 00:00:00 2001 From: Nguyen Viet <36178659+nqviet@users.noreply.github.com> Date: Sun, 21 Nov 2021 19:20:07 +0700 Subject: [PATCH 57/58] fixed some issues (#184) * fixed issues: - detailed page navigation should not refresh the page - Joi validation of url query should return default values if not matched - missing QA track icon * fixed track -> [track] --- src/constants/index.js | 4 +- .../Listing/ChallengeItem/index.jsx | 20 ++++---- src/containers/Challenges/Listing/index.jsx | 2 +- .../Filter/ChallengeFilter/index.jsx | 2 +- src/reducers/challenges.js | 50 ++++++++----------- src/utils/challenge.js | 34 +++++++++---- src/utils/lifeCycle.js | 3 +- 7 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/constants/index.js b/src/constants/index.js index f679d1d..77faca2 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -29,14 +29,14 @@ export const FILTER_CHALLENGE_TRACKS = [ "Design", "Development", "Data Science", - "QA", + "Quality Assurance", ]; export const FILTER_CHALLENGE_TRACK_ABBREVIATIONS = { Design: "DES", Development: "DEV", "Data Science": "DS", - QA: "QA", + "Quality Assurance": "QA", }; export const CHALLENGE_SORT_BY = { diff --git a/src/containers/Challenges/Listing/ChallengeItem/index.jsx b/src/containers/Challenges/Listing/ChallengeItem/index.jsx index 82653ef..e9605b0 100644 --- a/src/containers/Challenges/Listing/ChallengeItem/index.jsx +++ b/src/containers/Challenges/Listing/ChallengeItem/index.jsx @@ -12,6 +12,8 @@ import * as utils from "../../../../utils"; import ProgressTooltip from "../tooltips/ProgressTooltip"; import PlacementsTooltip from "../tooltips/PlacementsTooltip"; import TagsMoreTooltip from "../tooltips/TagsMoreTooltip"; +import { CHALLENGES_URL } from 'constants'; +import { Link } from '@reach/router'; import "./styles.scss"; @@ -25,7 +27,7 @@ const ChallengeItem = ({ challenge, onClickTag, onClickTrack, isLoggedIn }) => { challenge.prizeSets ); - let submissionLink = `/earn/find/challenges/${challenge.id}`; + let submissionLink = `${CHALLENGES_URL}/${challenge.id}`; if (isLoggedIn && challenge.numOfSubmissions > 0) { submissionLink += "?tab=submissions"; } @@ -43,11 +45,11 @@ const ChallengeItem = ({ challenge, onClickTag, onClickTrack, isLoggedIn }) => {
    diff --git a/src/containers/Challenges/Listing/index.jsx b/src/containers/Challenges/Listing/index.jsx index d2cd3e4..e376d19 100644 --- a/src/containers/Challenges/Listing/index.jsx +++ b/src/containers/Challenges/Listing/index.jsx @@ -129,7 +129,7 @@ const Listing = ({ }} onClickTrack={(track) => { const filterChange = { - tracks: [track.replace("Quality Assurance", "QA")], + tracks: [track], page: 1, }; updateFilter(filterChange); diff --git a/src/containers/Filter/ChallengeFilter/index.jsx b/src/containers/Filter/ChallengeFilter/index.jsx index 2573dde..cc3e9ae 100644 --- a/src/containers/Filter/ChallengeFilter/index.jsx +++ b/src/containers/Filter/ChallengeFilter/index.jsx @@ -121,7 +121,7 @@ const ChallengeFilter = ({ updateFilter(filterChange); }} /> - {track} + {track.replace('Quality Assurance', 'QA')} ))}
    diff --git a/src/reducers/challenges.js b/src/reducers/challenges.js index 37fc947..31ae15a 100644 --- a/src/reducers/challenges.js +++ b/src/reducers/challenges.js @@ -17,14 +17,9 @@ function onGetChallengesInit(state) { return { ...state, loadingChallenges: true, loadingChallengesError: null }; } -function onGetChallengesDone(state, { payload }) { - const error = payload; - if (error.name === "AbortError") { - return { - ...state, - loadingChallenges: false, - loadingChallengesError: null, - }; +function onGetChallengesDone(state, { error, payload }) { + if (error) { + return onGetChallengesFailure(state, { payload }); } return { @@ -39,32 +34,31 @@ function onGetChallengesDone(state, { payload }) { }; } -// function onGetChallengesFailure(state, { payload }) { -// const error = payload; -// if (error.name === "AbortError") { -// return { -// ...state, -// loadingChallenges: false, -// loadingChallengesError: null, -// }; -// } +function onGetChallengesFailure(state, { payload }) { + const error = payload; + if (error.name === "AbortError") { + return { + ...state, + loadingChallenges: false, + loadingChallengesError: null, + }; + } -// return { -// ...state, -// loadingChallenges: false, -// loadingChallengesError: payload, -// challenges: [], -// total: 0, -// openForRegistrationCount: 0, -// initialized: true, -// }; -// } + return { + ...state, + loadingChallenges: false, + loadingChallengesError: payload, + challenges: [], + total: 0, + openForRegistrationCount: 0, + initialized: true, + }; +} export default handleActions( { GET_CHALLENGE_INIT: onGetChallengesInit, GET_CHALLENGES_DONE: onGetChallengesDone, - // GET_CHALLENGES_FAILURE: onGetChallengesFailure, }, defaultState ); diff --git a/src/utils/challenge.js b/src/utils/challenge.js index 5aca8a4..1775a04 100644 --- a/src/utils/challenge.js +++ b/src/utils/challenge.js @@ -6,34 +6,49 @@ import Joi from "joi"; import { initialChallengeFilter } from "../reducers/filter"; Joi.optionalId = () => Joi.string().uuid(); -Joi.page = () => Joi.number().integer().min(1); + +Joi.page = () => + Joi.alternatives() + .try( + Joi.number() + .min(1), + Joi.any().custom(() => 1) + ); + Joi.perPage = () => - Joi.number() - .integer() - .min(1) - .max(100) - .valid(...constants.PAGINATION_PER_PAGES); + Joi.alternatives() + .try( + Joi.number() + .integer() + .min(1) + .max(100) + .valid(...constants.PAGINATION_PER_PAGES), + Joi.any().custom(() => constants.PAGINATION_PER_PAGES[0]) + ); + Joi.bucket = () => Joi.string().custom((param) => constants.FILTER_BUCKETS.find( (bucket) => param && param.toLowerCase() === bucket.toLowerCase() - ) + ) || null ); + Joi.track = () => Joi.string().custom((param) => _.findKey( constants.FILTER_CHALLENGE_TRACK_ABBREVIATIONS, (trackAbbreviation) => param && param.toLowerCase() === trackAbbreviation.toLowerCase() - ) + ) || null ); + Joi.type = () => Joi.string().custom((param) => _.findKey( constants.FILTER_CHALLENGE_TYPE_ABBREVIATIONS, (typeAbbreviation) => param && param.toLowerCase() === typeAbbreviation.toLowerCase() - ) + ) || null ); export function getCurrencySymbol(prizeSets) { @@ -65,6 +80,7 @@ export function getCheckpointPrizes(prizeSets) { */ export function createChallengeFilter(params) { const schema = createChallengeFilter.schema; + const normalized = Joi.attempt( params, schema, diff --git a/src/utils/lifeCycle.js b/src/utils/lifeCycle.js index 3ccf7ff..0f64daf 100644 --- a/src/utils/lifeCycle.js +++ b/src/utils/lifeCycle.js @@ -1,6 +1,7 @@ import store from "../store"; import action from "../actions/initApp"; import * as utils from "../utils"; +import { CHALLENGES_URL } from '../constants'; export default function appInit() { let initialQuery; @@ -17,7 +18,7 @@ export default function appInit() { async function mount() { try { if (firstMounted) { - if (initialQuery && urlPath === "/earn/find/challenges") { + if (initialQuery && urlPath === CHALLENGES_URL) { const params = utils.url.parseUrlQuery(initialQuery); const filter = utils.challenge.createChallengeFilter(params); store.dispatch(action.initApp(filter)); From 6314460b17994eee8fa20202d8afb6f96ed8ae5a Mon Sep 17 00:00:00 2001 From: LieutenantRoger Date: Sun, 21 Nov 2021 21:27:05 +0800 Subject: [PATCH 58/58] ci: revert --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eddbd3b..21fcb93 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,7 +77,6 @@ workflows: branches: only: - dev - - challenges-bug-bash # Production builds are exectuted only on tagged commits to the # master branch.