Skip to content

Commit 05358ca

Browse files
authored
Merge branch 'integration-v5-challenge-api' into issue_4435_new
2 parents b0f737e + a1f1951 commit 05358ca

File tree

13 files changed

+273
-93
lines changed

13 files changed

+273
-93
lines changed

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.3",
138+
"topcoder-react-lib": "1000.19.4",
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ function getAllRecommendedChallengesInit(uuid) {
221221
function getAllRecommendedChallengesDone(uuid, tokenV3, recommendedTags) {
222222
const filter = {
223223
status: 'Active',
224-
tag: recommendedTags,
224+
...(!_.isEmpty(recommendedTags) && { tag: recommendedTags }),
225225
};
226226
return getAllActiveChallengesWithUsersDone(uuid, tokenV3, filter);
227227
}

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));

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,14 @@ export default function SideBar({
172172
)
173173
}
174174
{
175+
screeningScorecardId && screeningScorecardId.length > 0
176+
&& (
175177
<p styleName="link-like-paragraph">
176178
<a href={`${scorecardURL}${screeningScorecardId}`}>
177179
Screening Scorecard
178180
</a>
179181
</p>
182+
)
180183
}
181184
{
182185
<span styleName="link-like-paragraph tooltip-container">
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: 28 additions & 23 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,20 +41,31 @@ export default function ChallengeDetailsView(props) {
4041
groups,
4142
description,
4243
privateDescription,
44+
descriptionFormat,
4345
legacy,
4446
documents,
4547
finalSubmissionGuidelines,
46-
environment,
47-
codeRepo,
4848
userDetails,
4949
metadata,
50+
events,
5051
} = challenge;
5152

5253
const tags = challenge.tags || [];
5354
const roles = (userDetails || {}).roles || [];
5455
const { track, reviewScorecardId, screeningScorecardId } = legacy;
5556

5657
const allowStockArt = _.find(metadata, { type: 'allowStockArt' });
58+
let environment = '';
59+
const environmentData = _.find(metadata, { type: 'environment' });
60+
if (environmentData) {
61+
environment = environmentData.value;
62+
}
63+
64+
let codeRepo = '';
65+
const codeRepoData = _.find(metadata, { type: 'codeRepo' });
66+
if (codeRepoData) {
67+
codeRepo = codeRepoData.value;
68+
}
5769

5870
let forumLink = track.toLowerCase() === 'design'
5971
? `/?module=ThreadList&forumID=${forumId}`
@@ -156,13 +168,9 @@ export default function ChallengeDetailsView(props) {
156168
ref={n => n && n.setHtml(description)}
157169
/>
158170
) : (
159-
<div
160-
/* eslint-disable react/no-danger */
161-
dangerouslySetInnerHTML={{
162-
__html: description,
163-
}}
164-
/* eslint-enable react/no-danger */
165-
styleName="rawHtml"
171+
<SpecificationComponent
172+
bodyText={description}
173+
format={descriptionFormat}
166174
/>
167175
)
168176
}
@@ -218,13 +226,9 @@ export default function ChallengeDetailsView(props) {
218226
ref={n => n && n.setHtml(privateDescription)}
219227
/>
220228
) : (
221-
<div
222-
/* eslint-disable react/no-danger */
223-
dangerouslySetInnerHTML={{
224-
__html: privateDescription,
225-
}}
226-
/* eslint-enable react/no-danger */
227-
styleName="rawHtml"
229+
<SpecificationComponent
230+
bodyText={privateDescription}
231+
format={descriptionFormat}
228232
/>
229233
)
230234
}
@@ -256,13 +260,9 @@ export default function ChallengeDetailsView(props) {
256260
ref={n => n && n.setHtml(privateDescription)}
257261
/>
258262
) : (
259-
<div
260-
/* eslint-disable react/no-danger */
261-
dangerouslySetInnerHTML={{
262-
__html: privateDescription,
263-
}}
264-
/* eslint-enable react/no-danger */
265-
styleName="rawHtml"
263+
<SpecificationComponent
264+
bodyText={privateDescription}
265+
format={descriptionFormat}
266266
/>
267267
)
268268
}
@@ -410,6 +410,7 @@ export default function ChallengeDetailsView(props) {
410410
hasRegistered={hasRegistered}
411411
isDesign={track.toLowerCase() === 'design'}
412412
isDevelop={track.toLowerCase() === 'develop'}
413+
eventDetail={_.isEmpty(events) ? null : events[0]}
413414
isMM={isMM(challenge)}
414415
terms={terms}
415416
shareable={_.isEmpty(groups)}
@@ -435,8 +436,10 @@ ChallengeDetailsView.defaultProps = {
435436
numberOfCheckpointsPrizes: 0,
436437
finalSubmissionGuidelines: '',
437438
environment: '',
439+
descriptionFormat: 'HTML',
438440
codeRepo: '',
439441
metadata: {},
442+
events: [],
440443
reviewScorecardId: '',
441444
screeningScorecardId: '',
442445
},
@@ -447,6 +450,7 @@ ChallengeDetailsView.propTypes = {
447450
hasRegistered: PT.bool.isRequired,
448451
challenge: PT.shape({
449452
description: PT.string,
453+
descriptionFormat: PT.string,
450454
documents: PT.any,
451455
id: PT.any,
452456
subTrack: PT.any,
@@ -468,6 +472,7 @@ ChallengeDetailsView.propTypes = {
468472
roles: PT.arrayOf(PT.string).isRequired,
469473
}),
470474
metadata: PT.shape(),
475+
events: PT.arrayOf(PT.string),
471476
}),
472477
challengesUrl: PT.string.isRequired,
473478
communitiesList: PT.arrayOf(PT.shape({

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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,30 @@ const DESCRIPTION = {
2121
BUG_HUNT: 'Quickly find Bugs in apps, websites',
2222
CODE: 'Develop code for apps, services, etc. Final fixes are not included',
2323
DEVELOPMENT: 'Develop code for apps, services, etc. Final fixes are not included',
24+
TEST_SCENARIOS: 'Provide simple, easy information about what to test',
25+
CONTENT_CREATION: 'Generate topic ideas as a blog, video, infographic, or other format',
26+
IDEA_GENERATION: 'Generate feasible concepts for products, apps, features, etc',
27+
SPECIFICATION: 'Document requirements to be satisfied for design, product, or service',
28+
TASK: 'An assigned piece of work',
29+
AUTOMATED_TESTING: 'Challenges were submissions are auto-scored against a set of automated test cases',
30+
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',
33+
DESIGN: 'Prepare the visual sketch or the plans for a website, feature, app, etc',
2434
TEST_SUITES: 'Develop test cases to be used to validate apps, website, etc.',
2535
CONCEPTUALIZATION: 'Discover and define user stories and requirements',
36+
DESIGN_FIRST2FINISH: 'Be the first to deliver the design solution',
2637
DESIGN_FIRST_2_FINISH: 'Be the first to deliver the design solution',
2738
FIRST_2_FINISH: 'Be the first to deliver the development solution',
39+
FIRST2FINISH: 'Be the first to deliver the development solution',
2840
LOGO_DESIGN: 'Logo Design',
2941
MARATHON_MATCH: 'Write algorithms to solve complex problems, often for real world issues',
3042
DEVELOP_MARATHON_MATCH: 'Write algorithms to solve complex problems, often for real world issues',
3143
PRINT_OR_PRESENTATION: 'Design print and presentation assets',
3244
SRM: 'Single Round Match - quickly write code to solve algorythm problems head to head against other competitors',
3345
STUDIO_OTHER: 'Studio other',
3446
UI_PROTOTYPE_COMPETITION: 'Develop the front end of a UX',
47+
WEB_DESIGN: 'Design UI and front end experiences for web experiences',
3548
WEB_DESIGNS: 'Design UI and front end experiences for web experiences',
3649
WIDGET_OR_MOBILE_SCREEN_DESIGN: 'Design UI and front end experiences for mobile',
3750
WIREFRAMES: 'Produce the information architecture for user experiences',
@@ -47,15 +60,28 @@ const HEADER = {
4760
CODE: 'Code (Cd)',
4861
DEVELOPMENT: 'Development (Dv)',
4962
TEST_SUITES: 'Test Suites (TS)',
63+
TEST_SCENARIOS: 'Test Scenarios (Ts)',
64+
CONTENT_CREATION: 'Content Creation (CC)',
65+
IDEA_GENERATION: 'Idea Generation (IG)',
66+
SPECIFICATION: 'Specification (Sp)',
67+
TASK: 'Task (Tk)',
68+
AUTOMATED_TESTING: 'Automated Testing (AT)',
69+
COPILOT_POSTING: 'Copilot Posting (CP)',
70+
SPEC_REVIEW: 'Specification Review (SR)',
71+
MARATHON: 'Marathon (MM)',
72+
DESIGN: 'Design (Ds)',
5073
CONCEPTUALIZATION: 'Conceptualization (Cn)',
74+
DESIGN_FIRST2FINISH: 'Design First2Finish(DF2F)',
5175
DESIGN_FIRST_2_FINISH: 'Design First2Finish(DF2F)',
76+
FIRST2FINISH: 'First2Finish (F2F)',
5277
FIRST_2_FINISH: 'First2Finish (F2F)',
5378
LOGO_DESIGN: 'Logo Design (Lg)',
5479
MARATHON_MATCH: 'Marathon Match (MM)',
5580
DEVELOP_MARATHON_MATCH: 'Marathon Match (MM)',
5681
PRINT_OR_PRESENTATION: 'Print/Presentation (PP)',
5782
SRM: 'Single Round Match (SRM)',
5883
UI_PROTOTYPE_COMPETITION: 'UI Prototype (Pr)',
84+
WEB_DESIGN: 'Web Design (Wb)',
5985
WEB_DESIGNS: 'Web Design (Wb)',
6086
WIDGET_OR_MOBILE_SCREEN_DESIGN: 'Widget or Mobile Screen Design (Wg)',
6187
STUDIO_OTHER: 'Generic design challenge (D)',

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,12 @@ class ChallengeDetailPageContainer extends React.Component {
249249
const { legacy } = nextProps.challenge;
250250
const track = legacy ? legacy.track : nextProps.challenge.track;
251251
if (track && track.toLowerCase() !== 'design' && thriveArticles.length === 0) {
252-
const { tags } = nextProps.challenge;
253-
if (tags.length > 0 && !(tags.length === 1 && tags[0] === 'Other')) {
254-
// for tags = ['Other', ...], if 'Other' is first, use second value
252+
// filter all tags with value 'Other'
253+
const tags = _.filter(nextProps.challenge.tags, tag => tag !== 'Other');
254+
if (tags.length > 0) {
255255
this.apiService.getEDUContent({
256256
limit: 3,
257-
phrase: tags[0] === 'Other' ? tags[1] : tags[0],
257+
phrase: tags[0],
258258
types: ['Article'],
259259
}).then((content) => {
260260
// format image file data

0 commit comments

Comments
 (0)