Skip to content

Commit 4a16124

Browse files
authored
Merge pull request #5212 from topcoder-platform/develop
Release 2020/11/24
2 parents 2a3ffcc + 538bf84 commit 4a16124

File tree

32 files changed

+282
-65
lines changed

32 files changed

+282
-65
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ workflows:
230230
filters:
231231
branches:
232232
only:
233-
- develop
233+
- free
234234
# This is alternate dev env for parallel testing
235235
- "build-test":
236236
context : org-global

config/default.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ module.exports = {
112112
COMMUNITY: 'https://community.topcoder-dev.com',
113113
FORUMS: 'https://apps.topcoder-dev.com/forums',
114114
HELP: 'https://www.topcoder.com/thrive/tracks?track=Topcoder&tax=Help%20Articles',
115+
SUBMISSION_REVIEW: 'https://submission-review.topcoder-dev.com',
115116

116117
THRIVE: 'https://www.topcoder.com/thrive',
117118

config/production.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ module.exports = {
3232
COMMUNITY: 'https://community.topcoder.com',
3333
FORUMS: 'https://apps.topcoder.com/forums',
3434
HELP: 'https://www.topcoder.com/thrive/tracks?track=Topcoder&tax=Help%20Articles',
35+
SUBMISSION_REVIEW: 'https://submission-review.topcoder.com',
3536
MEMBER: 'https://member.topcoder.com',
3637
ONLINE_REVIEW: 'https://software.topcoder.com',
3738
PAYMENT_TOOL: 'https://payment.topcoder.com',

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"supertest": "^3.1.0",
141141
"tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.3",
142142
"tc-ui": "^1.0.12",
143-
"topcoder-react-lib": "1.1.2",
143+
"topcoder-react-lib": "1.1.3",
144144
"topcoder-react-ui-kit": "2.0.1",
145145
"topcoder-react-utils": "0.7.8",
146146
"turndown": "^4.0.2",

src/shared/components/Contentful/Route.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import _ from 'lodash';
77
import ContentfulLoader from 'containers/ContentfulLoader';
88
import Error404 from 'components/Error404';
99
import LoadingIndicator from 'components/LoadingIndicator';
10-
import { MetaTags } from 'topcoder-react-utils';
10+
import MetaTags from 'components/MetaTags';
1111
import PT from 'prop-types';
1212
import React from 'react';
1313
import { Route, Switch } from 'react-router-dom';

src/shared/components/MMatchLeaderboard/index.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export default class MMLeaderboard extends Component {
7070
// Use Lodash to sort array
7171
data = _.orderBy(
7272
data,
73-
[d => String(d[sortParam.field]).toLowerCase()], [sortParam.order],
73+
[d => Number(d[sortParam.field]) || String(d[sortParam.field]).toLowerCase()],
74+
[sortParam.order],
7475
);
7576
}
7677

src/shared/components/MetaTags.jsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Auxiliary wrapper around React Helmet that helps to generate meta tags for
3+
* generic use cases.
4+
*
5+
* NOTE: This component relies on `domain` path of Redux store to hold
6+
* the current app domain, which will serve as the base path for the bundled
7+
* images.
8+
*/
9+
10+
import PT from 'prop-types';
11+
import React from 'react';
12+
import { connect } from 'react-redux';
13+
import { Helmet } from 'react-helmet';
14+
15+
function MetaTags({
16+
description,
17+
domain,
18+
image,
19+
siteName,
20+
socialDescription,
21+
socialTitle,
22+
title,
23+
url,
24+
}) {
25+
const img = `${domain}${image}`;
26+
const socTitle = socialTitle || title;
27+
const socDesc = socialDescription || description;
28+
return (
29+
<Helmet>
30+
{/* General tags. */}
31+
<title>
32+
{title}
33+
</title>
34+
<meta name="description" content={description} />
35+
36+
{/* Twitter cards. */}
37+
<meta name="twitter:card" content="summary_large_image" />
38+
<meta name="twitter:title" content={socTitle} />
39+
<meta name="twitter:description" content={socDesc} />
40+
{ image ? <meta name="twitter:image" content={img} /> : null }
41+
{
42+
siteName ? (
43+
<meta name="twitter:site" content={`@${siteName}`} />
44+
) : null
45+
}
46+
47+
{/* Open Graph data. */}
48+
<meta property="og:title" content={socTitle} />
49+
{ image ? <meta property="og:image" content={img} /> : null }
50+
{ image ? <meta property="og:image:alt" content={socTitle} /> : null }
51+
<meta property="og:description" content={socDesc} />
52+
{
53+
siteName ? (<meta property="og:sitename" content={siteName} />) : null
54+
}
55+
{ url ? (<meta property="og:url" content={url} />) : null }
56+
</Helmet>
57+
);
58+
}
59+
60+
MetaTags.defaultProps = {
61+
image: null,
62+
siteName: null,
63+
socialDescription: null,
64+
socialTitle: null,
65+
url: null,
66+
};
67+
68+
MetaTags.propTypes = {
69+
description: PT.string.isRequired,
70+
domain: PT.string.isRequired,
71+
image: PT.string,
72+
siteName: PT.string,
73+
socialDescription: PT.string,
74+
socialTitle: PT.string,
75+
title: PT.string.isRequired,
76+
url: PT.string,
77+
};
78+
79+
/* TODO: It is not good to depend on the domain written into redux state here,
80+
* better pass it via the renderer context at the server side, and get it from
81+
* the location at the frontend side, or something similar? */
82+
export default connect(state => ({ domain: state.domain }))(MetaTags);

src/shared/components/Settings/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import React from 'react';
55
import PT from 'prop-types';
6-
import { MetaTags } from 'topcoder-react-utils';
6+
import MetaTags from 'components/MetaTags';
77

88
import { TABS } from 'actions/page/settings';
99

src/shared/components/challenge-detail/Header/TabSelector/index.jsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ export default function ChallengeViewSelector(props) {
160160
</a>
161161
) : null
162162
}
163+
{
164+
(hasRegistered && mySubmissions.length > 0) && (
165+
<a
166+
href={`${config.URL.SUBMISSION_REVIEW}/challenges/${challenge.legacyId}`}
167+
styleName="challenge-selector-common challenge-unselected-view"
168+
target="_blank"
169+
rel="oopener noreferrer"
170+
>
171+
SUBMISSION REVIEW
172+
</a>
173+
)
174+
}
163175
{
164176
numWinners ? (
165177
<a
@@ -225,6 +237,7 @@ ChallengeViewSelector.defaultProps = {
225237
ChallengeViewSelector.propTypes = {
226238
isLoggedIn: PT.bool,
227239
challenge: PT.shape({
240+
legacyId: PT.string,
228241
legacy: PT.shape({
229242
forumId: PT.number,
230243
}),

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ export default function ChallengeHeader(props) {
8181
const sortedAllPhases = _.cloneDeep(allPhases)
8282
.sort((a, b) => moment(phaseEndDate(a)).diff(phaseEndDate(b)));
8383

84-
const { prizes } = prizeSets && prizeSets.length ? prizeSets[0] : [];
84+
const placementPrizes = _.find(prizeSets, { type: 'placement' });
85+
const { prizes } = placementPrizes || [];
8586

8687
const checkpointPrizes = _.find(prizeSets, { type: 'checkpoint' });
8788
let numberOfCheckpointsPrizes = 0;

src/shared/containers/EDU/Home.jsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import React from 'react';
55
import { config } from 'topcoder-react-utils';
6-
import { Helmet } from 'react-helmet';
6+
import MetaTags from 'components/MetaTags';
77
import Viewport from 'components/Contentful/Viewport';
88
import SearchBar from 'components/Contentful/SearchBar/SearchBar';
99
import { getService } from 'services/contentful';
@@ -44,15 +44,15 @@ export default class EDUHome extends React.Component {
4444

4545
render() {
4646
const { taxonomy } = this.state;
47+
const title = 'Topcoder Thrive | Topcoder Community | Topcoder';
48+
const description = 'Thrive is our vault of content that we have been gathering over the years. It is full of tutorials and workshops that matter. Grow with us!';
49+
4750
return (
4851
<div className={homeTheme.container}>
49-
<Helmet>
50-
<title>THRIVE - Grow with us. Tutorials and workshops that matter.</title>
51-
<meta name="title" property="og:title" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
52-
<meta name="description" property="og:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
53-
<meta name="description" property="description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
54-
<meta name="twitter:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
55-
</Helmet>
52+
<MetaTags
53+
description={description}
54+
title={title}
55+
/>
5656
{/* Banner */}
5757
<div className={homeTheme.bannerContainer}>
5858
<div className={homeTheme.bannerImage} />

src/shared/containers/EDU/Search.jsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import _ from 'lodash';
55
import moment from 'moment';
66
import React from 'react';
77
import { config, isomorphy } from 'topcoder-react-utils';
8+
import MetaTags from 'components/MetaTags';
89
import Viewport from 'components/Contentful/Viewport';
910
import SearchBar from 'components/Contentful/SearchBar/SearchBar';
1011
import { getService } from 'services/contentful';
@@ -13,7 +14,6 @@ import { updateQuery } from 'utils/url';
1314
import qs from 'qs';
1415
import LoadingIndicator from 'components/LoadingIndicator';
1516
import SearchPageFilter from 'components/Contentful/SearchPageFilter/SearchPageFilter';
16-
import { Helmet } from 'react-helmet';
1717
// Partials
1818
import ResultTabs from './partials/ResultTabs';
1919
// CSS
@@ -87,18 +87,28 @@ export default class EDUSearch extends React.Component {
8787
const {
8888
taxonomy, query, tree, isShowFilter,
8989
} = this.state;
90+
const title = 'Topcoder Thrive | Topcoder Community | Topcoder';
91+
const description = 'Thrive is our vault of content that we have been gathering over the years. It is full of tutorials and workshops that matter. Grow with us!';
92+
93+
const metaTags = (
94+
<MetaTags
95+
description={description}
96+
title={title}
97+
/>
98+
);
9099
// This container needs at least those variables
91100
// to be able to render meaningful data
92-
if (!taxonomy) return <LoadingIndicator />;
101+
if (!taxonomy) {
102+
return (
103+
<React.Fragment>
104+
{ metaTags }
105+
<LoadingIndicator />;
106+
</React.Fragment>
107+
);
108+
}
93109
return (
94110
<div className={searchTheme.container}>
95-
<Helmet>
96-
<title>THRIVE - Search {`${query.title}`}</title>
97-
<meta name="title" property="og:title" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
98-
<meta name="description" property="og:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
99-
<meta name="description" property="description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
100-
<meta name="twitter:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
101-
</Helmet>
111+
{ metaTags }
102112
{/* Banner */}
103113
<div className={searchTheme.bannerContainer}>
104114
<div className={searchTheme.searchBarWrapp}>

src/shared/containers/EDU/Tracks.jsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import _ from 'lodash';
55
import moment from 'moment';
66
import React from 'react';
77
import { config, isomorphy } from 'topcoder-react-utils';
8+
import MetaTags from 'components/MetaTags';
89
import Viewport from 'components/Contentful/Viewport';
910
import SearchBar from 'components/Contentful/SearchBar/SearchBar';
1011
import { getService } from 'services/contentful';
@@ -14,7 +15,6 @@ import qs from 'qs';
1415
import TracksTree from 'components/Contentful/TracksTree/TracksTree';
1516
import LoadingIndicator from 'components/LoadingIndicator';
1617
import TracksFilter from 'components/Contentful/TracksFilter/TracksFilter';
17-
import { Helmet } from 'react-helmet';
1818
// SVGs & Assets
1919
import Dev from 'assets/images/img-development.png';
2020
import Design from 'assets/images/img_design.png';
@@ -163,18 +163,28 @@ export default class EDUTracks extends React.Component {
163163
taxonomy, query, tree, isShowFilter,
164164
articleCnt, videoCnt, forumCnt,
165165
} = this.state;
166+
const title = 'Topcoder Thrive | Topcoder Community | Topcoder';
167+
const description = 'Thrive is our vault of content that we have been gathering over the years. It is full of tutorials and workshops that matter. Grow with us!';
168+
169+
const metaTags = (
170+
<MetaTags
171+
description={description}
172+
title={title}
173+
/>
174+
);
166175
// This container needs at least those variables
167176
// to be able to render meaningful data
168-
if (!taxonomy) return <LoadingIndicator />;
177+
if (!taxonomy) {
178+
return (
179+
<React.Fragment>
180+
{ metaTags }
181+
<LoadingIndicator />;
182+
</React.Fragment>
183+
);
184+
}
169185
return (
170186
<div className={tracksTheme.container}>
171-
<Helmet>
172-
<title>THRIVE - {`${query.track}`}</title>
173-
<meta name="title" property="og:title" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
174-
<meta name="description" property="og:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
175-
<meta name="description" property="description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
176-
<meta name="twitter:description" content="THRIVE - Grow with us. Tutorials and workshops that matter." />
177-
</Helmet>
187+
{ metaTags }
178188
{/* Banner */}
179189
<div
180190
className={tracksTheme.bannerContainer}

src/shared/containers/EDU/styles/home.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
.container {
44
display: flex;
5+
flex: 1;
56
flex-direction: column;
6-
overflow: hidden;
7+
width: 100%;
78

89
.bannerContainer {
910
background-image: linear-gradient(98.81deg, #8b41b0 0%, #ef476f 100%);

src/shared/containers/EDU/styles/search.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
.container {
44
display: flex;
5+
flex: 1;
56
flex-direction: column;
6-
overflow: hidden;
7+
width: 100%;
78

89
.bannerContainer {
910
background-color: #2a2a2a;

src/shared/containers/EDU/styles/tracks.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
.container {
44
display: flex;
5+
flex: 1;
56
flex-direction: column;
6-
overflow: hidden;
7+
width: 100%;
78

89
.bannerContainer {
910
min-height: 475px;

src/shared/containers/GigsPages.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ import Viewport from 'components/Contentful/Viewport';
99
import { config } from 'topcoder-react-utils';
1010
import RecruitCRMJobDetails from 'containers/Gigs/RecruitCRMJobDetails';
1111
import { Helmet } from 'react-helmet';
12+
import MetaTags from 'components/MetaTags';
1213

1314

1415
export default function GigsPagesContainer(props) {
1516
const { match } = props;
1617
const { id } = match.params;
1718
const isApply = `${config.GIGS_PAGES_PATH}/${id}/apply` === match.url;
19+
const title = 'Gig Work | Topcoder Community | Topcoder';
20+
const description = 'Compete and build up your profiles and skills! Topcoder members become eligible to work on Gig Work projects by first proving themselves in various skill sets through Topcoder competitions.';
1821
return (
1922
<div>
2023
<Helmet>
21-
<title>Topcoder - Gig Work Opportunities</title>
2224
<script type="text/javascript">{`
2325
window._chatlio = window._chatlio||[];
2426
!function(){ var t=document.getElementById("chatlio-widget-embed");if(t&&window.ChatlioReact&&_chatlio.init)return void _chatlio.init(t,ChatlioReact);for(var e=function(t){return function(){_chatlio.push([t].concat(arguments)) }},i=["configure","identify","track","show","hide","isShown","isOnline", "page", "open", "showOrHide"],a=0;a<i.length;a++)_chatlio[i[a]]||(_chatlio[i[a]]=e(i[a]));var n=document.createElement("script"),c=document.getElementsByTagName("script")[0];n.id="chatlio-widget-embed",n.src="https://w.chatlio.com/w.chatlio-widget.js",n.async=!0,n.setAttribute("data-embed-version","2.3");
@@ -28,6 +30,10 @@ window._chatlio = window._chatlio||[];
2830
`}
2931
</script>
3032
</Helmet>
33+
<MetaTags
34+
description={description}
35+
title={title}
36+
/>
3137
<Header />
3238
{
3339
id ? (

src/shared/containers/Profile.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import PT from 'prop-types';
77
import { connect } from 'react-redux';
88

99
import { actions } from 'topcoder-react-lib';
10-
import { MetaTags } from 'topcoder-react-utils';
10+
import MetaTags from 'components/MetaTags';
1111
import Error404 from 'components/Error404';
1212
import LoadingIndicator from 'components/LoadingIndicator';
1313
import ProfilePage from 'components/ProfilePage';

0 commit comments

Comments
 (0)