Skip to content

Commit 6e9b1b1

Browse files
Merge pull request #21 from topcoder-platform/integration-v5-challenge-api
Integration v5 challenge api
2 parents 4b51669 + fa4908d commit 6e9b1b1

File tree

15 files changed

+255
-105
lines changed

15 files changed

+255
-105
lines changed

config/default.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,4 @@ module.exports = {
401401
TC_EDU_ARTICLES_PATH: '/articles',
402402
TC_EDU_SEARCH_PATH: '/search',
403403
TC_EDU_SEARCH_BAR_MAX_RESULTS_EACH_GROUP: 3,
404-
// SRM ChallengeType ID
405-
SRM_TYPE_ID: '7494c009-b425-45c5-923a-fd3a6ace3196',
406404
};

package-lock.json

Lines changed: 166 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
"filestack-react": "^2.0.0",
6363
"flag-icon-css": "^3.3.0",
6464
"focus-trap-react": "^6.0.0",
65-
"react-ga": "^2.7.0",
6665
"helmet": "^3.12.1",
6766
"highlight.js": "^9.18.1",
6867
"html-to-text": "^5.1.1",
@@ -100,12 +99,14 @@
10099
"react-dates": "^18.2.2",
101100
"react-dom": "^16.4.1",
102101
"react-dotdotdot": "^1.3.1",
102+
"react-ga": "^2.7.0",
103103
"react-helmet": "^5.2.0",
104104
"react-html-parser": "^2.0.2",
105105
"react-image-fallback": "^7.1.0",
106106
"react-image-filter": "^0.1.2",
107107
"react-infinite-scroller": "^1.1.4",
108108
"react-inlinesvg": "^0.8.4",
109+
"react-markdown": "^4.3.1",
109110
"react-player": "^0.24.1",
110111
"react-redux": "^5.0.7",
111112
"react-redux-toastr": "^7.2.6",
@@ -134,7 +135,7 @@
134135
"tc-accounts": "git+https://github.com/appirio-tech/accounts-app.git#dev",
135136
"tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3",
136137
"tc-ui": "^1.0.12",
137-
"topcoder-react-lib": "1000.19.4",
138+
"topcoder-react-lib": "1000.19.6",
138139
"topcoder-react-ui-kit": "^1.0.11",
139140
"topcoder-react-utils": "0.7.8",
140141
"turndown": "^4.0.2",

src/shared/actions/challenge-listing/index.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { decodeToken } from 'tc-accounts';
88
import 'isomorphic-fetch';
99
import { processSRM } from 'utils/tc';
1010
import { errors, services } from 'topcoder-react-lib';
11-
import { config } from 'topcoder-react-utils';
1211

