From c242cffdbda47a9e5ae4706c5b0b4604a13d668b Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Thu, 29 Oct 2015 17:04:31 +0100 Subject: [PATCH 01/13] Bring over changes for acl_button from Lumenus --- js/components/ascribe_buttons/acl_button.js | 81 +++++++++------------ js/utils/form_utils.js | 62 +++++++++++++--- 2 files changed, 85 insertions(+), 58 deletions(-) diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index 67f4a430..5197a744 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -16,7 +16,7 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import ApiUrls from '../../constants/api_urls'; -import { getAclFormMessage } from '../../utils/form_utils'; +import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils'; import { getLangText } from '../../utils/lang_utils'; let AclButton = React.createClass({ @@ -30,32 +30,37 @@ let AclButton = React.createClass({ currentUser: React.PropTypes.object, buttonAcceptName: React.PropTypes.string, buttonAcceptClassName: React.PropTypes.string, + email: React.PropTypes.string, handleSuccess: React.PropTypes.func.isRequired, className: React.PropTypes.string }, - isPiece(){ + isPiece() { return this.props.pieceOrEditions.constructor !== Array; }, - actionProperties(){ + actionProperties() { + let message = getAclFormMessage({ + aclName: this.props.action, + entities: this.props.pieceOrEditions, + isPiece: this.isPiece(), + senderName: this.props.currentUser.username + }); - let message = getAclFormMessage(this.props.action, this.getTitlesString(), this.props.currentUser.username); - - if (this.props.action === 'acl_consign'){ + if (this.props.action === 'acl_consign') { return { title: getLangText('Consign artwork'), tooltip: getLangText('Have someone else sell the artwork'), form: ( - ), + ), handleSuccess: this.showNotification }; - } - if (this.props.action === 'acl_unconsign'){ + } else if (this.props.action === 'acl_unconsign') { return { title: getLangText('Unconsign artwork'), tooltip: getLangText('Have the owner manage his sales again'), @@ -64,10 +69,10 @@ let AclButton = React.createClass({ message={message} id={this.getFormDataId()} url={ApiUrls.ownership_unconsigns}/> - ), + ), handleSuccess: this.showNotification }; - }else if (this.props.action === 'acl_transfer') { + } else if (this.props.action === 'acl_transfer') { return { title: getLangText('Transfer artwork'), tooltip: getLangText('Transfer the ownership of the artwork'), @@ -79,32 +84,33 @@ let AclButton = React.createClass({ ), handleSuccess: this.showNotification }; - } - else if (this.props.action === 'acl_loan'){ + } else if (this.props.action === 'acl_loan') { return { title: getLangText('Loan artwork'), tooltip: getLangText('Loan your artwork for a limited period of time'), - form: ( + url={this.isPiece() ? ApiUrls.ownership_loans_pieces + : ApiUrls.ownership_loans_editions}/> ), handleSuccess: this.showNotification }; - } - else if (this.props.action === 'acl_loan_request'){ + } else if (this.props.action === 'acl_loan_request') { return { title: getLangText('Loan artwork'), tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time'), - form: ( ), handleSuccess: this.showNotification }; - } - else if (this.props.action === 'acl_share'){ + } else if (this.props.action === 'acl_share') { return { title: getLangText('Share artwork'), tooltip: getLangText('Share the artwork'), @@ -112,8 +118,9 @@ let AclButton = React.createClass({ - ), + url={this.isPiece() ? ApiUrls.ownership_shares_pieces + : ApiUrls.ownership_shares_editions}/> + ), handleSuccess: this.showNotification }; } else { @@ -121,36 +128,16 @@ let AclButton = React.createClass({ } }, - showNotification(response){ + showNotification(response) { this.props.handleSuccess(); - if(response.notification) { + if (response.notification) { let notification = new GlobalNotificationModel(response.notification, 'success'); GlobalNotificationActions.appendGlobalNotification(notification); } }, - // plz move to share form - getTitlesString(){ - if (this.isPiece()){ - return '\"' + this.props.pieceOrEditions.title + '\"'; - } - else { - return this.props.pieceOrEditions.map(function(edition) { - return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n'; - }).join(''); - } - - }, - getFormDataId(){ - if (this.isPiece()) { - return {piece_id: this.props.pieceOrEditions.id}; - } - else { - return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){ - return edition.bitcoin_id; - }).join()}; - } + return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions); }, // Removes the acl_ prefix and converts to upper case @@ -162,7 +149,7 @@ let AclButton = React.createClass({ }, render() { - if (this.props.availableAcls){ + if (this.props.availableAcls) { let shouldDisplay = this.props.availableAcls[this.props.action]; let aclProps = this.actionProperties(); let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : ''; @@ -184,4 +171,4 @@ let AclButton = React.createClass({ } }); -export default AclButton; \ No newline at end of file +export default AclButton; diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js index 7f9cfb07..d2d2cd29 100644 --- a/js/utils/form_utils.js +++ b/js/utils/form_utils.js @@ -2,14 +2,42 @@ import { getLangText } from './lang_utils'; +import AppConstants from '../constants/application_constants'; + +/** + * Get the data ids of the given piece or editions. + * @param {boolean} isPiece Is the given entities parameter a piece? (False: array of editions) + * @param {(object|object[])} pieceOrEditions Piece or array of editions + * @return {(object|object[])} Data IDs of the pieceOrEditions for the form + */ +export function getAclFormDataId(isPiece, pieceOrEditions) { + if (isPiece) { + return {piece_id: pieceOrEditions.id}; + } else { + return {bitcoin_id: pieceOrEditions.map(function(edition){ + return edition.bitcoin_id; + }).join()}; + } +} + /** * Generates a message for submitting a form - * @param {string} aclName Enum name of a acl - * @param {string} entities Already computed name of entities - * @param {string} senderName Name of the sender - * @return {string} Completed message + * @param {object} options Options object for creating the message: + * @param {string} options.aclName Enum name of an acl + * @param {(object|object[])} options.entities Piece or array of Editions + * @param {boolean} options.isPiece Is the given entities parameter a piece? (False: array of editions) + * @param {string} [options.senderName] Name of the sender + * @return {string} Completed message */ -export function getAclFormMessage(aclName, entities, senderName) { +export function getAclFormMessage(options) { + if (!options || options.aclName === undefined || options.isPiece === undefined || + !(typeof options.entities === 'object' || options.entities.constructor === Array)) { + throw new Error('You must specify an acl class, entities in the correct format, and entity type'); + } + + let aclName = options.aclName; + let entityTitles = options.isPiece ? getTitlesStringOfPiece(options.entities) + : getTitlesStringOfEditions(options.entities); let message = ''; message += getLangText('Hi'); @@ -32,7 +60,7 @@ export function getAclFormMessage(aclName, entities, senderName) { } message += ':\n'; - message += entities; + message += entityTitles; if(aclName === 'acl_transfer' || aclName === 'acl_loan' || aclName === 'acl_consign') { message += getLangText('to you'); @@ -44,10 +72,22 @@ export function getAclFormMessage(aclName, entities, senderName) { throw new Error('Your specified aclName did not match a an acl class.'); } - message += '\n\n'; - message += getLangText('Truly yours,'); - message += '\n'; - message += senderName; + if (options.senderName) { + message += '\n\n'; + message += getLangText('Truly yours,'); + message += '\n'; + message += options.senderName; + } return message; -} \ No newline at end of file +} + +function getTitlesStringOfPiece(piece){ + return '\"' + piece.title + '\"'; +} + +function getTitlesStringOfEditions(editions) { + return editions.map(function(edition) { + return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n'; + }).join(''); +} From 03e0bbd024115b545480f3452d6337ba7a5e3f06 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 30 Oct 2015 11:10:31 +0100 Subject: [PATCH 02/13] Separate form building concerns from AclButton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AclButton’s form building is now delegated to AclFormFactory so other components can use the same forms with ease. Its show/hide behaviour is also now controlled with AclProxy. --- js/components/ascribe_buttons/acl_button.js | 174 ------------------ .../ascribe_buttons/acl_button_list.js | 31 ++-- .../ascribe_buttons/acls/acl_button.js | 89 +++++++++ .../ascribe_buttons/acls/consign_button.js | 21 +++ .../ascribe_buttons/acls/loan_button.js | 21 +++ .../acls/loan_request_button.js | 21 +++ .../ascribe_buttons/acls/share_button.js | 21 +++ .../ascribe_buttons/acls/transfer_button.js | 21 +++ .../ascribe_buttons/acls/unconsign_button.js | 21 +++ .../ascribe_forms/acl_form_factory.js | 134 ++++++++++++++ .../ascribe_forms/form_request_action.js | 15 +- 11 files changed, 372 insertions(+), 197 deletions(-) delete mode 100644 js/components/ascribe_buttons/acl_button.js create mode 100644 js/components/ascribe_buttons/acls/acl_button.js create mode 100644 js/components/ascribe_buttons/acls/consign_button.js create mode 100644 js/components/ascribe_buttons/acls/loan_button.js create mode 100644 js/components/ascribe_buttons/acls/loan_request_button.js create mode 100644 js/components/ascribe_buttons/acls/share_button.js create mode 100644 js/components/ascribe_buttons/acls/transfer_button.js create mode 100644 js/components/ascribe_buttons/acls/unconsign_button.js create mode 100644 js/components/ascribe_forms/acl_form_factory.js diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js deleted file mode 100644 index 5197a744..00000000 --- a/js/components/ascribe_buttons/acl_button.js +++ /dev/null @@ -1,174 +0,0 @@ -'use strict'; - -import React from 'react'; - -import ConsignForm from '../ascribe_forms/form_consign'; -import UnConsignForm from '../ascribe_forms/form_unconsign'; -import TransferForm from '../ascribe_forms/form_transfer'; -import LoanForm from '../ascribe_forms/form_loan'; -import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer'; -import ShareForm from '../ascribe_forms/form_share_email'; -import ModalWrapper from '../ascribe_modal/modal_wrapper'; -import AppConstants from '../../constants/application_constants'; - -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import ApiUrls from '../../constants/api_urls'; - -import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils'; -import { getLangText } from '../../utils/lang_utils'; - -let AclButton = React.createClass({ - propTypes: { - action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, - availableAcls: React.PropTypes.object.isRequired, - pieceOrEditions: React.PropTypes.oneOfType([ - React.PropTypes.object, - React.PropTypes.array - ]).isRequired, - currentUser: React.PropTypes.object, - buttonAcceptName: React.PropTypes.string, - buttonAcceptClassName: React.PropTypes.string, - email: React.PropTypes.string, - handleSuccess: React.PropTypes.func.isRequired, - className: React.PropTypes.string - }, - - isPiece() { - return this.props.pieceOrEditions.constructor !== Array; - }, - - actionProperties() { - let message = getAclFormMessage({ - aclName: this.props.action, - entities: this.props.pieceOrEditions, - isPiece: this.isPiece(), - senderName: this.props.currentUser.username - }); - - if (this.props.action === 'acl_consign') { - return { - title: getLangText('Consign artwork'), - tooltip: getLangText('Have someone else sell the artwork'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else if (this.props.action === 'acl_unconsign') { - return { - title: getLangText('Unconsign artwork'), - tooltip: getLangText('Have the owner manage his sales again'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else if (this.props.action === 'acl_transfer') { - return { - title: getLangText('Transfer artwork'), - tooltip: getLangText('Transfer the ownership of the artwork'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else if (this.props.action === 'acl_loan') { - return { - title: getLangText('Loan artwork'), - tooltip: getLangText('Loan your artwork for a limited period of time'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else if (this.props.action === 'acl_loan_request') { - return { - title: getLangText('Loan artwork'), - tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else if (this.props.action === 'acl_share') { - return { - title: getLangText('Share artwork'), - tooltip: getLangText('Share the artwork'), - form: ( - - ), - handleSuccess: this.showNotification - }; - } else { - throw new Error('Your specified action did not match a form.'); - } - }, - - showNotification(response) { - this.props.handleSuccess(); - if (response.notification) { - let notification = new GlobalNotificationModel(response.notification, 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - } - }, - - getFormDataId(){ - return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions); - }, - - // Removes the acl_ prefix and converts to upper case - sanitizeAction() { - if (this.props.buttonAcceptName) { - return this.props.buttonAcceptName; - } - return this.props.action.split('acl_')[1].toUpperCase(); - }, - - render() { - if (this.props.availableAcls) { - let shouldDisplay = this.props.availableAcls[this.props.action]; - let aclProps = this.actionProperties(); - let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : ''; - return ( - - {this.sanitizeAction()} - - } - handleSuccess={aclProps.handleSuccess} - title={aclProps.title}> - {aclProps.form} - - ); - } - return null; - } -}); - -export default AclButton; diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index e87a6407..6aec6c77 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -5,21 +5,25 @@ import React from 'react/addons'; import UserActions from '../../actions/user_actions'; import UserStore from '../../stores/user_store'; -import AclButton from '../ascribe_buttons/acl_button'; +import ConsignButton from './acls/consign_button'; +import LoanButton from './acls/loan_button'; +import LoanRequestButton from './acls/loan_request_button'; +import ShareButton from './acls/share_button'; +import TransferButton from './acls/transfer_button'; +import UnconsignButton from './acls/unconsign_button'; import { mergeOptions } from '../../utils/general_utils'; - let AclButtonList = React.createClass({ propTypes: { className: React.PropTypes.string, editions: React.PropTypes.oneOfType([ React.PropTypes.object, React.PropTypes.array - ]), - availableAcls: React.PropTypes.object, + ]).isRequired, + availableAcls: React.PropTypes.object.isRequired, buttonsStyle: React.PropTypes.object, - handleSuccess: React.PropTypes.func, + handleSuccess: React.PropTypes.func.isRequired, children: React.PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.element @@ -86,33 +90,28 @@ let AclButtonList = React.createClass({ return (
- - - - - @@ -123,4 +122,4 @@ let AclButtonList = React.createClass({ } }); -export default AclButtonList; \ No newline at end of file +export default AclButtonList; diff --git a/js/components/ascribe_buttons/acls/acl_button.js b/js/components/ascribe_buttons/acls/acl_button.js new file mode 100644 index 00000000..f7149e79 --- /dev/null +++ b/js/components/ascribe_buttons/acls/acl_button.js @@ -0,0 +1,89 @@ +'use strict'; + +import React from 'react'; +import classNames from 'classnames'; + +import AclProxy from '../../acl_proxy'; + +import AclFormFactory from '../../ascribe_forms/acl_form_factory'; + +import ModalWrapper from '../../ascribe_modal/modal_wrapper'; + +import AppConstants from '../../../constants/application_constants'; + +import GlobalNotificationModel from '../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../actions/global_notification_actions'; + +import ApiUrls from '../../../constants/api_urls'; + +import { getAclFormMessage, getAclFormDataId } from '../../../utils/form_utils'; +import { getLangText } from '../../../utils/lang_utils'; + +let AclButton = React.createClass({ + propTypes: { + action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, + availableAcls: React.PropTypes.object.isRequired, + buttonAcceptName: React.PropTypes.string, + buttonAcceptClassName: React.PropTypes.string, + currentUser: React.PropTypes.object.isRequired, + email: React.PropTypes.string, + pieceOrEditions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]).isRequired, + title: React.PropTypes.string, + handleSuccess: React.PropTypes.func.isRequired, + className: React.PropTypes.string + }, + + getDefaultProps() { + return { + buttonAcceptClassName: '' + }; + }, + + // Removes the acl_ prefix and converts to upper case + sanitizeAction() { + if (this.props.buttonAcceptName) { + return this.props.buttonAcceptName; + } + return this.props.action.split('acl_')[1].toUpperCase(); + }, + + render() { + const { + action, + availableAcls, + buttonAcceptClassName, + currentUser, + email, + pieceOrEditions, + handleSuccess, + title } = this.props; + + return ( + + + {this.sanitizeAction()} + + } + handleSuccess={handleSuccess} + title={title}> + + + + ); + } +}); + +export default AclButton; diff --git a/js/components/ascribe_buttons/acls/consign_button.js b/js/components/ascribe_buttons/acls/consign_button.js new file mode 100644 index 00000000..3eb88fc4 --- /dev/null +++ b/js/components/ascribe_buttons/acls/consign_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let ConsignButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default ConsignButton; diff --git a/js/components/ascribe_buttons/acls/loan_button.js b/js/components/ascribe_buttons/acls/loan_button.js new file mode 100644 index 00000000..aa0036c4 --- /dev/null +++ b/js/components/ascribe_buttons/acls/loan_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let LoanButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default LoanButton; diff --git a/js/components/ascribe_buttons/acls/loan_request_button.js b/js/components/ascribe_buttons/acls/loan_request_button.js new file mode 100644 index 00000000..85483ab1 --- /dev/null +++ b/js/components/ascribe_buttons/acls/loan_request_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let LoanButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default LoanButton; diff --git a/js/components/ascribe_buttons/acls/share_button.js b/js/components/ascribe_buttons/acls/share_button.js new file mode 100644 index 00000000..30792ef1 --- /dev/null +++ b/js/components/ascribe_buttons/acls/share_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let ShareButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default ShareButton; diff --git a/js/components/ascribe_buttons/acls/transfer_button.js b/js/components/ascribe_buttons/acls/transfer_button.js new file mode 100644 index 00000000..da8728f6 --- /dev/null +++ b/js/components/ascribe_buttons/acls/transfer_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let TransferButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default TransferButton; diff --git a/js/components/ascribe_buttons/acls/unconsign_button.js b/js/components/ascribe_buttons/acls/unconsign_button.js new file mode 100644 index 00000000..daaf488b --- /dev/null +++ b/js/components/ascribe_buttons/acls/unconsign_button.js @@ -0,0 +1,21 @@ +'use strict'; + +import React from 'react'; + +import AclButton from './acl_button'; + +import { getLangText } from '../../../utils/lang_utils'; + +let UnconsignButton = React.createClass({ + render() { + return ( + + ); + } +}); + +export default UnconsignButton; diff --git a/js/components/ascribe_forms/acl_form_factory.js b/js/components/ascribe_forms/acl_form_factory.js new file mode 100644 index 00000000..dc5ebd4e --- /dev/null +++ b/js/components/ascribe_forms/acl_form_factory.js @@ -0,0 +1,134 @@ +'use strict'; + +import React from 'react'; + +import ConsignForm from '../ascribe_forms/form_consign'; +import UnConsignForm from '../ascribe_forms/form_unconsign'; +import TransferForm from '../ascribe_forms/form_transfer'; +import LoanForm from '../ascribe_forms/form_loan'; +import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer'; +import ShareForm from '../ascribe_forms/form_share_email'; + +import AppConstants from '../../constants/application_constants'; +import ApiUrls from '../../constants/api_urls'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils'; + +let AclFormFactory = React.createClass({ + propTypes: { + action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, + currentUser: React.PropTypes.object.isRequired, + email: React.PropTypes.string, + message: React.PropTypes.string, + pieceOrEditions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]).isRequired, + handleSuccess: React.PropTypes.func, + showNotification: React.PropTypes.bool + }, + + getDefaultProps() { + return { + showNotification: false + }; + }, + + isPiece() { + return this.props.pieceOrEditions.constructor !== Array; + }, + + getFormDataId() { + return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions); + }, + + showSuccessNotification(response) { + if (typeof this.props.handleSuccess === 'function') { + this.props.handleSuccess(); + } + + if (response.notification) { + const notification = new GlobalNotificationModel(response.notification, 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + } + }, + + render() { + const { + action, + pieceOrEditions, + currentUser, + email, + message, + handleSuccess, + showNotification } = this.props; + + const formMessage = message || getAclFormMessage({ + aclName: action, + entities: pieceOrEditions, + isPiece: this.isPiece(), + senderName: currentUser.username + }); + + if (action === 'acl_consign') { + return ( + + ); + } else if (action === 'acl_unconsign') { + return ( + + ); + } else if (action === 'acl_transfer') { + return ( + + ); + } else if (action === 'acl_loan') { + return ( + + ); + } else if (action === 'acl_loan_request') { + return ( + + ); + } else if (action === 'acl_share') { + return ( + + ); + } else { + throw new Error('Your specified action did not match a form.'); + } + } +}); + +export default AclFormFactory; diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index b0f3b6c6..b3b6e3a4 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -2,10 +2,13 @@ import React from 'react'; -import AclButton from './../ascribe_buttons/acl_button'; -import ActionPanel from '../ascribe_panel/action_panel'; import Form from './form'; +import LoanRequestButton from '../ascribe_buttons/acls/loan_request_button'; +import UnconsignButton from '../ascribe_buttons/acls/unconsign_button'; + +import ActionPanel from '../ascribe_panel/action_panel'; + import NotificationActions from '../../actions/notification_actions'; import GlobalNotificationModel from '../../models/global_notification_model'; @@ -100,9 +103,8 @@ let RequestActionForm = React.createClass({ getAcceptButtonForm(urls) { if(this.props.notifications.action === 'unconsign') { return ( - Date: Fri, 30 Oct 2015 11:16:44 +0100 Subject: [PATCH 03/13] Remove unnecessary import from form utils --- js/utils/form_utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js index d2d2cd29..c15eb067 100644 --- a/js/utils/form_utils.js +++ b/js/utils/form_utils.js @@ -2,8 +2,6 @@ import { getLangText } from './lang_utils'; -import AppConstants from '../constants/application_constants'; - /** * Get the data ids of the given piece or editions. * @param {boolean} isPiece Is the given entities parameter a piece? (False: array of editions) From 67fbfbd470392ed82cbf76785a089f8f4880fe12 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 30 Oct 2015 11:46:01 +0100 Subject: [PATCH 04/13] Update RequestActionForm to use form utils --- .../ascribe_forms/form_request_action.js | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index b3b6e3a4..ddf832b4 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -16,9 +16,9 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import ApiUrls from '../../constants/api_urls'; +import { getAclFormDataId } from '../../utils/form_utils'; import { getLangText } from '../../utils/lang_utils.js'; - let RequestActionForm = React.createClass({ propTypes: { pieceOrEditions: React.PropTypes.oneOfType([ @@ -30,26 +30,26 @@ let RequestActionForm = React.createClass({ handleSuccess: React.PropTypes.func }, - isPiece(){ + isPiece() { return this.props.pieceOrEditions.constructor !== Array; }, getUrls() { let urls = {}; - if (this.props.notifications.action === 'consign'){ + if (this.props.notifications.action === 'consign') { urls.accept = ApiUrls.ownership_consigns_confirm; urls.deny = ApiUrls.ownership_consigns_deny; - } else if (this.props.notifications.action === 'unconsign'){ + } else if (this.props.notifications.action === 'unconsign') { urls.accept = ApiUrls.ownership_unconsigns; urls.deny = ApiUrls.ownership_unconsigns_deny; - } else if (this.props.notifications.action === 'loan' && !this.isPiece()){ + } else if (this.props.notifications.action === 'loan' && !this.isPiece()) { urls.accept = ApiUrls.ownership_loans_confirm; urls.deny = ApiUrls.ownership_loans_deny; - } else if (this.props.notifications.action === 'loan' && this.isPiece()){ + } else if (this.props.notifications.action === 'loan' && this.isPiece()) { urls.accept = ApiUrls.ownership_loans_pieces_confirm; urls.deny = ApiUrls.ownership_loans_pieces_deny; - } else if (this.props.notifications.action === 'loan_request' && this.isPiece()){ + } else if (this.props.notifications.action === 'loan_request' && this.isPiece()) { urls.accept = ApiUrls.ownership_loans_pieces_request_confirm; urls.deny = ApiUrls.ownership_loans_pieces_request_deny; } @@ -57,37 +57,29 @@ let RequestActionForm = React.createClass({ return urls; }, - getFormData(){ - if (this.isPiece()) { - return {piece_id: this.props.pieceOrEditions.id}; - } - else { - return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){ - return edition.bitcoin_id; - }).join()}; - } + getFormData() { + return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions); }, showNotification(option, action, owner) { return () => { - let message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; + const message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; - let notifications = new GlobalNotificationModel(message, 'success'); + const notifications = new GlobalNotificationModel(message, 'success'); GlobalNotificationActions.appendGlobalNotification(notifications); this.handleSuccess(); - }; }, handleSuccess() { - if (this.isPiece()){ + if (this.isPiece()) { NotificationActions.fetchPieceListNotifications(); - } - else { + } else { NotificationActions.fetchEditionListNotifications(); } - if(this.props.handleSuccess) { + + if (typeof this.props.handleSuccess === 'function') { this.props.handleSuccess(); } }, @@ -101,7 +93,7 @@ let RequestActionForm = React.createClass({ }, getAcceptButtonForm(urls) { - if(this.props.notifications.action === 'unconsign') { + if (this.props.notifications.action === 'unconsign') { return ( ); - } else if(this.props.notifications.action === 'loan_request') { + } else if (this.props.notifications.action === 'loan_request') { return ( @@ -157,7 +149,7 @@ let RequestActionForm = React.createClass({ {acceptButtonForm} @@ -169,7 +161,7 @@ let RequestActionForm = React.createClass({ return ( + buttons={this.getButtonForm()} /> ); } }); From 6c8016e094138db91f7e602ea2381eb7a1e762ac Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 15:19:52 +0100 Subject: [PATCH 05/13] Remove misleading editions prop to pieceOrEditions --- js/components/ascribe_buttons/acl_button_list.js | 14 +++++++------- .../ascribe_detail/edition_action_panel.js | 4 ++-- js/components/ascribe_detail/piece_container.js | 2 +- .../piece_list_bulk_modal.js | 4 ++-- .../ascribe_detail/wallet_action_panel.js | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index 6aec6c77..83495363 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -17,7 +17,7 @@ import { mergeOptions } from '../../utils/general_utils'; let AclButtonList = React.createClass({ propTypes: { className: React.PropTypes.string, - editions: React.PropTypes.oneOfType([ + pieceOrEditions: React.PropTypes.oneOfType([ React.PropTypes.object, React.PropTypes.array ]).isRequired, @@ -82,7 +82,7 @@ let AclButtonList = React.createClass({ const { className, buttonsStyle, availableAcls, - editions, + pieceOrEditions, handleSuccess } = this.props; const { currentUser } = this.state; @@ -92,27 +92,27 @@ let AclButtonList = React.createClass({ {this.renderChildren()} diff --git a/js/components/ascribe_detail/edition_action_panel.js b/js/components/ascribe_detail/edition_action_panel.js index 7b075ce0..a2ad1e58 100644 --- a/js/components/ascribe_detail/edition_action_panel.js +++ b/js/components/ascribe_detail/edition_action_panel.js @@ -107,7 +107,7 @@ let EditionActionPanel = React.createClass({ Date: Mon, 2 Nov 2015 15:20:02 +0100 Subject: [PATCH 06/13] Remove unnecessary default props --- js/components/ascribe_buttons/acls/acl_button.js | 6 ------ js/components/ascribe_forms/acl_form_factory.js | 6 ------ 2 files changed, 12 deletions(-) diff --git a/js/components/ascribe_buttons/acls/acl_button.js b/js/components/ascribe_buttons/acls/acl_button.js index f7149e79..d81a19f4 100644 --- a/js/components/ascribe_buttons/acls/acl_button.js +++ b/js/components/ascribe_buttons/acls/acl_button.js @@ -36,12 +36,6 @@ let AclButton = React.createClass({ className: React.PropTypes.string }, - getDefaultProps() { - return { - buttonAcceptClassName: '' - }; - }, - // Removes the acl_ prefix and converts to upper case sanitizeAction() { if (this.props.buttonAcceptName) { diff --git a/js/components/ascribe_forms/acl_form_factory.js b/js/components/ascribe_forms/acl_form_factory.js index dc5ebd4e..d5494c2d 100644 --- a/js/components/ascribe_forms/acl_form_factory.js +++ b/js/components/ascribe_forms/acl_form_factory.js @@ -31,12 +31,6 @@ let AclFormFactory = React.createClass({ showNotification: React.PropTypes.bool }, - getDefaultProps() { - return { - showNotification: false - }; - }, - isPiece() { return this.props.pieceOrEditions.constructor !== Array; }, From 7746241a592d9f0876e21c2e2167fd4288870a5e Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 15:21:27 +0100 Subject: [PATCH 07/13] Fix getLangText() when using multiple placeholders --- js/utils/lang_utils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index f2e2fa14..ee2d292c 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -22,15 +22,15 @@ export function getLangText(s, ...args) { let lang = getLang(); try { if(lang in languages) { - return formatText(languages[lang][s], args); + return formatText(languages[lang][s], ...args); } else { // just use the english language - return formatText(languages['en-US'][s], args); + return formatText(languages['en-US'][s], ...args); } } catch(err) { //if(!(s in languages[lang])) { //console.warn('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file. Defaulting to keyname'); - return formatText(s, args); + return formatText(s, ...args); //} else { // console.error(err); //} From a0ebc7dc58ca948f477b6d6e3e1323f00f43813f Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 2 Nov 2015 15:21:33 +0100 Subject: [PATCH 08/13] Use string formatting for RequestActionForm's notification message --- js/components/ascribe_forms/form_request_action.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index ddf832b4..d3d1bc71 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -63,8 +63,7 @@ let RequestActionForm = React.createClass({ showNotification(option, action, owner) { return () => { - const message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; - + const message = getLangText('You have successfully %s the %s request from %s', getLangText(option), getLangText(action), owner); const notifications = new GlobalNotificationModel(message, 'success'); GlobalNotificationActions.appendGlobalNotification(notifications); @@ -118,7 +117,7 @@ let RequestActionForm = React.createClass({ url={urls.accept} getFormData={this.getFormData} handleSuccess={ - this.showNotification(getLangText('accepted'), this.props.notifications.action, this.props.notifications.by) + this.showNotification('accepted', this.props.notifications.action, this.props.notifications.by) } isInline={true} className='inline pull-right'> @@ -143,7 +142,7 @@ let RequestActionForm = React.createClass({ isInline={true} getFormData={this.getFormData} handleSuccess={ - this.showNotification(getLangText('denied'), this.props.notifications.action, this.props.notifications.by) + this.showNotification('denied', this.props.notifications.action, this.props.notifications.by) } className='inline pull-right'> - } - handleSuccess={handleSuccess} - title={title}> - - - - ); +export default function ({ action, displayName, title, tooltip }) { + if (AppConstants.aclList.indexOf(action) < 0) { + console.warn('Your specified aclName did not match a an acl class.'); } -}); -export default AclButton; + return React.createClass({ + displayName: displayName, + + propTypes: { + availableAcls: React.PropTypes.object.isRequired, + buttonAcceptName: React.PropTypes.string, + buttonAcceptClassName: React.PropTypes.string, + currentUser: React.PropTypes.object.isRequired, + email: React.PropTypes.string, + pieceOrEditions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]).isRequired, + handleSuccess: React.PropTypes.func.isRequired, + className: React.PropTypes.string + }, + + // Removes the acl_ prefix and converts to upper case + sanitizeAction() { + if (this.props.buttonAcceptName) { + return this.props.buttonAcceptName; + } + return action.split('acl_')[1].toUpperCase(); + }, + + render() { + const { + availableAcls, + buttonAcceptClassName, + currentUser, + email, + pieceOrEditions, + handleSuccess } = this.props; + + return ( + + + {this.sanitizeAction()} + + } + handleSuccess={handleSuccess} + title={title}> + + + + ); + } + }); +} diff --git a/js/components/ascribe_buttons/acls/consign_button.js b/js/components/ascribe_buttons/acls/consign_button.js index 6a3759db..88c86097 100644 --- a/js/components/ascribe_buttons/acls/consign_button.js +++ b/js/components/ascribe_buttons/acls/consign_button.js @@ -4,24 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let ConsignButton = React.createClass({ - propTypes: { - ...omitFromObject(AclButton.propTypes, ['action']), - email: React.PropTypes.string - }, - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_consign', + displayName: 'ConsignButton', + title: getLangText('Consign artwork'), + tooltip: getLangText('Have someone else sell the artwork') }); - -export default ConsignButton; diff --git a/js/components/ascribe_buttons/acls/loan_button.js b/js/components/ascribe_buttons/acls/loan_button.js index 283b43eb..4b803ceb 100644 --- a/js/components/ascribe_buttons/acls/loan_button.js +++ b/js/components/ascribe_buttons/acls/loan_button.js @@ -4,24 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let LoanButton = React.createClass({ - propTypes: { - ...omitFromObject(AclButton.propTypes, ['action']), - email: React.PropTypes.string - }, - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_loan', + displayName: 'LoanButton', + title: getLangText('Loan artwork'), + tooltip: getLangText('Loan your artwork for a limited period of time') }); - -export default LoanButton; diff --git a/js/components/ascribe_buttons/acls/loan_request_button.js b/js/components/ascribe_buttons/acls/loan_request_button.js index f4ffe9a4..a1ec5f3b 100644 --- a/js/components/ascribe_buttons/acls/loan_request_button.js +++ b/js/components/ascribe_buttons/acls/loan_request_button.js @@ -4,21 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let LoanButton = React.createClass({ - propTypes: omitFromObject(AclButton.propTypes, ['action']), - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_loan_request', + displayName: 'LoanRequestButton', + title: getLangText('Loan artwork'), + tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time') }); - -export default LoanButton; diff --git a/js/components/ascribe_buttons/acls/share_button.js b/js/components/ascribe_buttons/acls/share_button.js index 4fb914a0..83781aed 100644 --- a/js/components/ascribe_buttons/acls/share_button.js +++ b/js/components/ascribe_buttons/acls/share_button.js @@ -4,21 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let ShareButton = React.createClass({ - propTypes: omitFromObject(AclButton.propTypes, ['action']), - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_share', + displayName: 'ShareButton', + title: getLangText('Share artwork'), + tooltip: getLangText('Share the artwork') }); - -export default ShareButton; diff --git a/js/components/ascribe_buttons/acls/transfer_button.js b/js/components/ascribe_buttons/acls/transfer_button.js index e85a81d1..346907ca 100644 --- a/js/components/ascribe_buttons/acls/transfer_button.js +++ b/js/components/ascribe_buttons/acls/transfer_button.js @@ -4,21 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let TransferButton = React.createClass({ - propTypes: omitFromObject(AclButton.propTypes, ['action']), - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_transfer', + displayName: 'TransferButton', + title: getLangText('Transfer artwork'), + tooltip: getLangText('Transfer the ownership of the artwork') }); - -export default TransferButton; diff --git a/js/components/ascribe_buttons/acls/unconsign_button.js b/js/components/ascribe_buttons/acls/unconsign_button.js index 39029c18..ce1ed0bc 100644 --- a/js/components/ascribe_buttons/acls/unconsign_button.js +++ b/js/components/ascribe_buttons/acls/unconsign_button.js @@ -4,21 +4,11 @@ import React from 'react'; import AclButton from './acl_button'; -import { omitFromObject } from '../../../utils/general_utils'; import { getLangText } from '../../../utils/lang_utils'; -let UnconsignButton = React.createClass({ - propTypes: omitFromObject(AclButton.propTypes, ['action']), - - render() { - return ( - - ); - } +export default AclButton({ + action: 'acl_unconsign', + displayName: 'UnconsignButton', + title: getLangText('Unconsign artwork'), + tooltip: getLangText('Have the owner manage his sales again') }); - -export default UnconsignButton; diff --git a/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js b/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js index cdfc129b..4f0fe307 100644 --- a/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js +++ b/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js @@ -31,6 +31,8 @@ export default function AuthProxyHandler({to, when}) { return (Component) => { return React.createClass({ + displayName: 'AuthProxyHandler', + propTypes: { location: object }, diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 0fe5e210..84e8fd2f 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -11,7 +11,7 @@ let constants = { 'serverUrl': window.SERVER_URL, 'baseUrl': window.BASE_URL, 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions', - 'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', + 'acl_loan', 'acl_loan_request', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', 'acl_withdraw_transfer', 'acl_wallet_submit'], 'version': 0.1,