diff --git a/js/actions/edition_list_actions.js b/js/actions/edition_list_actions.js index f04b63c8..5c5303b0 100644 --- a/js/actions/edition_list_actions.js +++ b/js/actions/edition_list_actions.js @@ -44,7 +44,7 @@ class EditionListActions { }) .catch((err) => { reject(err); - console.log(err); + //console.log(err); }); }); diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 188935f7..f0d3e5f1 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -9,7 +9,8 @@ class PieceListActions { this.generateActions( 'updatePieceList', 'updatePieceListRequestActions', - 'addFirstEditionToPiece' + 'addFirstEditionToPiece', + 'updatePropertyForPiece' ); } diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index b3e31265..03d14425 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -3,13 +3,18 @@ import React from 'react'; import Router from 'react-router'; -import PieceListActions from '../../actions/piece_list_actions'; - import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; +import AccordionListItemCreateEditions from './accordion_list_item_create_editions'; + +import PieceListActions from '../../actions/piece_list_actions'; +import EditionListActions from '../../actions/edition_list_actions'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; import { getLangText } from '../../utils/lang_utils'; @@ -24,8 +29,15 @@ let AccordionListItem = React.createClass({ mixins: [Router.Navigation], + getInitialState() { + return { + showCreateEditionsDialog: false, + creatingEditions: false + }; + }, + componentDidMount() { - if(this.props.content.num_editions !== 0) { + if(this.props.content.num_editions > 0) { PieceListActions.fetchFirstEditionForPiece(this.props.content.id); } }, @@ -45,10 +57,57 @@ let AccordionListItem = React.createClass({ return null; }, + toggleCreateEditionsDialog() { + this.setState({ + showCreateEditionsDialog: !this.state.showCreateEditionsDialog + }); + }, + + handleEditionCreationSuccess(response) { + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0}); + + this.setState({ + creatingEditions: true + }); + + this.toggleCreateEditionsDialog(); + + // start polling until editions are defined + let pollingIntervalIndex = setInterval(() => { + EditionListActions.fetchEditionList(this.props.content.id) + .then((res) => { + + clearInterval(this.state.pollingIntervalIndex); + + this.setState({ + creatingEditions: false + }); + + PieceListActions.updatePropertyForPiece({ + pieceId: this.props.content.id, + key: 'num_editions', + value: res.editions[0].num_editions + }); + + EditionListActions.toggleEditionList(this.props.content.id); + + }) + .catch(() => { + /* Ignore and keep going */ + }); + }, 5000); + + this.setState({ + pollingIntervalIndex + }); + }, + render() { let linkData; - if(this.props.content.num_editions === 0) { + if(this.props.content.num_editions < 1) { linkData = { to: 'piece', params: { @@ -81,9 +140,13 @@ let AccordionListItem = React.createClass({

{getLangText('by %s', this.props.content.artist_name)}

- {this.props.content.date_created.split('-')[0]}, + {this.props.content.date_created.split('-')[0]} +
+
+ piece={this.props.content} + toggleCreateEditionsDialog={this.toggleCreateEditionsDialog} + creatingEditions={this.state.creatingEditions}/> {/* {getLangText('%s license', this.props.content.license_type.code)} */} @@ -95,6 +158,8 @@ let AccordionListItem = React.createClass({
+ {this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog ? : null} + {/* this.props.children is AccordionListItemTableEditions */} {this.props.children} diff --git a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js new file mode 100644 index 00000000..30a6efbc --- /dev/null +++ b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js @@ -0,0 +1,51 @@ +'use strict'; + +import React from 'react'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import apiUrls from '../../constants/api_urls'; +import { getLangText } from '../../utils/lang_utils'; + +let AccordionListItemCreateEditions = React.createClass({ + + propTypes: { + pieceId: React.PropTypes.number, + handleSuccess: React.PropTypes.func + }, + + getFormData(){ + return { + piece_id: parseInt(this.props.pieceId, 10) + }; + }, + + render() { + return ( +
+
+ + + }> + + + +
+
+ ); + } +}); + +export default AccordionListItemCreateEditions; \ No newline at end of file diff --git a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js index baa9778e..0c6a1082 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js @@ -9,7 +9,9 @@ import { getLangText } from '../../utils/lang_utils'; let AccordionListItemEditionWidget = React.createClass({ propTypes: { - piece: React.PropTypes.object.isRequired + piece: React.PropTypes.object.isRequired, + toggleCreateEditionsDialog: React.PropTypes.func.isRequired, + creatingEditions: React.PropTypes.bool.isRequired }, getInitialState() { @@ -73,15 +75,23 @@ let AccordionListItemEditionWidget = React.createClass({ let piece = this.props.piece; let numEditions = piece.num_editions; - if(numEditions === 0) { + if(numEditions === -1) { return ( - Create editions + + Editions ); - } else if(numEditions === 1) { + } + else if(numEditions === 0) { + return ( + + Creating Editions + + ); + } + else if(numEditions === 1) { let editionMapping = piece && piece.firstEdition ? piece.firstEdition.edition_number + '/' + piece.num_editions : ''; return ( @@ -91,7 +101,8 @@ let AccordionListItemEditionWidget = React.createClass({ {editionMapping + ' ' + getLangText('Edition')} {this.getGlyphicon()} ); - } else { + } + else { return ( , + form: , handleSuccess: this.showNotification }; } @@ -39,14 +42,14 @@ let AclButton = React.createClass({ return { title: getLangText('Unconsign artwork'), tooltip: getLangText('Have the owner manage his sales again'), - form: , + form: , handleSuccess: this.showNotification }; }else if (this.props.action === 'transfer') { return { title: getLangText('Transfer artwork'), tooltip: getLangText('Transfer the ownership of the artwork'), - form: , + form: , handleSuccess: this.showNotification }; } @@ -54,7 +57,7 @@ let AclButton = React.createClass({ return { title: getLangText('Loan artwork'), tooltip: getLangText('Loan your artwork for a limited period of time'), - form: , + form: , handleSuccess: this.showNotification }; } @@ -62,16 +65,46 @@ let AclButton = React.createClass({ return { title: getLangText('Share artwork'), tooltip: getLangText('Share the artwork'), - form: , + form: ( + + ), handleSuccess: this.showNotification }; } }, + showNotification(response){ this.props.handleSuccess(); let notification = new GlobalNotificationModel(response.notification, 'success'); GlobalNotificationActions.appendGlobalNotification(notification); }, + + 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()}; + } + }, + render() { let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; let aclProps = this.actionProperties(); @@ -88,6 +121,18 @@ let AclButton = React.createClass({ { aclProps.form } ); + }, + + getShareMessage(){ + return ( +`${getLangText('Hi')}, + +${getLangText('I am sharing')} : +${this.getTitlesString()}${getLangText('with you')}. + +${getLangText('Truly yours')}, +${this.props.currentUser.username}` + ); } }); diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index ae639aa4..eb3dc720 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -7,11 +7,12 @@ import UserStore from '../../stores/user_store'; import AclButton from '../ascribe_buttons/acl_button'; import DeleteButton from '../ascribe_buttons/delete_button'; +import CreateEditionButton from '../ascribe_buttons/create_editions_button'; let AclButtonList = React.createClass({ propTypes: { className: React.PropTypes.string, - editions: React.PropTypes.array, + editions: React.PropTypes.object, availableAcls: React.PropTypes.array, handleSuccess: React.PropTypes.func }, @@ -39,34 +40,37 @@ let AclButtonList = React.createClass({ - + + ); } diff --git a/js/components/ascribe_buttons/create_editions_button.js b/js/components/ascribe_buttons/create_editions_button.js new file mode 100644 index 00000000..4b189db2 --- /dev/null +++ b/js/components/ascribe_buttons/create_editions_button.js @@ -0,0 +1,44 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import Button from 'react-bootstrap/lib/Button'; + +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 AccordionListItemCreateEditions from './../ascribe_accordion_list/accordion_list_item_create_editions'; +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import { getAvailableAcls } from '../../utils/acl_utils'; +import { getLangText } from '../../utils/lang_utils.js' + +import EditionListActions from '../../actions/edition_list_actions'; + +let CreateEditionsButton = React.createClass({ + propTypes: { + piece: React.PropTypes.object.isRequired + }, + + mixins: [Router.Navigation], + + render: function () { + if (this.props.piece.constructor === Array){ + return null; + } + let availableAcls = getAvailableAcls([this.props.piece]); + if (availableAcls.indexOf('editions') === -1){ + return null; + } + return ( + + ); + } +}); + +export default CreateEditionsButton; + diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 94f6e507..028cb8ae 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -84,7 +84,8 @@ let Edition = React.createClass({ -1 || this.props.edition.public_note)}> + (this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note)} + defaultExpanded={true}> {this.getStatus()} -
{this.getActions()}
@@ -275,11 +275,11 @@ let EditionPersonalNote = React.createClass({ label={getLangText('Personal note (private)')} editable={true}> + required="required"/>