1312
const { fireErrorMessage } = errors;
1413
const { getService } = services.challenge;
@@ -292,11 +291,7 @@ function getSrmsInit(uuid) {
292291
*/
293292
function getSrmsDone(uuid, handle, params, tokenV3) {
294293
const service = getService(tokenV3);
295-
const newParams = {
296-
...params,
297-
typeId: config.SRM_TYPE_ID,
298-
};
299-
const promises = [service.getSrms(newParams)];
294+
const promises = [service.getSrms(params)];
300295
if (handle) {
301296
promises.push(service.getUserSrms(handle, params));
302297
}

src/shared/components/Dashboard/CurrentActivity/Challenges/ChallengeCard/index.jsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,17 @@ export default function ChallengeCard({
4646
}) {
4747
const {
4848
currentPhases,
49-
forumId,
49+
legacy,
5050
id,
5151
registrationStartDate,
5252
status,
5353
subTrack,
54-
track,
5554
userDetails,
5655
} = challenge;
5756

5857
let EventTag;
5958
// let TrackTag;
60-
switch (track) {
59+
switch (legacy.track) {
6160
case 'DATA_SCIENCE':
6261
EventTag = DataScienceTrackEventTag;
6362
// TrackTag = DataScienceTrackTag;
@@ -73,9 +72,9 @@ export default function ChallengeCard({
7372
default:
7473
}
7574

76-
const forumEndpoint = _.toLower(track) === 'design'
77-
? `/?module=ThreadList&forumID=${forumId}`
78-
: `/?module=Category&categoryID=${forumId}`;
75+
const forumEndpoint = _.toLower(legacy.track) === 'design'
76+
? `/?module=ThreadList&forumID=${legacy.forumId}`
77+
: `/?module=Category&categoryID=${legacy.forumId}`;
7978

8079
const isTco = challenge.events
8180
&& challenge.events.find(x => x.eventName.match(/tco\d{2}/));
@@ -275,10 +274,12 @@ export default function ChallengeCard({
275274

276275
ChallengeCard.propTypes = {
277276
challenge: PT.shape({
278-
forumId: PT.number.isRequired,
279-
id: PT.number.isRequired,
277+
legacy: PT.shape({
278+
track: PT.oneOf(['DATA_SCIENCE', 'DESIGN', 'DEVELOP']).isRequired,
279+
forumId: PT.oneOfType([PT.number, PT.string]),
280+
}).isRequired,
281+
id: PT.oneOfType([PT.number, PT.string]).isRequired,
280282
name: PT.string.isRequired,
281-
track: PT.oneOf(['DATA_SCIENCE', 'DESIGN', 'DEVELOP']).isRequired,
282283
currentPhases: PT.any,
283284
registrationStartDate: PT.any,
284285
status: PT.any,

src/shared/components/SubmissionPage/Submit/index.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ class Submit extends React.Component {
8080
let subPhaseId;
8181

8282
// Submission type logic
83-
if (checkpoint && checkpoint.isActive) {
83+
if (checkpoint && checkpoint.isOpen) {
8484
subType = 'Checkpoint Submission';
8585
subPhaseId = checkpoint.id;
86-
} else if (checkpoint && !checkpoint.isActive && submission && submission.isActive) {
86+
} else if (checkpoint && !checkpoint.isOpen && submission && submission.isOpen) {
8787
subType = 'Contest Submission';
8888
subPhaseId = submission.id;
89-
} else if (finalFix && finalFix.isActive) {
89+
} else if (finalFix && finalFix.isOpen) {
9090
subType = 'Studio Final Fix Submission';
9191
subPhaseId = finalFix.id;
9292
} else {

src/shared/components/challenge-detail/Header/ChallengeTags.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export default function ChallengeTags(props) {
3636
/* TODO: Probably, we don't need this anymore, if we use correct data from
3737
* APIs (they should contain human-readable names, I believe). */
3838
const stylizedSubTrack = (t) => {
39-
if (challengeSubtracksMap[t]) {
40-
return challengeSubtracksMap[t].name;
39+
const filteredSubtrack = Object.values(challengeSubtracksMap)
40+
.filter(subtrack => subtrack.abbreviation === t)[0];
41+
if (filteredSubtrack) {
42+
return filteredSubtrack.name;
4143
}
4244
return (t || '').replace(/_/g, ' ')
4345
.replace(/\w\S*/g, txt => _.capitalize(txt));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import PT from 'prop-types';
2+
import React from 'react';
3+
import Markdown from 'react-markdown';
4+
5+
export default function SpecificationComponent({
6+
bodyText,
7+
format,
8+
}) {
9+
if (format === 'markdown') {
10+
return (<Markdown source={bodyText} />);
11+
}
12+
return (
13+
<div
14+
/* eslint-disable react/no-danger */
15+
dangerouslySetInnerHTML={{
16+
__html: bodyText,
17+
}}
18+
/* eslint-enable react/no-danger */
19+
/* styleName="rawHtml" */
20+
/>
21+
);
22+
}
23+
24+
SpecificationComponent.defaultProps = {
25+
bodyText: '',
26+
format: 'HTML',
27+
};
28+
29+
SpecificationComponent.propTypes = {
30+
bodyText: PT.string,
31+
format: PT.string,
32+
};

src/shared/components/challenge-detail/Specification/index.jsx

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { isMM } from 'utils/challenge';
1515
import PT from 'prop-types';
1616
import { DangerButton } from 'topcoder-react-ui-kit';
1717
import { SPECS_TAB_STATES } from 'actions/page/challenge-details';
18+
import SpecificationComponent from './SpecificationComponent';
1819
// import { editorStateToHTML } from 'utils/editor';
1920

2021
import SaveConfirmationModal from './SaveConfirmationModal';
@@ -40,6 +41,7 @@ export default function ChallengeDetailsView(props) {
4041
groups,
4142
description,
4243
privateDescription,
44+
descriptionFormat,
4345
legacy,
4446
documents,
4547
finalSubmissionGuidelines,
@@ -166,13 +168,9 @@ export default function ChallengeDetailsView(props) {
166168
ref={n => n && n.setHtml(description)}
167169
/>
168170
) : (
169-
<div
170-
/* eslint-disable react/no-danger */
171-
dangerouslySetInnerHTML={{
172-
__html: description,
173-
}}
174-
/* eslint-enable react/no-danger */
175-
styleName="rawHtml"
171+
<SpecificationComponent
172+
bodyText={description}
173+
format={descriptionFormat}
176174
/>
177175
)
178176
}
@@ -228,13 +226,9 @@ export default function ChallengeDetailsView(props) {
228226
ref={n => n && n.setHtml(privateDescription)}
229227
/>
230228
) : (
231-
<div
232-
/* eslint-disable react/no-danger */
233-
dangerouslySetInnerHTML={{
234-
__html: privateDescription,
235-
}}
236-
/* eslint-enable react/no-danger */
237-
styleName="rawHtml"
229+
<SpecificationComponent
230+
bodyText={privateDescription}
231+
format={descriptionFormat}
238232
/>
239233
)
240234
}
@@ -266,13 +260,9 @@ export default function ChallengeDetailsView(props) {
266260
ref={n => n && n.setHtml(privateDescription)}
267261
/>
268262
) : (
269-
<div
270-
/* eslint-disable react/no-danger */
271-
dangerouslySetInnerHTML={{
272-
__html: privateDescription,
273-
}}
274-
/* eslint-enable react/no-danger */
275-
styleName="rawHtml"
263+
<SpecificationComponent
264+
bodyText={privateDescription}
265+
format={descriptionFormat}
276266
/>
277267
)
278268
}
@@ -446,6 +436,7 @@ ChallengeDetailsView.defaultProps = {
446436
numberOfCheckpointsPrizes: 0,
447437
finalSubmissionGuidelines: '',
448438
environment: '',
439+
descriptionFormat: 'HTML',
449440
codeRepo: '',
450441
metadata: {},
451442
events: [],
@@ -459,6 +450,7 @@ ChallengeDetailsView.propTypes = {
459450
hasRegistered: PT.bool.isRequired,
460451
challenge: PT.shape({
461452
description: PT.string,
453+
descriptionFormat: PT.string,
462454
documents: PT.any,
463455
id: PT.any,
464456
subTrack: PT.any,

src/shared/components/challenge-detail/Submissions/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class SubmissionsComponent extends React.Component {
245245

246246
let isReviewPhaseComplete = false;
247247
_.forEach(allPhases, (phase) => {
248-
if (phase.name === 'Review' && !phase.isActive) {
248+
if (phase.name === 'Review' && !phase.isOpen) {
249249
isReviewPhaseComplete = true;
250250
}
251251
});

src/shared/components/challenge-listing/ChallengeCard/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function ChallengeCard({
5757
}
5858

5959
const registrationPhase = (challenge.allPhases || challenge.phases || []).filter(phase => phase.name === 'Registration')[0];
60-
const isRegistrationOpen = registrationPhase ? registrationPhase.isActive : false;
60+
const isRegistrationOpen = registrationPhase ? registrationPhase.isOpen : false;
6161

6262
return (
6363
<div ref={domRef} styleName="challengeCard">

src/shared/components/challenge-listing/Tooltips/ProgressBarTooltip/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function Tip(props) {
111111
name: 'Checkpoint',
112112
});
113113
}
114-
const iterativeReviewPhase = allPhases.find(phase => phase.isActive && phase.name === 'Iterative Review');
114+
const iterativeReviewPhase = allPhases.find(phase => phase.isOpen && phase.name === 'Iterative Review');
115115
if (iterativeReviewPhase) {
116116
steps.push({
117117
date: new Date(iterativeReviewPhase.scheduledEndDate),

src/shared/components/challenge-listing/Tooltips/TrackAbbreviationTooltip/index.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,28 @@ const DESCRIPTION = {
2323
DEVELOPMENT: 'Develop code for apps, services, etc. Final fixes are not included',
2424
TEST_SCENARIOS: 'Provide simple, easy information about what to test',
2525
CONTENT_CREATION: 'Generate topic ideas as a blog, video, infographic, or other format',
26+
IDEA_GENERATION: 'Generate feasible concepts for products, apps, features, etc',
2627
SPECIFICATION: 'Document requirements to be satisfied for design, product, or service',
2728
TASK: 'An assigned piece of work',
2829
AUTOMATED_TESTING: 'Challenges were submissions are auto-scored against a set of automated test cases',
2930
COPILOT_POSTING: 'A post made to the copilot community which asks them to come back with a proposal for your project. This proposal typically includes a suggested gameplan, an estimated budget and their take on what approach to use.',
31+
SPEC_REVIEW: 'Review of technical writing of requirements for the scope of work',
32+
MARATHON: 'Programming competition',
3033
DESIGN: 'Prepare the visual sketch or the plans for a website, feature, app, etc',
3134
TEST_SUITES: 'Develop test cases to be used to validate apps, website, etc.',
3235
CONCEPTUALIZATION: 'Discover and define user stories and requirements',
36+
DESIGN_FIRST2FINISH: 'Be the first to deliver the design solution',
3337
DESIGN_FIRST_2_FINISH: 'Be the first to deliver the design solution',
3438
FIRST_2_FINISH: 'Be the first to deliver the development solution',
39+
FIRST2FINISH: 'Be the first to deliver the development solution',
3540
LOGO_DESIGN: 'Logo Design',
3641
MARATHON_MATCH: 'Write algorithms to solve complex problems, often for real world issues',
3742
DEVELOP_MARATHON_MATCH: 'Write algorithms to solve complex problems, often for real world issues',
3843
PRINT_OR_PRESENTATION: 'Design print and presentation assets',
3944
SRM: 'Single Round Match - quickly write code to solve algorythm problems head to head against other competitors',
4045
STUDIO_OTHER: 'Studio other',
4146
UI_PROTOTYPE_COMPETITION: 'Develop the front end of a UX',
47+
WEB_DESIGN: 'Design UI and front end experiences for web experiences',
4248
WEB_DESIGNS: 'Design UI and front end experiences for web experiences',
4349
WIDGET_OR_MOBILE_SCREEN_DESIGN: 'Design UI and front end experiences for mobile',
4450
WIREFRAMES: 'Produce the information architecture for user experiences',
@@ -56,20 +62,26 @@ const HEADER = {
5662
TEST_SUITES: 'Test Suites (TS)',
5763
TEST_SCENARIOS: 'Test Scenarios (Ts)',
5864
CONTENT_CREATION: 'Content Creation (CC)',
65+
IDEA_GENERATION: 'Idea Generation (IG)',
5966
SPECIFICATION: 'Specification (Sp)',
6067
TASK: 'Task (Tk)',
6168
AUTOMATED_TESTING: 'Automated Testing (AT)',
6269
COPILOT_POSTING: 'Copilot Posting (CP)',
70+
SPEC_REVIEW: 'Specification Review (SR)',
71+
MARATHON: 'Marathon (MM)',
6372
DESIGN: 'Design (Ds)',
6473
CONCEPTUALIZATION: 'Conceptualization (Cn)',
74+
DESIGN_FIRST2FINISH: 'Design First2Finish(DF2F)',
6575
DESIGN_FIRST_2_FINISH: 'Design First2Finish(DF2F)',
76+
FIRST2FINISH: 'First2Finish (F2F)',
6677
FIRST_2_FINISH: 'First2Finish (F2F)',
6778
LOGO_DESIGN: 'Logo Design (Lg)',
6879
MARATHON_MATCH: 'Marathon Match (MM)',
6980
DEVELOP_MARATHON_MATCH: 'Marathon Match (MM)',
7081
PRINT_OR_PRESENTATION: 'Print/Presentation (PP)',
7182
SRM: 'Single Round Match (SRM)',
7283
UI_PROTOTYPE_COMPETITION: 'UI Prototype (Pr)',
84+
WEB_DESIGN: 'Web Design (Wb)',
7385
WEB_DESIGNS: 'Web Design (Wb)',
7486
WIDGET_OR_MOBILE_SCREEN_DESIGN: 'Widget or Mobile Screen Design (Wg)',
7587
STUDIO_OTHER: 'Generic design challenge (D)',

src/shared/containers/Dashboard/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ function mapStateToProps(state, props) {
337337
finances: finances.data,
338338
financesLoading: Boolean(finances.loadingUuid),
339339
financesTimestamp: finances.timestamp,
340+
handle: userHandle,
340341
profile: state.auth.profile,
341342
showChallengeFilter: dash.showChallengeFilter,
342343
showEarnings: dash.showEarnings,

src/shared/containers/challenge-detail/index.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class ChallengeDetailPageContainer extends React.Component {
166166
reviewTypes,
167167
getAllCountries,
168168
getReviewTypes,
169+
history,
169170
} = this.props;
170171

171172
if (
@@ -191,7 +192,7 @@ class ChallengeDetailPageContainer extends React.Component {
191192
&& !challenge.fetchedWithAuth)
192193

193194
) {
194-
loadChallengeDetails(auth, challengeId);
195+
loadChallengeDetails(auth, challengeId, history);
195196
}
196197

197198
if (!allCountries.length) {
@@ -706,6 +707,7 @@ ChallengeDetailPageContainer.propTypes = {
706707
expandedTags: PT.arrayOf(PT.number).isRequired,
707708
expandTag: PT.func.isRequired,
708709
loadingRecommendedChallengesUUID: PT.string.isRequired,
710+
history: PT.shape().isRequired,
709711
};
710712

711713
function mapStateToProps(state, props) {
@@ -841,12 +843,15 @@ const mapDispatchToProps = (dispatch) => {
841843
dispatch(lookupActions.getReviewTypesInit());
842844
dispatch(lookupActions.getReviewTypesDone(tokenV3));
843845
},
844-
loadChallengeDetails: (tokens, challengeId) => {
846+
loadChallengeDetails: (tokens, challengeId, history) => {
845847
const a = actions.challenge;
846848
dispatch(a.getDetailsInit(challengeId));
847849
dispatch(a.getDetailsDone(challengeId, tokens.tokenV3, tokens.tokenV2))
848850
.then((res) => {
849851
const ch = res.payload;
852+
if (ch.isLegacyChallenge) {
853+
history.location.pathname = `/challenges/${ch.id}`; // eslint-disable-line no-param-reassign
854+
}
850855
if (ch.track === 'DESIGN') {
851856
const p = ch.allPhases || ch.phases || []
852857
.filter(x => x.name === 'Checkpoint Review');

0 commit comments

Comments
 (0)