From bee420a9196266f176ce1de48ad27333b0a1723c Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 11:57:10 +0100 Subject: [PATCH 1/8] Small fixes for PR's otherdata fileClass --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 1 + .../components/pr_forms/pr_register_piece_form.js | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 67b19e02..538b02b7 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -344,6 +344,7 @@ const ReactS3FineUploader = React.createClass({ // still we warn the user of this component console.warn('createBlobRoutine was not defined for ReactS3FineUploader. Continuing without creating the blob on the server.'); resolve(); + return; } window.fetch(createBlobRoutine.url, { 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 index 41f2c25a..ef2604f0 100644 --- 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 @@ -108,7 +108,7 @@ const PRRegisterPieceForm = React.createClass({ }) .then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`)) .catch(() => { - const notificationMessage = new GlobalNotificationModel(getLangText("Ups! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000); + const notificationMessage = new GlobalNotificationModel(getLangText("Oops! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000); GlobalNotificationActions.appendGlobalNotification(notificationMessage); }); }, @@ -311,7 +311,7 @@ const PRRegisterPieceForm = React.createClass({ createBlobRoutine={this.getCreateBlobRoutine()} keyRoutine={{ url: AppConstants.serverUrl + 's3/key/', - fileClass: 'other_data' + fileClass: 'otherdata' }} validation={{ itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit, @@ -333,7 +333,7 @@ const PRRegisterPieceForm = React.createClass({ createBlobRoutine={this.getCreateBlobRoutine()} keyRoutine={{ url: AppConstants.serverUrl + 's3/key/', - fileClass: 'other_data' + fileClass: 'otherdata' }} validation={{ itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit, @@ -372,4 +372,4 @@ const PRRegisterPieceForm = React.createClass({ } }); -export default PRRegisterPieceForm; \ No newline at end of file +export default PRRegisterPieceForm; From 3286ef77bf89feb57e3ddaa3afc81417c1971f03 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 11:57:14 +0100 Subject: [PATCH 2/8] Add 404 handling to prizes' piece container --- .../ascribe_detail/piece_container.js | 3 +- .../ascribe_detail/prize_piece_container.js | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 74584ba3..7dfc9570 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -85,6 +85,7 @@ let PieceContainer = React.createClass({ // store as it will otherwise display wrong/old data once the user loads // the piece detail a second time PieceActions.updatePiece({}); + this.loadPiece(); UserActions.fetchCurrentUser(); }, @@ -92,7 +93,7 @@ let PieceContainer = React.createClass({ componentDidUpdate() { const { pieceError } = this.state; - if(pieceError && pieceError.status === 404) { + if (pieceError && pieceError.status === 404) { this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist."))); } }, diff --git a/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js index 982af7b0..81f14077 100644 --- a/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js @@ -6,6 +6,9 @@ import Moment from 'moment'; import StarRating from 'react-star-rating'; +import ReactError from '../../../../../../mixins/react_error'; +import { ResourceNotFoundError } from '../../../../../../models/errors'; + import PieceActions from '../../../../../../actions/piece_actions'; import PieceStore from '../../../../../../stores/piece_store'; @@ -54,6 +57,8 @@ let PieceContainer = React.createClass({ params: React.PropTypes.object }, + mixins: [ReactError], + getInitialState() { return mergeOptions( PieceStore.getState(), @@ -63,14 +68,15 @@ let PieceContainer = React.createClass({ componentDidMount() { PieceStore.listen(this.onChange); - PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); - UserActions.fetchCurrentUser(); // Every time we enter the piece detail page, just reset the piece // store as it will otherwise display wrong/old data once the user loads // the piece detail a second time PieceActions.updatePiece({}); + + PieceActions.fetchOne(this.props.params.pieceId); + UserActions.fetchCurrentUser(); }, // This is done to update the container when the user clicks on the prev or next @@ -82,6 +88,14 @@ let PieceContainer = React.createClass({ } }, + componentDidUpdate() { + const { pieceError } = this.state; + + if (pieceError && pieceError.status === 404) { + this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist."))); + } + }, + componentWillUnmount() { PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); @@ -92,10 +106,6 @@ let PieceContainer = React.createClass({ this.setState(state); }, - loadPiece() { - PieceActions.fetchOne(this.props.params.pieceId); - }, - getActions() { if (this.state.piece && this.state.piece.notifications && @@ -112,7 +122,7 @@ let PieceContainer = React.createClass({ render() { if(this.state.piece && this.state.piece.id) { /* - + This really needs a refactor! - Tim @@ -122,7 +132,7 @@ let PieceContainer = React.createClass({ let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) || (this.state.currentUser.is_judge && !this.state.piece.selected )) ? null : this.state.piece.artist_name; - + // Only show the artist email if you are a judge and the piece is shortlisted let artistEmail = (this.state.currentUser.is_judge && this.state.piece.selected ) ? : null; @@ -146,7 +156,7 @@ let PieceContainer = React.createClass({ - +

{this.state.piece.title}

From be2f9bbc97834b2caab4ffab32952ec5b2bab17b Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 12:08:49 +0100 Subject: [PATCH 3/8] Make sure uploaded file from UploadButton has been linked with S3 before we try deleting it --- .../ascribe_upload_button/upload_button.js | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js b/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js index 5848bca1..6612f968 100644 --- a/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js +++ b/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js @@ -71,17 +71,9 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } = handleOnClick() { if(!this.state.disabled) { let evt; - const uploadingFiles = this.getUploadingFiles(); - const uploadedFile = this.getUploadedFile(); - this.clearSelection(); - if(uploadingFiles.length) { - this.props.handleCancelFile(uploadingFiles[0].id); - } else if(uploadedFile && !uploadedFile.s3UrlSafe) { - this.props.handleCancelFile(uploadedFile.id); - } else if(uploadedFile && uploadedFile.s3UrlSafe) { - this.props.handleDeleteFile(uploadedFile.id); - } + // First, remove any currently uploading or uploaded items + this.onClickRemove(); try { evt = new MouseEvent('click', { @@ -99,18 +91,19 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } = } }, - onClickCancel() { - this.clearSelection(); - const uploadingFile = this.getUploadingFiles()[0]; - this.props.handleCancelFile(uploadingFile.id); - }, - onClickRemove() { - this.clearSelection(); + const uploadingFiles = this.getUploadingFiles(); const uploadedFile = this.getUploadedFile(); - this.props.handleDeleteFile(uploadedFile.id); - }, + this.clearSelection(); + if(uploadingFiles.length) { + this.props.handleCancelFile(uploadingFiles[0].id); + } else if(uploadedFile && !uploadedFile.s3UrlSafe) { + this.props.handleCancelFile(uploadedFile.id); + } else if(uploadedFile && uploadedFile.s3UrlSafe) { + this.props.handleDeleteFile(uploadedFile.id); + } + }, getButtonLabel() { let { filesToUpload, fileClassToUpload } = this.props; @@ -133,7 +126,7 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } = return ( {' ' + truncateTextAtCharIndex(uploadingFiles[0].name, 40) + ' '} - [{getLangText('cancel upload')}] + [{getLangText('cancel upload')}] ); } else if(uploadedFile) { @@ -193,4 +186,4 @@ export default function UploadButton({ className = 'btn btn-default btn-sm' } = ); } }); -} \ No newline at end of file +} From d0cef8c8368a364dca4e2eb34c50c3d1279b8f5d Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 13:03:19 +0100 Subject: [PATCH 4/8] Add additional data fields requested by PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds way to sort the Properties in Prize Details by appending `[digit]-[label]` to the Property’s name. --- js/components/ascribe_forms/form_login.js | 2 - .../pr_forms/pr_register_piece_form.js | 46 +++++++++++++++---- .../ascribe_detail/prize_piece_container.js | 21 +++++---- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js index 8b7c1e23..a604850d 100644 --- a/js/components/ascribe_forms/form_login.js +++ b/js/components/ascribe_forms/form_login.js @@ -93,7 +93,6 @@ let LoginForm = React.createClass({ @@ -103,7 +102,6 @@ let LoginForm = React.createClass({ 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 index ef2604f0..34df8a41 100644 --- 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 @@ -191,7 +191,7 @@ const PRRegisterPieceForm = React.createClass({ label={getLangText('Full name')}> @@ -224,25 +224,51 @@ const PRRegisterPieceForm = React.createClass({ className="ascribe-form-bordered" ref="additionalDataForm"> + + + - + name='4-phone_number' + label={getLangText('Phone Number')}> + + + + + + +
- {Object.keys(this.props.piece.extra_data).map((data) => { - let label = data.replace('_', ' '); - const value = this.props.piece.extra_data[data] || 'N/A'; + {Object.keys(piece.extra_data).sort().map((data) => { + // Remove leading number (for sorting), if any, and underscores with spaces + let label = data.replace(/^\d-/, '').replace(/_/g, ' '); + const value = piece.extra_data[data] || 'N/A'; return ( {}} editable={false} overrideForm={true} - pieceId={this.props.piece.id} - otherData={this.props.piece.other_data} + pieceId={piece.id} + otherData={piece.other_data} multiple={true} /> From 9342262f5c27c570c2d0c71044575f5d563263b4 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 14:31:53 +0100 Subject: [PATCH 5/8] Move ignoreSentry parameter of logGlobal to be last in parameter list --- js/components/ascribe_forms/form.js | 2 +- js/components/ascribe_uploader/react_s3_fine_uploader.js | 4 ++-- js/utils/error_utils.js | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index a2b7b9bc..d4002e85 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -182,7 +182,7 @@ let Form = React.createClass({ delete formData.password; } - console.logGlobal(err, false, formData); + console.logGlobal(err, formData); if(this.props.isInline) { let notification = new GlobalNotificationModel(getLangText('Something went wrong, please try again later'), 'danger'); diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 538b02b7..eb211504 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -440,7 +440,7 @@ const ReactS3FineUploader = React.createClass({ onComplete(id, name, res, xhr) { // There has been an issue with the server's connection if (xhr && xhr.status === 0 && res.success) { - console.logGlobal(new Error('Upload succeeded with a status code 0'), false, { + console.logGlobal(new Error('Upload succeeded with a status code 0'), { files: this.state.filesToUpload, chunks: this.state.chunks, xhr: this.getXhrErrorComment(xhr) @@ -498,7 +498,7 @@ const ReactS3FineUploader = React.createClass({ }, onError(id, name, errorReason, xhr) { - console.logGlobal(errorReason, false, { + console.logGlobal(errorReason, { files: this.state.filesToUpload, chunks: this.state.chunks, xhr: this.getXhrErrorComment(xhr) diff --git a/js/utils/error_utils.js b/js/utils/error_utils.js index 753bbf61..44ebedbe 100644 --- a/js/utils/error_utils.js +++ b/js/utils/error_utils.js @@ -13,8 +13,7 @@ import AppConstants from '../constants/application_constants'; * @param {boolean} ignoreSentry Defines whether or not the error should be submitted to Sentry * @param {string} comment Will also be submitted to Sentry, but will not be logged */ -function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1, - comment) { +function logGlobal(error, comment, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1) { console.error(error); if(!ignoreSentry) { @@ -24,7 +23,6 @@ function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.inde Raven.captureException(error); } } - } export function initLogging() { @@ -36,4 +34,4 @@ export function initLogging() { window.onerror = Raven.process; console.logGlobal = logGlobal; -} \ No newline at end of file +} From e24c9c9c74789d1ca3f0d9ab26898c8066e8746e Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 14 Dec 2015 14:34:13 +0100 Subject: [PATCH 6/8] Small change to PR piece registration Ignore `success` return of request, as requests will error if this is returned false. --- .../pr_forms/pr_register_piece_form.js | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) 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 index 34df8a41..a8d946b5 100644 --- 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 @@ -75,7 +75,7 @@ const PRRegisterPieceForm = React.createClass({ const additionalDataFormData = additionalDataForm.getFormData(); // composing data for piece registration - let registerPieceFormData = registerPieceForm.getFormData(); + const registerPieceFormData = registerPieceForm.getFormData(); registerPieceFormData.digital_work_key = digitalWorkKey.state.value; registerPieceFormData.thumbnail_file = thumbnailKey.state.value; registerPieceFormData.terms = true; @@ -83,33 +83,33 @@ const PRRegisterPieceForm = React.createClass({ // submitting the piece requests .post(ApiUrls.pieces_list, { body: registerPieceFormData }) - .then(({ success, piece, notification }) => { - if(success) { - this.setState({ - piece - }, () => { - supportingMaterials.refs.input.createBlobRoutine(); - proofOfPayment.refs.input.createBlobRoutine(); - }); + .then(({ piece, notification }) => { + this.setState({piece}, () => { + supportingMaterials.refs.input.createBlobRoutine(); + proofOfPayment.refs.input.createBlobRoutine(); + }); - setCookie(currentUser.email, piece.id); + setCookie(currentUser.email, piece.id); - return requests.post(ApiUrls.piece_extradata, { + return requests + .post(ApiUrls.piece_extradata, { body: { extradata: additionalDataFormData, piece_id: piece.id }, piece_id: piece.id + }) + .then(() => { + const notificationMessage = new GlobalNotificationModel(notification || getLangText('You have successfully submitted "%s" to Portfolio Review 2015', piece.title), 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notificationMessage); }); - } else { - const notificationMessage = new GlobalNotificationModel(notification, 'danger', 5000); - GlobalNotificationActions.appendGlobalNotification(notificationMessage); - } }) .then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`)) - .catch(() => { + .catch((err) => { const notificationMessage = new GlobalNotificationModel(getLangText("Oops! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000); GlobalNotificationActions.appendGlobalNotification(notificationMessage); + + console.logGlobal(new Error('Portfolio Review piece registration failed'), err); }); }, @@ -167,7 +167,7 @@ const PRRegisterPieceForm = React.createClass({ } else { return (