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:
parent
af71196dfd
commit
bf0a2aeefb
@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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',
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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'>
|
||||||
|
@ -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';
|
||||||
|
@ -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?</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;
|
79
js/components/ascribe_forms/form_request_action.js
Normal file
79
js/components/ascribe_forms/form_request_action.js
Normal 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. </span>
|
||||||
|
{buttons}
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default RequestActionForm;
|
@ -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}`;
|
||||||
|
@ -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 (
|
||||||
|
@ -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'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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/'
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
|
@ -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
23
js/utils/acl_utils.js
Normal 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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user