onion/js/components/ascribe_detail/edition.js

349 lines
13 KiB
JavaScript
Raw Normal View History

2015-06-26 00:38:40 +02:00
'use strict';
import React from 'react';
import { Link, History } from 'react-router';
2015-06-26 00:38:40 +02:00
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
2015-07-07 15:48:09 +02:00
import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store';
import CoaActions from '../../actions/coa_actions';
import CoaStore from '../../stores/coa_store';
2015-08-20 15:50:30 +02:00
import HistoryIterator from './history_iterator';
2015-06-26 00:38:40 +02:00
2015-07-08 22:54:07 +02:00
import MediaContainer from './media_container';
2015-06-26 00:38:40 +02:00
2015-07-07 15:48:09 +02:00
import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
2015-06-26 00:38:40 +02:00
2015-07-07 15:48:09 +02:00
import Form from './../ascribe_forms/form';
import Property from './../ascribe_forms/property';
2015-07-08 22:54:07 +02:00
import EditionDetailProperty from './detail_property';
import LicenseDetail from './license_detail';
import FurtherDetails from './further_details';
2015-07-08 22:54:07 +02:00
2015-10-01 09:49:01 +02:00
import EditionActionPanel from './edition_action_panel';
2015-11-03 10:39:01 +01:00
import AclProxy from '../acl_proxy';
2015-06-26 00:38:40 +02:00
import Note from './note';
2015-08-07 15:08:02 +02:00
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
2015-06-26 00:38:40 +02:00
import { getLangText } from '../../utils/lang_utils';
2015-06-29 16:46:12 +02:00
2015-06-26 00:38:40 +02:00
/**
* This is the component that implements display-specific functionality
*/
let Edition = React.createClass({
propTypes: {
actionPanelButtonListType: React.PropTypes.func,
furtherDetailsType: React.PropTypes.func,
2015-06-26 00:38:40 +02:00
edition: React.PropTypes.object,
loadEdition: React.PropTypes.func,
location: React.PropTypes.object
2015-06-26 00:38:40 +02:00
},
mixins: [History],
getDefaultProps() {
return {
furtherDetailsType: FurtherDetails
};
},
2015-06-26 00:38:40 +02:00
getInitialState() {
2015-09-30 12:12:14 +02:00
return UserStore.getState();
2015-06-26 00:38:40 +02:00
},
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
},
componentWillUnmount() {
// Flushing the coa state is essential to not displaying the same
// data to the user while he's on another edition
//
// BUGFIX: Previously we had this line in the componentWillUnmount of
// CoaDetails, but since we're reloading the edition after performing an ACL action
// on it, this resulted in multiple events occupying the dispatcher, which eventually
// resulted in crashing the app.
CoaActions.flushCoa();
2015-06-26 00:38:40 +02:00
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() {
let FurtherDetailsType = this.props.furtherDetailsType;
2015-06-26 00:38:40 +02:00
return (
<Row>
<Col md={6}>
2015-07-03 12:35:45 +02:00
<MediaContainer
2015-07-08 22:54:07 +02:00
content={this.props.edition}/>
2015-06-26 00:38:40 +02:00
</Col>
<Col md={6} className="ascribe-edition-details">
2015-07-13 17:09:44 +02:00
<div className="ascribe-detail-header">
2015-10-12 17:55:02 +02:00
<hr style={{marginTop: 0}}/>
2015-08-20 15:50:30 +02:00
<h1 className="ascribe-detail-title">{this.props.edition.title}</h1>
2015-07-13 17:09:44 +02:00
<EditionDetailProperty label="BY" value={this.props.edition.artist_name} />
2015-11-03 10:39:01 +01:00
<EditionDetailProperty label="DATE" value={ new Date(this.props.edition.date_created).getFullYear() } />
2015-07-13 17:09:44 +02:00
<hr/>
</div>
2015-06-26 00:38:40 +02:00
<EditionSummary
actionPanelButtonListType={this.props.actionPanelButtonListType}
edition={this.props.edition}
2015-09-30 12:12:14 +02:00
currentUser={this.state.currentUser}
handleSuccess={this.props.loadEdition}/>
2015-06-26 00:38:40 +02:00
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Certificate of Authenticity')}
2015-07-14 17:42:15 +02:00
show={this.props.edition.acl.acl_coa === true}>
2015-06-26 00:38:40 +02:00
<CoaDetails
edition={this.props.edition}/>
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Provenance/Ownership History')}
2015-06-26 00:38:40 +02:00
show={this.props.edition.ownership_history && this.props.edition.ownership_history.length > 0}>
2015-08-20 15:50:30 +02:00
<HistoryIterator
2015-06-26 00:38:40 +02:00
history={this.props.edition.ownership_history} />
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Consignment History')}
2015-06-26 00:38:40 +02:00
show={this.props.edition.consign_history && this.props.edition.consign_history.length > 0}>
2015-08-20 15:50:30 +02:00
<HistoryIterator
2015-06-26 00:38:40 +02:00
history={this.props.edition.consign_history} />
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Loan History')}
2015-06-26 00:38:40 +02:00
show={this.props.edition.loan_history && this.props.edition.loan_history.length > 0}>
2015-08-20 15:50:30 +02:00
<HistoryIterator
2015-06-26 00:38:40 +02:00
history={this.props.edition.loan_history} />
</CollapsibleParagraph>
2015-07-13 14:30:24 +02:00
<CollapsibleParagraph
title="Notes"
2015-09-17 14:20:46 +02:00
show={!!(this.state.currentUser.username
|| this.props.edition.acl.acl_edit
|| this.props.edition.public_note)}>
<Note
id={() => {return {'bitcoin_id': this.props.edition.bitcoin_id}; }}
label={getLangText('Personal note (private)')}
defaultValue={this.props.edition.private_note ? this.props.edition.private_note : null}
2015-08-21 16:38:18 +02:00
placeholder={getLangText('Enter your comments ...')}
editable={true}
2015-08-21 16:38:18 +02:00
successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_edition}
currentUser={this.state.currentUser}/>
<Note
id={() => {return {'bitcoin_id': this.props.edition.bitcoin_id}; }}
label={getLangText('Edition note (public)')}
defaultValue={this.props.edition.public_note ? this.props.edition.public_note : null}
2015-08-21 16:38:18 +02:00
placeholder={getLangText('Enter your comments ...')}
editable={!!this.props.edition.acl.acl_edit}
show={!!this.props.edition.public_note || !!this.props.edition.acl.acl_edit}
2015-08-21 16:38:18 +02:00
successMessage={getLangText('Public edition note saved')}
url={ApiUrls.note_public_edition}
currentUser={this.state.currentUser}/>
2015-07-13 14:30:24 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Further Details')}
2015-07-13 20:16:08 +02:00
show={this.props.edition.acl.acl_edit
2015-07-13 14:30:24 +02:00
|| Object.keys(this.props.edition.extra_data).length > 0
|| this.props.edition.other_data.length > 0}>
<FurtherDetailsType
2015-07-13 20:16:08 +02:00
editable={this.props.edition.acl.acl_edit}
2015-07-13 14:30:24 +02:00
pieceId={this.props.edition.parent}
extraData={this.props.edition.extra_data}
otherData={this.props.edition.other_data}
handleSuccess={this.props.loadEdition}
location={this.props.location} />
2015-07-13 14:30:24 +02:00
</CollapsibleParagraph>
2015-06-26 00:38:40 +02:00
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('SPOOL Details')}>
2015-07-03 12:35:45 +02:00
<SpoolDetails
edition={this.props.edition} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
</Col>
</Row>
);
}
});
let EditionSummary = React.createClass({
propTypes: {
actionPanelButtonListType: React.PropTypes.func,
2015-07-14 17:42:15 +02:00
edition: React.PropTypes.object,
2015-07-14 17:46:19 +02:00
currentUser: React.PropTypes.object,
2015-09-30 12:12:14 +02:00
handleSuccess: React.PropTypes.func
2015-06-26 00:38:40 +02:00
},
handleSuccess() {
this.props.handleSuccess();
},
2015-07-08 22:54:07 +02:00
getStatus(){
2015-06-26 00:38:40 +02:00
let status = null;
if (this.props.edition.status.length > 0){
let statusStr = this.props.edition.status.join().replace(/_/, ' ');
status = <EditionDetailProperty label="STATUS" value={ statusStr }/>;
2015-07-13 20:16:08 +02:00
if (this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer){
status = (
<EditionDetailProperty label="STATUS" value={ statusStr } />
2015-06-26 00:38:40 +02:00
);
}
}
2015-07-08 22:54:07 +02:00
return status;
},
2015-07-08 22:54:07 +02:00
render() {
let { actionPanelButtonListType, edition, currentUser } = this.props;
2015-06-26 00:38:40 +02:00
return (
<div className="ascribe-detail-header">
<EditionDetailProperty
label={getLangText('EDITION')}
2015-10-01 09:49:01 +02:00
value={ edition.edition_number + ' ' + getLangText('of') + ' ' + edition.num_editions} />
<EditionDetailProperty
label={getLangText('ID')}
2015-09-30 12:12:14 +02:00
value={ edition.bitcoin_id }
ellipsis={true} />
<EditionDetailProperty
label={getLangText('OWNER')}
2015-09-30 12:12:14 +02:00
value={ edition.owner } />
<LicenseDetail license={edition.license_type}/>
2015-07-08 22:54:07 +02:00
{this.getStatus()}
2015-11-03 10:39:01 +01:00
<AclProxy show={currentUser && currentUser.email}>
<EditionDetailProperty
label={getLangText('ACTIONS')}>
<EditionActionPanel
actionPanelButtonListType={actionPanelButtonListType}
edition={edition}
currentUser={currentUser}
handleSuccess={this.handleSuccess} />
</EditionDetailProperty>
</AclProxy>
2015-06-26 00:38:40 +02:00
<hr/>
</div>
);
}
});
let CoaDetails = React.createClass({
propTypes: {
edition: React.PropTypes.object
},
getInitialState() {
return CoaStore.getState();
},
componentDidMount() {
2015-09-30 11:26:31 +02:00
let { edition } = this.props;
2015-06-26 00:38:40 +02:00
CoaStore.listen(this.onChange);
2015-09-30 11:26:31 +02:00
if(edition.coa) {
CoaActions.fetchOrCreate(edition.coa, edition.bitcoin_id);
2015-06-26 00:38:40 +02:00
}
2015-07-10 14:15:22 +02:00
else {
2015-09-30 11:26:31 +02:00
CoaActions.create(edition.bitcoin_id);
2015-06-26 00:38:40 +02:00
}
},
componentWillUnmount() {
CoaStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() {
if(this.state.coa && this.state.coa.url_safe) {
2015-06-26 00:38:40 +02:00
return (
<div>
2015-06-30 17:12:13 +02:00
<p className="text-center ascribe-button-list">
2015-07-02 19:22:32 +02:00
<a href={this.state.coa.url_safe} target="_blank">
<button className="btn btn-default btn-xs">
2015-07-03 19:08:56 +02:00
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
2015-07-02 19:22:32 +02:00
</button>
</a>
<Link to="/coa_verify">
2015-06-30 17:12:13 +02:00
<button className="btn btn-default btn-xs">
2015-07-03 19:08:56 +02:00
{getLangText('Verify')} <Glyphicon glyph="check"/>
2015-06-30 17:12:13 +02:00
</button>
2015-06-26 00:38:40 +02:00
</Link>
</p>
</div>
);
} else if(typeof this.state.coa === 'string'){
2015-07-22 00:30:51 +02:00
return (
<div className="text-center">
{this.state.coa}
</div>
);
}
2015-06-26 00:38:40 +02:00
return (
<div className="text-center">
<AscribeSpinner color='dark-blue' size='lg'/>
2015-07-17 23:28:59 +02:00
</div>
);
2015-06-26 00:38:40 +02:00
}
});
2015-07-03 12:35:45 +02:00
let SpoolDetails = React.createClass({
propTypes: {
edition: React.PropTypes.object
},
render() {
let bitcoinIdValue = (
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.bitcoin_id}>{this.props.edition.bitcoin_id}</a>
);
let hashOfArtwork = (
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.hash_as_address}>{this.props.edition.hash_as_address}</a>
);
let ownerAddress = (
<a target="_blank" href={'https://www.blocktrail.com/BTC/address/' + this.props.edition.btc_owner_address_noprefix}>{this.props.edition.btc_owner_address_noprefix}</a>
);
return (
<Form >
<Property
name='artwork_id'
2015-07-03 19:08:56 +02:00
label={getLangText('Artwork ID')}
2015-07-03 12:35:45 +02:00
editable={false}>
<pre className="ascribe-pre">{bitcoinIdValue}</pre>
</Property>
<Property
name='hash_of_artwork'
2015-07-03 19:08:56 +02:00
label={getLangText('Hash of Artwork, title, etc')}
2015-07-03 12:35:45 +02:00
editable={false}>
<pre className="ascribe-pre">{hashOfArtwork}</pre>
</Property>
<Property
name='owner_address'
2015-07-03 19:08:56 +02:00
label={getLangText('Owned by SPOOL address')}
2015-07-03 12:35:45 +02:00
editable={false}>
<pre className="ascribe-pre">{ownerAddress}</pre>
</Property>
<hr />
</Form>);
}
});
2015-06-26 00:38:40 +02:00
export default Edition;