From 0f3d3625702c971afd79e3079ae1199106f24028 Mon Sep 17 00:00:00 2001 From: "Dr. Sergey Pogodin" Date: Mon, 21 Aug 2017 17:27:12 +0200 Subject: [PATCH 1/8] Finalizing refactoring of communties routing and code splitting --- config/webpack/production.js | 8 +- docs/code-splitting.md | 8 + docs/how-to-add-a-new-topcoder-community.md | 23 +- src/assets/themes/green/Header.css | 12 - src/assets/themes/red/Header.css | 12 - src/server/renderer.jsx | 4 +- .../example-theme-default/metadata.json | 26 -- .../example-theme-green/metadata.json | 27 -- .../example-theme-red/metadata.json | 27 -- .../communities/wipro/Footer/index.jsx | 5 +- .../containers/tc-communities/Loader.jsx | 9 +- .../containers/tc-communities/Page/index.jsx | 305 ------------------ .../containers/tc-communities/Page/style.scss | 8 - .../containers/tc-communities/srmx/Home.js | 10 + .../containers/tc-communities/wipro/Home.js | 19 ++ .../routes/Communities/ChallengeListing.jsx | 59 ++++ .../routes/Communities/Community2/Routes.jsx | 66 ++++ .../routes/Communities/Community2/index.jsx | 41 +++ .../routes/Communities/DemoExpert/Routes.jsx | 66 ++++ .../routes/Communities/DemoExpert/index.jsx | 41 +++ src/shared/routes/Communities/Leaderboard.jsx | 32 ++ src/shared/routes/Communities/QA/Routes.jsx | 66 ++++ src/shared/routes/Communities/QA/index.jsx | 41 +++ src/shared/routes/Communities/Routes.jsx | 39 +++ src/shared/routes/Communities/SRMx/Routes.jsx | 66 ++++ src/shared/routes/Communities/SRMx/index.jsx | 41 +++ .../routes/Communities/TaskForce/Routes.jsx | 60 ++++ .../routes/Communities/TaskForce/index.jsx | 41 +++ .../routes/Communities/TcProdDev/Routes.jsx | 66 ++++ .../routes/Communities/TcProdDev/index.jsx | 41 +++ .../routes/Communities/Veterans/Routes.jsx | 66 ++++ .../routes/Communities/Veterans/index.jsx | 41 +++ .../routes/Communities/Wipro/Routes.jsx | 66 ++++ src/shared/routes/Communities/Wipro/index.jsx | 41 +++ src/shared/routes/Communities/index.jsx | 50 +++ src/shared/routes/Topcoder/Routes.jsx | 38 +++ src/shared/routes/Topcoder/index.jsx | 57 ++-- src/shared/routes/index.jsx | 61 +--- src/shared/services/.exchange-rates.cache | 2 +- src/shared/utils/router/SplitRoute.jsx | 9 +- 40 files changed, 1176 insertions(+), 524 deletions(-) delete mode 100644 src/assets/themes/green/Header.css delete mode 100644 src/assets/themes/red/Header.css delete mode 100644 src/server/tc-communities/example-theme-default/metadata.json delete mode 100644 src/server/tc-communities/example-theme-green/metadata.json delete mode 100644 src/server/tc-communities/example-theme-red/metadata.json delete mode 100644 src/shared/containers/tc-communities/Page/index.jsx delete mode 100644 src/shared/containers/tc-communities/Page/style.scss create mode 100644 src/shared/containers/tc-communities/srmx/Home.js create mode 100644 src/shared/containers/tc-communities/wipro/Home.js create mode 100644 src/shared/routes/Communities/ChallengeListing.jsx create mode 100644 src/shared/routes/Communities/Community2/Routes.jsx create mode 100644 src/shared/routes/Communities/Community2/index.jsx create mode 100644 src/shared/routes/Communities/DemoExpert/Routes.jsx create mode 100644 src/shared/routes/Communities/DemoExpert/index.jsx create mode 100644 src/shared/routes/Communities/Leaderboard.jsx create mode 100644 src/shared/routes/Communities/QA/Routes.jsx create mode 100644 src/shared/routes/Communities/QA/index.jsx create mode 100644 src/shared/routes/Communities/Routes.jsx create mode 100644 src/shared/routes/Communities/SRMx/Routes.jsx create mode 100644 src/shared/routes/Communities/SRMx/index.jsx create mode 100644 src/shared/routes/Communities/TaskForce/Routes.jsx create mode 100644 src/shared/routes/Communities/TaskForce/index.jsx create mode 100644 src/shared/routes/Communities/TcProdDev/Routes.jsx create mode 100644 src/shared/routes/Communities/TcProdDev/index.jsx create mode 100644 src/shared/routes/Communities/Veterans/Routes.jsx create mode 100644 src/shared/routes/Communities/Veterans/index.jsx create mode 100644 src/shared/routes/Communities/Wipro/Routes.jsx create mode 100644 src/shared/routes/Communities/Wipro/index.jsx create mode 100644 src/shared/routes/Communities/index.jsx create mode 100644 src/shared/routes/Topcoder/Routes.jsx diff --git a/config/webpack/production.js b/config/webpack/production.js index f02c629373..6e2f843912 100644 --- a/config/webpack/production.js +++ b/config/webpack/production.js @@ -52,7 +52,13 @@ module.exports = webpackMerge(defaultConfig, { }, }), new OptimizeCssAssetsPlugin(), - new webpack.optimize.ModuleConcatenationPlugin(), + + /* TODO: It tends to make problems with dynamically loaded chunks, + * I guess it may move some code between modules being in different + * chunks, thus breaking the code when they are loaded in different + * order. Should be further investigated. */ + // new webpack.optimize.ModuleConcatenationPlugin(), + new webpack.optimize.UglifyJsPlugin(), ], }); diff --git a/docs/code-splitting.md b/docs/code-splitting.md index 41f815e59f..99c90f9abf 100644 --- a/docs/code-splitting.md +++ b/docs/code-splitting.md @@ -84,6 +84,14 @@ First of all, under the hood `SplitRoute` uses **react-router**'s `Route` to mak - By default, when you leave a split route, the CSS reference is removed from the document. You can pass in boolean `cacheCss` option to prevent it. +### Caveats + +Here are some non-trivial points, that should be merged into the body of documentation above, but for now they are just mentioned here as points to remember: + +- Although `` is technically a route, it is not quite possible to use it inside ``, so in many cases you just have to use it as a usual component. + +- If the chunk of code you split uses routing, you should use `` inside `renderServer` prop. + ### Demo / Test A simple demo / test of the code splitting is available at `/examples/code-splitting` endpoint of the app. \ No newline at end of file diff --git a/docs/how-to-add-a-new-topcoder-community.md b/docs/how-to-add-a-new-topcoder-community.md index b016fa0de9..a375e37e4d 100644 --- a/docs/how-to-add-a-new-topcoder-community.md +++ b/docs/how-to-add-a-new-topcoder-community.md @@ -114,23 +114,12 @@ To add a new community with the name **demo**, we should follow the following pr - `description`: A berief description which will be displayed in dashboard. - `image`: A image that located at `/assets/images/tc-communities/background` will be displayed in dashboard 3. Custom pages of the community (anything beside `Challenges` and `Leaderboard`) should be created inside `/src/shared/components/tc-communities/communities/demo`. At the moment all communities have two custom pages: `Home` and `Learn`, you may just copy these from an existing community, and then customize to your particular needs. -4. Created custom pages should be registered inside `/src/shared/containers/tc-communities/Page/index.jsx`. - - First, import your custom pages into the file as - ```js - import DemoHome from 'components/tc-communities/communities/demo/Home'; - import DemoLearn from 'components/tc-communities/communities/demo/Learn'; - ``` - - Second, add them into `renderCustomPage()` method. It includes a big `if-else` block, where you should add something similar to: - ```js - } else if (communityId === 'demo') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } - ``` - here the page IDs inside the switch statement should match the relative URLs you have configured inside `metadata.json` file (the address `.` is internally aliased to `home`, thus `home` pageId should be used to specify the page at the `.` route). + +4. The routing inside community, and code splitting of the related code, should be set up inside `/src/shared/routes/Communities`: + - Copy/paste one of the existing community folders and rename it into `/src/shared/routes/Communities/Demo`; + - Inside `/src/shared/routes/Communities/Demo/index.jsx` you should change the name of code chunk in two places it is present (as value of `chunkName` prop, and inside `webpackChunkName` "magic comment"); + - Inside `/src/shared/routes/Communities/Demo/Routes.jsx` you define necesary routing, as with usual `react-router` routing code; + - Finally, you link this routing code into `/src/shared/routes/Communities/Routes.jsx`. 5. At this point **demo** community is ready and accessible at the `/community/demo` route of the App (i.e., if we deploy dev version of the App to `community-west.topcoder-dev.com`, community will be accessible as `community-west.topcoder-dev.com/community/demo`). diff --git a/src/assets/themes/green/Header.css b/src/assets/themes/green/Header.css deleted file mode 100644 index b5fb6de7b3..0000000000 --- a/src/assets/themes/green/Header.css +++ /dev/null @@ -1,12 +0,0 @@ -.tc-communities__header__container { - background-color: green; -} - -.tc-communities__header__menu-link, -.tc-communities__header__menu-link:visited { - color: #fff; -} - -.tc-communities__header__menu-link:hover { - color: #2886af; -} diff --git a/src/assets/themes/red/Header.css b/src/assets/themes/red/Header.css deleted file mode 100644 index e1dd5009c0..0000000000 --- a/src/assets/themes/red/Header.css +++ /dev/null @@ -1,12 +0,0 @@ -.tc-communities__header__container { - background-color: red; -} - -.tc-communities__header__menu-link, -.tc-communities__header__menu-link:visited { - color: #fff; -} - -.tc-communities__header__menu-link:hover { - color: #2886af; -} diff --git a/src/server/renderer.jsx b/src/server/renderer.jsx index b756febb71..29d2e2c8d7 100644 --- a/src/server/renderer.jsx +++ b/src/server/renderer.jsx @@ -53,8 +53,8 @@ export default (req, res) => { if (context.status) res.status(context.status); const sanitizedExchangeRates = serializeJs(exchangeRates, { isJSON: true }); const styles = context.chunks.map(chunk => ( - `` - )).join(); + `` + )).join(''); res.send(( ` diff --git a/src/server/tc-communities/example-theme-default/metadata.json b/src/server/tc-communities/example-theme-default/metadata.json deleted file mode 100644 index 79e6c174d8..0000000000 --- a/src/server/tc-communities/example-theme-default/metadata.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "authorizedGroupIds": [], - "communityId": "example-theme-default", - "communityName": "Example Community", - "logos": ["http://predix.topcoder.com/wp-content/uploads/sites/7/2016/11/topcoder-hat-logo.png"], - "menuItems": [ - { - "title": "HOME", - "url": "header" - }, { - "title": "GET STARTED", - "url": "get-started" - }, { - "title": "ABOUT PREDIX", - "url": "about" - }, { - "title": "RESOURCES", - "url": "resources" - }, { - "title": "COMPETE", - "url": "complete" - } - ], - "description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore.", - "image":"3.jpg" -} diff --git a/src/server/tc-communities/example-theme-green/metadata.json b/src/server/tc-communities/example-theme-green/metadata.json deleted file mode 100644 index 7272dbcf77..0000000000 --- a/src/server/tc-communities/example-theme-green/metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "authorizedGroupIds": [], - "communityId": "example-theme-green", - "communityName": "Example Community", - "logos": ["http://predix.topcoder.com/wp-content/uploads/sites/7/2016/11/topcoder-hat-logo.png"], - "menuItems": [ - { - "title": "HOME", - "url": "header" - }, { - "title": "GET STARTED", - "url": "get-started" - }, { - "title": "ABOUT PREDIX", - "url": "about" - }, { - "title": "RESOURCES", - "url": "resources" - }, { - "title": "COMPETE", - "url": "complete" - } - ], - "style": "/themes/green/Header.css", - "description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore.", - "image":"1.jpg" -} diff --git a/src/server/tc-communities/example-theme-red/metadata.json b/src/server/tc-communities/example-theme-red/metadata.json deleted file mode 100644 index 237d359bee..0000000000 --- a/src/server/tc-communities/example-theme-red/metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "authorizedGroupIds": [], - "communityId": "example-theme-red", - "communityName": "Example Community", - "logos": ["http://predix.topcoder.com/wp-content/uploads/sites/7/2016/11/topcoder-hat-logo.png"], - "menuItems": [ - { - "title": "HOME", - "url": "header" - }, { - "title": "GET STARTED", - "url": "get-started" - }, { - "title": "ABOUT PREDIX", - "url": "about" - }, { - "title": "RESOURCES", - "url": "resources" - }, { - "title": "COMPETE", - "url": "complete" - } - ], - "style": "/themes/red/Header.css", - "description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore.", - "image":"2.jpg" -} diff --git a/src/shared/components/tc-communities/communities/wipro/Footer/index.jsx b/src/shared/components/tc-communities/communities/wipro/Footer/index.jsx index 6b6ad2ea3b..678a545373 100644 --- a/src/shared/components/tc-communities/communities/wipro/Footer/index.jsx +++ b/src/shared/components/tc-communities/communities/wipro/Footer/index.jsx @@ -7,7 +7,9 @@ import defaultStyle from './style.scss'; function Footer(props) { return (
-
{props.text}
+
+ © Copyright Wipro Ltd 2017 +
); } @@ -21,7 +23,6 @@ Footer.defaultProps = { }; Footer.propTypes = { - text: PT.string.isRequired, theme: PT.shape({ footer: PT.string.isRequired, footerText: PT.string, diff --git a/src/shared/containers/tc-communities/Loader.jsx b/src/shared/containers/tc-communities/Loader.jsx index 7f8da6addc..47153ab749 100644 --- a/src/shared/containers/tc-communities/Loader.jsx +++ b/src/shared/containers/tc-communities/Loader.jsx @@ -81,7 +81,7 @@ class Loader extends React.Component { /* Visitor belongs to at least one of the groups authorized to access this * community. */ - if (_.intersection(visitorGroups, meta.authorizedGroupIds)) { + if (_.intersection(visitorGroups.map(g => g.id), meta.authorizedGroupIds)) { return ; } @@ -104,7 +104,7 @@ Loader.propTypes = { authorizedGroupIds: PT.arrayOf(PT.string), communityId: PT.string.isRequired, }), - visitorGroups: PT.arrayOf(PT.string), + visitorGroups: PT.arrayOf(PT.shape({ id: PT.string.isRequired })), }; function mapStateToProps(state, ownProps) { @@ -114,15 +114,12 @@ function mapStateToProps(state, ownProps) { const loadingMetaDataForCommunityId = meta.loadingMetaDataForCommunityId; if (meta.communityId !== communityId) meta = null; - let visitorGroups = _.get(state, 'auth.profile.groups'); - if (visitorGroups) visitorGroups = visitorGroups.map(g => g.id); - return { communityId, Community: ownProps.communityComponent, loadingMetaDataForCommunityId, meta, - visitorGroups, + visitorGroups: _.get(state, 'auth.profile.groups'), }; } diff --git a/src/shared/containers/tc-communities/Page/index.jsx b/src/shared/containers/tc-communities/Page/index.jsx deleted file mode 100644 index 7283ef1fba..0000000000 --- a/src/shared/containers/tc-communities/Page/index.jsx +++ /dev/null @@ -1,305 +0,0 @@ -/** - * A generic Topcoder Community page, which contains header, footer and content. - * - * It shows authentication request if user is not authorized. - * It redirects to 404 page if community is not found by its id. - - * It renders community page content depend on the pageId - * There are two kind of pages: - * - typical pages like leaderboard and challenges which has same relative url - * for all communities, these are kind of reserved pageId - * - also there could be pages created by a landing page editor with arbitrary pageId - * renderCustomPage() method has to return a page made in the editor - * It redirects to 404 page if content cannot be rendered by its pageId. - */ - -import _ from 'lodash'; -import challengeListingActions from 'actions/challenge-listing'; -import challengeListingSidebarActions from 'actions/challenge-listing/sidebar'; -import PT from 'prop-types'; -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import actions from 'actions/tc-communities/meta'; -import newsActions from 'actions/tc-communities/news'; -import { bindActionCreators } from 'redux'; -import standardHeaderActions from 'actions/topcoder_header'; -import Header from 'containers/tc-communities/Header'; -import Footer from 'containers/tc-communities/Footer'; -import Error404 from 'components/Error404'; -import qs from 'qs'; -import { BUCKETS } from 'utils/challenge-listing/buckets'; - -// page content components -import ChallengeListing from 'containers/challenge-listing/Listing'; -import Leaderboard from 'containers/Leaderboard'; -import WiproHome from 'components/tc-communities/communities/wipro/Home'; -import WiproFooter from 'components/tc-communities/communities/wipro/Footer'; -import WiproLearn from 'components/tc-communities/communities/wipro/Learn'; - -import QaHome from 'components/tc-communities/communities/qa/Home'; -import QaLearn from 'components/tc-communities/communities/qa/Learn'; - -import SrmxHome from 'components/tc-communities/communities/srmx/Home'; -import SrmxLearn from 'components/tc-communities/communities/srmx/Learn'; - -import TcProdDevHome from 'components/tc-communities/communities/tc-prod-dev/Home'; -import TcProdDevLearn from 'components/tc-communities/communities/tc-prod-dev/Learn'; - -import VeteransHome from 'components/tc-communities/communities/veterans/Home'; -import VeteransLearn from 'components/tc-communities/communities/veterans/Learn'; - -import DemoExpertHome from 'components/tc-communities/communities/demo-expert/Home'; -import DemoExpertLearn from 'components/tc-communities/communities/demo-expert/Learn'; - -import Community2Home from 'components/tc-communities/communities/community-2/Home'; -import Community2Learn from 'components/tc-communities/communities/community-2/Learn'; - -import TaskforceHome from 'components/tc-communities/communities/taskforce/Home'; - -import './style.scss'; - -export class Page extends Component { - componentDidMount() { - if (this.props.meta.isMobileOpen) this.props.mobileToggle(); - - if (this.props.meta.newsFeed && !this.props.news && !this.props.loadingNews) { - this.props.loadNews(this.props.meta.newsFeed); - } - } - - componentWillUpdate(nextProps) { - if (nextProps.meta.communityId === this.props.communityId - && nextProps.meta.newsFeed && !this.props.news) { - nextProps.loadNews(nextProps.meta.newsFeed); - } - } - - /** - * Returns custom page content which is created by landing page editor - * - * TODO: as editor is not implemented yet, this method returns static - * mock pages. It has to be rewritten when landing page editor is available - */ - renderCustomPage() { - let pageContent; - const communityId = this.props.meta.communityId; - const pageId = this.props.pageId; - - // as for now landing page editor is not implemented yet - // for Wipro and Wipro 2 communities we return static pages - // TODO: this have to be removed when editor implemented - if (communityId === 'wipro') { - if (pageId === 'home') { - pageContent = ; - } else if (pageId === 'learn') { - pageContent = ; - } - } else if (communityId === 'community-2') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'qa') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'veterans') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'srmx') { - switch (pageId) { - case 'home': - pageContent = ; - break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'tc-prod-dev') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'demo-expert') { - switch (pageId) { - case 'home': pageContent = ; break; - case 'learn': pageContent = ; break; - default: break; - } - } else if (communityId === 'taskforce') { - switch (pageId) { - case 'home': pageContent = ; break; - default: break; - } - } else if (communityId.match(/example-theme-\w/)) { - pageContent =
; - } - - // if page it not found redirect to 404 - if (!pageContent) { - pageContent = ; - // pageContent = ; - } - - pageContent = React.cloneElement(pageContent, { - news: this.props.news, - }); - - return pageContent; - } - - /** - * Returns community page content depend on the pageId - * There are two kind of pages: - * - typical pages like leaderboard and challenges which has same relative url - * for all challenges, these are kind of reserved pageId - * - also there could be pages created by a landing page editor with arbitrary pageId - * renderCustomPage() method has to return a page made in the editor - */ - renderPageContent() { - const pageId = this.props.pageId; - let pageContent =
; - switch (pageId) { - case 'leaderboard': - pageContent = (); - break; - case 'challenges': { - const query = this.props.location.search ? - qs.parse(this.props.location.search.slice(1)) : null; - - const currencyFromUrl = _.get(query, 'currency'); - const prizeMode = currencyFromUrl ? `money-${currencyFromUrl}` - : _.get(this.props.meta, 'challengeListing.prizeMode'); - - pageContent = (); - break; - } - default: - pageContent = this.renderCustomPage(); - break; - } - - return pageContent; - } - - render() { - return ( -
-
- {this.renderPageContent()} - { - this.props.meta.communityId === 'wipro' ? - : -
- } -
- ); - } -} - -Page.defaultProps = { - isMobileOpen: false, - loadingNews: false, - news: null, -}; - -Page.propTypes = { - communityId: PT.string.isRequired, - meta: PT.shape({ - authorizedGroupIds: PT.arrayOf(PT.string), - challengeFilterTag: PT.string, - groupId: PT.string, - challengeListing: PT.shape({ - openChallengesInNewTabs: PT.bool, - prizeMode: PT.string, - }), - communityId: PT.string, - communityName: PT.string, - communitySelector: PT.arrayOf(PT.shape()), - cssUrl: PT.string, - - // TODO: isMobileOpen does not belong to community meta data, should be - // moved to a proper place! - isMobileOpen: PT.bool, - - leaderboardApiUrl: PT.string, - loading: PT.bool, - logos: PT.arrayOf(PT.oneOfType([ - PT.string, - PT.shape({ - img: PT.string.isRequired, - url: PT.string, - }), - ])), - additionalLogos: PT.arrayOf(PT.string), - stats: PT.shape(), - hideSearch: PT.bool, - chevronOverAvatar: PT.bool, - footerText: PT.string, - menuItems: PT.arrayOf(PT.shape({})).isRequired, - newsFeed: PT.string, - }).isRequired, - loadingNews: PT.bool, - news: PT.arrayOf(PT.shape), - loadNews: PT.func.isRequired, - mobileToggle: PT.func.isRequired, - pageId: PT.string.isRequired, - history: PT.shape().isRequired, - location: PT.shape().isRequired, - resetChallengeListing: PT.func.isRequired, - tokenV2: PT.string.isRequired, -}; - -const mapStateToProps = (state, props) => ({ - ...state.auth, - ...state.topcoderHeader, - meta: props.meta, - loadingNews: state.tcCommunities.news.loading, - news: state.tcCommunities.news.data, - profile: state.auth ? state.auth.profile : null, - communityId: props.communityId || props.match.params.communityId, - pageId: props.pageId || props.match.params.pageId, -}); - -const mapDispatchToProps = dispatch => _.merge( - bindActionCreators(standardHeaderActions.topcoderHeader, dispatch), { - loadNews: (url) => { - dispatch(newsActions.tcCommunities.news.getNewsInit()); - dispatch(newsActions.tcCommunities.news.getNewsDone(url)); - }, - mobileToggle: () => { - dispatch(actions.tcCommunities.meta.mobileToggle()); - }, - resetChallengeListing: () => { - const a = challengeListingActions.challengeListing; - const sa = challengeListingSidebarActions.challengeListing.sidebar; - dispatch(a.selectCommunity('')); - dispatch(a.setFilter({})); - dispatch(sa.selectBucket(BUCKETS.ALL)); - }, - }); - -export default connect( - mapStateToProps, - mapDispatchToProps, -)(Page); diff --git a/src/shared/containers/tc-communities/Page/style.scss b/src/shared/containers/tc-communities/Page/style.scss deleted file mode 100644 index 1788df2d97..0000000000 --- a/src/shared/containers/tc-communities/Page/style.scss +++ /dev/null @@ -1,8 +0,0 @@ -@import '~styles/tc-styles'; - -.loading { - @include tc-body-large; - - padding-top: 100px; - text-align: center; -} diff --git a/src/shared/containers/tc-communities/srmx/Home.js b/src/shared/containers/tc-communities/srmx/Home.js new file mode 100644 index 0000000000..a58c719841 --- /dev/null +++ b/src/shared/containers/tc-communities/srmx/Home.js @@ -0,0 +1,10 @@ +import Home from 'components/tc-communities/communities/srmx/Home'; +import { connect } from 'react-redux'; + +function mapStateToProps(state) { + return { + tokenV2: state.auth.tokenV2, + }; +} + +export default connect(mapStateToProps)(Home); diff --git a/src/shared/containers/tc-communities/wipro/Home.js b/src/shared/containers/tc-communities/wipro/Home.js new file mode 100644 index 0000000000..98fdafe988 --- /dev/null +++ b/src/shared/containers/tc-communities/wipro/Home.js @@ -0,0 +1,19 @@ +import challengeListingActions from 'actions/challenge-listing'; +import challengeListingSidebarActions from 'actions/challenge-listing/sidebar'; +import Home from 'components/tc-communities/communities/wipro/Home'; +import { connect } from 'react-redux'; +import { BUCKETS } from 'utils/challenge-listing/buckets'; + +function mapDispatchToProps(dispatch) { + return { + resetChallengeListing: () => { + const a = challengeListingActions.challengeListing; + const sa = challengeListingSidebarActions.challengeListing.sidebar; + dispatch(a.selectCommunity('')); + dispatch(a.setFilter({})); + dispatch(sa.selectBucket(BUCKETS.ALL)); + }, + }; +} + +export default connect(() => ({}), mapDispatchToProps)(Home); diff --git a/src/shared/routes/Communities/ChallengeListing.jsx b/src/shared/routes/Communities/ChallengeListing.jsx new file mode 100644 index 0000000000..53eadc4c3e --- /dev/null +++ b/src/shared/routes/Communities/ChallengeListing.jsx @@ -0,0 +1,59 @@ +/** + * Code chunk for Challenge Listing inside community. + */ + +import _ from 'lodash'; +import LoadingIndicator from 'components/LoadingIndicator'; +import PT from 'prop-types'; +import qs from 'qs'; +import React from 'react'; +import { SplitRoute } from 'utils/router'; + +export default function ChallengeListingRoute({ meta }) { + return ( + + import( + /* webpackChunkName: "challenge-listing" */ + 'containers/challenge-listing/Listing', + ).then(({ default: ChallengeListing }) => { + let query = routeProps.location.search; + query = query ? qs.parse(query.slice(1)) : {}; + const currencyFromUrl = query ? query.currency : undefined; + const prizeMode = currencyFromUrl && `money-${currencyFromUrl}`; + return ( + + ); + }) + } + renderPlaceholder={() => } + /> + ); +} + +ChallengeListingRoute.propTypes = { + meta: PT.shape({ + challengeListing: PT.shape({ + openChallengesInNewTabs: PT.bool, + }), + communityId: PT.string.isRequired, + communityName: PT.string.isRequired, + groupId: PT.string.isRequired, + }).isRequired, +}; diff --git a/src/shared/routes/Communities/Community2/Routes.jsx b/src/shared/routes/Communities/Community2/Routes.jsx new file mode 100644 index 0000000000..9612bc088d --- /dev/null +++ b/src/shared/routes/Communities/Community2/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/community-2/Home'; +import Learn from 'components/tc-communities/communities/community-2/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Community2/index.jsx b/src/shared/routes/Communities/Community2/index.jsx new file mode 100644 index 0000000000..b12cbf028a --- /dev/null +++ b/src/shared/routes/Communities/Community2/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "community-2" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/DemoExpert/Routes.jsx b/src/shared/routes/Communities/DemoExpert/Routes.jsx new file mode 100644 index 0000000000..2f9f4b31ea --- /dev/null +++ b/src/shared/routes/Communities/DemoExpert/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/demo-expert/Home'; +import Learn from 'components/tc-communities/communities/demo-expert/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/DemoExpert/index.jsx b/src/shared/routes/Communities/DemoExpert/index.jsx new file mode 100644 index 0000000000..27a6eaf945 --- /dev/null +++ b/src/shared/routes/Communities/DemoExpert/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "demo-expert-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Leaderboard.jsx b/src/shared/routes/Communities/Leaderboard.jsx new file mode 100644 index 0000000000..9ca4662fbb --- /dev/null +++ b/src/shared/routes/Communities/Leaderboard.jsx @@ -0,0 +1,32 @@ +/** + * Code chunk fro Leaderboard. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import PT from 'prop-types'; +import React from 'react'; +import { SplitRoute } from 'utils/router'; + +export default function LeaderboardRoute({ meta }) { + return ( + + import( + /* webpackChunkName: "leaderboard" */ + 'containers/Leaderboard', + ).then(({ default: Leaderboard }) => ( + + )) + } + renderPlaceholder={() => } + /> + ); +} + +LeaderboardRoute.propTypes = { + meta: PT.shape({ + leaderboardApiUrl: PT.string.isRequired, + }).isRequired, +}; diff --git a/src/shared/routes/Communities/QA/Routes.jsx b/src/shared/routes/Communities/QA/Routes.jsx new file mode 100644 index 0000000000..b43d8e28b5 --- /dev/null +++ b/src/shared/routes/Communities/QA/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/qa/Home'; +import Learn from 'components/tc-communities/communities/qa/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/QA/index.jsx b/src/shared/routes/Communities/QA/index.jsx new file mode 100644 index 0000000000..f8a41f845a --- /dev/null +++ b/src/shared/routes/Communities/QA/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "qa-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Routes.jsx b/src/shared/routes/Communities/Routes.jsx new file mode 100644 index 0000000000..d94307085e --- /dev/null +++ b/src/shared/routes/Communities/Routes.jsx @@ -0,0 +1,39 @@ +/** + * Auxiliary wrapper, which returns routes for the specified community. + */ + +import PT from 'prop-types'; +import React from 'react'; + +import Community2 from './Community2'; +import DemoExpert from './DemoExpert'; +import QA from './QA'; +import SRMx from './SRMx'; +import TaskForce from './TaskForce'; +import TcProdDev from './TcProdDev'; +import Veterans from './Veterans'; +import Wipro from './Wipro'; + +export default function Communities({ base, communityId, meta }) { + switch (communityId) { + case 'community-2': return ; + case 'demo-expert': return ; + case 'qa': return ; + case 'srmx': return ; + case 'taskforce': return ; + case 'tc-prod-dev': return ; + case 'veterans': return ; + case 'wipro': return ; + default: throw new Error('Unknown community ID!'); + } +} + +Communities.defaultProps = { + base: '', +}; + +Communities.propTypes = { + base: PT.string, + communityId: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/SRMx/Routes.jsx b/src/shared/routes/Communities/SRMx/Routes.jsx new file mode 100644 index 0000000000..9094694988 --- /dev/null +++ b/src/shared/routes/Communities/SRMx/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'containers/tc-communities/srmx/Home'; +import Learn from 'components/tc-communities/communities/srmx/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/SRMx/index.jsx b/src/shared/routes/Communities/SRMx/index.jsx new file mode 100644 index 0000000000..b8f0816820 --- /dev/null +++ b/src/shared/routes/Communities/SRMx/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "srmx-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/TaskForce/Routes.jsx b/src/shared/routes/Communities/TaskForce/Routes.jsx new file mode 100644 index 0000000000..2f2ab9ed80 --- /dev/null +++ b/src/shared/routes/Communities/TaskForce/Routes.jsx @@ -0,0 +1,60 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/taskforce/Home'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/TaskForce/index.jsx b/src/shared/routes/Communities/TaskForce/index.jsx new file mode 100644 index 0000000000..8c50e38f89 --- /dev/null +++ b/src/shared/routes/Communities/TaskForce/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "taskforce-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/TcProdDev/Routes.jsx b/src/shared/routes/Communities/TcProdDev/Routes.jsx new file mode 100644 index 0000000000..828e3d808f --- /dev/null +++ b/src/shared/routes/Communities/TcProdDev/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/tc-prod-dev/Home'; +import Learn from 'components/tc-communities/communities/tc-prod-dev/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/TcProdDev/index.jsx b/src/shared/routes/Communities/TcProdDev/index.jsx new file mode 100644 index 0000000000..71f48c2f10 --- /dev/null +++ b/src/shared/routes/Communities/TcProdDev/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "tc-prod-dev-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Veterans/Routes.jsx b/src/shared/routes/Communities/Veterans/Routes.jsx new file mode 100644 index 0000000000..34b95068f3 --- /dev/null +++ b/src/shared/routes/Communities/Veterans/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'components/tc-communities/communities/veterans/Home'; +import Learn from 'components/tc-communities/communities/veterans/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Veterans/index.jsx b/src/shared/routes/Communities/Veterans/index.jsx new file mode 100644 index 0000000000..656b7ca9f6 --- /dev/null +++ b/src/shared/routes/Communities/Veterans/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "veterans-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Wipro/Routes.jsx b/src/shared/routes/Communities/Wipro/Routes.jsx new file mode 100644 index 0000000000..f4639e7f35 --- /dev/null +++ b/src/shared/routes/Communities/Wipro/Routes.jsx @@ -0,0 +1,66 @@ +/** + * Routing of Wipro Community. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/tc-communities/communities/wipro/Footer'; +import Header from 'containers/tc-communities/Header'; +import Home from 'containers/tc-communities/wipro/Home'; +import Learn from 'components/tc-communities/communities/wipro/Learn'; +import PT from 'prop-types'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeListing from '../ChallengeListing'; +import Leaderboard from '../Leaderboard'; + +export default function Wipro({ base, meta }) { + return ( + ( +
+
+ + } + exact + path={`${base}/challenges`} + /> + } + exact + path={`${base}/leaderboard`} + /> + + + + + +
+
+ )} + path={`${base}/:pageId?`} + /> + ); +} + +Wipro.defaultProps = { + base: '', +}; + +Wipro.propTypes = { + base: PT.string, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/Wipro/index.jsx b/src/shared/routes/Communities/Wipro/index.jsx new file mode 100644 index 0000000000..097de3eca3 --- /dev/null +++ b/src/shared/routes/Communities/Wipro/index.jsx @@ -0,0 +1,41 @@ +/** + * Loader for the community's code chunks. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, meta }) { + return ( + + import( + /* webpackChunkName: "wipro-community" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Communities/index.jsx b/src/shared/routes/Communities/index.jsx new file mode 100644 index 0000000000..f22b0175ee --- /dev/null +++ b/src/shared/routes/Communities/index.jsx @@ -0,0 +1,50 @@ +/** + * Chunk loader for communities code. + */ + +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; +import PT from 'prop-types'; +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; + +export default function ChunkLoader({ base, communityId, meta }) { + return ( + + import( + /* webpackChunkName: "communities" */ + './Routes', + ).then(({ default: Routes }) => ( + + )) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + + + ); + }} + /> + ); +} + +ChunkLoader.propTypes = { + base: PT.string.isRequired, + communityId: PT.string.isRequired, + meta: PT.shape().isRequired, +}; diff --git a/src/shared/routes/Topcoder/Routes.jsx b/src/shared/routes/Topcoder/Routes.jsx new file mode 100644 index 0000000000..1a55423472 --- /dev/null +++ b/src/shared/routes/Topcoder/Routes.jsx @@ -0,0 +1,38 @@ +/** + * Groups together all routes related to the main Topcoder website. + * As we do not use any special prefix for such routes, this group of routes + * always matches, renders the standard Topcoder header and footer, and the + * content of the route, or the HTTP 404 page. + */ + +import Error404 from 'components/Error404'; +import Footer from 'components/TopcoderFooter'; +import Header from 'containers/TopcoderHeader'; + +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import ChallengeDetails from './ChallengeDetails'; +import ChallengeListing from './ChallengeListing'; +import Dashboard from './Dashboard'; +import SubmissionManagement from './SubmissionManagement'; + +export default function Topcoder() { + return ( +
+
+ + + + + + + +
+
+ ); +} diff --git a/src/shared/routes/Topcoder/index.jsx b/src/shared/routes/Topcoder/index.jsx index 1a55423472..d0e3b1f142 100644 --- a/src/shared/routes/Topcoder/index.jsx +++ b/src/shared/routes/Topcoder/index.jsx @@ -1,38 +1,35 @@ /** - * Groups together all routes related to the main Topcoder website. - * As we do not use any special prefix for such routes, this group of routes - * always matches, renders the standard Topcoder header and footer, and the - * content of the route, or the HTTP 404 page. + * Chunk loader for Topcoder website code. */ -import Error404 from 'components/Error404'; -import Footer from 'components/TopcoderFooter'; -import Header from 'containers/TopcoderHeader'; - +import LoadingIndicator from 'components/LoadingIndicator'; +import path from 'path'; import React from 'react'; -import { Route, Switch } from 'react-router-dom'; - -import ChallengeDetails from './ChallengeDetails'; -import ChallengeListing from './ChallengeListing'; -import Dashboard from './Dashboard'; -import SubmissionManagement from './SubmissionManagement'; +import { StaticRouter } from 'react-router-dom'; +import { requireWeak, resolveWeak, SplitRoute } from 'utils/router'; -export default function Topcoder() { +export default function ChunkLoader() { return ( -
-
- - - - - - - -
-
+ + import( + /* webpackChunkName: "topcoder-website" */ + './Routes', + ).then(({ default: Routes }) => ) + } + renderPlaceholder={() => } + renderServer={(routeProps) => { + const p = resolveWeak('./Routes'); + const Routes = requireWeak(path.resolve(__dirname, p)); + return ( + + ); + }} + /> ); } diff --git a/src/shared/routes/index.jsx b/src/shared/routes/index.jsx index 727bf1826c..47ed69ca9f 100644 --- a/src/shared/routes/index.jsx +++ b/src/shared/routes/index.jsx @@ -10,10 +10,9 @@ import { Switch, Route, withRouter } from 'react-router-dom'; import PT from 'prop-types'; -import TcCommunitiesPage from 'containers/tc-communities/Page'; - import { connect } from 'react-redux'; +import Communities from './Communities'; import Examples from './Examples'; import Topcoder from './Topcoder'; @@ -30,31 +29,12 @@ function Routes({ subdomains }) { else if (subdomains.includes('veterans')) communityId = 'veterans'; if (communityId) { return ( -
- ( - ( - - )} - communityId={communityId} - /> - )} - exact - path="/" - /> - ( - ( - - )} - communityId={communityId} - /> - )} - path="/:pageId" - /> -
+ ( + + )} + communityId={communityId} + /> ); } return ( @@ -62,37 +42,26 @@ function Routes({ subdomains }) { { Examples() } ( + component={({ match }) => ( ( - + communityComponent={({ meta }) => ( + )} - communityId={routeProps.match.params.communityId} + communityId={match.params.communityId} /> )} - exact path="/community/:communityId" /> - ( - ( - - )} - communityId={routeProps.match.params.communityId} - /> - )} - path="/community/:communityId/:pageId" - /> ); } Routes.propTypes = { - location: PT.shape({ - search: PT.string.isRequired, - }).isRequired, subdomains: PT.arrayOf(PT.string).isRequired, }; diff --git a/src/shared/services/.exchange-rates.cache b/src/shared/services/.exchange-rates.cache index 5d92a0a1d8..a2fe2927f8 100644 --- a/src/shared/services/.exchange-rates.cache +++ b/src/shared/services/.exchange-rates.cache @@ -1 +1 @@ -{"disclaimer":"Usage subject to terms: https://openexchangerates.org/terms","license":"https://openexchangerates.org/license","timestamp":1503234006,"base":"USD","rates":{"AED":3.673018,"AFN":68.62,"ALL":112.78,"AMD":477.815313,"ANG":1.778253,"AOA":165.9205,"ARS":17.329,"AUD":1.261034,"AWG":1.785,"AZN":1.686,"BAM":1.663083,"BBD":2,"BDT":81.132616,"BGN":1.66097,"BHD":0.377029,"BIF":1737.1,"BMD":1,"BND":1.362037,"BOB":6.910011,"BRL":3.1469,"BSD":1,"BTC":0.000241800309,"BTN":58.535434,"BWP":10.209769,"BYN":1.936056,"BZD":2.0137,"CAD":1.258653,"CDF":1600.102407,"CHF":0.964735,"CLF":0.024072,"CLP":646.4,"CNH":6.680275,"CNY":6.666994,"COP":2989.79,"CRC":576.505,"CUC":1,"CUP":25.75,"CVE":93.870351,"CZK":22.1528,"DJF":177.594999,"DKK":6.324,"DOP":47.047096,"DZD":110.004,"EGP":17.7715,"ERN":15.278472,"ETB":23.350278,"EUR":0.85023,"FJD":2.016997,"FKP":0.7769,"GBP":0.7769,"GEL":2.392033,"GGP":0.7769,"GHS":4.42,"GIP":0.7769,"GMD":45.25,"GNF":8886.1,"GTQ":7.264251,"GYD":207.997754,"HKD":7.82375,"HNL":23.356183,"HRK":6.292611,"HTG":64.417736,"HUF":257.98,"IDR":13360.5,"ILS":3.619015,"IMP":0.7769,"INR":64.0859,"IQD":1165.8,"IRR":32934.2931,"ISK":105.888433,"JEP":0.7769,"JMD":127.675593,"JOD":0.709002,"JPY":109.215,"KES":103.15,"KGS":55.912251,"KHR":4115.45,"KMF":386.149994,"KPW":899.91,"KRW":1139.75,"KWD":0.301971,"KYD":0.832461,"KZT":332.8,"LAK":8280.25,"LBP":1505,"LKR":153.197538,"LRD":114.411442,"LSL":13.206225,"LYD":1.370605,"MAD":9.464947,"MDL":17.857,"MGA":2950.55,"MKD":52.35,"MMK":1362.6,"MNT":2438.5,"MOP":8.048883,"MRO":363.95,"MUR":33.364333,"MVR":14.14,"MWK":724.675734,"MXN":17.7067,"MYR":4.289546,"MZN":61.315,"NAD":13.206225,"NGN":337.64,"NIO":29.9645,"NOK":7.90891,"NPR":102.482551,"NZD":1.367241,"OMR":0.38517,"PAB":1,"PEN":3.238992,"PGK":3.171065,"PHP":51.393,"PKR":105.328422,"PLN":3.63365,"PYG":5563.45,"QAR":3.65625,"RON":3.901513,"RSD":101.473285,"RUB":58.944892,"RWF":827.733566,"SAR":3.75025,"SBD":7.748625,"SCR":13.502301,"SDG":6.669914,"SEK":8.1106,"SGD":1.3632,"SHP":0.7769,"SLL":7500.75,"SOS":577.955,"SRD":7.438,"SSP":125.635435,"STD":20835.384111,"SVC":8.741134,"SYP":515.04499,"SZL":13.211179,"THB":33.21225,"TJS":8.813795,"TMT":3.4504,"TND":2.4073,"TOP":2.190219,"TRY":3.516523,"TTD":6.763951,"TWD":30.323,"TZS":2236.75,"UAH":25.443313,"UGX":3601.5,"USD":1,"UYU":28.576479,"UZS":4150.2,"VEF":10.30325,"VND":22728.15,"VUV":104.490002,"WST":2.44275,"XAF":557.71432,"XAG":0.05894228,"XAU":0.00077842,"XCD":2.70255,"XDR":0.709706,"XOF":557.71432,"XPD":0.00108054,"XPF":101.459427,"XPT":0.00102087,"YER":249.796999,"ZAR":13.16008,"ZMW":9.000848,"ZWL":322.322775}} \ No newline at end of file +{"disclaimer":"Usage subject to terms: https://openexchangerates.org/terms","license":"https://openexchangerates.org/license","timestamp":1503320400,"base":"USD","rates":{"AED":3.673158,"AFN":68.656,"ALL":112.41,"AMD":478.39,"ANG":1.779113,"AOA":165.9205,"ARS":17.34,"AUD":1.258533,"AWG":1.788333,"AZN":1.686,"BAM":1.662492,"BBD":2,"BDT":81.260068,"BGN":1.661406,"BHD":0.37722,"BIF":1738.3,"BMD":1,"BND":1.362399,"BOB":6.971365,"BRL":3.143578,"BSD":1,"BTC":0.000245786919,"BTN":64.109632,"BWP":10.199062,"BYN":1.930973,"BZD":2.014625,"CAD":1.257105,"CDF":1600.102407,"CHF":0.965015,"CLF":0.02406,"CLP":642.74,"CNH":6.674255,"CNY":6.66995,"COP":2987.85,"CRC":576.636761,"CUC":1,"CUP":25.5,"CVE":93.739999,"CZK":22.1381,"DJF":177.88,"DKK":6.313208,"DOP":47.235401,"DZD":109.8775,"EGP":17.751,"ERN":15.335,"ETB":23.365963,"EUR":0.848867,"FJD":2.029307,"FKP":0.775561,"GBP":0.775561,"GEL":2.3901,"GGP":0.775561,"GHS":4.41592,"GIP":0.775561,"GMD":45.25,"GNF":8888.3,"GTQ":7.270847,"GYD":207.863351,"HKD":7.823825,"HNL":23.362162,"HRK":6.285378,"HTG":64.443846,"HUF":257.4805,"IDR":13349.27042,"ILS":3.61777,"IMP":0.775561,"INR":64.1222,"IQD":1167.4,"IRR":32829,"ISK":105.58884,"JEP":0.775561,"JMD":127.77,"JOD":0.709001,"JPY":108.9369,"KES":103.1,"KGS":68.727849,"KHR":4114.8,"KMF":419.45,"KPW":900,"KRW":1138.3,"KWD":0.301816,"KYD":0.832923,"KZT":332.730868,"LAK":8282.1,"LBP":1505.7,"LKR":153.078195,"LRD":114.700001,"LSL":13.173642,"LYD":1.370305,"MAD":9.477963,"MDL":17.849263,"MGA":2958.4,"MKD":52.2547,"MMK":1358.8,"MNT":2439.959961,"MOP":8.053858,"MRO":364.81,"MUR":33.435,"MVR":15.47,"MWK":725.275,"MXN":17.66503,"MYR":4.286787,"MZN":61.28,"NAD":13.195,"NGN":362.5,"NIO":29.950331,"NOK":7.88513,"NPR":102.543085,"NZD":1.364778,"OMR":0.385005,"PAB":1,"PEN":3.242597,"PGK":3.180222,"PHP":51.3985,"PKR":105.328422,"PLN":3.62423,"PYG":5576.1,"QAR":3.638,"RON":3.89236,"RSD":101.355,"RUB":58.984213,"RWF":827.576066,"SAR":3.7504,"SBD":7.754399,"SCR":13.638957,"SDG":6.673181,"SEK":8.080053,"SGD":1.361433,"SHP":0.775561,"SLL":7550,"SOS":578.19,"SRD":7.438,"SSP":125.3948,"STD":20813.700196,"SVC":8.745961,"SYP":514.98999,"SZL":13.163774,"THB":33.244,"TJS":8.805499,"TMT":3.466667,"TND":2.404752,"TOP":2.215897,"TRY":3.495594,"TTD":6.767229,"TWD":30.33,"TZS":2240,"UAH":25.476771,"UGX":3601.15,"USD":1,"UYU":28.563778,"UZS":4152.15,"VEF":10.303375,"VND":22718.166667,"VUV":104.118876,"WST":2.488972,"XAF":556.820087,"XAG":0.05864423,"XAU":0.00077622,"XCD":2.70255,"XDR":0.709706,"XOF":556.820087,"XPD":0.00106943,"XPF":101.296748,"XPT":0.00101627,"YER":249.878749,"ZAR":13.167543,"ZMW":9.014201,"ZWL":322.355011}} \ No newline at end of file diff --git a/src/shared/utils/router/SplitRoute.jsx b/src/shared/utils/router/SplitRoute.jsx index 001e520050..ff7425cc33 100644 --- a/src/shared/utils/router/SplitRoute.jsx +++ b/src/shared/utils/router/SplitRoute.jsx @@ -23,6 +23,10 @@ export default class SplitRoute extends React.Component { this.state = { component: null }; } + componentWillUnmount() { + this.unmounted = true; + } + reset() { /* Removing chunk's stylesheet from the DOM. */ if (!this.props.cacheCss) { @@ -131,7 +135,8 @@ export default class SplitRoute extends React.Component { * it gives a better control over reloading of the stylesheets and * helps to avoid some unnecessary flickering when the app loads a * page already pre-rendered at the server side. */ - let link = document.querySelector(`link[data-chunk=${chunkName}]`); + let link = + document.querySelector(`link[data-chunk="${chunkName}"]`); if (!link) { link = document.createElement('link'); link.setAttribute('data-chunk', chunkName); @@ -150,7 +155,7 @@ export default class SplitRoute extends React.Component { * that the next time the route is matched, its content will * be re-rendered from scratch. */ renderClientAsync(props).then(component => - this.setState({ + !this.unmounted && this.setState({ component: () => (
Date: Mon, 21 Aug 2017 13:20:52 -0400 Subject: [PATCH 2/8] moved continue button --- .../components/tc-communities/communities/wipro/Learn/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/components/tc-communities/communities/wipro/Learn/index.jsx b/src/shared/components/tc-communities/communities/wipro/Learn/index.jsx index d4b9f02499..9a88e97c98 100644 --- a/src/shared/components/tc-communities/communities/wipro/Learn/index.jsx +++ b/src/shared/components/tc-communities/communities/wipro/Learn/index.jsx @@ -43,13 +43,13 @@ export default function Learn() { />
+

If you are accessing TopGear Learning Platform from Wipro backbone network, click on “CONTINUE” to access the platform.

-

If you are accessing TopGear Learning Platform from Wipro backbone network, click on “CONTINUE” to access the platform.

To access TopGear Learning Platform outside of Wipro network, please follow the below instructions:

  1. From c2df89b72a32ac8a0ea39019ea152b4bd7d353ef Mon Sep 17 00:00:00 2001 From: ajefts Date: Mon, 21 Aug 2017 13:32:14 -0400 Subject: [PATCH 3/8] Updated faq --- .../tc-communities/communities/wipro/Home/index.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/components/tc-communities/communities/wipro/Home/index.jsx b/src/shared/components/tc-communities/communities/wipro/Home/index.jsx index 5faefc732b..f2faafda17 100644 --- a/src/shared/components/tc-communities/communities/wipro/Home/index.jsx +++ b/src/shared/components/tc-communities/communities/wipro/Home/index.jsx @@ -200,13 +200,13 @@ export default function Home(props) { > -

    Just do it! (A better answer will be placed here soon)

    +

    Find a challenge that interests you on the challenge listings page. You can filter by challenge types, prizes, deadlines, etc. Look for challenges that are still open for registration. If you see something that interests you, click it and then you can read the details and register for the challenge.

    -

    Just do it! (A better answer will be placed here soon)

    +

    Do all of your coding/design work offline, or as specified in the challenge spec. When you are ready to submit, come back to the challenge page and click the Submit button. The Submit page will give instructions to upload your submission.

    - -

    Just do it! (A better answer will be placed here soon)

    + +

    If you are a reviewer or copilot and need information about managing projects and challenges, please visit the Help Center.

From a1cae87fcfbc59447f6d3d7f3d0a847f466a25e2 Mon Sep 17 00:00:00 2001 From: TonyJ Date: Mon, 21 Aug 2017 14:11:50 -0400 Subject: [PATCH 4/8] updated tests --- .../wipro/__snapshots__/Learn.jsx.snap | 34 +- package-lock.json | 1457 +++++++++++++++-- 2 files changed, 1297 insertions(+), 194 deletions(-) diff --git a/__tests__/shared/components/tc-communities/communities/wipro/__snapshots__/Learn.jsx.snap b/__tests__/shared/components/tc-communities/communities/wipro/__snapshots__/Learn.jsx.snap index 2c3be78a62..7b8fa9d2f1 100644 --- a/__tests__/shared/components/tc-communities/communities/wipro/__snapshots__/Learn.jsx.snap +++ b/__tests__/shared/components/tc-communities/communities/wipro/__snapshots__/Learn.jsx.snap @@ -40,6 +40,23 @@ exports[`Snapshot match 1`] = `
+

+ If you are accessing TopGear + + Learning + + Platform from + + Wipro backbone network + + , click on “ + + CONTINUE + + ” to access the platform. +

-

- If you are accessing TopGear - - Learning - - Platform from - - Wipro backbone network - - , click on “ - - CONTINUE - - ” to access the platform. -

To access TopGear - - - -

-
-
- - -
-
- -
- - - -
- - - - - ); } From 4aa04bd6c60ff927b936f77314e4963ba211e3a8 Mon Sep 17 00:00:00 2001 From: TonyJ Date: Mon, 21 Aug 2017 14:40:25 -0400 Subject: [PATCH 6/8] removed imports not used --- .../tc-communities/communities/srmx/Home/index.jsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/shared/components/tc-communities/communities/srmx/Home/index.jsx b/src/shared/components/tc-communities/communities/srmx/Home/index.jsx index 932ff5357a..0145174404 100644 --- a/src/shared/components/tc-communities/communities/srmx/Home/index.jsx +++ b/src/shared/components/tc-communities/communities/srmx/Home/index.jsx @@ -8,22 +8,11 @@ import React from 'react'; import Section from 'components/tc-communities/Section'; -import Banner from 'components/tc-communities/Banner'; -import ImageText from 'components/tc-communities/ImageText'; -import ResourceCard from 'components/tc-communities/ResourceCard'; -import NewsletterSignup from 'components/tc-communities/NewsletterSignup'; -import NewsSection from 'components/tc-communities/NewsSection'; import PT from 'prop-types'; import LoadingIndicator from 'components/LoadingIndicator'; -import CommunityStats from 'containers/tc-communities/CommunityStats'; -import JoinCommunity from 'containers/tc-communities/JoinCommunity'; - import { getApiV2 } from 'services/api'; -import IconRocket from '../../../../../../assets/images/tc-communities/rocket.svg'; -import IconNetwork from '../../../../../../assets/images/tc-communities/network.svg'; -import IconMedal from '../../../../../../assets/images/tc-communities/medal.svg'; import style from './style.scss'; @@ -74,9 +63,6 @@ export default class Home extends React.Component { } } -Home.defaultProps = { - news: [], -}; Home.propTypes = { news: PT.arrayOf(PT.shape()), From 58739bd0c967eec7940c145dbe3020d45dddd646 Mon Sep 17 00:00:00 2001 From: TonyJ Date: Mon, 21 Aug 2017 14:58:37 -0400 Subject: [PATCH 7/8] fixing tests --- .../components/tc-communities/communities/srmx/Home/index.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/components/tc-communities/communities/srmx/Home/index.jsx b/src/shared/components/tc-communities/communities/srmx/Home/index.jsx index 0145174404..eb428d1a86 100644 --- a/src/shared/components/tc-communities/communities/srmx/Home/index.jsx +++ b/src/shared/components/tc-communities/communities/srmx/Home/index.jsx @@ -65,7 +65,6 @@ export default class Home extends React.Component { Home.propTypes = { - news: PT.arrayOf(PT.shape()), tokenV2: PT.string.isRequired, }; From 0bcb233fbd26f597a8fb2a5860cfea6ce5f872e2 Mon Sep 17 00:00:00 2001 From: "Dr. Sergey Pogodin" Date: Mon, 21 Aug 2017 21:01:11 +0200 Subject: [PATCH 8/8] Fix: Avoid deadlocks caused by SplitRoute component --- src/shared/utils/router/SplitRoute.jsx | 59 ++++++++++++++++++++------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/shared/utils/router/SplitRoute.jsx b/src/shared/utils/router/SplitRoute.jsx index ff7425cc33..95cc298c85 100644 --- a/src/shared/utils/router/SplitRoute.jsx +++ b/src/shared/utils/router/SplitRoute.jsx @@ -8,9 +8,11 @@ /* global document, window */ +import _ from 'lodash'; import PT from 'prop-types'; import React from 'react'; import ReactDomServer from 'react-dom/server'; +import shortid from 'shortid'; import { Provider } from 'react-redux'; import { Route } from 'react-router-dom'; import { isServerSide } from 'utils/isomorphy'; @@ -29,12 +31,14 @@ export default class SplitRoute extends React.Component { reset() { /* Removing chunk's stylesheet from the DOM. */ - if (!this.props.cacheCss) { - const link = document.querySelector( - `link[data-chunk=${this.props.chunkName}]`); - const head = document.getElementsByTagName('head')[0]; - head.removeChild(link); - } + /* NOTE: It look like caching CSS makes no sense, as it starts conflicting + * with other stylesheets. */ + // if (!this.props.cacheCss) { + const link = document.querySelector( + `link[data-chunk=${this.props.chunkName}]`); + const head = document.getElementsByTagName('head')[0]; + head.removeChild(link); + // } /* Reset to the initial state. */ this.setState({ component: null }); @@ -137,7 +141,16 @@ export default class SplitRoute extends React.Component { * page already pre-rendered at the server side. */ let link = document.querySelector(`link[data-chunk="${chunkName}"]`); - if (!link) { + if (link) { + /* Even if the stylesheet is already loaded, we should move it + * to the end of the head, to ensure that it gets priority over + * anything else. + * On the other hand, if we drop cacheCss option, this should not + * be a problem, and can be more efficient. + */ + // const head = document.getElementsByTagName('head')[0]; + // head.appendChild(link); + } else { link = document.createElement('link'); link.setAttribute('data-chunk', chunkName); link.setAttribute('href', `/${chunkName}.css`); @@ -146,6 +159,24 @@ export default class SplitRoute extends React.Component { head.appendChild(link); } + /* Checking, whether we need to trigger async rendering process, + * as it might be already launched before and we can end up with + * a deadlock. We want to re-trigger it only if some props having + * impact on the rendering result have been changed. */ + let shouldReRender = !this.pendingRender; + if (!shouldReRender) { + shouldReRender = this.pendingRender !== renderClientAsync; + _.forIn(this.pendingRenderProps, (value, key) => { + shouldReRender = shouldReRender || (value !== props[key]); + }); + } + if (!shouldReRender) return res; + + const renderUUID = shortid(); + this.pendingRenderUUID = renderUUID; + this.pendingRender = renderClientAsync; + this.pendingRenderProps = props; + /* Finally, we call the async renderer and once the promise it * returns is resolved, we set the resulting component to the state, * which causes it to be set on this route via "component" props, @@ -154,8 +185,12 @@ export default class SplitRoute extends React.Component { * removing it from the state once it is unmounted, to ensure * that the next time the route is matched, its content will * be re-rendered from scratch. */ - renderClientAsync(props).then(component => - !this.unmounted && this.setState({ + renderClientAsync(props).then((component) => { + if (renderUUID !== this.pendingRenderUUID) return; + this.pendingRenderUUID = null; + this.pendingRender = null; + this.pendingRenderProps = null; + this.setState({ component: () => (
), - }), - ); + }); + }); } return res; @@ -188,7 +223,7 @@ SplitRoute.defaultProps = { }; SplitRoute.propTypes = { - cacheCss: PT.bool, + // cacheCss: PT.bool, chunkName: PT.string.isRequired, exact: PT.bool, location: PT.shape(),