From d23331d9b9e46f6862d0212ef1c0278001ac885f Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 30 Oct 2015 17:43:20 +0100 Subject: [PATCH 01/60] Remove ReactS3FineUploader's dependency on react-router's location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ReactS3FineUploader used to check the current url’s query params to determine which method it should use to upload, but this decision means the component is tightly coupled with react-router and history.js. A major pain point is having to propagate the location prop all the way down to this component even when it’s not necessary. Now, ReactS3FineUploader’s parent elements can either parse the current query params themselves or, if they have a location from react-router, simply use the location. Added a few utils to help parse url params. --- .../further_details_fileuploader.js | 8 +- .../ascribe_forms/form_create_contract.js | 8 +- .../ascribe_forms/form_register_piece.js | 9 +- .../ascribe_forms/input_fineuploader.js | 10 +-- .../contract_settings_update_button.js | 8 +- .../file_drag_and_drop.js | 34 ++++---- .../file_drag_and_drop_dialog.js | 56 +++++++------ .../react_s3_fine_uploader.js | 74 +++++++---------- js/fetchers/edition_list_fetcher.js | 2 +- js/fetchers/piece_list_fetcher.js | 2 +- js/utils/fetch_api_utils.js | 57 +------------ js/utils/requests.js | 6 +- js/utils/url_utils.js | 83 +++++++++++++++++++ package.json | 3 + 14 files changed, 190 insertions(+), 170 deletions(-) create mode 100644 js/utils/url_utils.js diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index c5ef8a1c..33caf9b0 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -20,8 +20,7 @@ let FurtherDetailsFileuploader = React.createClass({ submitFile: React.PropTypes.func, isReadyForFormSubmission: React.PropTypes.func, editable: React.PropTypes.bool, - multiple: React.PropTypes.bool, - location: React.PropTypes.object + multiple: React.PropTypes.bool }, getDefaultProps() { @@ -89,11 +88,10 @@ let FurtherDetailsFileuploader = React.createClass({ }} areAssetsDownloadable={true} areAssetsEditable={this.props.editable} - multiple={this.props.multiple} - location={this.props.location}/> + multiple={this.props.multiple} /> ); } }); -export default FurtherDetailsFileuploader; \ No newline at end of file +export default FurtherDetailsFileuploader; diff --git a/js/components/ascribe_forms/form_create_contract.js b/js/components/ascribe_forms/form_create_contract.js index fe00cebc..aac4c5ea 100644 --- a/js/components/ascribe_forms/form_create_contract.js +++ b/js/components/ascribe_forms/form_create_contract.js @@ -28,8 +28,7 @@ let CreateContractForm = React.createClass({ fileClassToUpload: React.PropTypes.shape({ singular: React.PropTypes.string, plural: React.PropTypes.string - }), - location: React.PropTypes.object + }) }, getInitialState() { @@ -87,8 +86,7 @@ let CreateContractForm = React.createClass({ areAssetsEditable={true} setIsUploadReady={this.setIsUploadReady} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} - fileClassToUpload={this.props.fileClassToUpload} - location={this.props.location}/> + fileClassToUpload={this.props.fileClassToUpload} /> + uploadMethod={this.props.location.query.method} /> + uploadMethod={this.props.uploadMethod} + fileClassToUpload={this.props.fileClassToUpload} /> ); } }); -export default InputFineUploader; \ No newline at end of file +export default InputFineUploader; diff --git a/js/components/ascribe_settings/contract_settings_update_button.js b/js/components/ascribe_settings/contract_settings_update_button.js index f3bab156..ffd5ef4b 100644 --- a/js/components/ascribe_settings/contract_settings_update_button.js +++ b/js/components/ascribe_settings/contract_settings_update_button.js @@ -20,8 +20,7 @@ import { getLangText } from '../../utils/lang_utils'; let ContractSettingsUpdateButton = React.createClass({ propTypes: { - contract: React.PropTypes.object, - location: React.PropTypes.object + contract: React.PropTypes.object }, submitFile(file) { @@ -90,10 +89,9 @@ let ContractSettingsUpdateButton = React.createClass({ plural: getLangText('UPDATE') }} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} - submitFile={this.submitFile} - location={this.props.location}/> + submitFile={this.submitFile} /> ); } }); -export default ContractSettingsUpdateButton; \ No newline at end of file +export default ContractSettingsUpdateButton; diff --git a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js index 38ec459a..430dcab3 100644 --- a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js +++ b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js @@ -27,6 +27,7 @@ let FileDragAndDrop = React.createClass({ areAssetsEditable: React.PropTypes.bool, enableLocalHashing: React.PropTypes.bool, + uploadMethod: React.PropTypes.string, // triggers a FileDragAndDrop-global spinner hashingProgress: React.PropTypes.number, @@ -41,8 +42,7 @@ let FileDragAndDrop = React.createClass({ plural: React.PropTypes.string }), - allowedExtensions: React.PropTypes.string, - location: React.PropTypes.object + allowedExtensions: React.PropTypes.string }, handleDragOver(event) { @@ -137,19 +137,19 @@ let FileDragAndDrop = React.createClass({ }, render: function () { - let { filesToUpload, - dropzoneInactive, - className, - hashingProgress, - handleCancelHashing, - multiple, - enableLocalHashing, - fileClassToUpload, - areAssetsDownloadable, - areAssetsEditable, - allowedExtensions, - location - } = this.props; + const { + filesToUpload, + dropzoneInactive, + className, + hashingProgress, + handleCancelHashing, + multiple, + enableLocalHashing, + uploadMethod, + fileClassToUpload, + areAssetsDownloadable, + areAssetsEditable, + allowedExtensions } = this.props; // has files only is true if there are files that do not have the status deleted or canceled let hasFiles = filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0; @@ -185,8 +185,8 @@ let FileDragAndDrop = React.createClass({ hasFiles={hasFiles} onClick={this.handleOnClick} enableLocalHashing={enableLocalHashing} - fileClassToUpload={fileClassToUpload} - location={location}/> + uploadMethod={uploadMethod} + fileClassToUpload={fileClassToUpload} /> {getLangText('Drag %s here', fileClass)}

,

{getLangText('or')}

@@ -37,26 +35,31 @@ let FileDragAndDropDialog = React.createClass({ }, render() { - const queryParams = this.props.location.query; + const { + hasFiles, + multipleFiles, + enableLocalHashing, + uploadMethod, + fileClassToUpload, + onClick } = this.props; - if(this.props.hasFiles) { + if (hasFiles) { return null; } else { - if(this.props.enableLocalHashing && !queryParams.method) { + if (enableLocalHashing && !uploadMethod) { + const currentQueryParams = getCurrentQueryParams(); - let queryParamsHash = Object.assign({}, queryParams); + const queryParamsHash = Object.assign({}, currentQueryParams); queryParamsHash.method = 'hash'; - let queryParamsUpload = Object.assign({}, queryParams); + const queryParamsUpload = Object.assign({}, currentQueryParams); queryParamsUpload.method = 'upload'; - let { location } = this.props; - return (

{getLangText('Would you rather')}

{getLangText('Hash your work')} @@ -64,9 +67,9 @@ let FileDragAndDropDialog = React.createClass({ or - + {getLangText('Upload and hash your work')} @@ -75,26 +78,27 @@ let FileDragAndDropDialog = React.createClass({
); } else { - if(this.props.multipleFiles) { + if (multipleFiles) { return ( - {this.getDragDialog(this.props.fileClassToUpload.plural)} + {this.getDragDialog(fileClassToUpload.plural)} - {getLangText('choose %s to upload', this.props.fileClassToUpload.plural)} + onClick={onClick}> + {getLangText('choose %s to upload', fileClassToUpload.plural)} ); } else { - let dialog = queryParams.method === 'hash' ? getLangText('choose a %s to hash', this.props.fileClassToUpload.singular) : getLangText('choose a %s to upload', this.props.fileClassToUpload.singular); + const dialog = uploadMethod === 'hash' ? getLangText('choose a %s to hash', fileClassToUpload.singular) + : getLangText('choose a %s to upload', fileClassToUpload.singular); return ( - {this.getDragDialog(this.props.fileClassToUpload.singular)} + {this.getDragDialog(fileClassToUpload.singular)} + onClick={onClick}> {dialog} @@ -105,4 +109,4 @@ let FileDragAndDropDialog = React.createClass({ } }); -export default FileDragAndDropDialog; \ No newline at end of file +export default FileDragAndDropDialog; diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index e8cc8bfa..61dbcbcc 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -18,7 +18,6 @@ import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp } import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; - let ReactS3FineUploader = React.createClass({ propTypes: { keyRoutine: React.PropTypes.shape({ @@ -107,11 +106,14 @@ let ReactS3FineUploader = React.createClass({ // One solution we found in the process of tackling this problem was to hash // the file in the browser using md5 and then uploading the resulting text document instead // of the actual file. - // This boolean essentially enables that behavior + // + // This boolean and string essentially enable that behavior. + // Right now, we determine which upload method to use by appending a query parameter, + // which should be passed into 'uploadMethod': + // 'hash': upload using the hash + // 'upload': upload full file (default if not specified) enableLocalHashing: React.PropTypes.bool, - - // automatically injected by React-Router - query: React.PropTypes.object, + uploadMethod: React.PropTypes.string, // A class of a file the user has to upload // Needs to be defined both in singular as well as in plural @@ -126,9 +128,7 @@ let ReactS3FineUploader = React.createClass({ fileInputElement: React.PropTypes.oneOfType([ React.PropTypes.func, React.PropTypes.element - ]), - - location: React.PropTypes.object + ]) }, getDefaultProps() { @@ -192,11 +192,11 @@ let ReactS3FineUploader = React.createClass({ filesToUpload: [], uploader: new fineUploader.s3.FineUploaderBasic(this.propsToConfig()), csrfToken: getCookie(AppConstants.csrftoken), - + // -1: aborted // -2: uninitialized hashingProgress: -2, - + // this is for logging chunks: {} }; @@ -354,7 +354,6 @@ let ReactS3FineUploader = React.createClass({ /* FineUploader specific callback function handlers */ onUploadChunk(id, name, chunkData) { - let chunks = this.state.chunks; chunks[id + '-' + chunkData.startByte + '-' + chunkData.endByte] = { @@ -370,10 +369,9 @@ let ReactS3FineUploader = React.createClass({ }, onUploadChunkSuccess(id, chunkData, responseJson, xhr) { - let chunks = this.state.chunks; let chunkKey = id + '-' + chunkData.startByte + '-' + chunkData.endByte; - + if(chunks[chunkKey]) { chunks[chunkKey].completed = true; chunks[chunkKey].responseJson = responseJson; @@ -414,7 +412,7 @@ let ReactS3FineUploader = React.createClass({ } else { console.warn('You didn\'t define submitFile in as a prop in react-s3-fine-uploader'); } - + // for explanation, check comment of if statement above if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) { // also, lets check if after the completion of this upload, @@ -597,7 +595,6 @@ let ReactS3FineUploader = React.createClass({ } else { throw new Error(getLangText('File upload could not be paused.')); } - }, handleResumeFile(fileId) { @@ -647,16 +644,14 @@ let ReactS3FineUploader = React.createClass({ // md5 hash of a file locally and just upload a txt file containing that hash. // // In the view this only happens when the user is allowed to do local hashing as well - // as when the correct query parameter is present in the url ('hash' and not 'upload') - let queryParams = this.props.location.query; - if(this.props.enableLocalHashing && queryParams && queryParams.method === 'hash') { - - let convertedFilePromises = []; + // as when the correct method prop is present ('hash' and not 'upload') + if (this.props.enableLocalHashing && this.props.uploadMethod === 'hash') { + const convertedFilePromises = []; let overallFileSize = 0; + // "files" is not a classical Javascript array but a Javascript FileList, therefore // we can not use map to convert values for(let i = 0; i < files.length; i++) { - // for calculating the overall progress of all submitted files // we'll need to calculate the overall sum of all files' sizes overallFileSize += files[i].size; @@ -668,7 +663,6 @@ let ReactS3FineUploader = React.createClass({ // we're using promises to handle that let hashedFilePromise = computeHashOfFile(files[i]); convertedFilePromises.push(hashedFilePromise); - } // To react after the computation of all files, we define the resolvement @@ -676,7 +670,6 @@ let ReactS3FineUploader = React.createClass({ // with their txt representative Q.all(convertedFilePromises) .progress(({index, value: {progress, reject}}) => { - // hashing progress has been aborted from outside // To get out of the executing, we need to call reject from the // inside of the promise's execution. @@ -696,18 +689,14 @@ let ReactS3FineUploader = React.createClass({ // currently hashing files let overallHashingProgress = 0; for(let i = 0; i < files.length; i++) { - let filesSliceOfOverall = files[i].size / overallFileSize; overallHashingProgress += filesSliceOfOverall * files[i].progress; - } // Multiply by 100, since react-progressbar expects decimal numbers this.setState({ hashingProgress: overallHashingProgress * 100}); - }) .then((convertedFiles) => { - // clear hashing progress, since its done this.setState({ hashingProgress: -2}); @@ -823,20 +812,18 @@ let ReactS3FineUploader = React.createClass({ changeSet.status = { $set: status }; let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet }); - + this.setState({ filesToUpload }); }, isDropzoneInactive() { - let filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1); - let queryParams = this.props.location.query; + const filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1); - if((this.props.enableLocalHashing && !queryParams.method) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) { + if ((this.props.enableLocalHashing && !this.props.uploadMethod) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) { return true; } else { return false; } - }, getAllowedExtensions() { @@ -850,17 +837,16 @@ let ReactS3FineUploader = React.createClass({ }, render() { - let { - multiple, - areAssetsDownloadable, - areAssetsEditable, - onInactive, - enableLocalHashing, - fileClassToUpload, - validation, - fileInputElement, - location - } = this.props; + const { + multiple, + areAssetsDownloadable, + areAssetsEditable, + onInactive, + enableLocalHashing, + uploadMethod, + fileClassToUpload, + validation, + fileInputElement } = this.props; // Here we initialize the template that has been either provided from the outside // or the default input that is FileDragAndDrop. @@ -870,8 +856,8 @@ let ReactS3FineUploader = React.createClass({ areAssetsEditable, onInactive, enableLocalHashing, + uploadMethod, fileClassToUpload, - location, onDrop: this.handleUploadFile, filesToUpload: this.state.filesToUpload, handleDeleteFile: this.handleDeleteFile, diff --git a/js/fetchers/edition_list_fetcher.js b/js/fetchers/edition_list_fetcher.js index b416c595..93e4553d 100644 --- a/js/fetchers/edition_list_fetcher.js +++ b/js/fetchers/edition_list_fetcher.js @@ -2,8 +2,8 @@ import requests from '../utils/requests'; -import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import { mergeOptions } from '../utils/general_utils'; +import { generateOrderingQueryParams } from '../utils/url_utils'; let EditionListFetcher = { /** diff --git a/js/fetchers/piece_list_fetcher.js b/js/fetchers/piece_list_fetcher.js index 8e58402a..6bd4eb3a 100644 --- a/js/fetchers/piece_list_fetcher.js +++ b/js/fetchers/piece_list_fetcher.js @@ -3,7 +3,7 @@ import requests from '../utils/requests'; import { mergeOptions } from '../utils/general_utils'; -import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; +import { generateOrderingQueryParams } from '../utils/url_utils'; let PieceListFetcher = { /** diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index 3ed964ba..cb676fce 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -2,63 +2,10 @@ import Q from 'q'; -import { sanitize } from './general_utils'; import AppConstants from '../constants/application_constants'; // TODO: Create Unittests that test all functions - /** - * Takes a key-value object of this form: - * - * { - * 'page': 1, - * 'pageSize': 10 - * } - * - * and converts it to a query-parameter, which you can append to your URL. - * The return looks like this: - * - * ?page=1&page_size=10 - * - * CamelCase gets converted to snake_case! - * - */ -export function argsToQueryParams(obj) { - - obj = sanitize(obj); - - return Object - .keys(obj) - .map((key, i) => { - let s = ''; - - if(i === 0) { - s += '?'; - } else { - s += '&'; - } - - let snakeCaseKey = key.replace(/[A-Z]/, (match) => '_' + match.toLowerCase()); - - return s + snakeCaseKey + '=' + encodeURIComponent(obj[key]); - }) - .join(''); -} - -/** - * Takes a string and a boolean and generates a string query parameter for - * an API call. - */ -export function generateOrderingQueryParams(orderBy, orderAsc) { - let interpolation = ''; - - if(!orderAsc) { - interpolation += '-'; - } - - return interpolation + orderBy; -} - export function status(response) { if (response.status >= 200 && response.status < 300) { return response; @@ -68,7 +15,7 @@ export function status(response) { export function getCookie(name) { let parts = document.cookie.split(';'); - + for(let i = 0; i < parts.length; i++) { if(parts[i].indexOf(AppConstants.csrftoken + '=') > -1) { return parts[i].split('=').pop(); @@ -111,4 +58,4 @@ export function fetchImageAsBlob(url) { xhr.send(); }); -} \ No newline at end of file +} diff --git a/js/utils/requests.js b/js/utils/requests.js index 7e9c9a58..bf203751 100644 --- a/js/utils/requests.js +++ b/js/utils/requests.js @@ -2,11 +2,11 @@ import Q from 'q'; -import { argsToQueryParams, getCookie } from '../utils/fetch_api_utils'; - import AppConstants from '../constants/application_constants'; -import {excludePropFromObject} from '../utils/general_utils'; +import { getCookie } from '../utils/fetch_api_utils'; +import { excludePropFromObject } from '../utils/general_utils'; +import { argsToQueryParams } from '../utils/url_utils'; class Requests { _merge(defaults, options) { diff --git a/js/utils/url_utils.js b/js/utils/url_utils.js new file mode 100644 index 00000000..cc875981 --- /dev/null +++ b/js/utils/url_utils.js @@ -0,0 +1,83 @@ +'use strict' + +import camelCase from 'camelcase'; +import snakeCase from 'snake-case'; +import qs from 'qs'; + +import { sanitize } from './general_utils'; + +// TODO: Create Unittests that test all functions + +/** + * Takes a key-value dictionary of this form: + * + * { + * 'page': 1, + * 'pageSize': 10 + * } + * + * and converts it to a query-parameter, which you can append to your URL. + * The return looks like this: + * + * ?page=1&page_size=10 + * + * CamelCase gets converted to snake_case! + * + * @param {object} obj Query params dictionary + * @return {string} Query params string + */ +export function argsToQueryParams(obj) { + const sanitizedObj = sanitize(obj); + const queryParamObj = {}; + + Object + .keys(sanitizedObj) + .forEach((key) => { + queryParamObj[snakeCase(key)] = sanitizedObj[key]; + }); + + // Use bracket arrayFormat as history.js and react-router use it + return '?' + qs.stringify(queryParamObj, { arrayFormat: 'brackets' }); +} + +/** + * Get the current url's query params as an key-val dictionary. + * snake_case gets converted to CamelCase! + * @return {object} Query params dictionary + */ +export function getCurrentQueryParams() { + return queryParamsToArgs(window.location.search.substring(1)); +} + +/** + * Convert the given query param string into a key-val dictionary. + * snake_case gets converted to CamelCase! + * @param {string} queryParamString Query params string + * @return {object} Query params dictionary + */ +export function queryParamsToArgs(queryParamString) { + const qsQueryParamObj = qs.parse(queryParamString); + const camelCaseParamObj = {}; + + Object + .keys(qsQueryParamObj) + .forEach((key) => { + camelCaseParamObj[camelCase(key)] = qsQueryParamObj[key]; + }); + + return camelCaseParamObj; +} + +/** + * Takes a string and a boolean and generates a string query parameter for + * an API call. + */ +export function generateOrderingQueryParams(orderBy, orderAsc) { + let interpolation = ''; + + if(!orderAsc) { + interpolation += '-'; + } + + return interpolation + orderBy; +} diff --git a/package.json b/package.json index 2b770fd3..4e7cd6a9 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "browser-sync": "^2.7.5", "browserify": "^9.0.8", "browserify-shim": "^3.8.10", + "camelcase": "^1.2.1", "classnames": "^1.2.2", "compression": "^1.4.4", "envify": "^3.4.0", @@ -73,6 +74,7 @@ "object-assign": "^2.0.0", "opn": "^3.0.2", "q": "^1.4.1", + "qs": "^5.2.0", "raven-js": "^1.1.19", "react": "0.13.2", "react-bootstrap": "0.25.1", @@ -83,6 +85,7 @@ "react-textarea-autosize": "^2.5.2", "reactify": "^1.1.0", "shmui": "^0.1.0", + "snake-case": "^1.1.1", "spark-md5": "~1.0.0", "uglifyjs": "^2.4.10", "vinyl-buffer": "^1.0.0", From 1e328b722b8009a6ec3e9c8a2f4e7998041d5ac4 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 30 Oct 2015 17:46:51 +0100 Subject: [PATCH 02/60] Sanitize utility should not modify given object Mutating arguments and then returning them is redundant and confusing behaviour (why pass it back if they already have it? Am I getting a new copy since it returns something?). --- js/utils/general_utils.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 7c13f9b5..cd73ba45 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -1,29 +1,23 @@ 'use strict'; +import _ from 'lodash'; + /** - * Takes an object and deletes all keys that are - * - * tagged as false by the passed in filter function + * Takes an object and returns a shallow copy without any keys + * that fail the passed in filter function. + * Does not modify the passed in object. * * @param {object} obj regular javascript object * @return {object} regular javascript object without null values or empty strings */ export function sanitize(obj, filterFn) { - if(!filterFn) { + if (!filterFn) { // By matching null with a double equal, we can match undefined and null // http://stackoverflow.com/a/15992131 filterFn = (val) => val == null || val === ''; } - Object - .keys(obj) - .map((key) => { - if(filterFn(obj[key])) { - delete obj[key]; - } - }); - - return obj; + return _.omit(obj, filterFn); } /** From 147c852b022adb0a5214d8a28924c7e12c4bb3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 2 Nov 2015 10:32:48 +0100 Subject: [PATCH 03/60] Replace getFullYear() with getUTCFullYear() --- .../ascribe_accordion_list/accordion_list_item_wallet.js | 2 +- js/components/ascribe_detail/edition.js | 2 +- js/components/ascribe_detail/piece_container.js | 2 +- .../ascribe_accordion_list/accordion_list_item_prize.js | 2 +- .../prize/components/ascribe_detail/prize_piece_container.js | 2 +- .../wallet/components/ascribe_detail/wallet_piece_container.js | 2 +- .../cyland/cyland_accordion_list/cyland_accordion_list_item.js | 2 +- .../ikonotv_accordion_list/ikonotv_accordion_list_item.js | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js index 185f6e05..8899c67e 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js @@ -129,7 +129,7 @@ let AccordionListItemWallet = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getFullYear()} + {new Date(this.props.content.date_created).getUTCFullYear()} {this.getLicences()}
} buttons={ diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 64cbf714..ae53728f 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -85,7 +85,7 @@ let Edition = React.createClass({

{this.props.edition.title}

- +

{this.state.piece.title}

- + {this.state.piece.num_editions > 0 ? : null}
diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index caef504b..8eac81d1 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -182,7 +182,7 @@ let AccordionListItemPrize = React.createClass({ artistName={artistName} subsubheading={
- {new Date(this.props.content.date_created).getFullYear()} + {new Date(this.props.content.date_created).getUTCFullYear()}
} buttons={this.getPrizeButtons()} badge={this.getPrizeBadge()}> diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 07e84b0e..6bd47c18 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -141,7 +141,7 @@ let PieceContainer = React.createClass({

{this.state.piece.title}

- + {artistEmail} {this.getActions()}
diff --git a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js index 5644b5b0..e765bd7b 100644 --- a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js +++ b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js @@ -39,7 +39,7 @@ let WalletPieceContainer = React.createClass({

{this.props.piece.title}

- +
} diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js index 755e550b..0b4ec543 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js @@ -100,7 +100,7 @@ let CylandAccordionListItem = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getFullYear()} + {new Date(this.props.content.date_created).getUTCFullYear()}
} buttons={this.getSubmitButtons()}> {this.props.children} diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js index 7445eb36..e1187b7c 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js @@ -106,7 +106,7 @@ let IkonotvAccordionListItem = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getFullYear()} + {new Date(this.props.content.date_created).getUTCFullYear()}
} buttons={this.getSubmitButtons()}> {this.props.children} From a513af984d0d7e98d419b8ff376e3411d2d01360 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 10:41:59 +0100 Subject: [PATCH 04/60] Update cyland for FineUploader changes --- .../cyland/cyland_detail/cyland_piece_container.js | 4 +--- .../cyland/cyland_forms/cyland_additional_data_form.js | 8 +++----- .../wallet/components/cyland/cyland_register_piece.js | 3 +-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js index 79d63abf..7e784981 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js @@ -33,7 +33,6 @@ import { mergeOptions } from '../../../../../../utils/general_utils'; let CylandPieceContainer = React.createClass({ propTypes: { - location: React.PropTypes.object, params: React.PropTypes.object }, @@ -107,8 +106,7 @@ let CylandPieceContainer = React.createClass({ + isInline={true} /> ); diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js index 63863b2d..0adfcb40 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js @@ -26,8 +26,7 @@ let CylandAdditionalDataForm = React.createClass({ handleSuccess: React.PropTypes.func, piece: React.PropTypes.object.isRequired, disabled: React.PropTypes.bool, - isInline: React.PropTypes.bool, - location: React.PropTypes.object + isInline: React.PropTypes.bool }, getDefaultProps() { @@ -143,8 +142,7 @@ let CylandAdditionalDataForm = React.createClass({ isReadyForFormSubmission={formSubmissionValidation.fileOptional} pieceId={piece.id} otherData={piece.other_data} - multiple={true} - location={this.props.location}/> + multiple={true} /> ); } else { @@ -157,4 +155,4 @@ let CylandAdditionalDataForm = React.createClass({ } }); -export default CylandAdditionalDataForm; \ No newline at end of file +export default CylandAdditionalDataForm; diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js index ca755cf4..1903c7a2 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -210,8 +210,7 @@ let CylandRegisterPiece = React.createClass({ 1} handleSuccess={this.handleAdditionalDataSuccess} - piece={this.state.piece} - location={this.props.location}/> + piece={this.state.piece} /> From 5f5461c10ddd11362a79708913e3d937cdd74970 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 10:42:15 +0100 Subject: [PATCH 05/60] Remove warning for missing prop from FurtherDetailsFileUploader --- js/components/ascribe_detail/further_details_fileuploader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 33caf9b0..9a1f091c 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -43,6 +43,7 @@ let FurtherDetailsFileuploader = React.createClass({ return ( Date: Mon, 2 Nov 2015 12:10:41 +0100 Subject: [PATCH 06/60] Check for a new csrf token on componentWillReceiveProps instead of componentWillUpdate this.setState() should not be used in componentWillUpdate(): https://facebook.github.io/react/docs/component-specs.html#updating-comp onentwillupdate --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 61dbcbcc..685c2b2f 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -202,7 +202,7 @@ let ReactS3FineUploader = React.createClass({ }; }, - componentWillUpdate() { + componentWillReceiveProps() { // since the csrf header is defined in this component's props, // everytime the csrf cookie is changed we'll need to reinitalize // fineuploader and update the actual csrf token From fe4e33769073b3137ae6c7122b5e7559521c7807 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 18:27:45 +0100 Subject: [PATCH 07/60] Use Object.assign() instead of writing own merge function --- js/components/ascribe_forms/form.js | 8 ++--- js/utils/general_utils.js | 53 ++--------------------------- js/utils/requests.js | 27 +++++---------- 3 files changed, 14 insertions(+), 74 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index fe15f537..deee14d9 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -12,8 +12,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import requests from '../../utils/requests'; import { getLangText } from '../../utils/lang_utils'; -import { mergeOptionsWithDuplicates } from '../../utils/general_utils'; - let Form = React.createClass({ propTypes: { @@ -124,12 +122,12 @@ let Form = React.createClass({ getFormData() { let data = {}; - for(let ref in this.refs) { + for (let ref in this.refs) { data[this.refs[ref].props.name] = this.refs[ref].state.value; } - if(typeof this.props.getFormData === 'function') { - data = mergeOptionsWithDuplicates(data, this.props.getFormData()); + if (typeof this.props.getFormData === 'function') { + data = Object.assign(data, this.props.getFormData()); } return data; diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index cd73ba45..bce2dee6 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -76,8 +76,8 @@ export function formatText() { }); } -/* - Checks a list of objects for key duplicates and returns a boolean +/** + * Checks a list of objects for key duplicates and returns a boolean */ function _doesObjectListHaveDuplicates(l) { let mergedList = []; @@ -115,35 +115,7 @@ export function mergeOptions(...l) { throw new Error('The objects you submitted for merging have duplicates. Merge aborted.'); } - let newObj = {}; - - for(let i = 1; i < l.length; i++) { - newObj = _mergeOptions(newObj, _mergeOptions(l[i - 1], l[i])); - } - - return newObj; -} - -/** - * Merges a number of objects even if there're having duplicates. - * - * DOES NOT RETURN AN ERROR! - * - * Takes a list of object and merges their keys to one object. - * Uses mergeOptions for two objects. - * @param {[type]} l [description] - * @return {[type]} [description] - */ -export function mergeOptionsWithDuplicates(...l) { - // If the objects submitted in the list have duplicates,in their key names, - // abort the merge and tell the function's user to check his objects. - let newObj = {}; - - for(let i = 1; i < l.length; i++) { - newObj = _mergeOptions(newObj, _mergeOptions(l[i - 1], l[i])); - } - - return newObj; + return Object.assign({}, ...l); } /** @@ -159,25 +131,6 @@ export function update(a, ...l) { return a; } -/** - * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 - * @param obj1 - * @param obj2 - * @returns obj3 a new object based on obj1 and obj2 - * Taken from: http://stackoverflow.com/a/171256/1263876 - */ -function _mergeOptions(obj1, obj2) { - let obj3 = {}; - - for (let attrname in obj1) { - obj3[attrname] = obj1[attrname]; - } - for (let attrname in obj2) { - obj3[attrname] = obj2[attrname]; - } - return obj3; -} - /** * Escape HTML in a string so it can be injected safely using * React's `dangerouslySetInnerHTML` diff --git a/js/utils/requests.js b/js/utils/requests.js index bf203751..ce24aaba 100644 --- a/js/utils/requests.js +++ b/js/utils/requests.js @@ -9,17 +9,6 @@ import { excludePropFromObject } from '../utils/general_utils'; import { argsToQueryParams } from '../utils/url_utils'; class Requests { - _merge(defaults, options) { - let merged = {}; - for (let key in defaults) { - merged[key] = defaults[key]; - } - for (let key in options) { - merged[key] = options[key]; - } - return merged; - } - unpackResponse(response) { if (response.status >= 500) { throw new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url); @@ -112,7 +101,7 @@ class Requests { request(verb, url, options) { options = options || {}; - let merged = this._merge(this.httpOptions, options); + let merged = Object.assign({}, this.httpOptions, options); let csrftoken = getCookie(AppConstants.csrftoken); if (csrftoken) { merged.headers['X-CSRFToken'] = csrftoken; @@ -124,23 +113,23 @@ class Requests { } get(url, params) { - if (url === undefined){ + if (url === undefined) { throw new Error('Url undefined'); } - let paramsCopy = this._merge(params); + let paramsCopy = Object.assign({}, params); let newUrl = this.prepareUrl(url, paramsCopy, true); return this.request('get', newUrl); } delete(url, params) { - let paramsCopy = this._merge(params); + let paramsCopy = Object.assign({}, params); let newUrl = this.prepareUrl(url, paramsCopy, true); return this.request('delete', newUrl); } - _putOrPost(url, paramsAndBody, method){ - let paramsCopy = this._merge(paramsAndBody); let params = excludePropFromObject(paramsAndBody, ['body']); + _putOrPost(url, paramsAndBody, method) { + let paramsCopy = Object.assign({}, paramsAndBody); let newUrl = this.prepareUrl(url, params); let body = null; if (paramsCopy && paramsCopy.body) { @@ -153,11 +142,11 @@ class Requests { return this._putOrPost(url, params, 'post'); } - put(url, params){ + put(url, params) { return this._putOrPost(url, params, 'put'); } - patch(url, params){ + patch(url, params) { return this._putOrPost(url, params, 'patch'); } From 955e20d6b6643865f418f7ce3a586f6fb9cd3700 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 18:29:06 +0100 Subject: [PATCH 08/60] Reduce dependency footprint of new includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opted for decamelize instead of snake-case as it’s much smaller and we don’t need the extra functionality of snake-case. --- js/utils/url_utils.js | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/utils/url_utils.js b/js/utils/url_utils.js index cc875981..86c8dfc5 100644 --- a/js/utils/url_utils.js +++ b/js/utils/url_utils.js @@ -1,7 +1,7 @@ 'use strict' import camelCase from 'camelcase'; -import snakeCase from 'snake-case'; +import decamelize from 'decamelize'; import qs from 'qs'; import { sanitize } from './general_utils'; @@ -33,7 +33,7 @@ export function argsToQueryParams(obj) { Object .keys(sanitizedObj) .forEach((key) => { - queryParamObj[snakeCase(key)] = sanitizedObj[key]; + queryParamObj[decamelize(key)] = sanitizedObj[key]; }); // Use bracket arrayFormat as history.js and react-router use it diff --git a/package.json b/package.json index 4e7cd6a9..63c6d1e0 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "camelcase": "^1.2.1", "classnames": "^1.2.2", "compression": "^1.4.4", + "decamelize": "^1.1.1", "envify": "^3.4.0", "eslint": "^0.22.1", "eslint-plugin-react": "^2.5.0", @@ -74,7 +75,7 @@ "object-assign": "^2.0.0", "opn": "^3.0.2", "q": "^1.4.1", - "qs": "^5.2.0", + "qs": "^4.0.0", "raven-js": "^1.1.19", "react": "0.13.2", "react-bootstrap": "0.25.1", @@ -85,7 +86,6 @@ "react-textarea-autosize": "^2.5.2", "reactify": "^1.1.0", "shmui": "^0.1.0", - "snake-case": "^1.1.1", "spark-md5": "~1.0.0", "uglifyjs": "^2.4.10", "vinyl-buffer": "^1.0.0", From 1a3dffe8bc396ca6af2db768c86036573509ba65 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 18:31:01 +0100 Subject: [PATCH 09/60] Modify excludePropFromObject to be similar to lodash.omit() --- js/utils/general_utils.js | 39 +++++++++++++++++++++++++++++++++------ js/utils/requests.js | 4 ++-- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index bce2dee6..c13e936e 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -143,14 +143,41 @@ export function escapeHTML(s) { return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML; } -export function excludePropFromObject(obj, propList){ - let clonedObj = mergeOptions({}, obj); - for (let item in propList){ - if (clonedObj[propList[item]]){ - delete clonedObj[propList[item]]; +/** + * Returns a copy of the given object's own and inherited enumerable + * properties, omitting any keys that pass the given filter function. + */ +function filterObjOnFn(obj, filterFn) { + const filteredObj = {}; + + for (let key in obj) { + const val = obj[key]; + if (filterFn == null || !filterFn(val, key)) { + filteredObj[key] = val; } } - return clonedObj; + + return filteredObj; +} + +/** + * Similar to lodash's _.omit(), this returns a copy of the given object's + * own and inherited enumerable properties, omitting any keys that are + * in the given array or whose value pass the given filter function. + * @param {object} obj Source object + * @param {array|function} filter Array of key names to omit or function to invoke per iteration + * @return {object} The new object +*/ +export function omitFromObject(obj, filter) { + if (filter && filter.constructor === Array) { + return filterObjOnFn(obj, (_, key) => { + return filter.indexOf(key) >= 0; + }); + } else if (filter && typeof filter === 'function') { + return filterObjOnFn(obj, filter); + } else { + throw new Error('The given filter is not an array or function. Exclude aborted'); + } } /** diff --git a/js/utils/requests.js b/js/utils/requests.js index ce24aaba..8f015a11 100644 --- a/js/utils/requests.js +++ b/js/utils/requests.js @@ -5,7 +5,7 @@ import Q from 'q'; import AppConstants from '../constants/application_constants'; import { getCookie } from '../utils/fetch_api_utils'; -import { excludePropFromObject } from '../utils/general_utils'; +import { omitFromObject } from '../utils/general_utils'; import { argsToQueryParams } from '../utils/url_utils'; class Requests { @@ -127,9 +127,9 @@ class Requests { return this.request('delete', newUrl); } - let params = excludePropFromObject(paramsAndBody, ['body']); _putOrPost(url, paramsAndBody, method) { let paramsCopy = Object.assign({}, paramsAndBody); + let params = omitFromObject(paramsAndBody, ['body']); let newUrl = this.prepareUrl(url, params); let body = null; if (paramsCopy && paramsCopy.body) { From 0b4cc3123d9967d62301f846f7ed372f9b26f92d Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 18:45:06 +0100 Subject: [PATCH 10/60] Remove lodash dependency --- js/utils/general_utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index c13e936e..06e6d3ee 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -1,7 +1,5 @@ 'use strict'; -import _ from 'lodash'; - /** * Takes an object and returns a shallow copy without any keys * that fail the passed in filter function. From cb6e94c8f13d1183ae04a2a08d51d6eea0c70a54 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 18:57:56 +0100 Subject: [PATCH 11/60] Forgot to use our own omit instead of lodash's --- js/utils/general_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 06e6d3ee..e717fa75 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -15,7 +15,7 @@ export function sanitize(obj, filterFn) { filterFn = (val) => val == null || val === ''; } - return _.omit(obj, filterFn); + return omitFromObject(obj, filterFn); } /** From c6f6bb398dfa860c8eb2fb6c56bad4c54422b8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 3 Nov 2015 10:57:41 +0100 Subject: [PATCH 12/60] Replace all occurrences of with momentjs --- README.md | 1 + .../ascribe_accordion_list/accordion_list_item_wallet.js | 3 ++- js/components/ascribe_detail/edition.js | 3 ++- js/components/ascribe_detail/piece_container.js | 3 ++- .../ascribe_accordion_list/accordion_list_item_prize.js | 3 ++- .../prize/components/ascribe_detail/prize_piece_container.js | 2 +- .../components/ascribe_detail/wallet_piece_container.js | 3 ++- .../cyland_accordion_list/cyland_accordion_list_item.js | 3 ++- .../ikonotv_accordion_list/ikonotv_accordion_list_item.js | 3 ++- js/utils/file_utils.js | 5 +++-- 10 files changed, 19 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1dc4492b..a359657b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ For this project, we're using: * We don't use ES6's class declaration for React components because it does not support Mixins as well as Autobinding ([Blog post about it](http://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding)) * We don't use camel case for file naming but in everything Javascript related * We use `let` instead of `var`: [SA Post](http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword) +* We don't use Javascript's `Date` object, as its interface introduced bugs previously and we're including `momentjs` for other dependencies anyways SCSS Code Conventions diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js index 8899c67e..da45d1e8 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import Moment from 'moment'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; @@ -129,7 +130,7 @@ let AccordionListItemWallet = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getUTCFullYear()} + {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()} {this.getLicences()}
} buttons={ diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index ae53728f..6b38ddf8 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -2,6 +2,7 @@ import React from 'react'; import { Link, History } from 'react-router'; +import Moment from 'moment'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; @@ -85,7 +86,7 @@ let Edition = React.createClass({

{this.props.edition.title}

- +

{this.state.piece.title}

- + {this.state.piece.num_editions > 0 ? : null}
diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 8eac81d1..08ebce42 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -3,6 +3,7 @@ import React from 'react'; import { Link } from 'react-router'; import StarRating from 'react-star-rating'; +import Moment from 'moment'; import PieceListActions from '../../../../../actions/piece_list_actions'; import PieceListStore from '../../../../../stores/piece_list_store'; @@ -182,7 +183,7 @@ let AccordionListItemPrize = React.createClass({ artistName={artistName} subsubheading={
- {new Date(this.props.content.date_created).getUTCFullYear()} + {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()}
} buttons={this.getPrizeButtons()} badge={this.getPrizeBadge()}> diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 6bd47c18..e2de24df 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -141,7 +141,7 @@ let PieceContainer = React.createClass({

{this.state.piece.title}

- + {artistEmail} {this.getActions()}
diff --git a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js index e765bd7b..b263e517 100644 --- a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js +++ b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import Moment from 'moment'; import Piece from '../../../../../components/ascribe_detail/piece'; @@ -39,7 +40,7 @@ let WalletPieceContainer = React.createClass({

{this.props.piece.title}

- +
} diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js index 0b4ec543..9802e93e 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import Moment from 'moment'; import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece'; @@ -100,7 +101,7 @@ let CylandAccordionListItem = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getUTCFullYear()} + {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()}
} buttons={this.getSubmitButtons()}> {this.props.children} diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js index e1187b7c..f2f73767 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import Moment from 'moment'; import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece'; @@ -106,7 +107,7 @@ let IkonotvAccordionListItem = React.createClass({ piece={this.props.content} subsubheading={
- {new Date(this.props.content.date_created).getUTCFullYear()} + {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()}
} buttons={this.getSubmitButtons()}> {this.props.children} diff --git a/js/utils/file_utils.js b/js/utils/file_utils.js index 964ba7b8..3454404a 100644 --- a/js/utils/file_utils.js +++ b/js/utils/file_utils.js @@ -2,6 +2,7 @@ import Q from 'q'; import SparkMD5 from 'spark-md5'; +import Moment from 'moment'; import { getLangText } from './lang_utils'; @@ -37,7 +38,7 @@ export function computeHashOfFile(file) { let spark = new SparkMD5.ArrayBuffer(); let fileReader = new FileReader(); - let startTime = new Date(); + let startTime = new Moment(); // comment: We should convert this to es6 at some point, however if so please consider that // an arrow function will get rid of the function's scope... @@ -53,7 +54,7 @@ export function computeHashOfFile(file) { console.info('computed hash %s (took %d s)', fileHash, - Math.round(((new Date() - startTime) / 1000) % 60)); // Compute hash + Math.round(((new Moment() - startTime) / 1000) % 60)); // Compute hash let blobTextFile = makeTextFile(fileHash, file); resolve(blobTextFile); From 8892ac42252c86b201de50ddea09c00b10e6eaab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 5 Nov 2015 11:56:09 +0100 Subject: [PATCH 13/60] Add additional fields to step two of cyland's loan process --- .../cyland_additional_data_form.js | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js index 63863b2d..ac8e70ab 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js @@ -122,21 +122,69 @@ let CylandAdditionalDataForm = React.createClass({ {heading} + label={getLangText('Artist Biography')} + hidden={disabled && !this.props.piece.extra_data.artist_bio}> + + label={getLangText('Conceptual Overview')} + hidden={disabled && !this.props.piece.extra_data.conceptual_overview}> + + + + Date: Thu, 5 Nov 2015 16:45:12 +0100 Subject: [PATCH 14/60] Move and rename sluice prize app to 'simple_prize' --- .../prize/constants/prize_api_urls.js | 2 +- .../whitelabel/prize/prize_routes.js | 57 +++++++++++-------- .../actions/prize_actions.js | 2 +- .../actions/prize_jury_actions.js | 2 +- .../actions/prize_rating_actions.js | 2 +- .../accordion_list_item_prize.js | 20 +++---- .../ascribe_buttons/submit_to_prize_button.js | 6 +- .../ascribe_detail/prize_piece_container.js | 46 +++++++-------- .../components/prize_hero.js | 2 +- .../components/prize_landing.js | 8 +-- .../components/prize_login_container.js | 6 +- .../components/prize_piece_list.js | 12 ++-- .../components/prize_register_piece.js | 12 ++-- .../components/prize_settings_container.js | 26 ++++----- .../components/prize_signup_container.js | 6 +- .../fetchers/prize_fetcher.js | 2 +- .../fetchers/prize_jury_fetcher.js | 2 +- .../fetchers/prize_rating_fetcher.js | 2 +- .../prize/{ => simple_prize}/prize_app.js | 8 +-- .../stores/prize_jury_store.js | 2 +- .../stores/prize_rating_store.js | 2 +- .../{ => simple_prize}/stores/prize_store.js | 2 +- 22 files changed, 119 insertions(+), 110 deletions(-) rename js/components/whitelabel/prize/{ => simple_prize}/actions/prize_actions.js (94%) rename js/components/whitelabel/prize/{ => simple_prize}/actions/prize_jury_actions.js (97%) rename js/components/whitelabel/prize/{ => simple_prize}/actions/prize_rating_actions.js (98%) rename js/components/whitelabel/prize/{ => simple_prize}/components/ascribe_accordion_list/accordion_list_item_prize.js (89%) rename js/components/whitelabel/prize/{ => simple_prize}/components/ascribe_buttons/submit_to_prize_button.js (86%) rename js/components/whitelabel/prize/{ => simple_prize}/components/ascribe_detail/prize_piece_container.js (90%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_hero.js (83%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_landing.js (93%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_login_container.js (83%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_piece_list.js (86%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_register_piece.js (87%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_settings_container.js (91%) rename js/components/whitelabel/prize/{ => simple_prize}/components/prize_signup_container.js (86%) rename js/components/whitelabel/prize/{ => simple_prize}/fetchers/prize_fetcher.js (70%) rename js/components/whitelabel/prize/{ => simple_prize}/fetchers/prize_jury_fetcher.js (88%) rename js/components/whitelabel/prize/{ => simple_prize}/fetchers/prize_rating_fetcher.js (90%) rename js/components/whitelabel/prize/{ => simple_prize}/prize_app.js (87%) rename js/components/whitelabel/prize/{ => simple_prize}/stores/prize_jury_store.js (96%) rename js/components/whitelabel/prize/{ => simple_prize}/stores/prize_rating_store.js (93%) rename js/components/whitelabel/prize/{ => simple_prize}/stores/prize_store.js (87%) diff --git a/js/components/whitelabel/prize/constants/prize_api_urls.js b/js/components/whitelabel/prize/constants/prize_api_urls.js index 2d35cf19..e493cffd 100644 --- a/js/components/whitelabel/prize/constants/prize_api_urls.js +++ b/js/components/whitelabel/prize/constants/prize_api_urls.js @@ -18,7 +18,7 @@ function getPrizeApiUrls(subdomain) { 'ratings': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/', 'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/', 'rating_average': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/average/', - 'select_piece' : AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/select/', + 'select_piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/select/', 'notes': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/', 'note': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/${piece_id}/' diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index 14d8b4d9..a9004927 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -3,58 +3,67 @@ import React from 'react'; import { Route, IndexRoute } from 'react-router'; -import Landing from './components/prize_landing'; -import LoginContainer from './components/prize_login_container'; -import LogoutContainer from '../../../components/logout_container'; -import SignupContainer from './components/prize_signup_container'; -import PasswordResetContainer from '../../../components/password_reset_container'; -import PrizeRegisterPiece from './components/prize_register_piece'; -import PrizePieceList from './components/prize_piece_list'; -import PrizePieceContainer from './components/ascribe_detail/prize_piece_container'; -import EditionContainer from '../../ascribe_detail/edition_container'; -import SettingsContainer from './components/prize_settings_container'; -import CoaVerifyContainer from '../../../components/coa_verify_container'; -import ErrorNotFoundPage from '../../../components/error_not_found_page'; +import SPLanding from './simple_prize/components/prize_landing'; +import SPLoginContainer from './simple_prize/components/prize_login_container'; +import SPSignupContainer from './simple_prize/components/prize_signup_container'; +import SPRegisterPiece from './simple_prize/components/prize_register_piece'; +import SPPieceList from './simple_prize/components/prize_piece_list'; +import SPPieceContainer from './simple_prize/components/ascribe_detail/prize_piece_container'; +import SPSettingsContainer from './simple_prize/components/prize_settings_container'; +import SPApp from './simple_prize/prize_app'; -import App from './prize_app'; +import EditionContainer from '../../ascribe_detail/edition_container'; +import LogoutContainer from '../../logout_container'; +import PasswordResetContainer from '../../password_reset_container'; +import CoaVerifyContainer from '../../coa_verify_container'; +import ErrorNotFoundPage from '../../error_not_found_page'; import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler'; -function getRoutes() { - return ( - - +const ROUTES = { + 'sluice': ( + + + component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SPLoginContainer)} /> + component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SPSignupContainer)} /> + component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SPSettingsContainer)}/> - + - ); + ) +}; + + +function getRoutes(commonRoutes, subdomain) { + if(subdomain in ROUTES) { + return ROUTES[subdomain]; + } else { + throw new Error('Subdomain wasn\'t specified in the wallet app.'); + } } diff --git a/js/components/whitelabel/prize/actions/prize_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js similarity index 94% rename from js/components/whitelabel/prize/actions/prize_actions.js rename to js/components/whitelabel/prize/simple_prize/actions/prize_actions.js index fcd9e91e..27127035 100644 --- a/js/components/whitelabel/prize/actions/prize_actions.js +++ b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import Q from 'q'; import PrizeFetcher from '../fetchers/prize_fetcher'; diff --git a/js/components/whitelabel/prize/actions/prize_jury_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_jury_actions.js similarity index 97% rename from js/components/whitelabel/prize/actions/prize_jury_actions.js rename to js/components/whitelabel/prize/simple_prize/actions/prize_jury_actions.js index 9bd03f59..24cf08e8 100644 --- a/js/components/whitelabel/prize/actions/prize_jury_actions.js +++ b/js/components/whitelabel/prize/simple_prize/actions/prize_jury_actions.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import Q from 'q'; import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher'; diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js similarity index 98% rename from js/components/whitelabel/prize/actions/prize_rating_actions.js rename to js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js index 184d84e7..68b5334b 100644 --- a/js/components/whitelabel/prize/actions/prize_rating_actions.js +++ b/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import Q from 'q'; import PrizeRatingFetcher from '../fetchers/prize_rating_fetcher'; diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js similarity index 89% rename from js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js rename to js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js index caef504b..20184ff1 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -4,25 +4,25 @@ import React from 'react'; import { Link } from 'react-router'; import StarRating from 'react-star-rating'; -import PieceListActions from '../../../../../actions/piece_list_actions'; -import PieceListStore from '../../../../../stores/piece_list_store'; +import PieceListActions from '../../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../../stores/piece_list_store'; import PrizeRatingActions from '../../actions/prize_rating_actions'; -import UserStore from '../../../../../stores/user_store'; +import UserStore from '../../../../../../stores/user_store'; -import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; +import InputCheckbox from '../../../../../ascribe_forms/input_checkbox'; -import AccordionListItemPiece from '../../../../ascribe_accordion_list/accordion_list_item_piece'; +import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece'; -import GlobalNotificationModel from '../../../../../models/global_notification_model'; -import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; -import AclProxy from '../../../../acl_proxy'; +import AclProxy from '../../../../../acl_proxy'; import SubmitToPrizeButton from './../ascribe_buttons/submit_to_prize_button'; -import { getLangText } from '../../../../../utils/lang_utils'; -import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../../utils/general_utils'; let AccordionListItemPrize = React.createClass({ diff --git a/js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_buttons/submit_to_prize_button.js similarity index 86% rename from js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js rename to js/components/whitelabel/prize/simple_prize/components/ascribe_buttons/submit_to_prize_button.js index 409b8aa1..8ceb87ea 100644 --- a/js/components/whitelabel/prize/components/ascribe_buttons/submit_to_prize_button.js +++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_buttons/submit_to_prize_button.js @@ -3,10 +3,10 @@ import React from 'react'; import classNames from 'classnames'; -import ModalWrapper from '../../../../ascribe_modal/modal_wrapper'; -import PieceSubmitToPrizeForm from '../../../../ascribe_forms/form_submit_to_prize'; +import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; +import PieceSubmitToPrizeForm from '../../../../../ascribe_forms/form_submit_to_prize'; -import { getLangText } from '../../../../../utils/lang_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; let SubmitToPrizeButton = React.createClass({ propTypes: { diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js similarity index 90% rename from js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js rename to js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js index f2e22412..25354dc1 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js @@ -6,41 +6,41 @@ import Moment from 'moment'; import StarRating from 'react-star-rating'; -import PieceActions from '../../../../../actions/piece_actions'; -import PieceStore from '../../../../../stores/piece_store'; +import PieceActions from '../../../../../../actions/piece_actions'; +import PieceStore from '../../../../../../stores/piece_store'; -import PieceListStore from '../../../../../stores/piece_list_store'; -import PieceListActions from '../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../../stores/piece_list_store'; +import PieceListActions from '../../../../../../actions/piece_list_actions'; import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; -import UserStore from '../../../../../stores/user_store'; +import UserStore from '../../../../../../stores/user_store'; -import Piece from '../../../../../components/ascribe_detail/piece'; -import Note from '../../../../../components/ascribe_detail/note'; +import Piece from '../../../../../../components/ascribe_detail/piece'; +import Note from '../../../../../../components/ascribe_detail/note'; -import AscribeSpinner from '../../../../ascribe_spinner'; +import AscribeSpinner from '../../../../../ascribe_spinner'; -import Form from '../../../../../components/ascribe_forms/form'; -import Property from '../../../../../components/ascribe_forms/property'; -import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; -import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; +import Form from '../../../../../../components/ascribe_forms/form'; +import Property from '../../../../../../components/ascribe_forms/property'; +import InputTextAreaToggable from '../../../../../../components/ascribe_forms/input_textarea_toggable'; +import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph'; -import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; -import LoanForm from '../../../../ascribe_forms/form_loan'; -import ListRequestActions from '../../../../ascribe_forms/list_form_request_actions'; -import ModalWrapper from '../../../../ascribe_modal/modal_wrapper'; +import InputCheckbox from '../../../../../ascribe_forms/input_checkbox'; +import LoanForm from '../../../../../ascribe_forms/form_loan'; +import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions'; +import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; -import GlobalNotificationModel from '../../../../../models/global_notification_model'; -import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; -import DetailProperty from '../../../../ascribe_detail/detail_property'; +import DetailProperty from '../../../../../ascribe_detail/detail_property'; -import ApiUrls from '../../../../../constants/api_urls'; -import { mergeOptions } from '../../../../../utils/general_utils'; -import { getLangText } from '../../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../../utils/dom_utils'; +import ApiUrls from '../../../../../../constants/api_urls'; +import { mergeOptions } from '../../../../../../utils/general_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../../utils/dom_utils'; /** diff --git a/js/components/whitelabel/prize/components/prize_hero.js b/js/components/whitelabel/prize/simple_prize/components/prize_hero.js similarity index 83% rename from js/components/whitelabel/prize/components/prize_hero.js rename to js/components/whitelabel/prize/simple_prize/components/prize_hero.js index b98f407e..8842acf9 100644 --- a/js/components/whitelabel/prize/components/prize_hero.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_hero.js @@ -1,7 +1,7 @@ 'use strict'; import React from 'react'; -import constants from '../../../../constants/application_constants'; +import constants from '../../../../../constants/application_constants'; let Hero = React.createClass({ diff --git a/js/components/whitelabel/prize/components/prize_landing.js b/js/components/whitelabel/prize/simple_prize/components/prize_landing.js similarity index 93% rename from js/components/whitelabel/prize/components/prize_landing.js rename to js/components/whitelabel/prize/simple_prize/components/prize_landing.js index 355b3786..e26a05b5 100644 --- a/js/components/whitelabel/prize/components/prize_landing.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_landing.js @@ -11,11 +11,11 @@ import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'; import LinkContainer from 'react-router-bootstrap/lib/LinkContainer'; -import UserStore from '../../../../stores/user_store'; -import UserActions from '../../../../actions/user_actions'; +import UserStore from '../../../../../stores/user_store'; +import UserActions from '../../../../../actions/user_actions'; -import { mergeOptions } from '../../../../utils/general_utils'; -import { getLangText } from '../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; let Landing = React.createClass({ diff --git a/js/components/whitelabel/prize/components/prize_login_container.js b/js/components/whitelabel/prize/simple_prize/components/prize_login_container.js similarity index 83% rename from js/components/whitelabel/prize/components/prize_login_container.js rename to js/components/whitelabel/prize/simple_prize/components/prize_login_container.js index 9a0de06d..e168ca68 100644 --- a/js/components/whitelabel/prize/components/prize_login_container.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_login_container.js @@ -3,10 +3,10 @@ import React from 'react'; import { Link } from 'react-router'; -import LoginForm from '../../../ascribe_forms/form_login'; +import LoginForm from '../../../../ascribe_forms/form_login'; -import { getLangText } from '../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../utils/dom_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; let LoginContainer = React.createClass({ diff --git a/js/components/whitelabel/prize/components/prize_piece_list.js b/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js similarity index 86% rename from js/components/whitelabel/prize/components/prize_piece_list.js rename to js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js index 7a6a90ac..8e602012 100644 --- a/js/components/whitelabel/prize/components/prize_piece_list.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js @@ -1,10 +1,10 @@ 'use strict'; import React from 'react'; -import PieceList from '../../../piece_list'; +import PieceList from '../../../../piece_list'; -import UserActions from '../../../../actions/user_actions'; -import UserStore from '../../../../stores/user_store'; +import UserActions from '../../../../../actions/user_actions'; +import UserStore from '../../../../../stores/user_store'; import PrizeActions from '../actions/prize_actions'; import PrizeStore from '../stores/prize_store'; @@ -15,9 +15,9 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer'; import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize'; -import { mergeOptions } from '../../../../utils/general_utils'; -import { getLangText } from '../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../utils/dom_utils'; +import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; let PrizePieceList = React.createClass({ propTypes: { diff --git a/js/components/whitelabel/prize/components/prize_register_piece.js b/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js similarity index 87% rename from js/components/whitelabel/prize/components/prize_register_piece.js rename to js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js index 87a23591..a35893ed 100644 --- a/js/components/whitelabel/prize/components/prize_register_piece.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js @@ -5,13 +5,13 @@ import React from 'react'; import PrizeActions from '../actions/prize_actions'; import PrizeStore from '../stores/prize_store'; -import RegisterPiece from '../../../register_piece'; -import Property from '../../../ascribe_forms/property'; -import InputTextAreaToggable from '../../../ascribe_forms/input_textarea_toggable'; -import InputCheckbox from '../../../ascribe_forms/input_checkbox'; +import RegisterPiece from '../../../../register_piece'; +import Property from '../../../../ascribe_forms/property'; +import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable'; +import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; -import { getLangText } from '../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../utils/dom_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; let PrizeRegisterPiece = React.createClass({ diff --git a/js/components/whitelabel/prize/components/prize_settings_container.js b/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js similarity index 91% rename from js/components/whitelabel/prize/components/prize_settings_container.js rename to js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js index 81d62380..145a9d24 100644 --- a/js/components/whitelabel/prize/components/prize_settings_container.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js @@ -2,29 +2,29 @@ import React from 'react'; -import UserStore from '../../../../stores/user_store'; -import UserActions from '../../../../actions/user_actions'; +import UserStore from '../../../../../stores/user_store'; +import UserActions from '../../../../../actions/user_actions'; import PrizeActions from '../actions/prize_actions'; import PrizeStore from '../stores/prize_store'; import PrizeJuryActions from '../actions/prize_jury_actions'; import PrizeJuryStore from '../stores/prize_jury_store'; -import SettingsContainer from '../../../ascribe_settings/settings_container'; -import CollapsibleParagraph from '../../../ascribe_collapsible/collapsible_paragraph'; +import SettingsContainer from '../../../../ascribe_settings/settings_container'; +import CollapsibleParagraph from '../../../../ascribe_collapsible/collapsible_paragraph'; -import Form from '../../../ascribe_forms/form'; -import Property from '../../../ascribe_forms/property'; +import Form from '../../../../ascribe_forms/form'; +import Property from '../../../../ascribe_forms/property'; -import ActionPanel from '../../../ascribe_panel/action_panel'; +import ActionPanel from '../../../../ascribe_panel/action_panel'; -import GlobalNotificationModel from '../../../../models/global_notification_model'; -import GlobalNotificationActions from '../../../../actions/global_notification_actions'; +import GlobalNotificationModel from '../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; -import AscribeSpinner from '../../../ascribe_spinner'; -import ApiUrls from '../../../../constants/api_urls'; +import AscribeSpinner from '../../../../ascribe_spinner'; +import ApiUrls from '../../../../../constants/api_urls'; -import { getLangText } from '../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../utils/dom_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; let Settings = React.createClass({ diff --git a/js/components/whitelabel/prize/components/prize_signup_container.js b/js/components/whitelabel/prize/simple_prize/components/prize_signup_container.js similarity index 86% rename from js/components/whitelabel/prize/components/prize_signup_container.js rename to js/components/whitelabel/prize/simple_prize/components/prize_signup_container.js index 884062da..7a44d521 100644 --- a/js/components/whitelabel/prize/components/prize_signup_container.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_signup_container.js @@ -1,10 +1,10 @@ 'use strict'; import React from 'react'; -import SignupForm from '../../../ascribe_forms/form_signup'; +import SignupForm from '../../../../ascribe_forms/form_signup'; -import { getLangText } from '../../../../utils/lang_utils'; -import { setDocumentTitle } from '../../../../utils/dom_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; let SignupContainer = React.createClass({ propTypes: { diff --git a/js/components/whitelabel/prize/fetchers/prize_fetcher.js b/js/components/whitelabel/prize/simple_prize/fetchers/prize_fetcher.js similarity index 70% rename from js/components/whitelabel/prize/fetchers/prize_fetcher.js rename to js/components/whitelabel/prize/simple_prize/fetchers/prize_fetcher.js index 0bf9fc55..410d63a2 100644 --- a/js/components/whitelabel/prize/fetchers/prize_fetcher.js +++ b/js/components/whitelabel/prize/simple_prize/fetchers/prize_fetcher.js @@ -1,6 +1,6 @@ 'use strict'; -import requests from '../../../../utils/requests'; +import requests from '../../../../../utils/requests'; let PrizeFetcher = { diff --git a/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js b/js/components/whitelabel/prize/simple_prize/fetchers/prize_jury_fetcher.js similarity index 88% rename from js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js rename to js/components/whitelabel/prize/simple_prize/fetchers/prize_jury_fetcher.js index 1c5b0a0d..973107b4 100644 --- a/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js +++ b/js/components/whitelabel/prize/simple_prize/fetchers/prize_jury_fetcher.js @@ -1,6 +1,6 @@ 'use strict'; -import requests from '../../../../utils/requests'; +import requests from '../../../../../utils/requests'; let PrizeJuryFetcher = { diff --git a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js b/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js similarity index 90% rename from js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js rename to js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js index 33450dd6..38d0576e 100644 --- a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js +++ b/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js @@ -1,6 +1,6 @@ 'use strict'; -import requests from '../../../../utils/requests'; +import requests from '../../../../../utils/requests'; let PrizeRatingFetcher = { diff --git a/js/components/whitelabel/prize/prize_app.js b/js/components/whitelabel/prize/simple_prize/prize_app.js similarity index 87% rename from js/components/whitelabel/prize/prize_app.js rename to js/components/whitelabel/prize/simple_prize/prize_app.js index aadb0b05..d95d7772 100644 --- a/js/components/whitelabel/prize/prize_app.js +++ b/js/components/whitelabel/prize/simple_prize/prize_app.js @@ -2,11 +2,11 @@ import React from 'react'; import Hero from './components/prize_hero'; -import Header from '../../header'; -import Footer from '../../footer'; -import GlobalNotification from '../../global_notification'; +import Header from '../../../header'; +import Footer from '../../../footer'; +import GlobalNotification from '../../../global_notification'; -import { getSubdomain } from '../../../utils/general_utils'; +import { getSubdomain } from '../../../../utils/general_utils'; let PrizeApp = React.createClass({ diff --git a/js/components/whitelabel/prize/stores/prize_jury_store.js b/js/components/whitelabel/prize/simple_prize/stores/prize_jury_store.js similarity index 96% rename from js/components/whitelabel/prize/stores/prize_jury_store.js rename to js/components/whitelabel/prize/simple_prize/stores/prize_jury_store.js index 69d73e3a..536b8633 100644 --- a/js/components/whitelabel/prize/stores/prize_jury_store.js +++ b/js/components/whitelabel/prize/simple_prize/stores/prize_jury_store.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import PrizeJuryActions from '../actions/prize_jury_actions'; diff --git a/js/components/whitelabel/prize/stores/prize_rating_store.js b/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js similarity index 93% rename from js/components/whitelabel/prize/stores/prize_rating_store.js rename to js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js index d67fa603..9f1552bb 100644 --- a/js/components/whitelabel/prize/stores/prize_rating_store.js +++ b/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import PrizeRatingActions from '../actions/prize_rating_actions'; diff --git a/js/components/whitelabel/prize/stores/prize_store.js b/js/components/whitelabel/prize/simple_prize/stores/prize_store.js similarity index 87% rename from js/components/whitelabel/prize/stores/prize_store.js rename to js/components/whitelabel/prize/simple_prize/stores/prize_store.js index 68cc9264..8d9c4bbe 100644 --- a/js/components/whitelabel/prize/stores/prize_store.js +++ b/js/components/whitelabel/prize/simple_prize/stores/prize_store.js @@ -1,6 +1,6 @@ 'use strict'; -import { alt } from '../../../../alt'; +import { alt } from '../../../../../alt'; import PrizeActions from '../actions/prize_actions'; From f5a5e045a6b1d3e63a2242408e146102ac97d079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 6 Nov 2015 12:09:31 +0100 Subject: [PATCH 15/60] Finalize boilerplate for portfolioreview subdomain --- README.md | 2 + .../portfolioreview/components/pr_landing.js | 117 ++++++++++++++++++ .../prize/portfolioreview/pr_app.js | 35 ++++++ .../whitelabel/prize/prize_routes.js | 27 +++- js/constants/application_constants.js | 7 ++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 js/components/whitelabel/prize/portfolioreview/components/pr_landing.js create mode 100644 js/components/whitelabel/prize/portfolioreview/pr_app.js diff --git a/README.md b/README.md index 1dc4492b..16fba17d 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Additionally, to work on the white labeling functionality, you need to edit your 127.0.0.1 cyland.localhost.com 127.0.0.1 ikonotv.localhost.com 127.0.0.1 sluice.localhost.com +127.0.0.1 lumenus.localhost.com +127.0.0.1 portfolioreview.localhost.com ``` diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js b/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js new file mode 100644 index 00000000..e88efff2 --- /dev/null +++ b/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js @@ -0,0 +1,117 @@ +'use strict'; + +import React from 'react'; +import { History } from 'react-router'; + +import PrizeActions from '../../simple_prize/actions/prize_actions'; +import PrizeStore from '../../simple_prize/stores/prize_store'; + +import Button from 'react-bootstrap/lib/Button'; +import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'; + +import LinkContainer from 'react-router-bootstrap/lib/LinkContainer'; + +import UserStore from '../../../../../stores/user_store'; +import UserActions from '../../../../../actions/user_actions'; + +import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; + +const PRLanding = React.createClass({ + + mixins: [History], + + getInitialState() { + return mergeOptions( + PrizeStore.getState(), + UserStore.getState() + ); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + PrizeStore.listen(this.onChange); + PrizeActions.fetchPrize(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + PrizeStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + getButtons() { + if (this.state.prize && this.state.prize.active){ + return ( + + + + + +

+ {getLangText('or, already an ascribe user?')} +

+ + + +
+ ); + } + return ( + + + {getLangText('Sign up to ascribe')} + + +

+ {getLangText('or, already an ascribe user?')} +

+ + + +
+ ); + }, + + getTitle() { + if (this.state.prize && this.state.prize.active){ + return ( +

+ {getLangText('This is the submission page for Portfolio Review 2015.')} +

+ ); + } + return ( +

+ {getLangText('Submissions for Portfolio Review 2015 are now closed.')} +

+ ); + }, + render() { + return ( +
+
+
+

+ {getLangText('Welcome to Portfolio Review 2015')} +

+ {this.getTitle()} + {this.getButtons()} +
+
+
+ ); + } +}); + +export default PRLanding; \ No newline at end of file diff --git a/js/components/whitelabel/prize/portfolioreview/pr_app.js b/js/components/whitelabel/prize/portfolioreview/pr_app.js new file mode 100644 index 00000000..072542f9 --- /dev/null +++ b/js/components/whitelabel/prize/portfolioreview/pr_app.js @@ -0,0 +1,35 @@ +'use strict'; + +import React from 'react'; +import Footer from '../../../footer'; +import GlobalNotification from '../../../global_notification'; + +import { getSubdomain } from '../../../../utils/general_utils'; + + +let PrizeApp = React.createClass({ + propTypes: { + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]), + history: React.PropTypes.object, + routes: React.PropTypes.arrayOf(React.PropTypes.object) + }, + + render() { + const { children } = this.props; + let subdomain = getSubdomain(); + + return ( +
+ {children} + + +
+
+ ); + } +}); + +export default PrizeApp; diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index a9004927..9396a354 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -12,6 +12,9 @@ import SPPieceContainer from './simple_prize/components/ascribe_detail/prize_pie import SPSettingsContainer from './simple_prize/components/prize_settings_container'; import SPApp from './simple_prize/prize_app'; +import PRApp from './portfolioreview/pr_app'; +import PRLanding from './portfolioreview/components/pr_landing'; + import EditionContainer from '../../ascribe_detail/edition_container'; import LogoutContainer from '../../logout_container'; import PasswordResetContainer from '../../password_reset_container'; @@ -22,7 +25,7 @@ import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/au const ROUTES = { - 'sluice': ( + sluice: ( + ), + portfolioreview: ( + + + + + + + + + ) }; diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 0fe5e210..b175c158 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -46,6 +46,13 @@ let constants = { 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/ikonotv/ikono-logo-black.png', 'permissions': ['register', 'edit', 'share', 'del_from_collection'], 'type': 'wallet' + }, + { + 'subdomain': 'portfolioreview', + 'name': 'Portfolio Review', + 'logo': 'http://notfoundlogo.de', + 'permissions': ['register', 'edit', 'share', 'del_from_collection'], + 'type': 'prize' } ], 'defaultDomain': { From b78bc66fe9e3e95ee8b67e52b4ce4101c1cbf2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 6 Nov 2015 15:47:55 +0100 Subject: [PATCH 16/60] Fix minor bugs for simple_prize app --- c | 12 +++ js/components/register_piece.js | 6 -- .../whitelabel/prize/prize_routes.js | 6 +- .../simple_prize/actions/prize_actions.js | 23 ++--- .../components/prize_register_piece.js | 84 ++++++++++--------- 5 files changed, 70 insertions(+), 61 deletions(-) create mode 100644 c diff --git a/c b/c new file mode 100644 index 00000000..d3923303 --- /dev/null +++ b/c @@ -0,0 +1,12 @@ +commit 22fd8656e9e93a5d8d2a412dbed33fce0db57af8 +Author: Tim Daubenschütz +Date: Fri Nov 6 12:09:31 2015 +0100 + + Finalize boilerplate for portfolioreview subdomain + +commit d1dd33c094194bb6271e2ae11817837b4c39caa5 +Author: Tim Daubenschütz +Date: Thu Nov 5 16:45:12 2015 +0100 + + Move and rename sluice prize app to 'simple_prize' + diff --git a/js/components/register_piece.js b/js/components/register_piece.js index f127c149..43ac7bb7 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -40,12 +40,6 @@ let RegisterPiece = React.createClass( { mixins: [History], - getDefaultProps() { - return { - canSpecifyEditions: true - }; - }, - getInitialState(){ return mergeOptions( UserStore.getState(), diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index 9396a354..343de03a 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -67,16 +67,16 @@ const ROUTES = { headerTitle='+ NEW WORK'/> + component={AuthProxyHandler({to: '/register_piece', when: 'loggedIn'})(SPLoginContainer)} /> + component={AuthProxyHandler({to: '/register_piece', when: 'loggedIn'})(SPSignupContainer)} /> + component={AuthProxyHandler({to: '/register_piece', when: 'loggedIn'})(PasswordResetContainer)} /> ) diff --git a/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js index 27127035..dbca1b5d 100644 --- a/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js +++ b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js @@ -1,7 +1,6 @@ 'use strict'; import { alt } from '../../../../../alt'; -import Q from 'q'; import PrizeFetcher from '../fetchers/prize_fetcher'; @@ -13,20 +12,16 @@ class PrizeActions { } fetchPrize() { - return Q.Promise((resolve, reject) => { - PrizeFetcher - .fetch() - .then((res) => { - this.actions.updatePrize({ - prize: res.prize - }); - resolve(res); - }) - .catch((err) => { - console.logGlobal(err); - reject(err); + PrizeFetcher + .fetch() + .then((res) => { + this.actions.updatePrize({ + prize: res.prize }); - }); + }) + .catch((err) => { + console.logGlobal(err); + }); } } diff --git a/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js b/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js index a35893ed..424a2fdd 100644 --- a/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js +++ b/js/components/whitelabel/prize/simple_prize/components/prize_register_piece.js @@ -15,6 +15,10 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils'; let PrizeRegisterPiece = React.createClass({ + propTypes: { + location: React.PropTypes.object + }, + getInitialState() { return PrizeStore.getState(); }, @@ -33,48 +37,52 @@ let PrizeRegisterPiece = React.createClass({ }, render() { + const { location } = this.props; + setDocumentTitle(getLangText('Submit to the prize')); if(this.state.prize && this.state.prize.active){ return ( - - - - - - - - - - - {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} - ( - {getLangText('read')} - ) - - - - ); + + + + + + + + + + + {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + ( + {getLangText('read')} + ) + + + + + ); } else { return ( From 7721d623192368f1a89c54c11f90a8c30242466e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 6 Nov 2015 16:52:08 +0100 Subject: [PATCH 17/60] Create boilerplate code for portfolioreview --- .../pr_forms/pr_register_piece_form.js | 85 +++++++++++++++++++ .../components/pr_register_piece.js | 34 ++++++++ .../whitelabel/prize/prize_routes.js | 3 +- .../components/prize_register_piece.js | 80 ++++++++--------- sass/whitelabel/prize/index.scss | 3 +- .../portfolioreview_custom_style.scss | 33 +++++++ .../simple_prize_custom_style.scss} | 0 7 files changed, 197 insertions(+), 41 deletions(-) create mode 100644 js/components/whitelabel/prize/portfolioreview/components/pr_forms/pr_register_piece_form.js create mode 100644 js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js create mode 100644 sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss rename sass/whitelabel/prize/{sluice/sluice_custom_style.scss => simple_prize/simple_prize_custom_style.scss} (100%) diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_forms/pr_register_piece_form.js b/js/components/whitelabel/prize/portfolioreview/components/pr_forms/pr_register_piece_form.js new file mode 100644 index 00000000..df42b800 --- /dev/null +++ b/js/components/whitelabel/prize/portfolioreview/components/pr_forms/pr_register_piece_form.js @@ -0,0 +1,85 @@ +'use strict'; + +import React from 'react'; + +import Form from '../../../../../ascribe_forms/form'; +import Property from '../../../../../ascribe_forms/property'; +import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable'; + +import { getLangText } from '../../../../../../utils/lang_utils'; + + +const PRRegisterPieceForm = React.createClass({ + getInitialState(){ + return { + isUploadReady: false + }; + }, + + handleSuccess() { + + }, + + render() { + return ( +
+
+ + + + + + + + + +
+
+ + + + + + + + + +
+
+ ); + } +}); + +export default PRRegisterPieceForm; \ No newline at end of file diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js new file mode 100644 index 00000000..ab705b61 --- /dev/null +++ b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js @@ -0,0 +1,34 @@ +'use strict'; + +import React from 'react'; + +import Col from 'react-bootstrap/lib/Col'; +import Row from 'react-bootstrap/lib/Row'; + +import PRRegisterPieceForm from './pr_forms/pr_register_piece_form'; + +import { getLangText } from '../../../../../utils/lang_utils'; + + +const PRRegisterPiece = React.createClass({ + render() { + return ( + + +
+

Portfolio Review

+

{getLangText('Submission closing on %s', ' 21 Dec 2015')}

+

{getLangText('Submissions are open to everyone, we accept only PDFs.')}

+

{getLangText('We accept only one PDF with up to 20 images from every participant.')}

+

{getLangText('You need to pay 50€ in order to apply. We only accept PayPal.')}

+
+ + + + +
+ ); + } +}); + +export default PRRegisterPiece; \ No newline at end of file diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index 343de03a..7c4b40a3 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -14,6 +14,7 @@ import SPApp from './simple_prize/prize_app'; import PRApp from './portfolioreview/pr_app'; import PRLanding from './portfolioreview/components/pr_landing'; +import PRRegisterPiece from './portfolioreview/components/pr_register_piece'; import EditionContainer from '../../ascribe_detail/edition_container'; import LogoutContainer from '../../logout_container'; @@ -63,7 +64,7 @@ const ROUTES = { - - - - - - - - - - {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} - ( - {getLangText('read')} - ) - - - - +
+ + + + + + + + + + + {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + ( + {getLangText('read')} + ) + + + + +
); } else { diff --git a/sass/whitelabel/prize/index.scss b/sass/whitelabel/prize/index.scss index 5bc75746..24645c8a 100644 --- a/sass/whitelabel/prize/index.scss +++ b/sass/whitelabel/prize/index.scss @@ -1,4 +1,5 @@ -@import 'sluice/sluice_custom_style'; +@import 'simple_prize/simple_prize_custom_style'; +@import 'portfolioreview/portfolioreview_custom_style'; .ascribe-prize-app { border-radius: 0; diff --git a/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss b/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss new file mode 100644 index 00000000..a0eb64ec --- /dev/null +++ b/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss @@ -0,0 +1,33 @@ +.client--portfolioreview { + padding-top: 20px !important; + + .register-piece--hero { + text-align: center; + + h1, h2 { + font-variant: small-caps; + } + + h1 { + font-size: 5em; + color: #757575; + } + + h2 { + font-size: 1.25em; + } + + p { + margin-bottom: 0; + } + + p + p { + margin-top: 0; + } + + p:last-child { + margin-bottom: 1.5em; + } + + } +} \ No newline at end of file diff --git a/sass/whitelabel/prize/sluice/sluice_custom_style.scss b/sass/whitelabel/prize/simple_prize/simple_prize_custom_style.scss similarity index 100% rename from sass/whitelabel/prize/sluice/sluice_custom_style.scss rename to sass/whitelabel/prize/simple_prize/simple_prize_custom_style.scss From 3e22ad1d9d3282d4a680b662d1a33dfbde2e2117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 9 Nov 2015 10:35:23 +0100 Subject: [PATCH 18/60] Finalize layouting submission form --- .../ascribe_buttons/upload_file_button.js | 74 ++++++++++++ .../contract_settings_update_button.js | 1 - .../pr_forms/pr_register_piece_form.js | 105 +++++++++++++++++- .../components/pr_register_piece.js | 17 ++- sass/ascribe_form.scss | 2 +- sass/ascribe_property.scss | 15 +++ .../portfolioreview_custom_style.scss | 14 +++ 7 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 js/components/ascribe_buttons/upload_file_button.js diff --git a/js/components/ascribe_buttons/upload_file_button.js b/js/components/ascribe_buttons/upload_file_button.js new file mode 100644 index 00000000..7f76f2ef --- /dev/null +++ b/js/components/ascribe_buttons/upload_file_button.js @@ -0,0 +1,74 @@ +'use strict'; + +import React from 'react'; + +import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; +import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button'; + +import AppConstants from '../../constants/application_constants'; +import ApiUrls from '../../constants/api_urls'; + +import { getCookie } from '../../utils/fetch_api_utils'; +import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils'; + + +const { shape, arrayOf, string, object, number, oneOfType } = React.PropTypes; + +const UploadFileButton = React.createClass({ + propTypes: { + keyRoutine: shape({ + url: string, + fileClass: string + }).isRequired, + validation: shape({ + itemLimit: number, + sizeLimit: oneOfType([string, number]), + allowedExtensions: arrayOf(string) + }), + location: object, + fileClassToUpload: shape({ + singular: string, + plural: string + }).isRequired + }, + + submitFile(file) { + console.log(file); + }, + + render() { + + const { fileClassToUpload, validation, keyRoutine } = this.props; + + return ( + {/* So that ReactS3FineUploader is not complaining */}} + signature={{ + endpoint: AppConstants.serverUrl + 's3/signature/', + customHeaders: { + 'X-CSRFToken': getCookie(AppConstants.csrftoken) + } + }} + deleteFile={{ + enabled: true, + method: 'DELETE', + endpoint: AppConstants.serverUrl + 's3/delete', + customHeaders: { + 'X-CSRFToken': getCookie(AppConstants.csrftoken) + } + }} + fileClassToUpload={fileClassToUpload} + isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} + submitFile={this.submitFile} + location={this.props.location}/> + ); + } +}); + +export default UploadFileButton; \ No newline at end of file diff --git a/js/components/ascribe_settings/contract_settings_update_button.js b/js/components/ascribe_settings/contract_settings_update_button.js index f3bab156..265e6548 100644 --- a/js/components/ascribe_settings/contract_settings_update_button.js +++ b/js/components/ascribe_settings/contract_settings_update_button.js @@ -56,7 +56,6 @@ let ContractSettingsUpdateButton = React.createClass({ render() { return ( +
@@ -77,6 +90,96 @@ const PRRegisterPieceForm = React.createClass({ placeholder={getLangText('THIS NEEDS TEXT')}/>
+
+ {getLangText('Select the PDF with your work')} + +
+
+ {getLangText('Featured Cover photo')} + +
+
+ {getLangText('Supporting Materials (Optional)')} + +
+
+ {getLangText('Proof of payment')} + +
+
+ + +  {getLangText('I agree to the Terms and Conditions of the Portfolio Review')} + + +
+
); } diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js index ab705b61..5d1fd728 100644 --- a/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js +++ b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js @@ -8,13 +8,23 @@ import Row from 'react-bootstrap/lib/Row'; import PRRegisterPieceForm from './pr_forms/pr_register_piece_form'; import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; +const { object } = React.PropTypes; + const PRRegisterPiece = React.createClass({ + propTypes: { + location: object + }, + render() { + const { location } = this.props; + + setDocumentTitle(getLangText('Submission form')); return ( - +

Portfolio Review

{getLangText('Submission closing on %s', ' 21 Dec 2015')}

@@ -23,8 +33,9 @@ const PRRegisterPiece = React.createClass({

{getLangText('You need to pay 50€ in order to apply. We only accept PayPal.')}

- - + +
); diff --git a/sass/ascribe_form.scss b/sass/ascribe_form.scss index 41e17de1..1b265e91 100644 --- a/sass/ascribe_form.scss +++ b/sass/ascribe_form.scss @@ -23,4 +23,4 @@ @media (max-width: 550px) { width: 100%; } -} +} \ No newline at end of file diff --git a/sass/ascribe_property.scss b/sass/ascribe_property.scss index e938a7c3..cb7662e8 100644 --- a/sass/ascribe_property.scss +++ b/sass/ascribe_property.scss @@ -219,3 +219,18 @@ $ascribe-red-error: rgb(169, 68, 66); margin-top: 0; } } + +.input-upload-file-button-property { + background-color: white; + padding: 1.5em 0 1.5em 0; + text-align: right; + + button { + font-size: 1em; + margin-right: 1em; + } + + span + button { + margin-left: 1em; + } +} \ No newline at end of file diff --git a/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss b/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss index a0eb64ec..6c0d5d66 100644 --- a/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss +++ b/sass/whitelabel/prize/portfolioreview/portfolioreview_custom_style.scss @@ -28,6 +28,20 @@ p:last-child { margin-bottom: 1.5em; } + } + .register-piece--form { + + form { + border-top: none; + } + + form:first-child { + border-bottom: none; + } + + form + form, form:last-child { + border-bottom: 1px solid rgba(0, 0, 0, .05); + } } } \ No newline at end of file From 7c73b7fac78a60fb3c3518114699835d8993f1ec Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 9 Nov 2015 14:32:14 +0100 Subject: [PATCH 19/60] Refactor InjectInHeadMixin to be a util class instead --- js/components/ascribe_media/media_player.js | 29 ++++----- js/mixins/inject_in_head_mixin.js | 71 -------------------- js/utils/inject_utils.js | 72 +++++++++++++++++++++ 3 files changed, 84 insertions(+), 88 deletions(-) delete mode 100644 js/mixins/inject_in_head_mixin.js create mode 100644 js/utils/inject_utils.js diff --git a/js/components/ascribe_media/media_player.js b/js/components/ascribe_media/media_player.js index a7e56fb7..23e84945 100644 --- a/js/components/ascribe_media/media_player.js +++ b/js/components/ascribe_media/media_player.js @@ -3,12 +3,13 @@ import React from 'react'; import Q from 'q'; -import { escapeHTML } from '../../utils/general_utils'; - -import InjectInHeadMixin from '../../mixins/inject_in_head_mixin'; import Panel from 'react-bootstrap/lib/Panel'; import ProgressBar from 'react-bootstrap/lib/ProgressBar'; -import AppConstants from '../../constants/application_constants.js'; + +import AppConstants from '../../constants/application_constants'; + +import { escapeHTML } from '../../utils/general_utils'; +import { InjectInHeadUtils } from '../../utils/inject_utils'; /** * This is the component that implements display-specific functionality. @@ -54,14 +55,12 @@ let Image = React.createClass({ preview: React.PropTypes.string.isRequired }, - mixins: [InjectInHeadMixin], - componentDidMount() { - this.inject('https://code.jquery.com/jquery-2.1.4.min.js') + InjectInHeadUtils.inject('https://code.jquery.com/jquery-2.1.4.min.js') .then(() => Q.all([ - this.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/shmui.css'), - this.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/jquery.shmui.js') + InjectInHeadUtils.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/shmui.css'), + InjectInHeadUtils.inject(AppConstants.baseUrl + 'static/thirdparty/shmui/jquery.shmui.js') ]).then(() => { window.jQuery('.shmui-ascribe').shmui(); })); }, @@ -77,10 +76,8 @@ let Audio = React.createClass({ url: React.PropTypes.string.isRequired }, - mixins: [InjectInHeadMixin], - componentDidMount() { - this.inject(AppConstants.baseUrl + 'static/thirdparty/audiojs/audiojs/audio.min.js').then(this.ready); + InjectInHeadUtils.inject(AppConstants.baseUrl + 'static/thirdparty/audiojs/audiojs/audio.min.js').then(this.ready); }, ready() { @@ -111,7 +108,7 @@ let Video = React.createClass({ * `false` if we failed to load the external library) * 2) render the cover using the `` component (because libraryLoaded is null) * 3) on `componentDidMount`, we load the external `css` and `js` resources using - * the `InjectInHeadMixin`, attaching a function to `Promise.then` to change + * the `InjectInHeadUtils`, attaching a function to `Promise.then` to change * `state.libraryLoaded` to true * 4) when the promise is succesfully resolved, we change `state.libraryLoaded` triggering * a re-render @@ -129,16 +126,14 @@ let Video = React.createClass({ encodingStatus: React.PropTypes.number }, - mixins: [InjectInHeadMixin], - getInitialState() { return { libraryLoaded: null, videoMounted: false }; }, componentDidMount() { Q.all([ - this.inject('//vjs.zencdn.net/4.12/video-js.css'), - this.inject('//vjs.zencdn.net/4.12/video.js')]) + InjectInHeadUtils.inject('//vjs.zencdn.net/4.12/video-js.css'), + InjectInHeadUtils.inject('//vjs.zencdn.net/4.12/video.js')]) .then(() => this.setState({libraryLoaded: true})) .fail(() => this.setState({libraryLoaded: false})); }, diff --git a/js/mixins/inject_in_head_mixin.js b/js/mixins/inject_in_head_mixin.js deleted file mode 100644 index 6eacacad..00000000 --- a/js/mixins/inject_in_head_mixin.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -import Q from 'q'; - -let mapAttr = { - link: 'href', - script: 'src' -}; - -let mapTag = { - js: 'script', - css: 'link' -}; - - -let InjectInHeadMixin = { - /** - * Provide functions to inject `