1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-23 01:39:36 +01:00
onion/js/components/ascribe_detail/edition.js
Brett Sun 7014514654 Use UrlResolver to resolve api urls based on white labelling rather than updating ApiUrl's export
Keeping an export constant is more predictable and less surprising for
most people.
2016-06-14 17:58:00 +02:00

363 lines
14 KiB
JavaScript

'use strict';
import React from 'react';
import Link from 'react-router/es6/Link';
import Moment from 'moment';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
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';
import MediaContainer from './media_container';
import Note from './note';
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
import AclProxy from '../acl_proxy';
import withContext from '../context/with_context';
import AscribeSpinner from '../ascribe_spinner';
import { resolveUrl } from '../../utils/url_resolver';
import { getLangText } from '../../utils/lang';
/**
* This is the component that implements display-specific functionality
*/
const Edition = React.createClass({
propTypes: {
edition: React.PropTypes.object.isRequired,
actionPanelButtonListType: React.PropTypes.func,
coaError: React.PropTypes.object,
furtherDetailsType: React.PropTypes.func,
loadEdition: React.PropTypes.func,
// Injected through HOCs
isLoggedIn: React.PropTypes.bool.isRequired // eslint-disable-line react/sort-prop-types
},
getDefaultProps() {
return {
furtherDetailsType: FurtherDetails
};
},
render() {
const {
actionPanelButtonListType,
coaError,
edition,
isLoggedIn,
loadEdition,
furtherDetailsType: FurtherDetailsType
} = this.props;
return (
<Row>
<Col md={6} className="ascribe-print-col-left">
<MediaContainer
content={edition}
refreshObject={loadEdition} />
</Col>
<Col md={6} className="ascribe-edition-details ascribe-print-col-right">
<div className="ascribe-detail-header">
<hr className="hidden-print" style={{marginTop: 0}} />
<h1 className="ascribe-detail-title">{edition.title}</h1>
<DetailProperty label="CREATED BY" value={edition.artist_name} />
<DetailProperty
label="YEAR OF CREATION"
value={Moment(edition.date_created, 'YYYY-MM-DD').year()} />
<hr />
</div>
<EditionSummary
actionPanelButtonListType={actionPanelButtonListType}
edition={edition}
handleSuccess={loadEdition} />
<CollapsibleParagraph
title={getLangText('Certificate of Authenticity')}
show={edition.acl.acl_coa === true}>
<CoaDetails
coa={edition.coa}
coaError={coaError}
editionId={edition.bitcoin_id} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Provenance/Ownership History')}
show={!!(edition.ownership_history && edition.ownership_history.length)}>
<HistoryIterator history={edition.ownership_history} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Consignment History')}
show={!!(edition.consign_history && edition.consign_history.length)}>
<HistoryIterator history={edition.consign_history} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Loan History')}
show={!!(edition.loan_history && edition.loan_history.length)}>
<HistoryIterator history={edition.loan_history} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Notes')}
show={!!(isLoggedIn || edition.acl.acl_edit || edition.public_note)}>
<Note
id={() => {return {'bitcoin_id': edition.bitcoin_id}; }}
label={getLangText('Personal note (private)')}
defaultValue={edition.private_note ? edition.private_note : null}
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Private note saved')}
url={resolveUrl('note_private_edition')} />
<Note
id={() => {return {'bitcoin_id': edition.bitcoin_id}; }}
label={getLangText('Personal note (public)')}
defaultValue={edition.public_note ? edition.public_note : null}
placeholder={getLangText('Enter your comments ...')}
editable={!!edition.acl.acl_edit}
show={!!(edition.public_note || edition.acl.acl_edit)}
successMessage={getLangText('Public edition note saved')}
url={resolveUrl('note_public_edition')} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Further Details')}
show={!!(edition.acl.acl_edit || Object.keys(edition.extra_data).length || edition.other_data.length)}>
<FurtherDetailsType
editable={edition.acl.acl_edit}
pieceId={edition.parent}
extraData={edition.extra_data}
otherData={edition.other_data}
handleSuccess={loadEdition} />
</CollapsibleParagraph>
<CollapsibleParagraph title={getLangText('SPOOL Details')}>
<SpoolDetails edition={edition} />
</CollapsibleParagraph>
</Col>
</Row>
);
}
});
let EditionSummary = withContext(React.createClass({
propTypes: {
edition: React.PropTypes.object.isRequired,
actionPanelButtonListType: React.PropTypes.func,
handleSuccess: React.PropTypes.func,
// Injected through HOCs
isLoggedIn: React.PropTypes.bool.isRequired, // eslint-disable-line react/sort-prop-types
},
getStatus() {
const { status } = this.props.edition;
return status.length ? (
<DetailProperty
label="STATUS"
value={status.join(', ').replace(/_/g, ' ')} />
) : null;
},
render() {
const {
actionPanelButtonListType,
edition,
handleSuccess,
isLoggedIn,
} = this.props;
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} />
{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={isLoggedIn && Object.keys(edition.acl).length > 1}>
<DetailProperty
label={getLangText('ACTIONS')}
className="hidden-print">
<EditionActionPanel
actionPanelButtonListType={actionPanelButtonListType}
edition={edition}
handleSuccess={handleSuccess} />
</DetailProperty>
</AclProxy>
<hr/>
</div>
);
}
}), 'isLoggedIn');
let CoaDetails = React.createClass({
propTypes: {
editionId: React.PropTypes.string,
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);
},
render() {
const { coa, coaError } = this.props;
let coaDetailElement;
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>
];
} 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>
];
}
return (
<div>
<div className="text-center hidden-print">
{coaDetailElement}
</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')}
</div>
</div>
);
}
});
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>
);
const hashOfArtwork = (
<a className="anchor-no-expand-print"
target="_blank"
href={'https://www.blocktrail.com/BTC/address/' + hashAsAddress}>
{hashAsAddress}
</a>
);
const ownerAddress = (
<a className="anchor-no-expand-print"
target="_blank"
href={'https://www.blocktrail.com/BTC/address/' + bitcoinOwnerAddress}>
{bitcoinOwnerAddress}
</a>
);
return (
<Form >
<Property
name='artwork_id'
label={getLangText('Artwork ID')}
editable={false}>
<pre className="ascribe-pre">{bitcoinIdValue}</pre>
</Property>
<Property
name='hash_of_artwork'
label={getLangText('Hash of Artwork, title, etc')}
editable={false}>
<pre className="ascribe-pre">{hashOfArtwork}</pre>
</Property>
<Property
name='owner_address'
label={getLangText('Owned by SPOOL address')}
editable={false}>
<pre className="ascribe-pre">{ownerAddress}</pre>
</Property>
<hr />
</Form>
);
}
});
export default withContext(Edition, 'isLoggedIn');