onion/js/components/ascribe_detail/edition.js

363 lines
14 KiB
JavaScript
Raw Normal View History

2015-06-26 00:38:40 +02:00
'use strict';
import React from 'react';
2016-01-11 17:52:32 +01:00
import { Link } from 'react-router';
import Moment from 'moment';
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';
import EditionActions from '../../actions/edition_actions';
2015-06-26 00:38:40 +02:00
import DetailProperty from './detail_property';
import EditionActionPanel from './edition_action_panel';
import FurtherDetails from './further_details';
import HistoryIterator from './history_iterator';
import LicenseDetail from './license_detail';
2015-07-08 22:54:07 +02:00
import MediaContainer from './media_container';
import Note from './note';
2015-06-26 00:38:40 +02:00
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
2015-06-26 00:38:40 +02:00
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
2015-07-08 22:54:07 +02:00
2015-11-03 10:39:01 +01:00
import AclProxy from '../acl_proxy';
2015-06-26 00:38:40 +02:00
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: {
currentUser: React.PropTypes.object.isRequired,
edition: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
actionPanelButtonListType: React.PropTypes.func,
coaError: React.PropTypes.object,
furtherDetailsType: React.PropTypes.func,
loadEdition: React.PropTypes.func
2015-06-26 00:38:40 +02:00
},
getDefaultProps() {
return {
furtherDetailsType: FurtherDetails
};
},
2015-06-26 00:38:40 +02:00
render() {
const { actionPanelButtonListType,
coaError,
currentUser,
edition,
furtherDetailsType: FurtherDetailsType,
2016-02-08 14:08:54 +01:00
loadEdition,
whitelabel } = this.props;
2015-06-26 00:38:40 +02:00
return (
<Row>
<Col md={6} className="ascribe-print-col-left">
2015-07-03 12:35:45 +02:00
<MediaContainer
2016-01-11 17:52:32 +01:00
content={edition}
currentUser={currentUser}
refreshObject={loadEdition} />
2015-06-26 00:38:40 +02:00
</Col>
<Col md={6} className="ascribe-edition-details ascribe-print-col-right">
2015-07-13 17:09:44 +02:00
<div className="ascribe-detail-header">
<hr className="hidden-print" style={{marginTop: 0}} />
2016-01-11 17:52:32 +01:00
<h1 className="ascribe-detail-title">{edition.title}</h1>
2016-02-05 10:38:59 +01:00
<DetailProperty label="CREATED BY" value={edition.artist_name} />
<DetailProperty
label="YEAR OF CREATION"
value={Moment(edition.date_created, 'YYYY-MM-DD').year()} />
<hr />
2015-07-13 17:09:44 +02:00
</div>
2015-06-26 00:38:40 +02:00
<EditionSummary
2016-01-11 17:52:32 +01:00
actionPanelButtonListType={actionPanelButtonListType}
edition={edition}
currentUser={currentUser}
handleSuccess={loadEdition}
whitelabel={whitelabel} />
2015-06-26 00:38:40 +02:00
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Certificate of Authenticity')}
2016-01-11 17:52:32 +01:00
show={edition.acl.acl_coa === true}>
2015-06-26 00:38:40 +02:00
<CoaDetails
2016-01-11 17:52:32 +01:00
coa={edition.coa}
coaError={coaError}
editionId={edition.bitcoin_id} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Provenance/Ownership History')}
2016-02-09 12:07:23 +01:00
show={!!(edition.ownership_history && edition.ownership_history.length)}>
<HistoryIterator history={edition.ownership_history} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Consignment History')}
2016-02-09 12:07:23 +01:00
show={!!(edition.consign_history && edition.consign_history.length)}>
<HistoryIterator history={edition.consign_history} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph
2015-07-03 19:08:56 +02:00
title={getLangText('Loan History')}
2016-02-09 12:07:23 +01:00
show={!!(edition.loan_history && edition.loan_history.length)}>
<HistoryIterator history={edition.loan_history} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
2015-07-13 14:30:24 +02:00
<CollapsibleParagraph
2016-02-08 14:50:24 +01:00
title={getLangText('Notes')}
2016-01-11 17:52:32 +01:00
show={!!(currentUser.username || edition.acl.acl_edit || edition.public_note)}>
<Note
2016-01-11 17:52:32 +01:00
id={() => {return {'bitcoin_id': edition.bitcoin_id}; }}
label={getLangText('Personal note (private)')}
2016-01-11 17:52:32 +01:00
defaultValue={edition.private_note ? 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={currentUser} />
<Note
2016-01-11 17:52:32 +01:00
id={() => {return {'bitcoin_id': edition.bitcoin_id}; }}
2015-12-02 16:51:56 +01:00
label={getLangText('Personal note (public)')}
2016-01-11 17:52:32 +01:00
defaultValue={edition.public_note ? edition.public_note : null}
2015-08-21 16:38:18 +02:00
placeholder={getLangText('Enter your comments ...')}
2016-01-11 17:52:32 +01:00
editable={!!edition.acl.acl_edit}
show={!!(edition.public_note || edition.acl.acl_edit)}
2015-08-21 16:38:18 +02:00
successMessage={getLangText('Public edition note saved')}
url={ApiUrls.note_public_edition}
currentUser={currentUser} />
2015-07-13 14:30:24 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Further Details')}
2016-02-09 12:07:23 +01:00
show={!!(edition.acl.acl_edit || Object.keys(edition.extra_data).length || edition.other_data.length)}>
<FurtherDetailsType
2016-01-11 17:52:32 +01:00
editable={edition.acl.acl_edit}
pieceId={edition.parent}
extraData={edition.extra_data}
otherData={edition.other_data}
handleSuccess={loadEdition} />
2015-07-13 14:30:24 +02:00
</CollapsibleParagraph>
<CollapsibleParagraph title={getLangText('SPOOL Details')}>
<SpoolDetails edition={edition} />
2015-06-26 00:38:40 +02:00
</CollapsibleParagraph>
</Col>
</Row>
);
}
});
let EditionSummary = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
edition: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
actionPanelButtonListType: React.PropTypes.func,
2015-09-30 12:12:14 +02:00
handleSuccess: React.PropTypes.func
2015-06-26 00:38:40 +02:00
},
getStatus() {
const { status } = this.props.edition;
return status.length ? (
<DetailProperty
label="STATUS"
value={status.join(', ').replace(/_/g, ' ')} />
) : null;
2015-07-08 22:54:07 +02:00
},
2015-07-08 22:54:07 +02:00
render() {
const { actionPanelButtonListType, currentUser, edition, handleSuccess, whitelabel } = this.props;
2015-06-26 00:38:40 +02:00
return (
<div className="ascribe-detail-header">
<DetailProperty
label={getLangText('EDITION')}
value={edition.edition_number + ' ' + getLangText('of') + ' ' + edition.num_editions} />
<DetailProperty
label={getLangText('ID')}
value={edition.bitcoin_id}
ellipsis={true} />
<DetailProperty
label="DATE OF TIMESTAMPING"
value={Moment(edition.datetime_registered).format('MMM. DD, YYYY, h:mm:ss')} />
<DetailProperty
label={getLangText('OWNER')}
value={edition.owner} />
<LicenseDetail license={edition.license_type} />
2015-07-08 22:54:07 +02:00
{this.getStatus()}
{/*
`acl_view` is always available in `edition.acl`, therefore if it has
no more than 1 key, we're hiding the `DetailProperty` actions as otherwise
`AclInformation` would show up
*/}
<AclProxy show={currentUser.email && Object.keys(edition.acl).length > 1}>
<DetailProperty
label={getLangText('ACTIONS')}
className="hidden-print">
2015-11-03 10:39:01 +01:00
<EditionActionPanel
actionPanelButtonListType={actionPanelButtonListType}
currentUser={currentUser}
edition={edition}
handleSuccess={handleSuccess}
whitelabel={whitelabel} />
</DetailProperty>
2015-11-03 10:39:01 +01:00
</AclProxy>
2015-06-26 00:38:40 +02:00
<hr/>
</div>
);
}
});
let CoaDetails = React.createClass({
propTypes: {
editionId: React.PropTypes.string,
2016-01-11 17:52:32 +01:00
coa: React.PropTypes.oneOfType([
React.PropTypes.number,
React.PropTypes.string,
React.PropTypes.object
]),
coaError: React.PropTypes.object
},
contactOnIntercom() {
const { coaError, editionId } = this.props;
window.Intercom('showNewMessage', getLangText("Hi, I'm having problems generating a Certificate of Authenticity for Edition: %s", editionId));
console.logGlobal(new Error(`Coa couldn't be created for edition: ${editionId}`), coaError);
2015-06-26 00:38:40 +02:00
},
render() {
2016-01-04 18:06:26 +01:00
const { coa, coaError } = this.props;
let coaDetailElement;
2016-01-04 18:06:26 +01:00
if (coaError) {
coaDetailElement = [
<p>{getLangText('There was an error generating your Certificate of Authenticity.')}</p>,
<p>
{getLangText('Try to refresh the page. If this happens repeatedly, please ')}
<a style={{ cursor: 'pointer' }} onClick={this.contactOnIntercom}>{getLangText('contact us')}</a>.
</p>
];
2016-01-04 18:06:26 +01:00
} else if (coa && coa.url_safe) {
coaDetailElement = [
<div
className="notification-contract-pdf"
style={{paddingBottom: '1em'}}>
<embed
className="embed-form"
src={coa.url_safe}
alt="pdf"
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
</div>,
<div className="text-center ascribe-button-list">
<a href={coa.url_safe} target="_blank">
<button className="btn btn-default btn-xs">
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
</button>
</a>
<Link to="/coa_verify">
<button className="btn btn-default btn-xs">
{getLangText('Verify')} <Glyphicon glyph="check"/>
</button>
</Link>
</div>
];
} else if (typeof coa === 'string') {
coaDetailElement = coa;
} else {
coaDetailElement = [
<AscribeSpinner color='dark-blue' size='md'/>,
<p>{getLangText("Just a sec, we're generating your COA")}</p>,
<p>{getLangText('(you may leave the page)')}</p>
];
}
2015-06-26 00:38:40 +02:00
return (
<div>
<div className="text-center hidden-print">
{coaDetailElement}
2015-06-26 00:38:40 +02:00
</div>
{/* Hide the COA and just show that it's a seperate document when printing */}
<div className="visible-print ascribe-coa-print-placeholder">
{getLangText('The COA is available as a seperate document')}
2015-07-22 00:30:51 +02:00
</div>
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() {
const { edition: {
bitcoin_id: bitcoinId,
hash_as_address: hashAsAddress,
btc_owner_address_noprefix: bitcoinOwnerAddress
} } = this.props;
const bitcoinIdValue = (
<a className="anchor-no-expand-print"
target="_blank"
href={'https://www.blocktrail.com/BTC/address/' + bitcoinId}>
{bitcoinId}
</a>
2015-07-03 12:35:45 +02:00
);
const hashOfArtwork = (
<a className="anchor-no-expand-print"
target="_blank"
href={'https://www.blocktrail.com/BTC/address/' + hashAsAddress}>
{hashAsAddress}
</a>
2015-07-03 12:35:45 +02:00
);
const ownerAddress = (
<a className="anchor-no-expand-print"
target="_blank"
href={'https://www.blocktrail.com/BTC/address/' + bitcoinOwnerAddress}>
{bitcoinOwnerAddress}
</a>
2015-07-03 12:35:45 +02:00
);
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;