diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index d4002e85..91d00f65 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -178,20 +178,20 @@ let Form = React.createClass({ let formData = this.getFormData(); // sentry shouldn't post the user's password - if(formData.password) { + if (formData.password) { delete formData.password; } console.logGlobal(err, formData); - if(this.props.isInline) { + if (this.props.isInline) { let notification = new GlobalNotificationModel(getLangText('Something went wrong, please try again later'), 'danger'); GlobalNotificationActions.appendGlobalNotification(notification); } else { this.setState({errors: [getLangText('Something went wrong, please try again later')]}); } - } + this.setState({submitted: false}); }, 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 6b67467e..2c48fd9a 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 @@ -19,8 +19,10 @@ import ApiUrls from '../../../../../../constants/api_urls'; import requests from '../../../../../../utils/requests'; -import { getLangText } from '../../../../../../utils/lang_utils'; +import { getErrorNotificationMessage } from '../../../../../../utils/error_utils'; import { setCookie } from '../../../../../../utils/fetch_api_utils'; +import { validateForms } from '../../../../../../utils/form_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils'; @@ -35,7 +37,7 @@ const PRRegisterPieceForm = React.createClass({ mixins: [History], - getInitialState(){ + getInitialState() { return { digitalWorkKeyReady: true, thumbnailKeyReady: true, @@ -54,16 +56,16 @@ const PRRegisterPieceForm = React.createClass({ * second adding all the additional details */ submit() { - if(!this.validateForms()) { + if (!this.validateForms()) { return; - } else { - // disable the submission button right after the user - // clicks on it to avoid double submission - this.setState({ - submitted: true - }); } + // disable the submission button right after the user + // clicks on it to avoid double submission + this.setState({ + submitted: true + }); + const { currentUser } = this.props; const { registerPieceForm, additionalDataForm, @@ -106,10 +108,18 @@ const PRRegisterPieceForm = React.createClass({ }) .then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`)) .catch((err) => { - const notificationMessage = new GlobalNotificationModel(getLangText("Oops! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000); + const errMessage = (getErrorNotificationMessage(err) || getLangText("Oops! We weren't able to send your submission.")) + + getLangText(' Please contact support@ascribe.io'); + + const notificationMessage = new GlobalNotificationModel(errMessage, 'danger', 10000); GlobalNotificationActions.appendGlobalNotification(notificationMessage); console.logGlobal(new Error('Portfolio Review piece registration failed'), err); + + // Reset the submit button + this.setState({ + submitted: false + }); }); }, @@ -118,11 +128,7 @@ const PRRegisterPieceForm = React.createClass({ additionalDataForm, uploadersForm } = this.refs; - const registerPieceFormValidation = registerPieceForm.validate(); - const additionalDataFormValidation = additionalDataForm.validate(); - const uploaderFormValidation = uploadersForm.validate(); - - return registerPieceFormValidation && additionalDataFormValidation && uploaderFormValidation; + return validateForms([registerPieceForm, additionalDataForm, uploadersForm], true); }, getCreateBlobRoutine() { diff --git a/js/utils/error_utils.js b/js/utils/error_utils.js index 44ebedbe..eefe40d8 100644 --- a/js/utils/error_utils.js +++ b/js/utils/error_utils.js @@ -35,3 +35,31 @@ export function initLogging() { console.logGlobal = logGlobal; } + +/* + * Gets the json errors from the error as an array + * @param {Error} error A Javascript error + * @return {Array} List of json errors + */ +export function getJsonErrorsAsArray(error) { + const { json: { errors = {} } = {} } = error; + + const errorArrays = Object + .keys(errors) + .map((errorKey) => { + return errors[errorKey]; + }); + + // Collapse each errorKey's errors into a flat array + return [].concat(...errorArrays); +} + +/* + * Tries to get an error message from the error, either by using its notification + * property or first json error (if any) + * @param {Error} error A Javascript error + * @return {string} Error message string + */ +export function getErrorNotificationMessage(error) { + return (error && error.notification) || getJsonErrorsAsArray(error)[0] || ''; +} diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js index 8d12a8c1..0581b28b 100644 --- a/js/utils/form_utils.js +++ b/js/utils/form_utils.js @@ -2,8 +2,34 @@ import { getLangText } from './lang_utils'; +import GlobalNotificationActions from '../actions/global_notification_actions'; +import GlobalNotificationModel from '../models/global_notification_model'; + import AppConstants from '../constants/application_constants'; +/** + * Validates a given list of forms + * @param {Form} forms List of forms, each of which should have a `validate` method available + * @param {boolean} showFailureNotification Show global notification if there are validation failures + * @return {boolean} True if validation did *NOT* catch any errors + */ +export function validateForms(forms, showFailureNotification) { + const validationSuccessful = forms.reduce((result, form) => { + if (form && typeof form.validate === 'function') { + return form.validate() && result; + } else { + throw new Error('Form given for validation does not have a `validate` method'); + } + }, true); + + if (!validationSuccessful && showFailureNotification) { + const notification = new GlobalNotificationModel(getLangText('Oops, there may be missing or invalid fields. Please check your inputs again.'), 'danger'); + GlobalNotificationActions.appendGlobalNotification(notification); + } + + return validationSuccessful; +} + /** * Get the data ids of the given piece or editions. * @param {boolean} isPiece Is the given entities parameter a piece? (False: array of editions) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index e81a806d..c245cef6 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -84,8 +84,6 @@ export function formatText() { * Checks a list of objects for key duplicates and returns a boolean */ function _doesObjectListHaveDuplicates(l) { - let mergedList = []; - l = l.map((obj) => { if(!obj) { throw new Error('The object you are trying to merge is null instead of an empty object'); @@ -94,11 +92,11 @@ function _doesObjectListHaveDuplicates(l) { return Object.keys(obj); }); - // Taken from: http://stackoverflow.com/a/10865042 + // Taken from: http://stackoverflow.com/a/10865042 (but even better with rest) // How to flatten an array of arrays in javascript. // If two objects contain the same key, then these two keys // will actually be represented in the merged array - mergedList = mergedList.concat.apply(mergedList, l); + let mergedList = [].concat(...l); // Taken from: http://stackoverflow.com/a/7376645/1263876 // By casting the array to a set, and then checking if the size of the array