mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merge remote-tracking branch 'remotes/origin/master' into AD-1362-implement-portfolioreview-judging-flow
This commit is contained in:
commit
3461a28f36
@ -1,51 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import { alt } from '../alt';
|
|
||||||
import CoaFetcher from '../fetchers/coa_fetcher';
|
|
||||||
|
|
||||||
import Q from 'q';
|
|
||||||
|
|
||||||
class CoaActions {
|
|
||||||
constructor() {
|
|
||||||
this.generateActions(
|
|
||||||
'updateCoa',
|
|
||||||
'flushCoa'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchOrCreate(id, bitcoinId) {
|
|
||||||
return Q.Promise((resolve, reject) => {
|
|
||||||
CoaFetcher.fetchOne(id)
|
|
||||||
.then((res) => {
|
|
||||||
if (res.coa) {
|
|
||||||
this.actions.updateCoa(res.coa);
|
|
||||||
resolve(res.coa);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.actions.create(bitcoinId);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
this.actions.updateCoa(null);
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create(bitcoinId) {
|
|
||||||
return Q.Promise((resolve, reject) => {
|
|
||||||
CoaFetcher.create(bitcoinId)
|
|
||||||
.then((res) => {
|
|
||||||
this.actions.updateCoa(res.coa);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
this.actions.updateCoa(null);
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default alt.createActions(CoaActions);
|
|
@ -1,27 +1,19 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { alt } from '../alt';
|
import { alt } from '../alt';
|
||||||
import EditionFetcher from '../fetchers/edition_fetcher';
|
|
||||||
|
|
||||||
|
|
||||||
class EditionActions {
|
class EditionActions {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.generateActions(
|
this.generateActions(
|
||||||
'updateEdition',
|
'fetchEdition',
|
||||||
'editionFailed'
|
'successFetchEdition',
|
||||||
|
'successFetchCoa',
|
||||||
|
'flushEdition',
|
||||||
|
'errorCoa',
|
||||||
|
'errorEdition'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchOne(editionId) {
|
|
||||||
EditionFetcher.fetchOne(editionId)
|
|
||||||
.then((res) => {
|
|
||||||
this.actions.updateEdition(res.edition);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
this.actions.editionFailed(err.json);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default alt.createActions(EditionActions);
|
export default alt.createActions(EditionActions);
|
||||||
|
@ -8,11 +8,6 @@ import Row from 'react-bootstrap/lib/Row';
|
|||||||
import Col from 'react-bootstrap/lib/Col';
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
|
|
||||||
import UserActions from '../../actions/user_actions';
|
|
||||||
import UserStore from '../../stores/user_store';
|
|
||||||
import CoaActions from '../../actions/coa_actions';
|
|
||||||
import CoaStore from '../../stores/coa_store';
|
|
||||||
|
|
||||||
import HistoryIterator from './history_iterator';
|
import HistoryIterator from './history_iterator';
|
||||||
|
|
||||||
import MediaContainer from './media_container';
|
import MediaContainer from './media_container';
|
||||||
@ -44,6 +39,8 @@ let Edition = React.createClass({
|
|||||||
actionPanelButtonListType: React.PropTypes.func,
|
actionPanelButtonListType: React.PropTypes.func,
|
||||||
furtherDetailsType: React.PropTypes.func,
|
furtherDetailsType: React.PropTypes.func,
|
||||||
edition: React.PropTypes.object,
|
edition: React.PropTypes.object,
|
||||||
|
coaError: React.PropTypes.object,
|
||||||
|
currentUser: React.PropTypes.object,
|
||||||
loadEdition: React.PropTypes.func
|
loadEdition: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -55,32 +52,6 @@ let Edition = React.createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
|
||||||
return UserStore.getState();
|
|
||||||
},
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
UserStore.unlisten(this.onChange);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChange(state) {
|
|
||||||
this.setState(state);
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let FurtherDetailsType = this.props.furtherDetailsType;
|
let FurtherDetailsType = this.props.furtherDetailsType;
|
||||||
|
|
||||||
@ -101,13 +72,15 @@ let Edition = React.createClass({
|
|||||||
<EditionSummary
|
<EditionSummary
|
||||||
actionPanelButtonListType={this.props.actionPanelButtonListType}
|
actionPanelButtonListType={this.props.actionPanelButtonListType}
|
||||||
edition={this.props.edition}
|
edition={this.props.edition}
|
||||||
currentUser={this.state.currentUser}
|
currentUser={this.props.currentUser}
|
||||||
handleSuccess={this.props.loadEdition}/>
|
handleSuccess={this.props.loadEdition}/>
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
title={getLangText('Certificate of Authenticity')}
|
title={getLangText('Certificate of Authenticity')}
|
||||||
show={this.props.edition.acl.acl_coa === true}>
|
show={this.props.edition.acl.acl_coa === true}>
|
||||||
<CoaDetails
|
<CoaDetails
|
||||||
edition={this.props.edition}/>
|
coa={this.props.edition.coa}
|
||||||
|
coaError={this.props.coaError}
|
||||||
|
editionId={this.props.edition.bitcoin_id}/>
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
|
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
@ -133,7 +106,7 @@ let Edition = React.createClass({
|
|||||||
|
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
title="Notes"
|
title="Notes"
|
||||||
show={!!(this.state.currentUser.username
|
show={!!(this.props.currentUser.username
|
||||||
|| this.props.edition.acl.acl_edit
|
|| this.props.edition.acl.acl_edit
|
||||||
|| this.props.edition.public_note)}>
|
|| this.props.edition.public_note)}>
|
||||||
<Note
|
<Note
|
||||||
@ -144,7 +117,7 @@ let Edition = React.createClass({
|
|||||||
editable={true}
|
editable={true}
|
||||||
successMessage={getLangText('Private note saved')}
|
successMessage={getLangText('Private note saved')}
|
||||||
url={ApiUrls.note_private_edition}
|
url={ApiUrls.note_private_edition}
|
||||||
currentUser={this.state.currentUser}/>
|
currentUser={this.props.currentUser}/>
|
||||||
<Note
|
<Note
|
||||||
id={() => {return {'bitcoin_id': this.props.edition.bitcoin_id}; }}
|
id={() => {return {'bitcoin_id': this.props.edition.bitcoin_id}; }}
|
||||||
label={getLangText('Personal note (public)')}
|
label={getLangText('Personal note (public)')}
|
||||||
@ -154,7 +127,7 @@ let Edition = React.createClass({
|
|||||||
show={!!this.props.edition.public_note || !!this.props.edition.acl.acl_edit}
|
show={!!this.props.edition.public_note || !!this.props.edition.acl.acl_edit}
|
||||||
successMessage={getLangText('Public edition note saved')}
|
successMessage={getLangText('Public edition note saved')}
|
||||||
url={ApiUrls.note_public_edition}
|
url={ApiUrls.note_public_edition}
|
||||||
currentUser={this.state.currentUser}/>
|
currentUser={this.props.currentUser}/>
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
title={getLangText('Further Details')}
|
title={getLangText('Further Details')}
|
||||||
@ -246,38 +219,42 @@ let EditionSummary = React.createClass({
|
|||||||
|
|
||||||
let CoaDetails = React.createClass({
|
let CoaDetails = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
edition: React.PropTypes.object
|
editionId: React.PropTypes.string,
|
||||||
|
coa: React.PropTypes.object,
|
||||||
|
coaError: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
contactOnIntercom() {
|
||||||
return CoaStore.getState();
|
window.Intercom('showNewMessage', `Hi, I'm having problems generating a Certificate of Authenticity for Edition: ${this.props.editionId}`);
|
||||||
},
|
console.logGlobal(new Error(`Coa couldn't be created for edition: ${this.props.editionId}`));
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
let { edition } = this.props;
|
|
||||||
CoaStore.listen(this.onChange);
|
|
||||||
if(edition.coa) {
|
|
||||||
CoaActions.fetchOrCreate(edition.coa, edition.bitcoin_id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CoaActions.create(edition.bitcoin_id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
CoaStore.unlisten(this.onChange);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChange(state) {
|
|
||||||
this.setState(state);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if(this.state.coa && this.state.coa.url_safe) {
|
if(this.props.coaError) {
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(this.props.coa && this.props.coa.url_safe) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-center ascribe-button-list">
|
<div
|
||||||
<a href={this.state.coa.url_safe} target="_blank">
|
className="notification-contract-pdf"
|
||||||
|
style={{paddingBottom: '1em'}}>
|
||||||
|
<embed
|
||||||
|
className="embed-form"
|
||||||
|
src={this.props.coa.url_safe}
|
||||||
|
alt="pdf"
|
||||||
|
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
|
||||||
|
</div>
|
||||||
|
<div className="text-center ascribe-button-list">
|
||||||
|
<a href={this.props.coa.url_safe} target="_blank">
|
||||||
<button className="btn btn-default btn-xs">
|
<button className="btn btn-default btn-xs">
|
||||||
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
|
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
|
||||||
</button>
|
</button>
|
||||||
@ -288,19 +265,21 @@ let CoaDetails = React.createClass({
|
|||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if(typeof this.state.coa === 'string'){
|
} else if(typeof this.props.coa === 'string'){
|
||||||
return (
|
return (
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
{this.state.coa}
|
{this.props.coa}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<AscribeSpinner color='dark-blue' size='lg'/>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,16 @@ import { ResourceNotFoundError } from '../../models/errors';
|
|||||||
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';
|
||||||
|
|
||||||
import AscribeSpinner from '../ascribe_spinner';
|
import AscribeSpinner from '../ascribe_spinner';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
import { setDocumentTitle } from '../../utils/dom_utils';
|
import { setDocumentTitle } from '../../utils/dom_utils';
|
||||||
|
import { mergeOptions } from '../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,33 +34,37 @@ let EditionContainer = React.createClass({
|
|||||||
mixins: [History, ReactError],
|
mixins: [History, ReactError],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return EditionStore.getState();
|
return mergeOptions(
|
||||||
|
EditionStore.getState(),
|
||||||
|
UserStore.getState()
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
EditionStore.listen(this.onChange);
|
EditionStore.listen(this.onChange);
|
||||||
|
UserStore.listen(this.onChange);
|
||||||
|
|
||||||
// Every time we're entering the edition detail page,
|
// Every time we're entering the edition detail page,
|
||||||
// just reset the edition that is saved in the edition store
|
// just reset the edition that is saved in the edition store
|
||||||
// as it will otherwise display wrong/old data once the user loads
|
// as it will otherwise display wrong/old data once the user loads
|
||||||
// the edition detail a second time
|
// the edition detail a second time
|
||||||
EditionActions.updateEdition({});
|
EditionActions.flushEdition();
|
||||||
this.loadEdition();
|
EditionActions.fetchEdition(this.props.params.editionId);
|
||||||
|
|
||||||
|
UserActions.fetchCurrentUser();
|
||||||
},
|
},
|
||||||
|
|
||||||
// This is done to update the container when the user clicks on the prev or next
|
// This is done to update the container when the user clicks on the prev or next
|
||||||
// button to update the URL parameter (and therefore to switch pieces)
|
// button to update the URL parameter (and therefore to switch pieces)
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if(this.props.params.editionId !== nextProps.params.editionId) {
|
if(this.props.params.editionId !== nextProps.params.editionId) {
|
||||||
EditionActions.updateEdition({});
|
EditionActions.fetchEdition(this.props.params.editionId);
|
||||||
EditionActions.fetchOne(nextProps.params.editionId);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { editionError } = this.state;
|
const { editionMeta } = this.state;
|
||||||
|
if(editionMeta.err && editionMeta.err.json && editionMeta.err.json.status === 404) {
|
||||||
if(editionError && editionError.status === 404) {
|
|
||||||
this.throws(new ResourceNotFoundError(getLangText("Oops, the edition you're looking for doesn't exist.")));
|
this.throws(new ResourceNotFoundError(getLangText("Oops, the edition you're looking for doesn't exist.")));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -64,34 +72,36 @@ let EditionContainer = React.createClass({
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
window.clearInterval(this.state.timerId);
|
window.clearInterval(this.state.timerId);
|
||||||
EditionStore.unlisten(this.onChange);
|
EditionStore.unlisten(this.onChange);
|
||||||
|
UserStore.unlisten(this.onChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
if (!state.edition.digital_work) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let isEncoding = state.edition.digital_work.isEncoding;
|
|
||||||
if (state.edition.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
|
|
||||||
let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000);
|
|
||||||
this.setState({timerId: timerId});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
loadEdition() {
|
if(state && state.edition && state.edition.digital_work) {
|
||||||
EditionActions.fetchOne(this.props.params.editionId);
|
let isEncoding = state.edition.digital_work.isEncoding;
|
||||||
|
if (state.edition.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
|
||||||
|
let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000);
|
||||||
|
this.setState({timerId: timerId});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if(this.state.edition && this.state.edition.id) {
|
const { edition, currentUser, coaMeta } = this.state;
|
||||||
setDocumentTitle([this.state.edition.artist_name, this.state.edition.title].join(', '));
|
const { actionPanelButtonListType, furtherDetailsType } = this.props;
|
||||||
|
|
||||||
|
if (Object.keys(edition).length && edition.id && currentUser && currentUser.email) {
|
||||||
|
setDocumentTitle([edition.artist_name, edition.title].join(', '));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edition
|
<Edition
|
||||||
actionPanelButtonListType={this.props.actionPanelButtonListType}
|
actionPanelButtonListType={actionPanelButtonListType}
|
||||||
furtherDetailsType={this.props.furtherDetailsType}
|
furtherDetailsType={furtherDetailsType}
|
||||||
edition={this.state.edition}
|
edition={edition}
|
||||||
loadEdition={this.loadEdition} />
|
coaError={coaMeta.err}
|
||||||
|
currentUser={currentUser}
|
||||||
|
loadEdition={() => EditionActions.fetchEdition(this.props.params.editionId)} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
@ -17,7 +17,12 @@ import { setDocumentTitle } from '../utils/dom_utils';
|
|||||||
|
|
||||||
|
|
||||||
let CoaVerifyContainer = React.createClass({
|
let CoaVerifyContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { message, signature } = this.props.location.query;
|
||||||
setDocumentTitle(getLangText('Verify your Certificate of Authenticity'));
|
setDocumentTitle(getLangText('Verify your Certificate of Authenticity'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -27,7 +32,9 @@ let CoaVerifyContainer = React.createClass({
|
|||||||
{getLangText('Verify your Certificate of Authenticity')}
|
{getLangText('Verify your Certificate of Authenticity')}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CoaVerifyForm />
|
<CoaVerifyForm
|
||||||
|
message={message}
|
||||||
|
signature={signature}/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{getLangText('ascribe is using the following public key for verification')}:
|
{getLangText('ascribe is using the following public key for verification')}:
|
||||||
@ -47,6 +54,11 @@ let CoaVerifyContainer = React.createClass({
|
|||||||
|
|
||||||
|
|
||||||
let CoaVerifyForm = React.createClass({
|
let CoaVerifyForm = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
message: React.PropTypes.string,
|
||||||
|
signature: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
handleSuccess(response){
|
handleSuccess(response){
|
||||||
let notification = null;
|
let notification = null;
|
||||||
if (response.verdict) {
|
if (response.verdict) {
|
||||||
@ -56,6 +68,8 @@ let CoaVerifyForm = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { message, signature } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Form
|
<Form
|
||||||
@ -79,6 +93,7 @@ let CoaVerifyForm = React.createClass({
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder={getLangText('Copy paste the message on the bottom of your Certificate of Authenticity')}
|
placeholder={getLangText('Copy paste the message on the bottom of your Certificate of Authenticity')}
|
||||||
autoComplete="on"
|
autoComplete="on"
|
||||||
|
defaultValue={message}
|
||||||
name="username"
|
name="username"
|
||||||
required/>
|
required/>
|
||||||
</Property>
|
</Property>
|
||||||
@ -90,6 +105,7 @@ let CoaVerifyForm = React.createClass({
|
|||||||
<InputTextAreaToggable
|
<InputTextAreaToggable
|
||||||
rows={3}
|
rows={3}
|
||||||
placeholder={getLangText('Copy paste the signature on the bottom of your Certificate of Authenticity')}
|
placeholder={getLangText('Copy paste the signature on the bottom of your Certificate of Authenticity')}
|
||||||
|
defaultValue={signature}
|
||||||
required/>
|
required/>
|
||||||
</Property>
|
</Property>
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import requests from '../utils/requests';
|
|
||||||
|
|
||||||
let CoaFetcher = {
|
|
||||||
/**
|
|
||||||
* Fetch one user from the API.
|
|
||||||
* If no arg is supplied, load the current user
|
|
||||||
*/
|
|
||||||
fetchOne(id) {
|
|
||||||
return requests.get('coa', {'id': id});
|
|
||||||
},
|
|
||||||
create(bitcoinId) {
|
|
||||||
return requests.post('coa_create', {body: {'bitcoin_id': bitcoinId}});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CoaFetcher;
|
|
@ -1,15 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import requests from '../utils/requests';
|
|
||||||
|
|
||||||
let EditionFetcher = {
|
|
||||||
/**
|
|
||||||
* Fetch one user from the API.
|
|
||||||
* If no arg is supplied, load the current user
|
|
||||||
*/
|
|
||||||
fetchOne(editionId) {
|
|
||||||
return requests.get('edition', {'bitcoin_id': editionId});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EditionFetcher;
|
|
27
js/sources/coa_source.js
Normal file
27
js/sources/coa_source.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import requests from '../utils/requests';
|
||||||
|
|
||||||
|
import EditionActions from '../actions/edition_actions';
|
||||||
|
|
||||||
|
|
||||||
|
const CoaSource = {
|
||||||
|
lookupCoa: {
|
||||||
|
remote(state) {
|
||||||
|
return requests.get('coa', { id: state.edition.coa });
|
||||||
|
},
|
||||||
|
|
||||||
|
success: EditionActions.successFetchCoa,
|
||||||
|
error: EditionActions.errorCoa
|
||||||
|
},
|
||||||
|
|
||||||
|
performCreateCoa: {
|
||||||
|
remote(state) {
|
||||||
|
return requests.post('coa_create', {body: { bitcoin_id: state.edition.bitcoin_id }});
|
||||||
|
},
|
||||||
|
success: EditionActions.successFetchCoa,
|
||||||
|
error: EditionActions.errorCoa
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CoaSource;
|
19
js/sources/edition_source.js
Normal file
19
js/sources/edition_source.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import requests from '../utils/requests';
|
||||||
|
|
||||||
|
import EditionActions from '../actions/edition_actions';
|
||||||
|
|
||||||
|
|
||||||
|
const EditionSource = {
|
||||||
|
lookupEdition: {
|
||||||
|
remote(state) {
|
||||||
|
return requests.get('edition', { bitcoin_id: state.editionMeta.idToFetch });
|
||||||
|
},
|
||||||
|
|
||||||
|
success: EditionActions.successFetchEdition,
|
||||||
|
error: EditionActions.errorEdition
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditionSource;
|
@ -1,22 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import { alt } from '../alt';
|
|
||||||
import CoaActions from '../actions/coa_actions';
|
|
||||||
|
|
||||||
|
|
||||||
class CoaStore {
|
|
||||||
constructor() {
|
|
||||||
this.coa = {};
|
|
||||||
this.bindActions(CoaActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
onUpdateCoa(coa) {
|
|
||||||
this.coa = coa;
|
|
||||||
}
|
|
||||||
|
|
||||||
onFlushCoa() {
|
|
||||||
this.coa = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default alt.createStore(CoaStore, 'CoaStore');
|
|
@ -1,23 +1,77 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { alt } from '../alt';
|
import { alt } from '../alt';
|
||||||
|
|
||||||
import EditionActions from '../actions/edition_actions';
|
import EditionActions from '../actions/edition_actions';
|
||||||
|
|
||||||
|
import EditionSource from '../sources/edition_source';
|
||||||
|
import CoaSource from '../sources/coa_source';
|
||||||
|
|
||||||
|
|
||||||
class EditionStore {
|
class EditionStore {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.edition = {};
|
this.edition = {};
|
||||||
this.editionError = null;
|
this.editionMeta = {
|
||||||
|
err: null,
|
||||||
|
idToFetch: null
|
||||||
|
};
|
||||||
|
this.coaMeta = {
|
||||||
|
err: null
|
||||||
|
};
|
||||||
|
|
||||||
this.bindActions(EditionActions);
|
this.bindActions(EditionActions);
|
||||||
|
this.registerAsync(Object.assign(EditionSource, CoaSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateEdition(edition) {
|
onFetchEdition(idToFetch) {
|
||||||
this.edition = edition;
|
this.editionMeta.idToFetch = idToFetch;
|
||||||
this.editionError = null;
|
|
||||||
|
this.getInstance().lookupEdition();
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditionFailed(error) {
|
onSuccessFetchEdition(res) {
|
||||||
this.editionError = error;
|
if(res && res.edition) {
|
||||||
|
this.edition = res.edition;
|
||||||
|
this.editionMeta.err = null;
|
||||||
|
this.editionMeta.idToFetch = null;
|
||||||
|
|
||||||
|
if (this.edition.coa && this.edition.acl.acl_coa &&
|
||||||
|
typeof this.edition.coa.constructor !== Object) {
|
||||||
|
this.getInstance().lookupCoa();
|
||||||
|
} else if(!this.edition.coa && this.edition.acl.acl_coa) {
|
||||||
|
this.getInstance().performCreateCoa();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.editionMeta.err = new Error('Problem fetching the edition');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccessFetchCoa(res) {
|
||||||
|
if (res && res.coa && Object.keys(this.edition).length) {
|
||||||
|
this.edition.coa = res.coa;
|
||||||
|
this.coaMeta.err = null;
|
||||||
|
} else {
|
||||||
|
this.coaMeta.err = new Error('Problem generating/fetching the COA');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFlushEdition() {
|
||||||
|
this.edition = {};
|
||||||
|
this.editionMeta = {
|
||||||
|
err: null,
|
||||||
|
idToFetch: null
|
||||||
|
};
|
||||||
|
this.coaMeta = {
|
||||||
|
err: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onErrorEdition(err) {
|
||||||
|
this.editionMeta.err = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
onErrorCoa(err) {
|
||||||
|
this.coaMeta.err = err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,20 @@ import { argsToQueryParams } from '../utils/url_utils';
|
|||||||
class Requests {
|
class Requests {
|
||||||
unpackResponse(response) {
|
unpackResponse(response) {
|
||||||
if (response.status >= 500) {
|
if (response.status >= 500) {
|
||||||
throw new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url);
|
let err = new Error(response.status + ' - ' + response.statusText + ' - on URL:' + response.url);
|
||||||
|
|
||||||
|
return response
|
||||||
|
.text()
|
||||||
|
.then((resText) => {
|
||||||
|
const resJson = JSON.parse(resText);
|
||||||
|
err = new Error(resJson.errors.pop());
|
||||||
|
|
||||||
|
// ES6 promises don't have a .finally() clause so
|
||||||
|
// we fake that here by forcing the .catch() clause
|
||||||
|
// to run
|
||||||
|
return Promise.reject();
|
||||||
|
})
|
||||||
|
.catch(() => { throw err; });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Q.Promise((resolve, reject) => {
|
return Q.Promise((resolve, reject) => {
|
||||||
@ -50,9 +63,7 @@ class Requests {
|
|||||||
resolve({});
|
resolve({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch(reject);
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user