diff --git a/.exchange-rates.cache b/.exchange-rates.cache index 3ddffed910..3023d7ea24 100644 --- a/.exchange-rates.cache +++ b/.exchange-rates.cache @@ -1 +1 @@ -{"disclaimer":"Usage subject to terms: https://openexchangerates.org/terms","license":"https://openexchangerates.org/license","timestamp":1505736000,"base":"USD","rates":{"AED":3.673158,"AFN":68.5815,"ALL":111.8,"AMD":477.790313,"ANG":1.778804,"AOA":165.9215,"ARS":16.9755,"AUD":1.25125,"AWG":1.795504,"AZN":1.7,"BAM":1.634564,"BBD":2,"BDT":80.672708,"BGN":1.636335,"BHD":0.377082,"BIF":1741.930974,"BMD":1,"BND":1.34545,"BOB":6.960491,"BRL":3.109108,"BSD":1,"BTC":0.000253264491,"BTN":64.116668,"BWP":10.145655,"BYN":1.937212,"BZD":2.014389,"CAD":1.220886,"CDF":1562.881563,"CHF":0.959897,"CLF":0.02317,"CLP":624.3,"CNH":6.573772,"CNY":6.567823,"COP":2895.45,"CRC":576.47,"CUC":1,"CUP":25.5,"CVE":92.5,"CZK":21.844736,"DJF":178.57,"DKK":6.230533,"DOP":47.218414,"DZD":111.31,"EGP":17.657,"ERN":15.33,"ETB":23.555095,"EUR":0.837253,"FJD":2.021499,"FKP":0.738416,"GBP":0.738416,"GEL":2.4678,"GGP":0.738416,"GHS":4.389404,"GIP":0.738416,"GMD":45.875,"GNF":8956.4,"GTQ":7.288462,"GYD":207.825,"HKD":7.816553,"HNL":23.374343,"HRK":6.263403,"HTG":62.980903,"HUF":259.437857,"IDR":13250.485412,"ILS":3.522186,"IMP":0.738416,"INR":64.13575,"IQD":1165.334957,"IRR":33322.5,"ISK":106.536883,"JEP":0.738416,"JMD":130.80781,"JOD":0.7085,"JPY":111.36808333,"KES":103.163661,"KGS":68.5084,"KHR":4056.35,"KMF":412.198944,"KPW":900,"KRW":1127.07,"KWD":0.301343,"KYD":0.832734,"KZT":340.315,"LAK":8280.05,"LBP":1506.95,"LKR":153.01,"LRD":117.002232,"LSL":13.175459,"LYD":1.361065,"MAD":9.344244,"MDL":17.643449,"MGA":2988,"MKD":51.51,"MMK":1345.1,"MNT":2459.426676,"MOP":8.045534,"MRO":364.77,"MUR":33.434,"MVR":15.450233,"MWK":725.38,"MXN":17.68575,"MYR":4.186467,"MZN":61.32,"NAD":13.176312,"NGN":359.885566,"NIO":30.345231,"NOK":7.824174,"NPR":102.523085,"NZD":1.372936,"OMR":0.384999,"PAB":1,"PEN":3.250448,"PGK":3.237256,"PHP":51.254,"PKR":105.279978,"PLN":3.5905,"PYG":5655.55,"QAR":3.6391,"RON":3.8506,"RSD":99.645,"RUB":57.747,"RWF":830.004133,"SAR":3.7509,"SBD":7.830881,"SCR":13.550608,"SDG":6.672493,"SEK":7.970225,"SGD":1.346251,"SHP":0.738416,"SLL":7562.5,"SOS":577.104786,"SRD":7.438,"SSP":126.0479,"STD":20503.299805,"SVC":8.743343,"SYP":515.10499,"SZL":13.181602,"THB":33.090672,"TJS":8.79211,"TMT":3.50998,"TND":2.439804,"TOP":2.232925,"TRY":3.4586,"TTD":6.74155,"TWD":30.098212,"TZS":2244.6,"UAH":26.142754,"UGX":3593.6,"USD":1,"UYU":28.997418,"UZS":8086.95,"VEF":9.985022,"VND":22727.933333,"VUV":104.754453,"WST":2.500057,"XAF":549.202101,"XAG":0.05731152,"XAU":0.00076117,"XCD":2.70255,"XDR":0.702343,"XOF":549.202101,"XPD":0.00107202,"XPF":99.910884,"XPT":0.00103467,"YER":250.319142,"ZAR":13.207619,"ZMW":9.628588,"ZWL":322.355011}} \ No newline at end of file +{"disclaimer":"Usage subject to terms: https://openexchangerates.org/terms","license":"https://openexchangerates.org/license","timestamp":1505811600,"base":"USD","rates":{"AED":3.673014,"AFN":68.614,"ALL":111.776085,"AMD":478.295,"ANG":1.77968,"AOA":165.9215,"ARS":17.0995,"AUD":1.252216,"AWG":1.796504,"AZN":1.6855,"BAM":1.635351,"BBD":2,"BDT":80.708351,"BGN":1.63299,"BHD":0.377284,"BIF":1745.45,"BMD":1,"BND":1.348334,"BOB":6.963698,"BRL":3.13655,"BSD":1,"BTC":0.000253137519,"BTN":64.166558,"BWP":10.15073,"BYN":1.938191,"BZD":2.015375,"CAD":1.228379,"CDF":1562.881563,"CHF":0.961344,"CLF":0.02325,"CLP":624.6,"CNH":6.585748,"CNY":6.583106,"COP":2909,"CRC":576.745,"CUC":1,"CUP":25.5,"CVE":92.55,"CZK":21.791915,"DJF":178.57,"DKK":6.209958,"DOP":47.241072,"DZD":111.282333,"EGP":17.6487,"ERN":15.331922,"ETB":23.566647,"EUR":0.834449,"FJD":2.012549,"FKP":0.742007,"GBP":0.742007,"GEL":2.4717,"GGP":0.742007,"GHS":4.381672,"GIP":0.742007,"GMD":45.95,"GNF":8960.5,"GTQ":7.292123,"GYD":207.92,"HKD":7.803084,"HNL":23.385811,"HRK":6.235527,"HTG":63.0095,"HUF":258.117002,"IDR":13264.557907,"ILS":3.52281,"IMP":0.742007,"INR":64.245,"IQD":1165.609957,"IRR":33337.5,"ISK":105.94,"JEP":0.742007,"JMD":130.865,"JOD":0.709001,"JPY":111.5666875,"KES":103.367854,"KGS":68.455728,"KHR":4058.3,"KMF":412.561444,"KPW":900,"KRW":1131.54,"KWD":0.301307,"KYD":0.833119,"KZT":340.305898,"LAK":8284.05,"LBP":1507.65,"LKR":153.101598,"LRD":117.111232,"LSL":13.182434,"LYD":1.361748,"MAD":9.333026,"MDL":17.669492,"MGA":2989.5,"MKD":51.401508,"MMK":1345.8,"MNT":2468.97015,"MOP":8.049209,"MRO":364.935,"MUR":33.4205,"MVR":15.450233,"MWK":724.527458,"MXN":17.810955,"MYR":4.191489,"MZN":61.732957,"NAD":13.182434,"NGN":360.37226,"NIO":30.359705,"NOK":7.804146,"NPR":102.548085,"NZD":1.372687,"OMR":0.385015,"PAB":1,"PEN":3.247336,"PGK":3.23879,"PHP":50.99,"PKR":105.333422,"PLN":3.5831,"PYG":5658.3,"QAR":3.656908,"RON":3.840574,"RSD":99.257652,"RUB":58.1634,"RWF":831.55,"SAR":3.75035,"SBD":7.823231,"SCR":13.55,"SDG":6.675602,"SEK":7.95019,"SGD":1.348793,"SHP":0.742007,"SLL":7558.984779,"SOS":578.446731,"SRD":7.438,"SSP":126.2714,"STD":20487.565958,"SVC":8.747714,"SYP":515.00499,"SZL":13.187884,"THB":33.083,"TJS":8.795919,"TMT":3.50998,"TND":2.437494,"TOP":2.2232,"TRY":3.501853,"TTD":6.74491,"TWD":30.156,"TZS":2243.2,"UAH":26.155965,"UGX":3595.3,"USD":1,"UYU":28.986914,"UZS":8090.5,"VEF":9.995002,"VND":22731.335859,"VUV":104.480024,"WST":2.480432,"XAF":547.362622,"XAG":0.05821916,"XAU":0.00076407,"XCD":2.70255,"XDR":0.702671,"XOF":547.362622,"XPD":0.00107407,"XPF":99.576246,"XPT":0.00104276,"YER":250.344142,"ZAR":13.330636,"ZMW":9.633257,"ZWL":322.355011}} \ No newline at end of file diff --git a/README.md b/README.md index 00dd8ac7fb..09689571ce 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ If you need any operations related to currency conversions, pay attention to the - `PORT` Specifies the port to run the App at. Defaults to 3000; - `NODE_ENV` Specifies Topcoder backend to use. Should be either `development` either `production`. Defaults to `production`. -5. To rebuild the App's frontend (initially, it is automatically build as a part of the install step) run one of (the result of build will be output into `/build` folder in both cases): +5. To build the App's frontend run one of (the result of build will be output into `/build` folder in both cases): - `$ npm run build` To rebuild production frontend; - `$ npm run build:dev` This command should only be used to test whether development build of the front end works. You don't have to execute this command to run development version of the App (the server will automatically build frontend in memory anyway). You can't successfully execute this command without installing dev dependencies. diff --git a/__tests__/shared/components/challenge-listing/__snapshots__/index.jsx.snap b/__tests__/shared/components/challenge-listing/__snapshots__/index.jsx.snap index 4974af4e1d..2bce595e93 100644 --- a/__tests__/shared/components/challenge-listing/__snapshots__/index.jsx.snap +++ b/__tests__/shared/components/challenge-listing/__snapshots__/index.jsx.snap @@ -23,6 +23,7 @@ exports[`Matches shallow shapshot 1 shapshot 1 1`] = `
@@ -40,6 +41,7 @@ exports[`Matches shallow shapshot 1 shapshot 1 1`] = `
@@ -135,6 +137,7 @@ exports[`Matches shallow shapshot 2 shapshot 2 1`] = `
@@ -152,6 +155,7 @@ exports[`Matches shallow shapshot 2 shapshot 2 1`] = `
diff --git a/__tests__/shared/reducers/challenge.js b/__tests__/shared/reducers/challenge.js index 9c9261f882..c8ac648ec2 100644 --- a/__tests__/shared/reducers/challenge.js +++ b/__tests__/shared/reducers/challenge.js @@ -86,7 +86,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -112,7 +111,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -132,7 +130,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -154,7 +151,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -177,7 +173,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -200,7 +195,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); @@ -223,7 +217,6 @@ function testReducer(reducer, istate) { resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }); }); } @@ -242,7 +235,6 @@ describe('Default reducer', () => resultsLoadedForChallengeId: '', selectedTab: 'details', unregistering: false, - showTermsModal: false, }), ); @@ -260,7 +252,6 @@ describe('Factory without http request', () => mySubmissionsManagement: {}, registering: false, unregistering: false, - showTermsModal: false, }), ), ); @@ -282,7 +273,6 @@ describe('Factory with server-side rendering', () => mySubmissionsManagement: {}, registering: false, unregistering: false, - showTermsModal: false, }), ), ); @@ -300,7 +290,6 @@ describe('Factory without server-side rendering', () => mySubmissionsManagement: {}, registering: false, unregistering: false, - showTermsModal: false, }), ), ); diff --git a/docs/how-to-add-a-new-topcoder-community.md b/docs/how-to-add-a-new-topcoder-community.md index a375e37e4d..ee708700fc 100644 --- a/docs/how-to-add-a-new-topcoder-community.md +++ b/docs/how-to-add-a-new-topcoder-community.md @@ -123,10 +123,6 @@ To add a new community with the name **demo**, we should follow the following pr 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`). - To make **demo** community accessible via a dedicated sub-domain, e.g. like `demo.topcoder-dev.com`, you should edit `/src/shared/routes/index.jsx`. In the first `if-else` block inside `Routes()` function add the line - ```js - else if (subdomains.indexOf('demo') >= 0) communityId = 'demo'; - ``` - This takes care about proper sub-domain routing from our App's side. Beside it you should: + To make **demo** community accessible via a dedicated sub-domain, e.g. like `demo.topcoder-dev.com`, you should edit `/src/shared/routes/subdomains.js`; add `demo: 'demo',` record (i.e. the format is `subdomain: 'communityId'`) into the `SUBDOMAIN_COMMUNITY` map. Beside it you should: - Ensure that the web-server where the App is deployed allows access to the subdomain `demo.topcoder-dev`, and redirects incoming requests to the App. - Ensure that Topcoder `accounts-app` allows to authenticate from the new subdomain address. diff --git a/package-lock.json b/package-lock.json index c49e27d2dc..f81a0f5eb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4935,6 +4935,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" }, + "is_js": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz", + "integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=" + }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -5172,11 +5177,6 @@ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, - "is_js": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz", - "integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=" - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -11822,6 +11822,14 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, "string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -11851,14 +11859,6 @@ "strip-ansi": "3.0.1" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "requires": { - "safe-buffer": "5.1.1" - } - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -12394,10 +12394,6 @@ "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-5.0.5.tgz", "integrity": "sha512-z7zOXZKEFOloIeSMtsDpudWWfXd7L2qmhyxOAve4ZGFYwBn98zYBd2R4CIlPWMpcm4ZwfhIMTVUxCDgSSXrPKw==" }, - "Base64": { - "version": "https://registry.npmjs.org/Base64/-/Base64-0.1.4.tgz", - "integrity": "sha1-6fbGvvVn/WNepBYqsU3TKedKpt4=" - }, "abbrev": { "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" @@ -13488,6 +13484,10 @@ "version": "https://registry.npmjs.org/base62/-/base62-1.2.0.tgz", "integrity": "sha1-MeflYNyEbJ9EwaUx32UU2jVHQVc=" }, + "Base64": { + "version": "https://registry.npmjs.org/Base64/-/Base64-0.1.4.tgz", + "integrity": "sha1-6fbGvvVn/WNepBYqsU3TKedKpt4=" + }, "base64-js": { "version": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", "integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY=" @@ -15456,16 +15456,16 @@ } } }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=" - }, "string_decoder": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=" }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=" + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -18805,6 +18805,10 @@ "version": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "string-width": { "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", @@ -18814,10 +18818,6 @@ "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" } }, - "string_decoder": { - "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "stringstream": { "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" diff --git a/src/server/server.js b/src/server/server.js index 50845422e1..e2fab70e31 100644 --- a/src/server/server.js +++ b/src/server/server.js @@ -9,6 +9,7 @@ import path from 'path'; import favicon from 'serve-favicon'; import requestIp from 'request-ip'; import stream from 'stream'; +import serializeJs from 'serialize-javascript'; import { getRates as getExchangeRates } from 'services/money'; import { toJson as xmlToJson } from 'utils/xml2json'; @@ -105,9 +106,10 @@ app.use('/api/exchange-rates', (req, res) => { getExchangeRates().then(rates => res.send(rates)); }); +/* Receive the signing result from DocuSign server, and then send result to client + */ app.use('/iframe-break', (req, res) => { - const url = req.query.dest; - res.send(``); + res.send(``); }); /* Serves a mock DocuSign page. Which is, actually, just a simple local diff --git a/src/shared/actions/challenge.js b/src/shared/actions/challenge.js index 86042024d1..70ddc89e77 100644 --- a/src/shared/actions/challenge.js +++ b/src/shared/actions/challenge.js @@ -171,8 +171,6 @@ export default createActions({ REGISTER_DONE: registerDone, UNREGISTER_INIT: _.noop, UNREGISTER_DONE: unregisterDone, - OPEN_TERMS_MODAL: _.noop, - CLOSE_TERMS_MODAL: _.noop, SELECT_TAB: _.identity, }, }); diff --git a/src/shared/actions/terms.js b/src/shared/actions/terms.js index e0cd3a826c..8b3b3fc320 100644 --- a/src/shared/actions/terms.js +++ b/src/shared/actions/terms.js @@ -54,25 +54,80 @@ function getTermDetailsDone(termId, tokenV2) { return service.getTermDetails(termId).then(details => ({ termId, details })); } +/** + * Payload creator for TERMS/GET_DOCU_SIGN_URL_INIT + * @param {Number|String} templateId id of document template to sign + * @return {String} string format of the id + */ function getDocuSignUrlInit(templateId) { return _.toString(templateId); } +/** + * Payload creator for TERMS/GET_DOCU_SIGN_URL_DONE + * which generate the url of DoduSign term + * @param {Number|String} templateId id of document template to sign + * @param {String} returnUrl callback url after finishing singing + * @param {String} tokenV2 auth token + * @return {Promise} promise of request result + */ function getDocuSignUrlDone(templateId, returnUrl, tokenV2) { const service = getService(tokenV2); return service.getDocuSignUrl(templateId, returnUrl) .then(resp => ({ templateId, docuSignUrl: resp.recipientViewUrl })); } +/** + * Payload creator for TERMS/AGREE_TERM_INIT + * @param {Number|String} termId id of term + * @return {String} string format of the id + */ function agreeTermInit(termId) { return _.toString(termId); } +/** + * Payload creator for TERMS/AGREE_TERM_DONE + * @param {Number|String} termId id of term + * @param {String} tokenV2 auth token + * @return {Promise} promise of request result + */ function agreeTermDone(termId, tokenV2) { const service = getService(tokenV2); return service.agreeTerm(termId).then(resp => ({ termId, success: resp.success })); } +/** + * Payload creator for TERMS/CHECK_STATUS_DONE + * which will check if all terms of specified challenge have been agreed, + * if not, it will try again after a timeout + * @param {Number|String} challengeId id of challenge to check + * @param {String} tokenV2 auth token + * @return {Promise} promise of request result + */ +function checkStatusDone(challengeId, tokenV2) { + const TIME_OUT = 10000; + const service = getService(tokenV2); + const getStatus = (resolve, reject, callback) => { + service.getTerms(challengeId).then((res) => { + const allAgreed = _.every(res.terms, 'agreed'); + callback(allAgreed, res.terms); + }).catch(err => reject(err)); + }; + return new Promise((resolve, reject) => { + getStatus(resolve, reject, (allAgreed, terms) => { + if (allAgreed) { + resolve(terms); + } else { + // retrive terms again after a timeout, DocuSign result + // might take few seconds to get updated + setTimeout(() => getStatus(resolve, reject, + (a, t) => resolve(t)), TIME_OUT); + } + }); + }); +} + export default createActions({ TERMS: { GET_TERMS_INIT: getTermsInit, @@ -83,5 +138,11 @@ export default createActions({ GET_DOCU_SIGN_URL_DONE: getDocuSignUrlDone, AGREE_TERM_INIT: agreeTermInit, AGREE_TERM_DONE: agreeTermDone, + OPEN_TERMS_MODAL: _.identity, + CLOSE_TERMS_MODAL: _.noop, + SELECT_TERM: _.identity, + SIGN_DOCU: _.identity, + CHECK_STATUS_INIT: _.noop, + CHECK_STATUS_DONE: checkStatusDone, }, }); diff --git a/src/shared/components/challenge-detail/Header/index.jsx b/src/shared/components/challenge-detail/Header/index.jsx index 87f5c2aedd..56585a5bd8 100755 --- a/src/shared/components/challenge-detail/Header/index.jsx +++ b/src/shared/components/challenge-detail/Header/index.jsx @@ -54,7 +54,6 @@ export default function ChallengeHeader(props) { reliabilityBonus, userDetails, currentPhases, - registrationEndDate, submissionEndDate, numRegistrants, numSubmissions, @@ -63,6 +62,10 @@ export default function ChallengeHeader(props) { appealsEndDate, } = challenge; + const registrationPhase = allPhases.find(p => p.phaseType === 'Registration'); + const registrationEndDate = registrationPhase.actualEndTime + || registrationPhase.scheduledEndTime; + let trackLower = track ? track.toLowerCase() : 'design'; if (technologies.includes('Data Science')) { trackLower = 'datasci'; @@ -93,6 +96,10 @@ export default function ChallengeHeader(props) { if (props.showDeadlineDetail) { relevantPhases = (allPhases || []).filter((phase) => { + if (phase.phaseType === 'Iterative Review') { + const end = phase.actualEndTime || phase.scheduledEndTime; + return moment(end).isAfter(moment()); + } const phaseLowerCase = phase.phaseType.toLowerCase(); if (phaseLowerCase.includes('screening') || phaseLowerCase.includes('specification')) { return false; diff --git a/src/shared/components/challenge-detail/Specification/SideBar/index.jsx b/src/shared/components/challenge-detail/Specification/SideBar/index.jsx index 104c3c4c92..32b90a7cbd 100644 --- a/src/shared/components/challenge-detail/Specification/SideBar/index.jsx +++ b/src/shared/components/challenge-detail/Specification/SideBar/index.jsx @@ -1,3 +1,5 @@ +/* eslint jsx-a11y/no-static-element-interactions:0 */ + import config from 'utils/config'; import React from 'react'; import PT from 'prop-types'; @@ -21,6 +23,7 @@ export default function SideBar({ reviewType, isDesign, terms, + openTermsModal, }) { const scorecardURL = `${config.URL.ONLINE_REVIEW}/review/actions/ViewScorecard?scid=`; const faqURL = config.URL.INFO.DESIGN_CHALLENGE_SUBMISSION; @@ -31,9 +34,6 @@ export default function SideBar({ submissionLimitDisplay = `${submissionLimit} submissions`; } - const downloadsPlaceHolder = hasRegistered ? - 'None' : 'Register to Download Files (if available)'; - const reviewTypeTitle = reviewType === 'PEER' ? 'Peer Review' : 'Community Review Board'; const reviewTypeDescription = ( reviewType === 'PEER' ? @@ -56,7 +56,7 @@ export default function SideBar({

DOWNLOADS:

{ - hasRegistered && documents && documents.length > 0 ? ( + hasRegistered && documents && documents.length > 0 && (
    { documents.map(doc => ( @@ -64,8 +64,7 @@ export default function SideBar({ )) }
- ) : -

{downloadsPlaceHolder}

+ ) } {eventDetail && (
@@ -182,7 +181,7 @@ export default function SideBar({ terms.map(t => (
{t.agreed && } - + openTermsModal(t)}> {t.title}
@@ -249,4 +248,5 @@ SideBar.propTypes = { reviewType: PT.string, isDesign: PT.bool, terms: PT.arrayOf(PT.shape()), + openTermsModal: PT.func.isRequired, }; diff --git a/src/shared/components/challenge-detail/Specification/SideBar/styles.scss b/src/shared/components/challenge-detail/Specification/SideBar/styles.scss index 568301c165..df4685ef26 100644 --- a/src/shared/components/challenge-detail/Specification/SideBar/styles.scss +++ b/src/shared/components/challenge-detail/Specification/SideBar/styles.scss @@ -135,6 +135,10 @@ $tc-link-visited: #0c4e98; .term { display: flex; align-items: flex-start; + + a { + cursor: pointer; + } } .agreed { diff --git a/src/shared/components/challenge-detail/Specification/TermsModal/TermDetails.jsx b/src/shared/components/challenge-detail/Specification/TermsModal/TermDetails.jsx index d6ac86c4f0..54c6047529 100644 --- a/src/shared/components/challenge-detail/Specification/TermsModal/TermDetails.jsx +++ b/src/shared/components/challenge-detail/Specification/TermsModal/TermDetails.jsx @@ -2,36 +2,68 @@ import React from 'react'; import PT from 'prop-types'; -import { PrimaryButton } from 'components/buttons'; +import cn from 'classnames'; +import { PrimaryButton, Button } from 'components/buttons'; import LoadingIndicator from 'components/LoadingIndicator'; -import './TermDetails.scss'; +import style from './TermDetails.scss'; export default class TermDetails extends React.Component { - componentDidMount() { + constructor(props) { + super(props); + this.state = { + loadingFrame: false, + }; + this.frameLoaded = this.frameLoaded.bind(this); + } + + componentWillMount() { const { details } = this.props; if (details.agreeabilityType !== 'Electronically-agreeable' && details.docusignTemplateId) { this.props.getDocuSignUrl(details.docusignTemplateId); + this.setState({ loadingFrame: true }); } } + frameLoaded() { + this.setState({ + loadingFrame: false, + }); + } + render() { - const { details, docuSignUrl, agreeingTerm, agreeTerm, - deselectTerm, loadingDocuSignUrl } = this.props; + const { details, docuSignUrl, agreeingTerm, agreeTerm, closeModal, + loadingDocuSignUrl, viewOnly, agreed, nextTerm } = this.props; + return (
-
{details.title}
{ details.agreeabilityType === 'Electronically-agreeable' &&
-
- Back - agreeTerm(details.termsOfUseId)} - >Agree -
+ { + !viewOnly && +
+ { + agreed ? + (Next) : + (
+ agreeTerm(details.termsOfUseId)} + theme={style} + >I Agree + +
) + } +
+ }
} { @@ -43,10 +75,11 @@ export default class TermDetails extends React.Component { details.agreeabilityType !== 'Electronically-agreeable' && details.docusignTemplateId && !loadingDocuSignUrl && docuSignUrl &&
-