1
0
mirror of https://github.com/ascribe/onion.git synced 2025-02-14 21:10:27 +01:00

Set the consignee email by using the server's white label settings

Consignee email is available through the white label settings we get
from the server, so we don’t need to hardcode them into the constants.

Separated out AclButtonList from PieceListbulkModal to make the modal
more flexible and separated in concerns.
This commit is contained in:
Brett Sun 2015-10-26 19:17:06 +01:00
parent 84c459c426
commit ac1b43d24b
11 changed files with 230 additions and 101 deletions

View File

@ -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

View File

@ -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 (
<Form
ref='form'
@ -53,12 +50,12 @@ let ConsignForm = React.createClass({
<Property
name='consignee'
label={getLangText('Email')}
editable={!envSettings.consigneeDisabled}
overrideForm={true}>
editable={!this.props.email}
overrideForm={!!this.props.email}>
<input
type="email"
placeholder={getLangText('Email of the consignee')}
defaultValue={envSettings.consignee}
defaultValue={this.props.email}
required/>
</Property>
<Property

View File

@ -4,7 +4,6 @@ import React from 'react';
import { mergeOptions } from '../../utils/general_utils';
import EditionListStore from '../../stores/edition_list_store';
import EditionListActions from '../../actions/edition_list_actions';
import UserStore from '../../stores/user_store';
@ -14,27 +13,31 @@ import PieceListStore from '../../stores/piece_list_store';
import PieceListActions from '../../actions/piece_list_actions';
import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_selected_editions_widget';
import AclButtonList from '../ascribe_buttons/acl_button_list';
import DeleteButton from '../ascribe_buttons/delete_button';
import { getAvailableAcls } from '../../utils/acl_utils';
import { getLangText } from '../../utils/lang_utils.js';
let PieceListBulkModal = React.createClass({
propTypes: {
className: React.PropTypes.string
availableAcls: React.PropTypes.object.isRequired,
className: React.PropTypes.string,
selectedEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
])
},
getInitialState() {
return mergeOptions(
EditionListStore.getState(),
UserStore.getState(),
PieceListStore.getState()
);
},
componentDidMount() {
EditionListStore.listen(this.onChange);
UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
@ -44,7 +47,6 @@ let PieceListBulkModal = React.createClass({
},
componentWillUnmount() {
EditionListStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
},
@ -53,49 +55,13 @@ let PieceListBulkModal = React.createClass({
this.setState(state);
},
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;
},
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 (
<div className={this.props.className}>
<div className="row no-margin">
@ -104,7 +70,7 @@ let PieceListBulkModal = React.createClass({
<div className="row">
<div className="text-center">
<PieceListBulkModalSelectedEditionsWidget
numberOfSelectedEditions={this.fetchSelectedEditionList().length} />
numberOfSelectedEditions={this.props.selectedEditions.length} />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span
className="piece-list-bulk-modal-clear-all"
@ -113,15 +79,7 @@ let PieceListBulkModal = React.createClass({
</div>
<p></p>
<div className="row-fluid">
<AclButtonList
availableAcls={availableAcls}
editions={selectedEditions}
handleSuccess={this.handleSuccess}
className="text-center ascribe-button-list collapse-group">
<DeleteButton
handleSuccess={this.handleSuccess}
editions={selectedEditions}/>
</AclButtonList>
{this.props.children}
</div>
</div>
</div>

View File

@ -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 = <AscribeSpinner color='dark-blue' size='lg'/>;
let AccordionListItemType = this.props.accordionListItemType;
const loadingElement = <AscribeSpinner color='dark-blue' size='lg'/>;
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({
}
</PieceListToolbar>
<PieceListBulkModal
className="ascribe-piece-list-bulk-modal"/>
availableAcls={availableAcls}
selectedEditions={selectedEditions}
className="ascribe-piece-list-bulk-modal">
<BulkModalButtonListType
availableAcls={availableAcls}
editions={selectedEditions}
handleSuccess={this.handleAclSuccess}
className="text-center ascribe-button-list collapse-group">
<DeleteButton
handleSuccess={this.handleAclSuccess}
editions={selectedEditions}/>
</BulkModalButtonListType>
</PieceListBulkModal>
<PieceListFilterDisplay
filterBy={this.state.filterBy}
filterParams={this.props.filterParams}/>

View File

@ -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 (
<div className={this.props.className}>
<AclProxy
aclObject={this.props.availableAcls}
aclName={'acl_consign'}>
<LumenusSubmitButton
editions={this.props.editions}
handleSuccess={this.props.handleSuccess} />
</AclProxy>
{this.props.children}
</div>
);
}
});
export default LumenusAclButtonList;

View File

@ -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 (
<ModalWrapper
trigger={
<button className={classNames('btn', 'btn-default', 'btn-sm', className)}>
{title}
</button>
}
handleSuccess={this.showNotification}
title={title}>
<ConsignForm
email={this.state.whitelabel.user}
message={message}
id={getAclFormDataId(false, editions)}
url={ApiUrls.ownership_consigns}/>
</ModalWrapper>
);
}
});
export default LumenusSubmitButton;

View File

@ -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({
<div>
<PieceList
redirectTo="/register_piece?slide_num=0"
bulkModalButtonListType={LumenusAclButtonList}
filterParams={[{
label: getLangText('Show works I have'),
items: [{

View File

@ -9,9 +9,6 @@ import Row from 'react-bootstrap/lib/Row';
import Property from '../../../../ascribe_forms/property';
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../stores/whitelabel_store';
import PieceListStore from '../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../actions/piece_list_actions';
@ -42,7 +39,6 @@ let LumenusRegisterPiece = React.createClass({
UserStore.getState(),
PieceListStore.getState(),
PieceStore.getState(),
WhitelabelStore.getState(),
{
selectedLicense: 0,
isFineUploaderActive: false,
@ -54,9 +50,7 @@ let LumenusRegisterPiece = React.createClass({
PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
PieceStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
UserActions.fetchCurrentUser();
WhitelabelActions.fetchWhitelabel();
let queryParams = this.props.location.query;
@ -76,7 +70,6 @@ let LumenusRegisterPiece = React.createClass({
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
PieceStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
},
onChange(state) {

View File

@ -53,12 +53,6 @@ let constants = {
'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/lumenus/lumenus-logo.png',
'permissions': ['register', 'edit', 'share', 'del_from_collection'],
'type': 'wallet',
'formSettings': {
'consign': {
'consignee': 'submissions@lumenus.co',
'consigneeDisabled': true
}
}
}
],
'defaultDomain': {

View File

@ -8,7 +8,7 @@ function intersectAcls(a, b) {
export function getAvailableAcls(editions, filterFn) {
let availableAcls = [];
if (!editions || editions.constructor !== Array){
if (!editions || editions.constructor !== Array) {
return [];
}
// if you copy a javascript array of objects using slice, then
@ -39,21 +39,20 @@ export function getAvailableAcls(editions, filterFn) {
// If no edition has been selected, availableActions is empty
// If only one edition has been selected, their actions are available
// If more than one editions have been selected, their acl properties are intersected
if(editionsCopy.length >= 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;
}
}

View File

@ -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
*/