1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 17:33:14 +01:00

consign unconsign requests

async emails
This commit is contained in:
ddejongh 2015-06-11 15:03:55 +02:00
parent af71196dfd
commit bf0a2aeefb
17 changed files with 252 additions and 89 deletions

View File

@ -53,7 +53,7 @@ gulp.task('js:build', function() {
bundle(false); bundle(false);
}); });
gulp.task('serve', ['browser-sync', 'run-server', 'lint:watch', 'sass:build', 'sass:watch', 'copy'], function() { gulp.task('serve', ['browser-sync', 'run-server', 'sass:build', 'sass:watch', 'copy'], function() {
bundle(true); bundle(true);
}); });

View File

@ -111,10 +111,10 @@ let AccordionListItemTableEditions = React.createClass({
new ColumnModel( new ColumnModel(
(item) => { (item) => {
return { return {
'content': item.edition_number 'content': item.edition_number + ' of ' + item.num_editions
}; }, }; },
'edition_number', 'edition_number',
'#', 'Edition',
TableItemText, TableItemText,
1, 1,
true, true,

View File

@ -3,6 +3,7 @@
import React from 'react'; import React from 'react';
import ConsignForm from '../ascribe_forms/form_consign'; import ConsignForm from '../ascribe_forms/form_consign';
import UnConsignForm from '../ascribe_forms/form_unconsign';
import TransferForm from '../ascribe_forms/form_transfer'; import TransferForm from '../ascribe_forms/form_transfer';
import LoanForm from '../ascribe_forms/form_loan'; import LoanForm from '../ascribe_forms/form_loan';
import ShareForm from '../ascribe_forms/form_share_email'; import ShareForm from '../ascribe_forms/form_share_email';
@ -30,7 +31,14 @@ let AclButton = React.createClass({
handleSuccess: this.showNotification handleSuccess: this.showNotification
}; };
} }
else if (this.props.action === 'transfer') { if (this.props.action === 'unconsign'){
return {
title: 'Unconsign artwork',
tooltip: 'Have the owner manage his sales again',
form: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
handleSuccess: this.showNotification
};
}else if (this.props.action === 'transfer') {
return { return {
title: 'Transfer artwork', title: 'Transfer artwork',
tooltip: 'Transfer the ownership of the artwork', tooltip: 'Transfer the ownership of the artwork',

View File

@ -6,6 +6,7 @@ import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store'; import UserStore from '../../stores/user_store';
import AclButton from '../ascribe_buttons/acl_button'; import AclButton from '../ascribe_buttons/acl_button';
import DeleteButton from '../ascribe_buttons/delete_button';
let AclButtonList = React.createClass({ let AclButtonList = React.createClass({
propTypes: { propTypes: {
@ -47,6 +48,12 @@ let AclButtonList = React.createClass({
editions={this.props.editions} editions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<AclButton
availableAcls={this.props.availableAcls}
action="unconsign"
editions={this.props.editions}
currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} />
<AclButton <AclButton
availableAcls={this.props.availableAcls} availableAcls={this.props.availableAcls}
action="loan" action="loan"
@ -59,6 +66,7 @@ let AclButtonList = React.createClass({
editions={this.props.editions} editions={this.props.editions}
currentUser={this.state.currentUser} currentUser={this.state.currentUser}
handleSuccess={this.props.handleSuccess} /> handleSuccess={this.props.handleSuccess} />
<DeleteButton editions={this.props.editions}/>
</div> </div>
); );
} }

View File

@ -1,34 +1,51 @@
'use strict';
import React from 'react'; import React from 'react';
import Router from 'react-router'; import Router from 'react-router';
import Button from 'react-bootstrap/lib/Button'; import Button from 'react-bootstrap/lib/Button';
import EditionDeleteForm from '../ascribe_forms/form_delete_edition'; import EditionDeleteForm from '../ascribe_forms/form_delete_edition';
import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection';
import ModalWrapper from '../ascribe_modal/modal_wrapper'; import ModalWrapper from '../ascribe_modal/modal_wrapper';
import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions'; import GlobalNotificationActions from '../../actions/global_notification_actions';
import { getAvailableAcls } from '../../utils/acl_utils';
import EditionListActions from '../../actions/edition_list_actions';
let DeleteButton = React.createClass({ let DeleteButton = React.createClass({
propTypes: { propTypes: {
editions: React.PropTypes.array.isRequired, editions: React.PropTypes.array.isRequired
}, },
mixins: [Router.Navigation], mixins: [Router.Navigation],
showNotification(response){ showNotification(response){
this.props.editions
.forEach((edition) => {
EditionListActions.fetchEditionList(edition.parent);
});
EditionListActions.clearAllEditionSelections();
this.transitionTo('pieces'); this.transitionTo('pieces');
let notification = new GlobalNotificationModel(response.notification, 'success'); let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
}, },
render: function () { render: function () {
let availableAcls = getAvailableAcls(this.props.editions);
let btnDelete = null; let btnDelete = null;
let content = <EditionDeleteForm />; let content = null;
if (this.props.edition.acl.indexOf('delete') > -1) {
btnDelete = <Button bsStyle="danger">Delete this edition</Button>; if (availableAcls.indexOf('delete') > -1) {
content = <EditionDeleteForm editions={ this.props.editions }/>;
btnDelete = <Button bsStyle="danger" bsSize="small">DELETE</Button>;
} }
else if (this.props.edition.acl.indexOf('del_from_collection') > -1){ else if (availableAcls.indexOf('del_from_collection') > -1){
btnDelete = <Button bsStyle="danger">Remove this artwork from your list</Button>; content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>;
btnDelete = <Button bsStyle="danger" bsSize="small">REMOVE FROM LIST</Button>;
} }
else{ else{
return <div></div>; return <div></div>;
@ -36,8 +53,6 @@ let DeleteButton = React.createClass({
return ( return (
<ModalWrapper <ModalWrapper
button={ btnDelete } button={ btnDelete }
currentUser={ this.props.currentUser }
editions={ [this.props.edition] }
handleSuccess={ this.showNotification } handleSuccess={ this.showNotification }
title='Remove Edition' title='Remove Edition'
tooltip='Click to remove edition'> tooltip='Click to remove edition'>

View File

@ -11,7 +11,7 @@ let EditionDeleteForm = React.createClass({
mixins: [FormMixin], mixins: [FormMixin],
url() { url() {
return fetch.prepareUrl(ApiUrls.edition_delete, {edition_id: this.props.editions[0].bitcoin_id}); return fetch.prepareUrl(ApiUrls.edition_delete, {edition_id: this.getBitcoinIds().join()});
}, },
httpVerb(){ httpVerb(){
return 'delete'; return 'delete';

View File

@ -0,0 +1,35 @@
'use strict';
import React from 'react';
import fetch from '../../utils/fetch';
import apiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin';
let EditionRemoveFromCollectionForm = React.createClass({
mixins: [FormMixin],
url() {
return fetch.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()});
},
httpVerb(){
return 'delete';
},
renderForm () {
return (
<div className="modal-body">
<p>Are you sure you would like to remove these editions from your collection&#63;</p>
<p>This is an irrevocable action.</p>
<div className="modal-footer">
<button type="submit" className="btn btn-ascribe-inv" onClick={this.submit}>YES, REMOVE</button>
<button className="btn btn-ascribe" onClick={this.props.onRequestHide}>CLOSE</button>
</div>
</div>
);
}
});
export default EditionRemoveFromCollectionForm;

View File

@ -0,0 +1,79 @@
'use strict';
import React from 'react';
import Alert from 'react-bootstrap/lib/Alert';
import apiUrls from '../../constants/api_urls';
import FormMixin from '../../mixins/form_mixin';
let RequestActionForm = React.createClass({
mixins: [FormMixin],
url(e){
let edition = this.props.editions[0];
if (e.target.id === 'request_accept'){
if (edition.request_action === 'consign'){
return apiUrls.ownership_consigns_confirm;
}
else if (edition.request_action === 'unconsign'){
return apiUrls.ownership_unconsigns;
}
else if (edition.request_action === 'loan'){
return apiUrls.ownership_loans_confirm;
}
}
else if(e.target.id === 'request_deny'){
if (edition.request_action === 'consign') {
return apiUrls.ownership_consigns_deny;
}
else if (edition.request_action === 'unconsign') {
return apiUrls.ownership_unconsigns_deny;
}
else if (edition.request_action === 'loan') {
return apiUrls.ownership_loans_deny;
}
}
},
handleRequest: function(e){
e.preventDefault();
this.submit(e);
},
getFormData() {
return {
bitcoin_id: this.getBitcoinIds().join()
};
},
renderForm() {
let edition = this.props.editions[0];
let buttons = (
<span>
<span>
<div id="request_accept" onClick={this.handleRequest} className='btn btn-default btn-sm'>ACCEPT</div>
</span>
<span>
<div id="request_deny" onClick={this.handleRequest} className='btn btn-default btn-sm'>REJECT</div>
</span>
</span>
);
if (this.state.submitted){
buttons = (
<span>
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_small.gif" />
</span>
);
}
return (
<Alert bsStyle='warning'>
<span>{ edition.owner } requests you { edition.request_action } this edition.&nbsp;&nbsp;</span>
{buttons}
</Alert>
);
}
});
export default RequestActionForm;

View File

@ -17,19 +17,20 @@ let UnConsignForm = React.createClass({
getFormData() { getFormData() {
return { return {
bitcoin_id: this.props.edition.bitcoin_id, bitcoin_id: this.getBitcoinIds().join(),
unconsign_message: this.refs.unconsign_message.state.value, unconsign_message: this.refs.unconsign_message.state.value,
password: this.refs.password.state.value password: this.refs.password.state.value
}; };
}, },
renderForm() { renderForm() {
let title = this.props.edition.title; let title = this.getTitlesString().join('');
let username = this.props.currentUser.username; let username = this.props.currentUser.username;
let message = let message =
`Hi, `Hi,
I un-consign \" ${title} \" from you. I un-consign:
${title}from you.
Truly yours, Truly yours,
${username}`; ${username}`;

View File

@ -14,6 +14,9 @@ import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_se
import AclButtonList from '../ascribe_buttons/acl_button_list'; import AclButtonList from '../ascribe_buttons/acl_button_list';
import { getAvailableAcls } from '../../utils/acl_utils';
let PieceListBulkModal = React.createClass({ let PieceListBulkModal = React.createClass({
propTypes: { propTypes: {
className: React.PropTypes.string className: React.PropTypes.string
@ -60,29 +63,6 @@ let PieceListBulkModal = React.createClass({
return selectedEditionList; return selectedEditionList;
}, },
intersectAcls(a, b) {
return a.filter((val) => b.indexOf(val) > -1);
},
getAvailableAcls() {
let availableAcls = [];
let selectedEditionList = this.fetchSelectedEditionList();
// 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(selectedEditionList.length >= 1) {
availableAcls = selectedEditionList[0].acl;
}
if(selectedEditionList.length >= 2) {
for(let i = 1; i < selectedEditionList.length; i++) {
availableAcls = this.intersectAcls(availableAcls, selectedEditionList[i].acl);
}
}
return availableAcls;
},
clearAllSelections() { clearAllSelections() {
EditionListActions.clearAllEditionSelections(); EditionListActions.clearAllEditionSelections();
}, },
@ -96,8 +76,8 @@ let PieceListBulkModal = React.createClass({
}, },
render() { render() {
let availableAcls = this.getAvailableAcls();
let selectedEditions = this.fetchSelectedEditionList(); let selectedEditions = this.fetchSelectedEditionList();
let availableAcls = getAvailableAcls(selectedEditions);
if(availableAcls.length > 0) { if(availableAcls.length > 0) {
return ( return (

View File

@ -12,10 +12,10 @@ import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import PersonalNoteForm from './ascribe_forms/form_note_personal'; import PersonalNoteForm from './ascribe_forms/form_note_personal';
import PieceExtraDataForm from './ascribe_forms/form_piece_extradata'; import PieceExtraDataForm from './ascribe_forms/form_piece_extradata';
import RequestActionForm from './ascribe_forms/form_request_action';
import EditionActions from '../actions/edition_actions'; import EditionActions from '../actions/edition_actions';
import AclButtonList from './ascribe_buttons/acl_button_list'; import AclButtonList from './ascribe_buttons/acl_button_list';
import DeleteButton from './ascribe_buttons/delete_button';
import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationModel from '../models/global_notification_model';
import GlobalNotificationActions from '../actions/global_notification_actions'; import GlobalNotificationActions from '../actions/global_notification_actions';
@ -28,8 +28,6 @@ import classNames from 'classnames';
let Edition = React.createClass({ let Edition = React.createClass({
propTypes: { propTypes: {
edition: React.PropTypes.object, edition: React.PropTypes.object,
currentUser: React.PropTypes.object,
deleteEdition: React.PropTypes.func,
loadEdition: React.PropTypes.func loadEdition: React.PropTypes.func
}, },
@ -70,8 +68,7 @@ let Edition = React.createClass({
<Col md={6} className="ascribe-edition-details"> <Col md={6} className="ascribe-edition-details">
<EditionHeader edition={this.props.edition}/> <EditionHeader edition={this.props.edition}/>
<EditionSummary <EditionSummary
edition={this.props.edition} edition={this.props.edition} />
currentUser={ this.props.currentUser }/>
<CollapsibleEditionDetails <CollapsibleEditionDetails
title="Personal Note" title="Personal Note"
iconName="pencil"> iconName="pencil">
@ -93,6 +90,13 @@ let Edition = React.createClass({
history={this.props.edition.ownership_history} /> history={this.props.edition.ownership_history} />
</CollapsibleEditionDetails> </CollapsibleEditionDetails>
<CollapsibleEditionDetails
title="Consignment History"
show={this.props.edition.consign_history && this.props.edition.consign_history.length > 0}>
<EditionDetailHistoryIterator
history={this.props.edition.consign_history} />
</CollapsibleEditionDetails>
<CollapsibleEditionDetails <CollapsibleEditionDetails
title="Loan History" title="Loan History"
show={this.props.edition.loan_history && this.props.edition.loan_history.length > 0}> show={this.props.edition.loan_history && this.props.edition.loan_history.length > 0}>
@ -112,13 +116,6 @@ let Edition = React.createClass({
label="Owned by SPOOL address" label="Owned by SPOOL address"
value={ownerAddress} /> value={ownerAddress} />
</CollapsibleEditionDetails> </CollapsibleEditionDetails>
<CollapsibleEditionDetails
title="Delete Actions">
<DeleteButton
edition={this.props.edition}
currentUser={ this.props.currentUser } />
</CollapsibleEditionDetails>
</Col> </Col>
</Row> </Row>
); );
@ -146,22 +143,31 @@ let EditionHeader = React.createClass({
let EditionSummary = React.createClass({ let EditionSummary = React.createClass({
propTypes: { propTypes: {
edition: React.PropTypes.object, edition: React.PropTypes.object
currentUser: React.PropTypes.object
}, },
handleSuccess(){ handleSuccess(){
EditionActions.fetchOne(this.props.edition.id); EditionActions.fetchOne(this.props.edition.id);
}, },
showNotification(response){
this.handleSuccess();
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() { render() {
return ( let status = null;
<div className="ascribe-detail-header"> if (this.props.edition.status.length > 0){
<EditionDetailProperty label="EDITION" status = <EditionDetailProperty label="STATUS" value={ this.props.edition.status.join().replace(/_/, ' ') } />;
value={this.props.edition.edition_number + ' of ' + this.props.edition.num_editions} /> }
<EditionDetailProperty label="ID" value={ this.props.edition.bitcoin_id } /> let actions = null;
<EditionDetailProperty label="OWNER" value={ this.props.edition.owner } /> if (this.props.edition.request_action){
<br/> actions = (
<RequestActionForm
editions={ [this.props.edition] }
handleSuccess={this.showNotification}/>);
}
else {
actions = (
<Row> <Row>
<Col md={12}> <Col md={12}>
<AclButtonList <AclButtonList
@ -170,7 +176,18 @@ let EditionSummary = React.createClass({
editions={[this.props.edition]} editions={[this.props.edition]}
handleSuccess={this.handleSuccess} /> handleSuccess={this.handleSuccess} />
</Col> </Col>
</Row> </Row>);
}
return (
<div className="ascribe-detail-header">
<EditionDetailProperty label="EDITION"
value={this.props.edition.edition_number + ' of ' + this.props.edition.num_editions} />
<EditionDetailProperty label="ID" value={ this.props.edition.bitcoin_id } />
<EditionDetailProperty label="OWNER" value={ this.props.edition.owner } />
{status}
<br/>
{actions}
<hr/> <hr/>
</div> </div>
); );
@ -273,8 +290,8 @@ let EditionDetailProperty = React.createClass({
getDefaultProps() { getDefaultProps() {
return { return {
separator: ':', separator: ':',
labelClassName: 'col-xs-5 col-sm-5 col-md-5 col-lg-5', labelClassName: 'col-xs-5 col-sm-4 col-md-3 col-lg-3',
valueClassName: 'col-xs-7 col-sm-7 col-md-7 col-lg-7' valueClassName: 'col-xs-7 col-sm-8 col-md-9 col-lg-9'
}; };
}, },

View File

@ -2,12 +2,8 @@
import React from 'react'; import React from 'react';
import { mergeOptions } from '../utils/general_utils';
import EditionActions from '../actions/edition_actions'; import EditionActions from '../actions/edition_actions';
import EditionStore from '../stores/edition_store'; import EditionStore from '../stores/edition_store';
import UserActions from '../actions/user_actions';
import UserStore from '../stores/user_store';
import Edition from './edition'; import Edition from './edition';
@ -16,7 +12,7 @@ import Edition from './edition';
*/ */
let EditionContainer = React.createClass({ let EditionContainer = React.createClass({
getInitialState() { getInitialState() {
return mergeOptions(UserStore.getState(), EditionStore.getState()); return EditionStore.getState();
}, },
onChange(state) { onChange(state) {
@ -25,20 +21,13 @@ let EditionContainer = React.createClass({
componentDidMount() { componentDidMount() {
EditionStore.listen(this.onChange); EditionStore.listen(this.onChange);
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
EditionActions.fetchOne(this.props.params.editionId); EditionActions.fetchOne(this.props.params.editionId);
}, },
componentWillUnmount() { componentWillUnmount() {
EditionStore.unlisten(this.onChange); EditionStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
}, },
deleteEdition() {
// Delete Edition from server
},
loadEdition() { loadEdition() {
EditionActions.fetchOne(this.props.params.editionId); EditionActions.fetchOne(this.props.params.editionId);
@ -49,8 +38,6 @@ let EditionContainer = React.createClass({
return ( return (
<Edition <Edition
edition={this.state.edition} edition={this.state.edition}
currentUser={this.state.currentUser}
deleteEdition={this.deleteEdition}
loadEdition={this.loadEdition}/> loadEdition={this.loadEdition}/>
); );
} else { } else {

View File

@ -3,8 +3,6 @@
import AppConstants from './application_constants'; import AppConstants from './application_constants';
let apiUrls = { let apiUrls = {
'ownership_shares_mail': AppConstants.baseUrl + 'ownership/shares/mail/',
'ownership_transfers': AppConstants.baseUrl + 'ownership/transfers/',
'user': AppConstants.baseUrl + 'users/', 'user': AppConstants.baseUrl + 'users/',
'piece': AppConstants.baseUrl + 'pieces/${piece_id}', 'piece': AppConstants.baseUrl + 'pieces/${piece_id}',
'pieces_list': AppConstants.baseUrl + 'pieces/', 'pieces_list': AppConstants.baseUrl + 'pieces/',
@ -12,10 +10,19 @@ let apiUrls = {
'edition': AppConstants.baseUrl + 'editions/${bitcoin_id}/', 'edition': AppConstants.baseUrl + 'editions/${bitcoin_id}/',
'editions_list': AppConstants.baseUrl + 'pieces/${piece_id}/editions/', 'editions_list': AppConstants.baseUrl + 'pieces/${piece_id}/editions/',
'edition_delete': AppConstants.baseUrl + 'editions/${edition_id}/', 'edition_delete': AppConstants.baseUrl + 'editions/${edition_id}/',
'ownership_loans': AppConstants.baseUrl + 'ownership/loans/', 'edition_remove_from_collection': AppConstants.baseUrl + 'ownership/shares/${edition_id}/',
'ownership_shares_mail': AppConstants.baseUrl + 'ownership/shares/mail/',
'ownership_transfers': AppConstants.baseUrl + 'ownership/transfers/',
'ownership_consigns': AppConstants.baseUrl + 'ownership/consigns/', 'ownership_consigns': AppConstants.baseUrl + 'ownership/consigns/',
'ownership_consigns_confirm': AppConstants.baseUrl + 'ownership/consigns/confirm/',
'ownership_consigns_deny': AppConstants.baseUrl + 'ownership/consigns/deny/',
'ownership_unconsigns': AppConstants.baseUrl + 'ownership/unconsigns/', 'ownership_unconsigns': AppConstants.baseUrl + 'ownership/unconsigns/',
'ownership_unconsigns_request': AppConstants.baseUrl + 'ownership/unconsigns/request/', 'ownership_unconsigns_request': AppConstants.baseUrl + 'ownership/unconsigns/request/',
'ownership_unconsigns_deny': AppConstants.baseUrl + 'ownership/unconsigns/deny/',
'ownership_loans': AppConstants.baseUrl + 'ownership/loans/',
'ownership_loans_confirm': AppConstants.baseUrl + 'ownership/loans/confirm/',
'ownership_loans_deny': AppConstants.baseUrl + 'ownership/loans/deny/',
'note_notes': AppConstants.baseUrl + 'note/notes/' 'note_notes': AppConstants.baseUrl + 'note/notes/'
}; };

View File

@ -4,7 +4,8 @@ let constants = {
'baseUrl': 'http://localhost:8000/api/', 'baseUrl': 'http://localhost:8000/api/',
//'baseUrl': 'http://staging.ascribe.io/api/', //'baseUrl': 'http://staging.ascribe.io/api/',
'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000
'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'] 'aclList': ['edit', 'consign', 'consign_request', 'unconsign', 'unconsign_request', 'transfer',
'loan', 'loan_request', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection']
}; };
export default constants; export default constants;

View File

@ -25,19 +25,19 @@ export const FormMixin = {
this.setState({submitted: true}); this.setState({submitted: true});
this.clearErrors(); this.clearErrors();
let action = (this.httpVerb && this.httpVerb()) || 'post'; let action = (this.httpVerb && this.httpVerb()) || 'post';
this[action](); this[action](e);
}, },
post(){ post(e){
fetch fetch
.post(this.url(), { body: this.getFormData() }) .post(this.url(e), { body: this.getFormData() })
.then(this.handleSuccess) .then(this.handleSuccess)
.catch(this.handleError); .catch(this.handleError);
}, },
delete(){ delete(e){
fetch fetch
.delete(this.url()) .delete(this.url(e))
.then(this.handleSuccess) .then(this.handleSuccess)
.catch(this.handleError); .catch(this.handleError);
}, },

View File

@ -16,7 +16,9 @@ class EditionListStore {
this.editionList[pieceId].forEach((edition, i) => { this.editionList[pieceId].forEach((edition, i) => {
// This uses the index of the new editionList for determining the edition. // This uses the index of the new editionList for determining the edition.
// If the list of editions can be sorted in the future, this needs to be changed! // If the list of editions can be sorted in the future, this needs to be changed!
editionListOfPiece[i] = React.addons.update(edition, {$merge: editionListOfPiece[i]}); if (editionListOfPiece[i]){
editionListOfPiece[i] = React.addons.update(edition, {$merge: editionListOfPiece[i]});
}
}); });
} }
this.editionList[pieceId] = editionListOfPiece; this.editionList[pieceId] = editionListOfPiece;

23
js/utils/acl_utils.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
export function getAvailableAcls(editions) {
let availableAcls = [];
// 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(editions.length >= 1) {
availableAcls = editions[0].acl;
}
if(editions.length >= 2) {
for(let i = 1; i < editions.length; i++) {
availableAcls = intersectAcls(availableAcls, editions[i].acl);
}
}
return availableAcls;
}
export function intersectAcls(a, b) {
return a.filter((val) => b.indexOf(val) > -1);
}