diff --git a/package.json b/package.json
index c3681e5a40..d7b3c3337c 100644
--- a/package.json
+++ b/package.json
@@ -153,8 +153,8 @@
"supertest": "^3.1.0",
"tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3",
"tc-ui": "^1.0.12",
- "topcoder-react-lib": "1.2.10",
- "topcoder-react-ui-kit": "2.0.1",
+ "topcoder-react-lib": "1000.29.11",
+ "topcoder-react-ui-kit": "1000.1.2",
"topcoder-react-utils": "0.7.8",
"turndown": "^4.0.2",
"url-parse": "^1.4.1",
diff --git a/src/shared/components/ProfilePage/Awards/AwardBadge/index.jsx b/src/shared/components/ProfilePage/Awards/AwardBadge/index.jsx
index 39a2a126eb..1903b27c2f 100644
--- a/src/shared/components/ProfilePage/Awards/AwardBadge/index.jsx
+++ b/src/shared/components/ProfilePage/Awards/AwardBadge/index.jsx
@@ -17,6 +17,7 @@ const AwardBadge = ({
}
+ {/* eslint-disable-next-line react/no-danger */}
diff --git a/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx b/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx
index 7eb853efd1..081d958d84 100644
--- a/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx
+++ b/src/shared/components/challenge-detail/Header/DeadlinesPanel/index.jsx
@@ -35,7 +35,6 @@ export default function DeadlinesPanel({ deadlines }) {
}
}
if (index === deadlines.length - 1) {
- name = 'Winners Announced';
showRange = false;
}
diff --git a/src/shared/components/challenge-detail/Header/TabSelector/style.scss b/src/shared/components/challenge-detail/Header/TabSelector/style.scss
index f684f57548..33a3460bc2 100644
--- a/src/shared/components/challenge-detail/Header/TabSelector/style.scss
+++ b/src/shared/components/challenge-detail/Header/TabSelector/style.scss
@@ -133,8 +133,8 @@
.challenge-view-selector {
display: flex;
flex-wrap: wrap;
+ border-radius: 4px 0;
position: relative;
- padding-bottom: 10px;
border-bottom: silver solid 1px;
gap: 16px;
@@ -150,7 +150,7 @@
font-weight: 700;
line-height: 20px;
font-size: 14px;
- margin: 10px 10px 0;
+ padding: 10px 16px;
cursor: pointer;
white-space: nowrap;
position: relative;
@@ -158,6 +158,7 @@
.challenge-selected-view {
font-weight: 700 !important;
+ background: #bae1f9;
color: #2a2a2a;
&::after {
@@ -169,8 +170,8 @@
z-index: 100;
display: block;
position: absolute;
- top: 30px;
- left: 20%;
+ top: 40px;
+ left: 30%;
}
}
diff --git a/src/shared/components/challenge-detail/Header/index.jsx b/src/shared/components/challenge-detail/Header/index.jsx
index 9898b37059..3cd0d3328f 100644
--- a/src/shared/components/challenge-detail/Header/index.jsx
+++ b/src/shared/components/challenge-detail/Header/index.jsx
@@ -17,6 +17,9 @@ import { PrimaryButton } from 'topcoder-react-ui-kit';
import { Link } from 'topcoder-react-utils';
import { COMPETITION_TRACKS } from 'utils/tc';
import { phaseEndDate } from 'utils/challenge-listing/helper';
+import {
+ getTimeLeft,
+} from 'utils/challenge-detail/helper';
import LeftArrow from 'assets/images/arrow-prev.svg';
@@ -30,6 +33,10 @@ import TabSelector from './TabSelector';
import style from './style.scss';
+/* Holds day and hour range in ms. */
+const HOUR_MS = 60 * 60 * 1000;
+const DAY_MS = 24 * HOUR_MS;
+
export default function ChallengeHeader(props) {
const {
isLoggedIn,
@@ -108,6 +115,10 @@ export default function ChallengeHeader(props) {
registrationEnded = !regPhase.isOpen;
}
+ const currentPhases = challenge.phases
+ .filter(p => p.name !== 'Registration' && p.isOpen)
+ .sort((a, b) => moment(a.scheduledEndDate).diff(b.scheduledEndDate))[0];
+
const trackLower = track ? track.replace(' ', '-').toLowerCase() : 'design';
const eventNames = (events || []).map((event => (event.eventName || '').toUpperCase()));
@@ -128,6 +139,31 @@ export default function ChallengeHeader(props) {
*/
const hasSubmissions = !_.isEmpty(mySubmissions);
+ const openPhases = sortedAllPhases.filter(p => p.isOpen);
+ let nextPhase = openPhases[0];
+ if (hasRegistered && openPhases[0] && openPhases[0].name === 'Registration') {
+ nextPhase = openPhases[1] || {};
+ }
+
+ const deadlineEnd = moment(nextPhase && phaseEndDate(nextPhase));
+ const currentTime = moment();
+
+ const timeDiff = getTimeLeft(currentPhases, 'to go');
+
+ if (!timeDiff.late) {
+ timeDiff.text = timeDiff.text.replace('to go', '');
+ }
+
+ let timeLeft = deadlineEnd.isAfter(currentTime)
+ ? deadlineEnd.diff(currentTime) : 0;
+
+ let format;
+ if (timeLeft > DAY_MS) format = 'D[d] H[h]';
+ else if (timeLeft > HOUR_MS) format = 'H[h] m[min]';
+ else format = 'm[min] s[s]';
+
+ timeLeft = moment.duration(timeLeft).format(format);
+
let relevantPhases = [];
if (showDeadlineDetail) {
@@ -177,31 +213,52 @@ export default function ChallengeHeader(props) {
|| phaseEndDate(p).getTime() < endPhaseDate));
relevantPhases.push({
id: -1,
- name: 'Winners',
+ name: 'Winners Announced',
isOpen: false,
actualEndDate: endPhaseDate,
scheduledEndDate: endPhaseDate,
});
} else if (relevantPhases.length > 1) {
- const lastPhase = relevantPhases[relevantPhases.length - 1];
- const lastPhaseTime = phaseEndDate(lastPhase).getTime();
-
+ // const lastPhase = relevantPhases[relevantPhases.length - 1];
+ // const lastPhaseTime = phaseEndDate(lastPhase).getTime();
const appealsEndDate = phaseEndDate(sortedAllPhases[sortedAllPhases.length - 1]);
- const appealsEnd = appealsEndDate.getTime();
- if (lastPhaseTime < appealsEnd) {
- relevantPhases.push({
- id: -1,
- name: 'Winners',
- isOpen: false,
- actualEndDate: appealsEndDate,
- scheduledEndDate: appealsEndDate,
- });
- }
+ // const appealsEnd = appealsEndDate.getTime();
+ relevantPhases.push({
+ id: -1,
+ name: 'Winners Announced',
+ isOpen: false,
+ actualEndDate: appealsEndDate,
+ scheduledEndDate: appealsEndDate,
+ });
}
}
const checkpointCount = checkpoints && checkpoints.numberOfPassedScreeningSubmissions;
+ let nextDeadlineMsg;
+ switch ((status || '').toLowerCase()) {
+ case 'completed':
+ nextDeadlineMsg = (
+
+ The challenge is finished.
+
+ );
+ break;
+ case 'active':
+ break;
+ default:
+ nextDeadlineMsg = (
+
+ Status:
+
+
+ {_.upperFirst(_.lowerCase(status))}
+
+
+ );
+ break;
+ }
+
// Legacy MMs have a roundId field, but new MMs do not.
// This is used to disable registration/submission for legacy MMs.
const isLegacyMM = isMM(challenge) && Boolean(challenge.roundId);
@@ -340,7 +397,7 @@ export default function ChallengeHeader(props) {
onClick={unregisterFromChallenge}
theme={{
button: unregisterButtonDisabled
- ? style.submitButtonDisabled
+ ? style.unregisterButtonDisabled
: style.unregisterButton,
}}
>
@@ -366,23 +423,34 @@ export default function ChallengeHeader(props) {
Submit
{
- track === COMPETITION_TRACKS.DES && hasRegistered && !unregistering
+ track === COMPETITION_TRACKS.DES && hasRegistered && !unregistering
&& hasSubmissions && (
-
- View Submissions
-
- )
- }
+
+ View Submissions
+
+ )
+ }
- Competition Timeline
+ {nextDeadlineMsg}
+ {
+ (status || '').toLowerCase() === 'active'
+ && (
+
+ {currentPhases && `${currentPhases.name} Ends: `}
+
+ {timeDiff.text}
+
+
+ )
+ }
-
-
-
clearError()}
/>
) : undefined }
@@ -42,6 +43,7 @@ ErrorMessageContainer.propTypes = {
error: PT.shape({
title: PT.string.isRequired,
details: PT.string.isRequired,
+ support: PT.string.isRequired,
}),
};
diff --git a/src/shared/containers/challenge-detail/index.jsx b/src/shared/containers/challenge-detail/index.jsx
index fc026000f8..3347cb0216 100644
--- a/src/shared/containers/challenge-detail/index.jsx
+++ b/src/shared/containers/challenge-detail/index.jsx
@@ -192,6 +192,8 @@ class ChallengeDetailPageContainer extends React.Component {
reviewTypes,
getAllCountries,
getReviewTypes,
+ setCommunityId,
+ communityId,
} = this.props;
if (
@@ -220,6 +222,10 @@ class ChallengeDetailPageContainer extends React.Component {
loadChallengeDetails(auth, challengeId);
}
+ if (communityId) {
+ setCommunityId(communityId);
+ }
+
fetchChallengeStatistics(auth, challengeId);
if (!allCountries.length) {
@@ -746,6 +752,7 @@ ChallengeDetailPageContainer.propTypes = {
loadChallengeDetails: PT.func.isRequired,
fetchChallengeStatistics: PT.func.isRequired,
getAllCountries: PT.func.isRequired,
+ setCommunityId: PT.func.isRequired,
getReviewTypes: PT.func.isRequired,
// loadResults: PT.func.isRequired,
// loadingCheckpointResults: PT.bool,
@@ -919,6 +926,10 @@ const mapDispatchToProps = (dispatch) => {
dispatch(ca.getListInit(uuid));
dispatch(ca.getListDone(uuid, auth));
},
+ setCommunityId: (communityId) => {
+ const a = actions.challenge;
+ dispatch(a.setCommunityId(communityId));
+ },
getAllCountries: (tokenV3) => {
dispatch(lookupActions.getAllCountriesInit());
dispatch(lookupActions.getAllCountriesDone(tokenV3));