From 490c00bd9aafddc07f409302f06d0326ae0ed08a Mon Sep 17 00:00:00 2001 From: Cagdas U Date: Tue, 11 Aug 2020 12:00:02 +0300 Subject: [PATCH 01/21] fix(challenge-listing): sorting functions Fix for MOST_RECENT, TIME_TO_REGISTER and TIME_TO_SUBMIT sortings. * Since the V5 API returns inconistent values for (`registrationStartDate`, `registrationEndDate`, `submissionStartDate`, `submissionEndDate`), these dates will now be extracted from `challenge.phases` array. Reference topcoder-platform/community-app#4715, topcoder-platform/community-app#4716 --- src/shared/utils/challenge-listing/sort.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/shared/utils/challenge-listing/sort.js b/src/shared/utils/challenge-listing/sort.js index 8588f29048..4ef586d1f8 100644 --- a/src/shared/utils/challenge-listing/sort.js +++ b/src/shared/utils/challenge-listing/sort.js @@ -3,7 +3,7 @@ */ import moment from 'moment'; -import { sumBy } from 'lodash'; +import { find, sumBy } from 'lodash'; export const SORTS = { CURRENT_PHASE: 'current-phase', @@ -25,7 +25,15 @@ export default { name: 'Current phase', }, [SORTS.MOST_RECENT]: { - func: (a, b) => moment(b.registrationStartDate).diff(a.registrationStartDate), + func: (a, b) => { + const getRegistrationStartDate = (challenge) => { + const registrationPhase = find(challenge.phases, p => p.name === 'Registration'); + return registrationPhase.actualStartDate || registrationPhase.scheduledStartDate; + }; + const aRegistrationStartDate = getRegistrationStartDate(a); + const bRegistrationStartDate = getRegistrationStartDate(b); + return moment(bRegistrationStartDate).diff(aRegistrationStartDate); + }, name: 'Most recent', }, [SORTS.NUM_REGISTRANTS]: { @@ -42,8 +50,13 @@ export default { }, [SORTS.TIME_TO_REGISTER]: { func: (a, b) => { - const aDate = moment(a.registrationEndDate || a.submissionEndTimestamp); - const bDate = moment(b.registrationEndDate || b.submissionEndTimestamp); + const getRegistrationEndDate = (challenge) => { + const registrationPhase = find(challenge.phases, p => p.name === 'Registration'); + return registrationPhase.actualEndDate || registrationPhase.scheduledEndDate; + }; + + const aDate = moment(getRegistrationEndDate(a) || a.submissionEndTimestamp); + const bDate = moment(getRegistrationEndDate(b) || b.submissionEndTimestamp); if (aDate.isBefore() && bDate.isAfter()) return 1; if (aDate.isAfter() && bDate.isBefore()) return -1; From 1bf042d479608344e317995f4592b4c82a80d6dd Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Thu, 13 Aug 2020 09:15:19 +0530 Subject: [PATCH 02/21] ci: deploy on staging and test env --- .circleci/config.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 60c9bc9fd2..a5a599916a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -230,8 +230,7 @@ workflows: filters: branches: only: - - develop - - feature-contentful + - hot-fix # This is alternate dev env for parallel testing - "build-test": context : org-global @@ -245,21 +244,21 @@ workflows: filters: branches: only: - - develop + - hot-fix # This is beta env for production soft releases - "build-prod-beta": context : org-global filters: branches: only: - - integration-v5-challenge-api + - hot-fix # This is stage env for production QA releases - "build-prod-staging": context : org-global filters: branches: only: - - develop + - integration-v5-challenge-api # Production builds are exectuted # when PR is merged to the master # Don't change anything in this configuration From 75f0c022c6b205475cd91d3d57d6c068217742c5 Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Thu, 13 Aug 2020 16:46:57 +0530 Subject: [PATCH 03/21] fix: testing staging --- package-lock.json | 12 ++++++------ src/shared/utils/challenge-listing/buckets.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fbf39d9bb..6387811315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33162,9 +33162,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "topcoder-react-lib": { - "version": "1000.19.42", - "resolved": "https://registry.npmjs.org/topcoder-react-lib/-/topcoder-react-lib-1000.19.42.tgz", - "integrity": "sha512-+3VB+fEX4nVMxj8ZzpxH63WRkfOATyEdWqALfkPfah+494nGXYZfRESr11GWZzlMrHIP4ne2Ve3jslNY9Pax7w==", + "version": "1000.19.44", + "resolved": "https://registry.npmjs.org/topcoder-react-lib/-/topcoder-react-lib-1000.19.44.tgz", + "integrity": "sha512-WoBJbt5w50Hdho9xCzUFwCL/JOQLE0mfMCY3Y0YMUNAToieDpE2RloOwHZpqez+QgE1sxehLGQxlf61M9NZ95A==", "requires": { "auth0-js": "^6.8.4", "config": "^3.2.0", @@ -33394,9 +33394,9 @@ } }, "topcoder-react-ui-kit": { - "version": "1000.0.2", - "resolved": "https://registry.npmjs.org/topcoder-react-ui-kit/-/topcoder-react-ui-kit-1000.0.2.tgz", - "integrity": "sha512-IjKGiMuKLBsXvhGzMSzqRja6PiWBH2SojWFhc65mS5A7RLiwPL6wmi3cYY2DCiP+43HzStYp+9OnF7zifdck5Q==", + "version": "1000.0.4", + "resolved": "https://registry.npmjs.org/topcoder-react-ui-kit/-/topcoder-react-ui-kit-1000.0.4.tgz", + "integrity": "sha512-VvVvrVPhcnaJYLNv3YJLIY+CI+4sLLrhdqfulngMmTcUZft01BUorhMYEBtwhODrfotnx48GXnxu1TQmI3L6dA==", "requires": { "prop-types": "^15.6.2", "react": "^16.4.1", diff --git a/src/shared/utils/challenge-listing/buckets.js b/src/shared/utils/challenge-listing/buckets.js index 225203bc7b..1d83495beb 100644 --- a/src/shared/utils/challenge-listing/buckets.js +++ b/src/shared/utils/challenge-listing/buckets.js @@ -50,7 +50,7 @@ const BUCKET_DATA = { status: ['Active'], }, hideCount: false, - name: 'Open for registration', + name: 'Open for registration - this is for test - delete me', sorts: [ SORTS.MOST_RECENT, SORTS.TIME_TO_REGISTER, From 254ae1c52706c5dd45ba262dabc84721e4625b09 Mon Sep 17 00:00:00 2001 From: PrakashDurlabhji Date: Mon, 17 Aug 2020 23:46:45 +0530 Subject: [PATCH 04/21] Update index.jsx --- src/shared/components/challenge-detail/Specification/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/components/challenge-detail/Specification/index.jsx b/src/shared/components/challenge-detail/Specification/index.jsx index cbe1c9c619..06038c5ffa 100644 --- a/src/shared/components/challenge-detail/Specification/index.jsx +++ b/src/shared/components/challenge-detail/Specification/index.jsx @@ -59,7 +59,7 @@ export default function ChallengeDetailsView(props) { forumId, } = legacy; - const allowStockArt = _.find(metadata, { type: 'allowStockArt' }); + const allowStockArt = _.find(metadata, { name: 'allowStockArt' }).value; let environment = ''; const environmentData = _.find(metadata, { name: 'environment' }); if (environmentData) { From 1b32c1f9227a724f6f513a7f6c476bfc9e3fd2bb Mon Sep 17 00:00:00 2001 From: rashmi73 <41687423+rashmi73@users.noreply.github.com> Date: Tue, 18 Aug 2020 01:10:30 +0530 Subject: [PATCH 05/21] Update index.jsx --- .../challenge-detail/Specification/SideBar/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/components/challenge-detail/Specification/SideBar/index.jsx b/src/shared/components/challenge-detail/Specification/SideBar/index.jsx index c945832dbb..b2c5877bf5 100644 --- a/src/shared/components/challenge-detail/Specification/SideBar/index.jsx +++ b/src/shared/components/challenge-detail/Specification/SideBar/index.jsx @@ -36,13 +36,13 @@ export default function SideBar({ const scorecardURL = `${config.URL.ONLINE_REVIEW}/review/actions/ViewScorecard?scid=`; const faqURL = config.URL.INFO.DESIGN_CHALLENGE_SUBMISSION; let submissionLimitDisplay = 'Unlimited'; - const submissionLimit = _.find(metadata, { type: 'submissionLimit' }); + const submissionLimit = _.find(metadata, { name: 'submissionLimit' }); const fileTypes = _.find(metadata, { name: 'fileTypes' }); if (submissionLimit) { if (submissionLimit.value === 1) { submissionLimitDisplay = '1 submission'; - } else if (submissionLimit > 1) { + } else if (submissionLimit.value > 1) { submissionLimitDisplay = `${submissionLimit.value} submissions`; } } From 5cd686eed736ee3a14f0a5384beb61e9b9d037b9 Mon Sep 17 00:00:00 2001 From: Cagdas U Date: Tue, 18 Aug 2020 04:56:05 +0300 Subject: [PATCH 06/21] fix(challenge-listing): sorting by dates & phase displaying * Add `phaseStartDate` and `phaseEndDate` helper functions at `challenge-detail/helper` to get the correct start/end date of a phase. * `TIME_TO_REGISTER`, `TIME_TO_SUBMIT` and `MOST_RECENT` sorting functions updated to reflect above change. * `ProgressBarTooltip` and `ChallengeCard/Status` updated to display correct phase start/end dates. Addresses topcoder-platform/community-app#4715, topcoder-platform/community-app#4716 --- .../ChallengeCard/Status/index.jsx | 4 +- .../Tooltips/ProgressBarTooltip/index.jsx | 14 ++++--- src/shared/utils/challenge-detail/helper.jsx | 34 ++++++++++++++- src/shared/utils/challenge-listing/sort.js | 41 +++++++++++++++---- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx b/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx index 3cb06f6c46..921aa21076 100644 --- a/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx +++ b/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx @@ -7,7 +7,7 @@ import { config, Link } from 'topcoder-react-utils'; import { TABS as DETAIL_TABS } from 'actions/page/challenge-details'; import 'moment-duration-format'; import { - getTimeLeft, + getTimeLeft, phaseEndDate, } from 'utils/challenge-detail/helper'; import ChallengeProgressBar from '../../ChallengeProgressBar'; @@ -271,7 +271,7 @@ export default function ChallengeStatus(props) {
{getTimeLeft(statusPhase, 'to go').text} diff --git a/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx b/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx index 675e181bc4..ef83cee06e 100644 --- a/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx +++ b/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx @@ -18,6 +18,7 @@ import React from 'react'; import PT from 'prop-types'; import Tooltip from 'components/Tooltip'; import LoaderIcon from '../../../Loader/Loader'; +import { phaseStartDate, phaseEndDate } from '../../../../utils/challenge-detail/helper'; import './style.scss'; const getDate = date => moment(date).format('MMM DD'); @@ -95,31 +96,32 @@ function Tip(props) { if (!c || _.isEmpty(c)) return
; const allPhases = c.phases || []; - const endPhaseDate = Math.max(...allPhases.map(d => new Date(d.scheduledEndDate))); + const endPhaseDate = Math.max(...allPhases.map(d => phaseEndDate(d))); const registrationPhase = allPhases.find(phase => phase.name === 'Registration'); const submissionPhase = allPhases.find(phase => phase.name === 'Submission'); + const checkpointPhase = allPhases.find(phase => phase.name === 'Checkpoint Submission'); if (registrationPhase) { steps.push({ - date: new Date(registrationPhase.scheduledStartDate), + date: phaseStartDate(registrationPhase), name: 'Start', }); } - if (c.checkpointSubmissionEndDate) { + if (checkpointPhase) { steps.push({ - date: new Date(c.checkpointSubmissionEndDate), + date: phaseEndDate(checkpointPhase), name: 'Checkpoint', }); } const iterativeReviewPhase = allPhases.find(phase => phase.isOpen && phase.name === 'Iterative Review'); if (iterativeReviewPhase) { steps.push({ - date: new Date(iterativeReviewPhase.scheduledEndDate), + date: phaseEndDate(iterativeReviewPhase), name: 'Iterative Review', }); } else if (submissionPhase) { steps.push({ - date: new Date(submissionPhase.scheduledEndDate), + date: phaseEndDate(submissionPhase), name: 'Submission', }); } diff --git a/src/shared/utils/challenge-detail/helper.jsx b/src/shared/utils/challenge-detail/helper.jsx index 2a6fb4b8be..9e78f055a0 100644 --- a/src/shared/utils/challenge-detail/helper.jsx +++ b/src/shared/utils/challenge-detail/helper.jsx @@ -32,6 +32,36 @@ export function getChallengeTypeAbbr(track, challengeTypes) { return null; } +/** + * Returns phase's end date. + * @param {Object} phase + * @return {Date} + */ +export function phaseEndDate(phase) { + // Case 1: phase is still open. take the `scheduledEndDate` + // Case 2: phase is not open but `scheduledStartDate` is a future date. + // This means phase is not yet started. So take the `scheduledEndDate` + if (phase.isOpen || moment(phase.scheduledStartDate).isAfter()) { + return new Date(phase.scheduledEndDate); + } + // for other cases, take the `actualEndDate` as phase is already closed + return new Date(phase.actualEndDate); +} + +/** + * Returns phase's start date. + * @param {Object} phase + * @return {Date} + */ +export function phaseStartDate(phase) { + // Case 1: Phase is not yet started. take the `scheduledStartDate` + if (phase.isOpen !== true && moment(phase.scheduledStartDate).isAfter()) { + return new Date(phase.scheduledStartDate); + } + // For all other cases, take the `actualStartDate` as phase is already started + return new Date(phase.actualStartDate); +} + /** * Get end date * @param {Object} challenge challenge info @@ -42,7 +72,7 @@ export function getEndDate(challenge) { if (type === 'First2Finish' && challenge.status === 'Completed') { phases = challenge.phases.filter(p => p.phaseType === 'Iterative Review' && p.phaseStatus === 'Closed'); } - const endPhaseDate = Math.max(...phases.map(d => new Date(d.scheduledEndDate))); + const endPhaseDate = Math.max(...phases.map(d => phaseEndDate(d))); return moment(endPhaseDate).format('MMM DD'); } @@ -65,7 +95,7 @@ export function getTimeLeft( return { late: false, text: FF_TIME_LEFT_MSG }; } - let time = moment(phase.scheduledEndDate).diff(); + let time = moment(phaseEndDate(phase)).diff(); const late = time < 0; if (late) time = -time; diff --git a/src/shared/utils/challenge-listing/sort.js b/src/shared/utils/challenge-listing/sort.js index 4ef586d1f8..d1990931b9 100644 --- a/src/shared/utils/challenge-listing/sort.js +++ b/src/shared/utils/challenge-listing/sort.js @@ -4,6 +4,7 @@ import moment from 'moment'; import { find, sumBy } from 'lodash'; +import { phaseStartDate, phaseEndDate } from '../challenge-detail/helper'; export const SORTS = { CURRENT_PHASE: 'current-phase', @@ -27,12 +28,14 @@ export default { [SORTS.MOST_RECENT]: { func: (a, b) => { const getRegistrationStartDate = (challenge) => { + // extract the registration phase from `challenge.phases`, + // as `challenge.registrationStartDate` returned from API is not reliable const registrationPhase = find(challenge.phases, p => p.name === 'Registration'); - return registrationPhase.actualStartDate || registrationPhase.scheduledStartDate; + return moment(phaseStartDate(registrationPhase)); }; const aRegistrationStartDate = getRegistrationStartDate(a); const bRegistrationStartDate = getRegistrationStartDate(b); - return moment(bRegistrationStartDate).diff(aRegistrationStartDate); + return bRegistrationStartDate.diff(aRegistrationStartDate); }, name: 'Most recent', }, @@ -51,12 +54,20 @@ export default { [SORTS.TIME_TO_REGISTER]: { func: (a, b) => { const getRegistrationEndDate = (challenge) => { + // extract the registration phase from `challenge.phases`, + // as `challenge.registrationEndDate` returned from API is not reliable const registrationPhase = find(challenge.phases, p => p.name === 'Registration'); - return registrationPhase.actualEndDate || registrationPhase.scheduledEndDate; + const submissionPhase = find(challenge.phases, p => p.name === 'Submission'); + // case 1: registration phase exists + if (registrationPhase) { + return moment(phaseEndDate(registrationPhase)); + } + // case 2: registration phase doesn't exist. Take submission phase instead. + return moment(phaseEndDate(submissionPhase)); }; - const aDate = moment(getRegistrationEndDate(a) || a.submissionEndTimestamp); - const bDate = moment(getRegistrationEndDate(b) || b.submissionEndTimestamp); + const aDate = getRegistrationEndDate(a); + const bDate = getRegistrationEndDate(b); if (aDate.isBefore() && bDate.isAfter()) return 1; if (aDate.isAfter() && bDate.isBefore()) return -1; @@ -68,11 +79,23 @@ export default { }, [SORTS.TIME_TO_SUBMIT]: { func: (a, b) => { - function nextSubEndDate(o) { - if (o.checkpointSubmissionEndDate && moment(o.checkpointSubmissionEndDate).isAfter()) { - return moment(o.checkpointSubmissionEndDate); + function nextSubEndDate(challenge) { + // extract the submission and checkpoint (if any) phases from `challenge.phases`, + // as `challenge.submissionEndDate` returned from API is not reliable + const checkpointPhase = find(challenge.phases, p => p.name === 'Checkpoint Submission'); + const submissionPhase = find(challenge.phases, p => p.name === 'Submission'); + // Case 1: challenge has checkpoint submission phase + if (!!checkpointPhase === true) { + // Case 1.1: checkpoint submission phase is still open. + // then take the `scheduledEndDate` of this phase. + // Case 1.2: checkpoint submission phase is closed + // but its `scheduledStartDate` is a future date. + // This means this phase is not yet started. Take the `scheduledEndDate` of this phase. + if (checkpointPhase.isOpen || moment(checkpointPhase.scheduledStartDate).isAfter()) { + return moment(checkpointPhase.scheduledEndDate); + } } - return moment(o.submissionEndTimestamp); + return moment(phaseEndDate(submissionPhase)); } const aDate = nextSubEndDate(a); From 15a5023a483981882e3bfb73b79cb3b4998738d0 Mon Sep 17 00:00:00 2001 From: Cagdas U Date: Tue, 18 Aug 2020 06:45:27 +0300 Subject: [PATCH 07/21] fix(challenge-listing): `CURRENT_PHASE` sorting Addresses topcoder-platform/community-app#4129 --- src/shared/utils/challenge-listing/sort.js | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/shared/utils/challenge-listing/sort.js b/src/shared/utils/challenge-listing/sort.js index 4ef586d1f8..27a97696c8 100644 --- a/src/shared/utils/challenge-listing/sort.js +++ b/src/shared/utils/challenge-listing/sort.js @@ -21,7 +21,33 @@ export const SORTS = { export default { [SORTS.CURRENT_PHASE]: { - func: (a, b) => a.status.localeCompare(b.status), + func: (a, b) => { + const aPhases = a.phases || []; + const bPhases = b.phases || []; + const aPhase = aPhases + .filter(p => p.name !== 'Registration' && p.isOpen) + .sort((p1, p2) => moment(p1.scheduledEndDate).diff(p2.scheduledEndDate))[0]; + const bPhase = bPhases + .filter(p => p.name !== 'Registration' && p.isOpen) + .sort((p1, p2) => moment(p1.scheduledEndDate).diff(p2.scheduledEndDate))[0]; + + let aPhaseName = 'Stalled'; + let bPhaseName = 'Stalled'; + if (!aPhase && a.type === 'First2Finish' && aPhases.length) { + aPhaseName = 'Submission'; + } + if (!bPhase && b.type === 'First2Finish' && bPhases.length) { + bPhaseName = 'Submission'; + } + + if (aPhase) aPhaseName = aPhase.name; + else if (a.status === 'Draft') aPhaseName = 'Draft'; + + if (bPhase) bPhaseName = bPhase.name; + else if (b.status === 'Draft') bPhaseName = 'Draft'; + + return aPhaseName.localeCompare(bPhaseName); + }, name: 'Current phase', }, [SORTS.MOST_RECENT]: { From bae25468afa1a4eb0a1b4fc99699ee4d3e50dae5 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Tue, 18 Aug 2020 11:34:51 +0700 Subject: [PATCH 08/21] Fix Style in Challenge Page --- .../Specification/styles.scss | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/shared/components/challenge-detail/Specification/styles.scss b/src/shared/components/challenge-detail/Specification/styles.scss index e7ad57a1e0..04b3f00171 100644 --- a/src/shared/components/challenge-detail/Specification/styles.scss +++ b/src/shared/components/challenge-detail/Specification/styles.scss @@ -78,6 +78,8 @@ $tc-link-visited: #0c4e98; align-items: baseline; word-break: break-word; + @include linkStyle; + @include xs-to-sm { flex-direction: column; } @@ -118,7 +120,7 @@ $tc-link-visited: #0c4e98; } } -.h2 { +h2 { @include roboto-bold; font-size: 20px; @@ -127,7 +129,7 @@ $tc-link-visited: #0c4e98; margin: (6 * $base-unit) 0 (2 * $base-unit); } -.h3 { +h3 { @include roboto-bold; font-size: 15px; @@ -137,7 +139,17 @@ $tc-link-visited: #0c4e98; text-transform: uppercase; } -.p { +p, +em, +strong { + @include roboto-regular; + + font-size: 15px; + color: $tc-gray-90; + line-height: 25px; +} + +p { @include roboto-regular; font-size: 15px; @@ -149,7 +161,7 @@ $tc-link-visited: #0c4e98; margin: (2 * $base-unit) 0 (3 * $base-unit); } -.ul { +ul { @include roboto-regular; margin: 0 0 5px 20px; From d67a163e387315556081c5ea4025ac5e1d0d691b Mon Sep 17 00:00:00 2001 From: "Luiz R. Rodrigues" Date: Tue, 18 Aug 2020 03:24:51 -0300 Subject: [PATCH 09/21] Challenge Details - Fix submissions memberHandle --- .../challenge-detail/Submissions/index.jsx | 14 +++++++------- src/shared/containers/challenge-detail/index.jsx | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/shared/components/challenge-detail/Submissions/index.jsx b/src/shared/components/challenge-detail/Submissions/index.jsx index 4f54b38aff..b8e2e61c02 100644 --- a/src/shared/components/challenge-detail/Submissions/index.jsx +++ b/src/shared/components/challenge-detail/Submissions/index.jsx @@ -175,8 +175,8 @@ class SubmissionsComponent extends React.Component { valueA = `${a.member || ''}`.toLowerCase(); valueB = `${b.member || ''}`.toLowerCase(); } else { - valueA = `${a.createdBy}`.toLowerCase(); - valueB = `${b.createdBy}`.toLowerCase(); + valueA = _.get(a.registrant, 'memberHandle', ''); + valueB = _.get(b.registrant, 'memberHandle', ''); } valueIsString = true; break; @@ -314,12 +314,12 @@ class SubmissionsComponent extends React.Component { {`#${s.id}`} - {s.createdBy} + {_.get(s.registrant, 'memberHandle', '')}
@@ -705,7 +705,7 @@ class SubmissionsComponent extends React.Component { { !isMM && ( sortedSubmissions.map(s => ( -
+
{ !isF2F && !isBugHunt && (
@@ -715,12 +715,12 @@ class SubmissionsComponent extends React.Component { }
diff --git a/src/shared/containers/challenge-detail/index.jsx b/src/shared/containers/challenge-detail/index.jsx index 65cb2e339f..334758cd55 100644 --- a/src/shared/containers/challenge-detail/index.jsx +++ b/src/shared/containers/challenge-detail/index.jsx @@ -721,7 +721,7 @@ function mapStateToProps(state, props) { if (challenge.submissions) { challenge.submissions = challenge.submissions.map(submission => ({ ...submission, - registrant: _.find(challenge.registrants, { memberHandle: submission.createdBy }), + registrant: _.find(challenge.registrants, r => (`${r.memberId}` === `${submission.memberId}`)), })); } From 000c5990dc87390cc1b4e5f66f91da0ab682a628 Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Tue, 18 Aug 2020 13:43:55 +0530 Subject: [PATCH 10/21] ci: synched with integration develop --- package.json | 2 +- src/shared/utils/challenge-listing/buckets.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9ef32087c4..234d411548 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "tc-accounts": "git+https://github.com/appirio-tech/accounts-app.git#dev", "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3", "tc-ui": "^1.0.12", - "topcoder-react-lib": "1000.19.48", + "topcoder-react-lib": "1000.19.50", "topcoder-react-ui-kit": "1000.0.4", "topcoder-react-utils": "0.7.8", "turndown": "^4.0.2", diff --git a/src/shared/utils/challenge-listing/buckets.js b/src/shared/utils/challenge-listing/buckets.js index 1d83495beb..d091bff830 100644 --- a/src/shared/utils/challenge-listing/buckets.js +++ b/src/shared/utils/challenge-listing/buckets.js @@ -50,7 +50,7 @@ const BUCKET_DATA = { status: ['Active'], }, hideCount: false, - name: 'Open for registration - this is for test - delete me', + name: 'Open for registration - delete me', sorts: [ SORTS.MOST_RECENT, SORTS.TIME_TO_REGISTER, From dd90b49cf37501cc01f78a20b01c175a9e8eb11b Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Tue, 18 Aug 2020 13:46:31 +0530 Subject: [PATCH 11/21] ci: sync with integration develop --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 234d411548..84484a97e0 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "tc-accounts": "git+https://github.com/appirio-tech/accounts-app.git#dev", "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3", "tc-ui": "^1.0.12", - "topcoder-react-lib": "1000.19.50", + "topcoder-react-lib": "1000.19.51", "topcoder-react-ui-kit": "1000.0.4", "topcoder-react-utils": "0.7.8", "turndown": "^4.0.2", From 13599384b2471b58d9f2f3c148a87a733b90b2e9 Mon Sep 17 00:00:00 2001 From: "Luiz R. Rodrigues" Date: Tue, 18 Aug 2020 23:35:51 -0300 Subject: [PATCH 12/21] Redirect /challenge/legacyId/submit to /challenge/UUID/submit --- src/shared/containers/SubmissionPage.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/shared/containers/SubmissionPage.jsx b/src/shared/containers/SubmissionPage.jsx index da4e84aeba..80579b39ab 100644 --- a/src/shared/containers/SubmissionPage.jsx +++ b/src/shared/containers/SubmissionPage.jsx @@ -40,6 +40,19 @@ class SubmissionsPageContainer extends React.Component { getCommunitiesList(auth); } + componentWillReceiveProps() { + const { + challenge, + history, + } = this.props; + + const { details } = challenge; + + if (details && details.isLegacyChallenge && !history.location.pathname.includes(details.id)) { + history.push(`/challenges/${details.id}/submit`, history.state); + } + } + /* A child component has called their submitForm() prop, prepare the passed form data for submission and create a submit action */ handleSubmit(body) { @@ -150,6 +163,7 @@ SubmissionsPageContainer.propTypes = { submissionFilestackData: filestackDataProp.isRequired, winners: PT.arrayOf(PT.object).isRequired, loadChallengeDetails: PT.func.isRequired, + history: PT.shape().isRequired, }; /** From cf144341d0be17363cf1eb1393fcd8038bc86bce Mon Sep 17 00:00:00 2001 From: "Luiz R. Rodrigues" Date: Wed, 19 Aug 2020 23:14:41 -0300 Subject: [PATCH 13/21] updated isZurichCompetitor to use group 'oldId' instead 'id' --- src/shared/components/tc-communities/Header/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/components/tc-communities/Header/index.jsx b/src/shared/components/tc-communities/Header/index.jsx index ffc2e0862d..c610f947e6 100644 --- a/src/shared/components/tc-communities/Header/index.jsx +++ b/src/shared/components/tc-communities/Header/index.jsx @@ -55,7 +55,7 @@ function Header(props) { const AUTH_URL = config.URL.AUTH; const normalizedProfile = profile && _.clone(profile); const isZurichCompetitor = (profile && profile.groups) ? _.intersection( - _.map(profile.groups, 'id'), + _.map(profile.groups, 'oldId'), meta.competitorsGroupIds, ) : []; From 435212a9ab528daa8b0ca4a6cc130c5dac5945fd Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Thu, 20 Aug 2020 11:57:43 +0530 Subject: [PATCH 14/21] ci: deploy on dev as well --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 366712d55e..b8e19570b2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -231,7 +231,7 @@ workflows: branches: only: - hot-fix - - integration-v5-develop + - integration-v5-challenge-api - develop # This is alternate dev env for parallel testing - "build-test": @@ -239,7 +239,7 @@ workflows: filters: branches: only: - - integration-v5-challenge-api + - hot-fix # This is alternate dev env for parallel testing - "build-qa": context : org-global From f5e0e08c8023b66d5dec9727e9990bc663b91c72 Mon Sep 17 00:00:00 2001 From: M Fikri A Date: Thu, 20 Aug 2020 16:56:07 +0700 Subject: [PATCH 15/21] Fix Undefined StyleName --- .../challenge-detail/Specification/index.jsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/shared/components/challenge-detail/Specification/index.jsx b/src/shared/components/challenge-detail/Specification/index.jsx index cbe1c9c619..2200864a09 100644 --- a/src/shared/components/challenge-detail/Specification/index.jsx +++ b/src/shared/components/challenge-detail/Specification/index.jsx @@ -170,7 +170,7 @@ export default function ChallengeDetailsView(props) { description && (
-

+

Challenge Overview

{ @@ -195,7 +195,7 @@ export default function ChallengeDetailsView(props) { finalSubmissionGuidelines && (
-

+

Final Submission Guidelines

{ @@ -228,7 +228,7 @@ export default function ChallengeDetailsView(props) { description && (
-

+

Challenge Summary

{ @@ -246,8 +246,8 @@ export default function ChallengeDetailsView(props) { /> ) } -

-

+

+

Please read the challenge specification carefully and watch the forums for any questions or feedback concerning this challenge. It is important that you @@ -259,10 +259,10 @@ export default function ChallengeDetailsView(props) { ) }

-

+

How To Submit

-
    +
    • New to Studio? ‌ @@ -311,10 +311,10 @@ export default function ChallengeDetailsView(props) {
-

+

Winner Selection

-

+

Submissions are viewable to the client as they are entered into the challenge. Winners are selected by the client and are chosen solely at the client's discretion. @@ -324,13 +324,13 @@ export default function ChallengeDetailsView(props) { ) }

-

+

Payments

{ isWipro ? (
-

+

For employees of Wipro Technologies, following are the payment terms. Winner/s would be awarded the prize money on successful completion and acceptance of the submission by @@ -354,7 +354,7 @@ export default function ChallengeDetailsView(props) {

) : ( -

+

Topcoder will compensate members in accordance with our standard payment policies, unless otherwise specified in this challenge. For information on payment policies, setting up your profile to receive payments, and general payment questions, please refer to From f8c7b4c73657ac15e78afc033f31377b5da62b35 Mon Sep 17 00:00:00 2001 From: Cagdas U Date: Fri, 21 Aug 2020 01:54:36 +0300 Subject: [PATCH 16/21] fix(challenge-listing): fix failing test --- .../ChallengeCard/Status/index.jsx | 3 +- .../Tooltips/ProgressBarTooltip/index.jsx | 2 +- src/shared/utils/challenge-detail/helper.jsx | 31 +------------------ src/shared/utils/challenge-listing/helper.js | 31 +++++++++++++++++++ src/shared/utils/challenge-listing/sort.js | 20 +++++++----- 5 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 src/shared/utils/challenge-listing/helper.js diff --git a/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx b/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx index 921aa21076..d3315863aa 100644 --- a/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx +++ b/src/shared/components/challenge-listing/ChallengeCard/Status/index.jsx @@ -6,8 +6,9 @@ import LeaderboardAvatar from 'components/challenge-listing/LeaderboardAvatar'; import { config, Link } from 'topcoder-react-utils'; import { TABS as DETAIL_TABS } from 'actions/page/challenge-details'; import 'moment-duration-format'; +import { phaseEndDate } from 'utils/challenge-listing/helper'; import { - getTimeLeft, phaseEndDate, + getTimeLeft, } from 'utils/challenge-detail/helper'; import ChallengeProgressBar from '../../ChallengeProgressBar'; diff --git a/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx b/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx index ef83cee06e..432afcde8b 100644 --- a/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx +++ b/src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx @@ -17,8 +17,8 @@ import _ from 'lodash'; import React from 'react'; import PT from 'prop-types'; import Tooltip from 'components/Tooltip'; +import { phaseStartDate, phaseEndDate } from 'utils/challenge-listing/helper'; import LoaderIcon from '../../../Loader/Loader'; -import { phaseStartDate, phaseEndDate } from '../../../../utils/challenge-detail/helper'; import './style.scss'; const getDate = date => moment(date).format('MMM DD'); diff --git a/src/shared/utils/challenge-detail/helper.jsx b/src/shared/utils/challenge-detail/helper.jsx index 9e78f055a0..38b8317f90 100644 --- a/src/shared/utils/challenge-detail/helper.jsx +++ b/src/shared/utils/challenge-detail/helper.jsx @@ -9,6 +9,7 @@ import { challenge as challengeUtils } from 'topcoder-react-lib'; import { config } from 'topcoder-react-utils'; import Prize from 'components/challenge-listing/ChallengeCard/Prize'; import { BUCKETS, getBuckets } from 'utils/challenge-listing/buckets'; +import { phaseEndDate } from 'utils/challenge-listing/helper'; const Filter = challengeUtils.filter; @@ -32,36 +33,6 @@ export function getChallengeTypeAbbr(track, challengeTypes) { return null; } -/** - * Returns phase's end date. - * @param {Object} phase - * @return {Date} - */ -export function phaseEndDate(phase) { - // Case 1: phase is still open. take the `scheduledEndDate` - // Case 2: phase is not open but `scheduledStartDate` is a future date. - // This means phase is not yet started. So take the `scheduledEndDate` - if (phase.isOpen || moment(phase.scheduledStartDate).isAfter()) { - return new Date(phase.scheduledEndDate); - } - // for other cases, take the `actualEndDate` as phase is already closed - return new Date(phase.actualEndDate); -} - -/** - * Returns phase's start date. - * @param {Object} phase - * @return {Date} - */ -export function phaseStartDate(phase) { - // Case 1: Phase is not yet started. take the `scheduledStartDate` - if (phase.isOpen !== true && moment(phase.scheduledStartDate).isAfter()) { - return new Date(phase.scheduledStartDate); - } - // For all other cases, take the `actualStartDate` as phase is already started - return new Date(phase.actualStartDate); -} - /** * Get end date * @param {Object} challenge challenge info diff --git a/src/shared/utils/challenge-listing/helper.js b/src/shared/utils/challenge-listing/helper.js new file mode 100644 index 0000000000..192dafcc04 --- /dev/null +++ b/src/shared/utils/challenge-listing/helper.js @@ -0,0 +1,31 @@ +import moment from 'moment'; + +/** + * Returns phase's end date. + * @param {Object} phase + * @return {Date} + */ +export function phaseEndDate(phase) { + // Case 1: phase is still open. take the `scheduledEndDate` + // Case 2: phase is not open but `scheduledStartDate` is a future date. + // This means phase is not yet started. So take the `scheduledEndDate` + if (phase.isOpen || moment(phase.scheduledStartDate).isAfter()) { + return new Date(phase.scheduledEndDate); + } + // for other cases, take the `actualEndDate` as phase is already closed + return new Date(phase.actualEndDate); +} + +/** + * Returns phase's start date. + * @param {Object} phase + * @return {Date} + */ +export function phaseStartDate(phase) { + // Case 1: Phase is not yet started. take the `scheduledStartDate` + if (phase.isOpen !== true && moment(phase.scheduledStartDate).isAfter()) { + return new Date(phase.scheduledStartDate); + } + // For all other cases, take the `actualStartDate` as phase is already started + return new Date(phase.actualStartDate); +} diff --git a/src/shared/utils/challenge-listing/sort.js b/src/shared/utils/challenge-listing/sort.js index d1990931b9..bf6b52818f 100644 --- a/src/shared/utils/challenge-listing/sort.js +++ b/src/shared/utils/challenge-listing/sort.js @@ -4,7 +4,7 @@ import moment from 'moment'; import { find, sumBy } from 'lodash'; -import { phaseStartDate, phaseEndDate } from '../challenge-detail/helper'; +import { phaseStartDate, phaseEndDate } from './helper'; export const SORTS = { CURRENT_PHASE: 'current-phase', @@ -27,15 +27,21 @@ export default { }, [SORTS.MOST_RECENT]: { func: (a, b) => { - const getRegistrationStartDate = (challenge) => { - // extract the registration phase from `challenge.phases`, + const getChallengeStartDate = (challenge) => { + // extract the phases from `challenge.phases`, // as `challenge.registrationStartDate` returned from API is not reliable const registrationPhase = find(challenge.phases, p => p.name === 'Registration'); - return moment(phaseStartDate(registrationPhase)); + const submissionPhase = find(challenge.phases, p => p.name === 'Submission'); + // registration phase exists + if (registrationPhase) { + return moment(phaseStartDate(registrationPhase)); + } + // registration phase doesnt exist, This is possibly a F2F or TSK. Take submission phase + return moment(phaseStartDate(submissionPhase)); }; - const aRegistrationStartDate = getRegistrationStartDate(a); - const bRegistrationStartDate = getRegistrationStartDate(b); - return bRegistrationStartDate.diff(aRegistrationStartDate); + const aChallengeStartDate = getChallengeStartDate(a); + const bChallengeStartDate = getChallengeStartDate(b); + return bChallengeStartDate.diff(aChallengeStartDate); }, name: 'Most recent', }, From 38fea9fc17af9bfd093a8b3906f4115ff97af8a0 Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Fri, 21 Aug 2020 11:18:04 +0530 Subject: [PATCH 17/21] fix: null checking --- .../components/challenge-detail/Specification/index.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shared/components/challenge-detail/Specification/index.jsx b/src/shared/components/challenge-detail/Specification/index.jsx index e9f4f70ed3..96d728e4f5 100644 --- a/src/shared/components/challenge-detail/Specification/index.jsx +++ b/src/shared/components/challenge-detail/Specification/index.jsx @@ -59,7 +59,12 @@ export default function ChallengeDetailsView(props) { forumId, } = legacy; - const allowStockArt = _.find(metadata, { name: 'allowStockArt' }).value; + let stockArtValue = ''; + const allowStockArt = _.find(metadata, { name: 'allowStockArt' }); + if (allowStockArt) { + stockArtValue = allowStockArt.value; + } + let environment = ''; const environmentData = _.find(metadata, { name: 'environment' }); if (environmentData) { @@ -103,7 +108,7 @@ export default function ChallengeDetailsView(props) { const toolbarConnector = new ToolbarConnector(); const isSaving = specsTabState === SPECS_TAB_STATES.SAVING; - const stockArtText = allowStockArt + const stockArtText = stockArtValue ? 'Stock photography is allowed in this challenge.' : 'Stock photography is not allowed in this challenge. All submitted elements must be designed solely by you.'; From 7f0dede103547f33e44d7f15e5bafdf06dd40804 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Fri, 21 Aug 2020 12:39:04 +0300 Subject: [PATCH 18/21] Update Zurich groups #4797 --- src/server/tc-communities/zurich/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/tc-communities/zurich/metadata.json b/src/server/tc-communities/zurich/metadata.json index ba07aad20a..3dcf506b34 100644 --- a/src/server/tc-communities/zurich/metadata.json +++ b/src/server/tc-communities/zurich/metadata.json @@ -12,7 +12,7 @@ "communityId": "zurich", "communityName": "Zurich Community", "groupIds": ["20000145"], - "authorizedGroupIdsCatalog": ["20000160", "20000161"], + "authorizedGroupIdsCatalog": ["c40767a9-e02e-4872-87eb-d50dcb946055", "a1bcb865-7235-481f-ae62-b82dd958fc4c"], "competitorsGroupIds": ["20000226"], "logos": [{ "img": "/community-app-assets/themes/zurich/zurich.svg", From 1bb2499c1413465e5f86df5d1036764ff8a03726 Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Fri, 21 Aug 2020 15:19:15 +0530 Subject: [PATCH 19/21] ci: deploy on staging and develop --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e2bbcef814..b7220115d5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -258,7 +258,7 @@ workflows: filters: branches: only: - - hot-fix + - develop # Production builds are exectuted # when PR is merged to the master # Don't change anything in this configuration From a95a319c8bbc19eb09ddd96e8b0c7c4230450a3f Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Mon, 24 Aug 2020 14:50:43 +0530 Subject: [PATCH 20/21] fix: remove delete me --- src/shared/utils/challenge-listing/buckets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/utils/challenge-listing/buckets.js b/src/shared/utils/challenge-listing/buckets.js index d091bff830..225203bc7b 100644 --- a/src/shared/utils/challenge-listing/buckets.js +++ b/src/shared/utils/challenge-listing/buckets.js @@ -50,7 +50,7 @@ const BUCKET_DATA = { status: ['Active'], }, hideCount: false, - name: 'Open for registration - delete me', + name: 'Open for registration', sorts: [ SORTS.MOST_RECENT, SORTS.TIME_TO_REGISTER, From 4ad00c52d90602e1ae00a250a974ddc9590c0a0c Mon Sep 17 00:00:00 2001 From: Sushil Shinde Date: Mon, 24 Aug 2020 15:03:02 +0530 Subject: [PATCH 21/21] ci: deploy on staging and dev --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 35f86a19b6..c0b8f6fccb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -230,7 +230,7 @@ workflows: filters: branches: only: - - i-v5-develop-24Aug + - develop # This is alternate dev env for parallel testing - "build-test": context : org-global @@ -251,14 +251,14 @@ workflows: filters: branches: only: - - develop + - hot-fix # This is stage env for production QA releases - "build-prod-staging": context : org-global filters: branches: only: - - i-v5-develop-24Aug + - develop # Production builds are exectuted # when PR is merged to the master # Don't change anything in this configuration