diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index ee337149..7eec36f1 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({ @@ -134,13 +134,7 @@ let AclButton = React.createClass({ }, 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 diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index 7e3233e8..9617acd4 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -11,12 +11,11 @@ import InputTextAreaToggable from './input_textarea_toggable'; import AscribeSpinner from '../ascribe_spinner'; import { getLangText } from '../../utils/lang_utils.js'; -import { getSubdomainFormSettings } from '../../utils/form_utils'; - let ConsignForm = React.createClass({ propTypes: { url: React.PropTypes.string, id: React.PropTypes.object, + email: React.PropTypes.string, message: React.PropTypes.string, handleSuccess: React.PropTypes.func }, @@ -26,8 +25,6 @@ let ConsignForm = React.createClass({ }, render() { - let envSettings = getSubdomainFormSettings('consign'); - return (
+ editable={!this.props.email} + overrideForm={!!this.props.email}> { - return this.state.editionList[pieceId] - .filter((edition) => edition.selected).length > 0; - }); - return filteredPieceIdList; - }, - - fetchSelectedEditionList() { - let selectedEditionList = []; - - Object - .keys(this.state.editionList) - .forEach((pieceId) => { - let filteredEditionsForPiece = this.state.editionList[pieceId].filter((edition) => edition.selected); - selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece); - }); - - return selectedEditionList; - }, - clearAllSelections() { EditionListActions.clearAllEditionSelections(); EditionListActions.closeAllEditionLists(); }, - handleSuccess() { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - - this.fetchSelectedPieceEditionList() - .forEach((pieceId) => { - EditionListActions.refreshEditionList({pieceId, filterBy: {}}); - }); - EditionListActions.clearAllEditionSelections(); - }, - render() { - let selectedEditions = this.fetchSelectedEditionList(); - let availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view'); - - if(Object.keys(availableAcls).length > 0) { + if (Object.keys(this.props.availableAcls).length > 0) { return (
@@ -104,7 +70,7 @@ let PieceListBulkModal = React.createClass({
+ numberOfSelectedEditions={this.props.selectedEditions.length} />          

- - - + {this.props.children}
diff --git a/js/components/piece_list.js b/js/components/piece_list.js index c427a911..528ee409 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -13,6 +13,9 @@ import AccordionList from './ascribe_accordion_list/accordion_list'; import AccordionListItemWallet from './ascribe_accordion_list/accordion_list_item_wallet'; import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_list_item_table_editions'; +import AclButtonList from './ascribe_buttons/acl_button_list.js'; +import DeleteButton from './ascribe_buttons/delete_button'; + import Pagination from './ascribe_pagination/pagination'; import PieceListFilterDisplay from './piece_list_filter_display'; @@ -24,6 +27,7 @@ import AscribeSpinner from './ascribe_spinner'; import AppConstants from '../constants/application_constants'; +import { getAvailableAcls } from '../utils/acl_utils'; import { mergeOptions } from '../utils/general_utils'; import { getLangText } from '../utils/lang_utils'; import { setDocumentTitle } from '../utils/dom_utils'; @@ -32,6 +36,7 @@ import { setDocumentTitle } from '../utils/dom_utils'; let PieceList = React.createClass({ propTypes: { accordionListItemType: React.PropTypes.func, + bulkModalButtonListType: React.PropTypes.func, redirectTo: React.PropTypes.string, customSubmitButton: React.PropTypes.element, filterParams: React.PropTypes.array, @@ -45,6 +50,7 @@ let PieceList = React.createClass({ getDefaultProps() { return { accordionListItemType: AccordionListItemWallet, + bulkModalButtonListType: AclButtonList, orderParams: ['artist_name', 'title'], filterParams: [{ label: getLangText('Show works I can'), @@ -152,9 +158,46 @@ let PieceList = React.createClass({ orderBy, this.state.orderAsc, this.state.filterBy); }, + fetchSelectedPieceEditionList() { + let filteredPieceIdList = Object.keys(this.state.editionList) + .filter((pieceId) => { + return this.state.editionList[pieceId] + .filter((edition) => edition.selected).length > 0; + }); + return filteredPieceIdList; + }, + + fetchSelectedEditionList() { + let selectedEditionList = []; + + Object + .keys(this.state.editionList) + .forEach((pieceId) => { + let filteredEditionsForPiece = this.state.editionList[pieceId].filter((edition) => edition.selected); + selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece); + }); + + return selectedEditionList; + }, + + handleAclSuccess() { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + this.fetchSelectedPieceEditionList() + .forEach((pieceId) => { + EditionListActions.refreshEditionList({pieceId, filterBy: {}}); + }); + EditionListActions.clearAllEditionSelections(); + }, + render() { - let loadingElement = ; - let AccordionListItemType = this.props.accordionListItemType; + const loadingElement = ; + const AccordionListItemType = this.props.accordionListItemType; + const BulkModalButtonListType = this.props.bulkModalButtonListType; + + const selectedEditions = this.fetchSelectedEditionList(); + const availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view'); setDocumentTitle(getLangText('Collection')); @@ -178,7 +221,19 @@ let PieceList = React.createClass({ } + availableAcls={availableAcls} + selectedEditions={selectedEditions} + className="ascribe-piece-list-bulk-modal"> + + + + diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js new file mode 100644 index 00000000..6c1aa0ae --- /dev/null +++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js @@ -0,0 +1,39 @@ +'use strict'; + +import React from 'react'; + +import LumenusSubmitButton from './lumenus_submit_button'; + +import AclProxy from '../../../../../acl_proxy'; + +import DeleteButton from '../../../../../ascribe_buttons/delete_button'; + +let LumenusAclButtonList = React.createClass({ + propTypes: { + availableAcls: React.PropTypes.object.isRequired, + className: React.PropTypes.string, + editions: React.PropTypes.array, + handleSuccess: React.PropTypes.func, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) + }, + + render() { + return ( +
+ + + + {this.props.children} +
+ ); + } +}); + +export default LumenusAclButtonList; diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js new file mode 100644 index 00000000..13483502 --- /dev/null +++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js @@ -0,0 +1,91 @@ +'use strict'; + +import React from 'react'; +import classNames from 'classnames'; + + +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; +import UserActions from '../../../../../../actions/user_actions'; +import UserStore from '../../../../../../stores/user_store'; +import WhitelabelActions from '../../../../../../actions/whitelabel_actions'; +import WhitelabelStore from '../../../../../../stores/whitelabel_store'; + +import ConsignForm from '../../../../../ascribe_forms/form_consign'; + +import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; + +import ApiUrls from '../../../../../../constants/api_urls'; + +import { getAclFormMessage, getAclFormDataId } from '../../../../../../utils/form_utils'; +import { mergeOptions } from '../../../../../../utils/general_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; + +let LumenusSubmitButton = React.createClass({ + propTypes: { + className: React.PropTypes.string, + editions: React.PropTypes.array, + handleSuccess: React.PropTypes.func, + }, + + getInitialState() { + return mergeOptions( + UserStore.getState(), + WhitelabelStore.getState() + ); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + WhitelabelStore.listen(this.onChange); + WhitelabelActions.fetchWhitelabel(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + showNotification(response) { + this.props.handleSuccess(); + if (response.notification) { + let notification = new GlobalNotificationModel(response.notification, 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + } + }, + + render() { + const { className, editions, handleSuccess } = this.props; + const title = getLangText('Consign to Lumenus'); + const message = getAclFormMessage({ + aclName: 'acl_consign', + entities: editions, + isPiece: false, + senderName: this.state.currentUser.username + }); + + return ( + + {title} + + } + handleSuccess={this.showNotification} + title={title}> + + + ); + } +}); + +export default LumenusSubmitButton; diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js index c3f01374..403e226b 100644 --- a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js +++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js @@ -1,6 +1,9 @@ 'use strict'; import React from 'react'; + +import LumenusAclButtonList from './lumenus_buttons/lumenus_acl_button_list'; + import PieceList from '../../../../piece_list'; import UserActions from '../../../../../actions/user_actions'; @@ -39,6 +42,7 @@ let LumenusPieceList = React.createClass({
= 1) { + if (editionsCopy.length >= 1) { availableAcls = editionsCopy[0].acl; - } - if(editionsCopy.length >= 2) { - for(let i = 1; i < editionsCopy.length; i++) { + } else if (editionsCopy.length >= 2) { + for (let i = 1; i < editionsCopy.length; i++) { availableAcls = intersectAcls(availableAcls, editionsCopy[i].acl); } } // convert acls back to key-value object let availableAclsObj = {}; - for(let i = 0; i < availableAcls.length; i++) { + for (let i = 0; i < availableAcls.length; i++) { availableAclsObj[availableAcls[i]] = true; } return availableAclsObj; -} \ No newline at end of file +} diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js index a98d956f..d2d2cd29 100644 --- a/js/utils/form_utils.js +++ b/js/utils/form_utils.js @@ -5,15 +5,19 @@ import { getLangText } from './lang_utils'; import AppConstants from '../constants/application_constants'; /** - * Gets a dictionary of settings for a form based on the environment - * (ie. if on a whitelabel) - * @param {string} formName Name of the form - * @return {object} Settings key-val dictionary + * 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 getSubdomainFormSettings(formName) { - let subdomainFormSettings = AppConstants.whitelabel.formSettings || {}; - - return subdomainFormSettings[formName] || {}; +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()}; + } } /** @@ -21,6 +25,7 @@ export function getSubdomainFormSettings(formName) { * @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 */