mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
resolve cluster-merge-fuck
This commit is contained in:
commit
95c199bed6
@ -5,8 +5,9 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<title>ascribe</title>
|
<title>ascribe</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="build/css/main.css">
|
<link rel="stylesheet" href="node_modules/react-datepicker/dist/react-datepicker.css">
|
||||||
<link rel="stylesheet" href="//brick.a.ssl.fastly.net/Source+Sans+Pro:400,600,700,900">
|
<link rel="stylesheet" href="//brick.a.ssl.fastly.net/Source+Sans+Pro:400,600,700,900">
|
||||||
|
<link rel="stylesheet" href="build/css/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="main" class="container clear-paddings"></div>
|
<div id="main" class="container clear-paddings"></div>
|
||||||
|
@ -1,27 +1,66 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import ConsignForm from './ascribe_forms/form_consign';
|
||||||
|
import TransferForm from './ascribe_forms/form_transfer';
|
||||||
|
import LoanForm from './ascribe_forms/form_loan';
|
||||||
|
import ShareForm from './ascribe_forms/form_share_email';
|
||||||
|
import ModalWrapper from './ascribe_modal/modal_wrapper';
|
||||||
import AppConstants from '../constants/application_constants';
|
import AppConstants from '../constants/application_constants';
|
||||||
|
|
||||||
let AclButton = React.createClass({
|
let AclButton = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
|
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
|
||||||
availableAcls: React.PropTypes.array.isRequired,
|
availableAcls: React.PropTypes.array.isRequired,
|
||||||
actionFunction: React.PropTypes.func.isRequired
|
editions: React.PropTypes.array.isRequired,
|
||||||
|
currentUser: React.PropTypes.object,
|
||||||
|
handleSuccess: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
actionFunction() {
|
actionProperties(){
|
||||||
this.props.actionFunction(this.props.action);
|
if (this.props.action == 'consign'){
|
||||||
|
return {
|
||||||
|
title: "Consign artwork",
|
||||||
|
tooltip: "Have someone else sell the artwork",
|
||||||
|
form: <ConsignForm />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.props.action == 'transfer') {
|
||||||
|
return {
|
||||||
|
title: "Transfer artwork",
|
||||||
|
tooltip: "Transfer the ownership of the artwork",
|
||||||
|
form: <TransferForm />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.props.action == 'loan'){
|
||||||
|
return {
|
||||||
|
title: "Loan artwork",
|
||||||
|
tooltip: "Loan your artwork for a limited period of time",
|
||||||
|
form: <LoanForm />}
|
||||||
|
}
|
||||||
|
else if (this.props.action == 'share'){
|
||||||
|
return {
|
||||||
|
title: "Share artwork",
|
||||||
|
tooltip: "Share the artwork",
|
||||||
|
form: <ShareForm />}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1;
|
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1;
|
||||||
|
let aclProps = this.actionProperties();
|
||||||
return (
|
return (
|
||||||
<button
|
<ModalWrapper
|
||||||
type="button"
|
button={
|
||||||
className={shouldDisplay ? 'btn btn-default btn-sm' : 'hidden'}
|
<div className={shouldDisplay ? 'btn btn-default btn-sm' : 'hidden'}>
|
||||||
onClick={this.actionFunction}>
|
|
||||||
{this.props.action.toUpperCase()}
|
{this.props.action.toUpperCase()}
|
||||||
</button>
|
</div>
|
||||||
|
}
|
||||||
|
currentUser={ this.props.currentUser }
|
||||||
|
editions={ this.props.editions }
|
||||||
|
handleSuccess={ this.props.handleSuccess }
|
||||||
|
title={ aclProps.title }
|
||||||
|
tooltip={ aclProps.tooltip }>
|
||||||
|
{ aclProps.form }
|
||||||
|
</ModalWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3,11 +3,11 @@ import React from 'react';
|
|||||||
let ButtonSubmitOrClose = React.createClass({
|
let ButtonSubmitOrClose = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
if (this.props.submitted){
|
if (this.props.submitted){
|
||||||
return (
|
//return (
|
||||||
<div className="modal-footer">
|
// <div className="modal-footer">
|
||||||
Loading
|
// Loading
|
||||||
</div>
|
// </div>
|
||||||
)
|
//)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="modal-footer">
|
<div className="modal-footer">
|
||||||
|
68
js/components/ascribe_forms/form_consign.js
Normal file
68
js/components/ascribe_forms/form_consign.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import FormMixin from '../../mixins/form_mixin';
|
||||||
|
import InputText from './input_text';
|
||||||
|
import InputTextArea from './input_textarea';
|
||||||
|
import ButtonSubmitOrClose from './button_submit_close';
|
||||||
|
|
||||||
|
let ConsignForm = React.createClass({
|
||||||
|
mixins: [FormMixin],
|
||||||
|
|
||||||
|
url() {
|
||||||
|
return ApiUrls.ownership_consigns
|
||||||
|
},
|
||||||
|
getFormData() {
|
||||||
|
return {
|
||||||
|
bitcoin_id: this.getBitcoinIds().join(),
|
||||||
|
consignee: this.refs.consignee.state.value,
|
||||||
|
consign_message: this.refs.consign_message.state.value,
|
||||||
|
password: this.refs.password.state.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
renderForm() {
|
||||||
|
let title = this.getTitlesString().join("");
|
||||||
|
let username = this.props.currentUser.username;
|
||||||
|
let message =
|
||||||
|
`Hi,
|
||||||
|
|
||||||
|
I consign :
|
||||||
|
${title}to you.
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form id="consign_modal_content" role="form" onSubmit={this.submit}>
|
||||||
|
<input className="invisible" type="email" name="fake_consignee"/>
|
||||||
|
<input className="invisible" type="password" name="fake_password"/>
|
||||||
|
<InputText
|
||||||
|
ref="consignee"
|
||||||
|
placeHolder="Consignee email"
|
||||||
|
required="required"
|
||||||
|
type="email"
|
||||||
|
submitted={this.state.submitted}/>
|
||||||
|
<InputTextArea
|
||||||
|
ref="consign_message"
|
||||||
|
defaultValue={message}
|
||||||
|
required=""
|
||||||
|
/>
|
||||||
|
<InputText
|
||||||
|
ref="password"
|
||||||
|
placeHolder="Password"
|
||||||
|
required="required"
|
||||||
|
type="password"
|
||||||
|
submitted={this.state.submitted}/>
|
||||||
|
<ButtonSubmitOrClose
|
||||||
|
text="CONSIGN"
|
||||||
|
onClose={this.props.onRequestHide}
|
||||||
|
submitted={this.state.submitted} />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ConsignForm;
|
137
js/components/ascribe_forms/form_loan.js
Normal file
137
js/components/ascribe_forms/form_loan.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import FormMixin from '../../mixins/form_mixin';
|
||||||
|
import InputText from './input_text';
|
||||||
|
import InputHidden from './input_hidden';
|
||||||
|
import InputCheckbox from './input_checkbox';
|
||||||
|
import InputDate from './input_date';
|
||||||
|
import InputTextArea from './input_textarea';
|
||||||
|
import OwnershipFetcher from '../../fetchers/ownership_fetcher'
|
||||||
|
import ButtonSubmitOrClose from './button_submit_close';
|
||||||
|
|
||||||
|
let LoanForm = React.createClass({
|
||||||
|
mixins: [FormMixin],
|
||||||
|
|
||||||
|
url() {
|
||||||
|
return ApiUrls.ownership_loans
|
||||||
|
},
|
||||||
|
componentDidMount(){
|
||||||
|
this.setState({contract_key: null,
|
||||||
|
contract_url: null,
|
||||||
|
loaneeHasContract: false});
|
||||||
|
},
|
||||||
|
getFormData() {
|
||||||
|
return {
|
||||||
|
bitcoin_id: this.getBitcoinIds().join(),
|
||||||
|
loanee: this.refs.loanee.state.value,
|
||||||
|
gallery_name: this.refs.gallery_name.state.value,
|
||||||
|
startdate: this.refs.startdate.state.value.format("YYYY-MM-DD"),
|
||||||
|
enddate: this.refs.enddate.state.value.format("YYYY-MM-DD"),
|
||||||
|
loan_message: this.refs.loan_message.state.value,
|
||||||
|
password: this.refs.password.state.value,
|
||||||
|
terms: this.refs.terms.state.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleLoanEmailBlur(e){
|
||||||
|
OwnershipFetcher.fetchLoanContract(this.refs.loanee.state.value)
|
||||||
|
.then((res) => {
|
||||||
|
if (res && res.length > 0) {
|
||||||
|
this.setState({contract_key: res[0].s3Key,
|
||||||
|
contract_url: res[0].s3Url,
|
||||||
|
loaneeHasContract: true});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this.resetLoanContract();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
this.resetLoanContract();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetLoanContract(){
|
||||||
|
this.setState({contract_key: null,
|
||||||
|
contract_url: null,
|
||||||
|
loaneeHasContract: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderForm() {
|
||||||
|
let title = this.getTitlesString().join("");
|
||||||
|
let username = this.props.currentUser.username;
|
||||||
|
let message =
|
||||||
|
`Hi,
|
||||||
|
|
||||||
|
I loan :
|
||||||
|
${title}to you.
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
|
let contract = <InputHidden ref="terms" value="True"/>;
|
||||||
|
if (this.state.loaneeHasContract){
|
||||||
|
let label = <div>
|
||||||
|
I agree to the
|
||||||
|
<a href={this.state.contract_url} target="_blank">
|
||||||
|
terms of {this.refs.loanee.state.value}
|
||||||
|
</a>
|
||||||
|
</div>;
|
||||||
|
contract = <InputCheckbox
|
||||||
|
ref="terms"
|
||||||
|
required="required"
|
||||||
|
label={label}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<form id="loan_modal_content" role="form" onSubmit={this.submit}>
|
||||||
|
<input className="invisible" type="email" name="fake_loanee"/>
|
||||||
|
<input className="invisible" type="password" name="fake_password"/>
|
||||||
|
<InputText
|
||||||
|
ref="loanee"
|
||||||
|
placeHolder="Loanee email"
|
||||||
|
required="required"
|
||||||
|
type="email"
|
||||||
|
submitted={this.state.submitted}
|
||||||
|
onBlur={this.handleLoanEmailBlur}/>
|
||||||
|
<InputText
|
||||||
|
ref="gallery_name"
|
||||||
|
placeHolder="Gallery/exhibition (optional)"
|
||||||
|
required=""
|
||||||
|
type="text"
|
||||||
|
submitted={this.state.submitted}/>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-6">
|
||||||
|
<InputDate
|
||||||
|
ref="startdate"
|
||||||
|
placeholderText="Loan start date" />
|
||||||
|
</div>
|
||||||
|
<div className="col-md-6 form-group">
|
||||||
|
<InputDate
|
||||||
|
ref="enddate"
|
||||||
|
placeholderText="Loan end date" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<InputTextArea
|
||||||
|
ref="loan_message"
|
||||||
|
defaultValue={message}
|
||||||
|
required=""
|
||||||
|
/>
|
||||||
|
<InputText
|
||||||
|
ref="password"
|
||||||
|
placeHolder="Password"
|
||||||
|
required="required"
|
||||||
|
type="password"
|
||||||
|
submitted={this.state.submitted}/>
|
||||||
|
{contract}
|
||||||
|
<ButtonSubmitOrClose
|
||||||
|
text="LOAN"
|
||||||
|
onClose={this.props.onRequestHide}
|
||||||
|
submitted={this.state.submitted} />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LoanForm;
|
@ -16,18 +16,23 @@ let ShareForm = React.createClass({
|
|||||||
},
|
},
|
||||||
getFormData() {
|
getFormData() {
|
||||||
return {
|
return {
|
||||||
bitcoin_id: this.props.edition.bitcoin_id,
|
bitcoin_id: this.getBitcoinIds().join(),
|
||||||
share_emails: this.refs.share_emails.state.value,
|
share_emails: this.refs.share_emails.state.value,
|
||||||
share_message: this.refs.share_message.state.value
|
share_message: this.refs.share_message.state.value
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderForm() {
|
renderForm() {
|
||||||
let message = "Hi,\n" +
|
let title = this.getTitlesString().join("");
|
||||||
"\n" +
|
let username = this.props.currentUser.username;
|
||||||
"I am sharing \"" + this.props.edition.title + "\" with you.\n" +
|
let message =
|
||||||
"\n" +
|
`Hi,
|
||||||
"Truly yours,\n" +
|
|
||||||
this.props.currentUser.username;
|
I am sharing :
|
||||||
|
${title}with you.
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="share_modal_content" role="form" key="share_modal_content" onSubmit={this.submit}>
|
<form id="share_modal_content" role="form" key="share_modal_content" onSubmit={this.submit}>
|
||||||
<InputText
|
<InputText
|
||||||
|
@ -18,19 +18,24 @@ let TransferForm = React.createClass({
|
|||||||
},
|
},
|
||||||
getFormData() {
|
getFormData() {
|
||||||
return {
|
return {
|
||||||
bitcoin_id: this.props.edition.bitcoin_id,
|
bitcoin_id: this.getBitcoinIds().join(),
|
||||||
transferee: this.refs.transferee.state.value,
|
transferee: this.refs.transferee.state.value,
|
||||||
transfer_message: this.refs.transfer_message.state.value,
|
transfer_message: this.refs.transfer_message.state.value,
|
||||||
password: this.refs.password.state.value
|
password: this.refs.password.state.value
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderForm() {
|
renderForm() {
|
||||||
let message = "Hi,\n" +
|
let title = this.getTitlesString().join("");
|
||||||
"\n" +
|
let username = this.props.currentUser.username;
|
||||||
"I transfer ownership of \"" + this.props.edition.title + "\" to you.\n" +
|
let message =
|
||||||
"\n" +
|
`Hi,
|
||||||
"Truly yours,\n" +
|
|
||||||
this.props.currentUser.username;
|
I transfer ownership of :
|
||||||
|
${title}to you.
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id="transfer_modal_content" role="form" onSubmit={this.submit}>
|
<form id="transfer_modal_content" role="form" onSubmit={this.submit}>
|
||||||
<input className="invisible" type="email" name="fake_transferee"/>
|
<input className="invisible" type="email" name="fake_transferee"/>
|
||||||
|
58
js/components/ascribe_forms/form_unconsign.js
Normal file
58
js/components/ascribe_forms/form_unconsign.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import FormMixin from '../../mixins/form_mixin';
|
||||||
|
import InputText from './input_text';
|
||||||
|
import InputTextArea from './input_textarea';
|
||||||
|
import ButtonSubmitOrClose from './button_submit_close';
|
||||||
|
|
||||||
|
let UnConsignForm = React.createClass({
|
||||||
|
mixins: [FormMixin],
|
||||||
|
|
||||||
|
url() {
|
||||||
|
return ApiUrls.ownership_unconsigns
|
||||||
|
},
|
||||||
|
getFormData() {
|
||||||
|
return {
|
||||||
|
bitcoin_id: this.props.edition.bitcoin_id,
|
||||||
|
unconsign_message: this.refs.unconsign_message.state.value,
|
||||||
|
password: this.refs.password.state.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderForm() {
|
||||||
|
let title = this.props.edition.title;
|
||||||
|
let username = this.props.currentUser.username;
|
||||||
|
let message =
|
||||||
|
`Hi,
|
||||||
|
|
||||||
|
I un-consign \" ${title} \" from you.
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form id="unconsign_modal_content" role="form" onSubmit={this.submit}>
|
||||||
|
<input className="invisible" type="email" name="fake_unconsignee"/>
|
||||||
|
<input className="invisible" type="password" name="fake_password"/>
|
||||||
|
<InputTextArea
|
||||||
|
ref="unconsign_message"
|
||||||
|
defaultValue={message}
|
||||||
|
required="" />
|
||||||
|
<InputText
|
||||||
|
ref="password"
|
||||||
|
placeHolder="Password"
|
||||||
|
required="required"
|
||||||
|
type="password"
|
||||||
|
submitted={this.state.submitted} />
|
||||||
|
<ButtonSubmitOrClose
|
||||||
|
text="UNCONSIGN"
|
||||||
|
onClose={this.props.onRequestHide}
|
||||||
|
submitted={this.state.submitted} />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UnConsignForm;
|
49
js/components/ascribe_forms/form_unconsign_request.js
Normal file
49
js/components/ascribe_forms/form_unconsign_request.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import FormMixin from '../../mixins/form_mixin';
|
||||||
|
import InputText from './input_text';
|
||||||
|
import InputTextArea from './input_textarea';
|
||||||
|
import ButtonSubmitOrClose from './button_submit_close';
|
||||||
|
|
||||||
|
let UnConsignRequestForm = React.createClass({
|
||||||
|
mixins: [FormMixin],
|
||||||
|
|
||||||
|
url() {
|
||||||
|
return ApiUrls.ownership_unconsigns_request
|
||||||
|
},
|
||||||
|
getFormData() {
|
||||||
|
return {
|
||||||
|
bitcoin_id: this.props.edition.bitcoin_id,
|
||||||
|
unconsign_request_message: this.refs.unconsign_request_message.state.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderForm() {
|
||||||
|
let title = this.props.edition.title;
|
||||||
|
let username = this.props.currentUser.username;
|
||||||
|
let message =
|
||||||
|
`Hi,
|
||||||
|
|
||||||
|
I request you to un-consign \" ${title} \".
|
||||||
|
|
||||||
|
Truly yours,
|
||||||
|
${username}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form id="unconsign_request_modal_content" role="form" onSubmit={this.submit}>
|
||||||
|
<InputTextArea
|
||||||
|
ref="unconsign_request_message"
|
||||||
|
defaultValue={message}
|
||||||
|
required="" />
|
||||||
|
<ButtonSubmitOrClose
|
||||||
|
text="UNCONSIGN REQUEST"
|
||||||
|
onClose={this.props.onRequestHide}
|
||||||
|
submitted={this.state.submitted} />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UnConsignRequestForm;
|
40
js/components/ascribe_forms/input_checkbox.js
Normal file
40
js/components/ascribe_forms/input_checkbox.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import AlertMixin from '../../mixins/alert_mixin'
|
||||||
|
|
||||||
|
let InputCheckbox = React.createClass({
|
||||||
|
|
||||||
|
mixins : [AlertMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {value: null,
|
||||||
|
alerts: null // needed in AlertMixin
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({value: event.target.value});
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
let alerts = (this.props.submitted) ? null : this.state.alerts;
|
||||||
|
return (
|
||||||
|
<div className="form-group">
|
||||||
|
{alerts}
|
||||||
|
<div className="input-checkbox-ascribe">
|
||||||
|
<div className="checkbox">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
required={this.props.required}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
{this.props.label}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default InputCheckbox;
|
51
js/components/ascribe_forms/input_date.js
Normal file
51
js/components/ascribe_forms/input_date.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import AlertMixin from '../../mixins/alert_mixin'
|
||||||
|
import DatePicker from 'react-datepicker/dist/react-datepicker'
|
||||||
|
|
||||||
|
let InputDate = React.createClass({
|
||||||
|
|
||||||
|
mixins : [AlertMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {value: null,
|
||||||
|
alerts: null // needed in AlertMixin
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange(date) {
|
||||||
|
this.setState({value: date});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
let className = "form-control input-text-ascribe";
|
||||||
|
let alerts = (this.props.submitted) ? null : this.state.alerts;
|
||||||
|
return (
|
||||||
|
<DatePicker
|
||||||
|
key="example2"
|
||||||
|
dateFormat="YYYY-MM-DD"
|
||||||
|
selected={this.state.value}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
placeholderText={this.props.placeholderText}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
//return (
|
||||||
|
// <div className="input-group date"
|
||||||
|
// ref={this.props.name + "_picker"}
|
||||||
|
// onChange={this.handleChange}>
|
||||||
|
// <input className={className}
|
||||||
|
// ref={this.props.name}
|
||||||
|
// placeholder={this.props.placeholder}
|
||||||
|
// required={this.props.required}
|
||||||
|
// type="text"/>
|
||||||
|
// <span className="input-group-addon input-text-ascribe">
|
||||||
|
// <span className="glyphicon glyphicon-calendar" style={{"color": "black"}}></span>
|
||||||
|
// </span>
|
||||||
|
// </div>
|
||||||
|
//)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default InputDate;
|
33
js/components/ascribe_forms/input_hidden.js
Normal file
33
js/components/ascribe_forms/input_hidden.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import AlertMixin from '../../mixins/alert_mixin'
|
||||||
|
|
||||||
|
let InputHidden = React.createClass({
|
||||||
|
|
||||||
|
mixins : [AlertMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {value: this.props.value,
|
||||||
|
alerts: null // needed in AlertMixin
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({value: event.target.value});
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
let alerts = (this.props.submitted) ? null : this.state.alerts;
|
||||||
|
return (
|
||||||
|
<div className="form-group">
|
||||||
|
{alerts}
|
||||||
|
<input
|
||||||
|
value={this.props.value}
|
||||||
|
type="hidden"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default InputHidden;
|
@ -8,8 +8,7 @@ let InputText = React.createClass({
|
|||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {value: null,
|
return {value: null,
|
||||||
alerts: null, // needed in AlertMixin
|
alerts: null // needed in AlertMixin
|
||||||
retry: 0 // needed in AlertMixin for generating unique alerts
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
@ -25,7 +24,8 @@ let InputText = React.createClass({
|
|||||||
placeholder={this.props.placeHolder}
|
placeholder={this.props.placeHolder}
|
||||||
required={this.props.required}
|
required={this.props.required}
|
||||||
type={this.props.type}
|
type={this.props.type}
|
||||||
onChange={this.handleChange}/>
|
onChange={this.handleChange}
|
||||||
|
onBlur={this.props.onBlur}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ let InputTextArea = React.createClass({
|
|||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {value: this.props.defaultValue,
|
return {value: this.props.defaultValue,
|
||||||
alerts: null, // needed in AlertMixin
|
alerts: null // needed in AlertMixin
|
||||||
retry: 0 // needed in AlertMixin for generating unique alerts
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
@ -28,7 +27,6 @@ let InputTextArea = React.createClass({
|
|||||||
onChange={this.handleChange}></textarea>
|
onChange={this.handleChange}></textarea>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the component that implements display-specific functionality
|
|
||||||
*/
|
|
||||||
let ImageViewer = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
thumbnail: React.PropTypes.string.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let thumbnail = <img className="img-responsive" src={this.props.thumbnail}/>;
|
|
||||||
let aligner = <span className="vcenter"></span>;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
{aligner}
|
|
||||||
{thumbnail}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ImageViewer;
|
|
40
js/components/ascribe_media/resource_viewer.js
Normal file
40
js/components/ascribe_media/resource_viewer.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the component that implements display-specific functionality.
|
||||||
|
*
|
||||||
|
* ResourceViewer handles the following mimetypes:
|
||||||
|
* - image
|
||||||
|
* - video
|
||||||
|
* - audio
|
||||||
|
* - pdf
|
||||||
|
* - other
|
||||||
|
*/
|
||||||
|
|
||||||
|
let resourceMap = {
|
||||||
|
'image': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
let ResourceViewer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
thumbnail: React.PropTypes.string.isRequired,
|
||||||
|
mimetype: React.PropTypes.oneOf(['image', 'video', 'audio', 'pdf', 'other']).isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [InjectInHeadMixin],
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.inject('http://antani.com');
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
resourceviewer {this.props.thumbnail} {this.props.mimetype}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ResourceViewer;
|
43
js/components/ascribe_modal/modal_loan.js
Normal file
43
js/components/ascribe_modal/modal_loan.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Modal from 'react-bootstrap/lib/Modal';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||||
|
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
||||||
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
|
||||||
|
import LoanForm from '../ascribe_forms/form_loan'
|
||||||
|
import ModalMixin from '../../mixins/modal_mixin'
|
||||||
|
|
||||||
|
let LoanModalButton = React.createClass({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<OverlayTrigger delay={500} placement="left"
|
||||||
|
overlay={<Tooltip>Loan your artwork for a limited period of time</Tooltip>}>
|
||||||
|
<ModalTrigger modal={<LoanModal edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}/>}>
|
||||||
|
<div className="btn btn-ascribe-inv">
|
||||||
|
LOAN
|
||||||
|
</div>
|
||||||
|
</ModalTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let LoanModal = React.createClass({
|
||||||
|
mixins : [ModalMixin],
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal {...this.props} title="Loan artwork">
|
||||||
|
<div className="modal-body">
|
||||||
|
<LoanForm edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
onRequestHide={this.onRequestHide}/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default LoanModalButton;
|
@ -4,6 +4,7 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
|||||||
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
||||||
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
|
||||||
|
import ModalMixin from '../../mixins/modal_mixin'
|
||||||
|
|
||||||
|
|
||||||
import ShareForm from '../ascribe_forms/form_share_email'
|
import ShareForm from '../ascribe_forms/form_share_email'
|
||||||
@ -24,11 +25,8 @@ let ShareModalButton = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ShareModal = React.createClass({
|
let ShareModal = React.createClass({
|
||||||
onRequestHide(e){
|
mixins : [ModalMixin],
|
||||||
if (e)
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onRequestHide();
|
|
||||||
},
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal {...this.props} title="Share artwork">
|
<Modal {...this.props} title="Share artwork">
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import Modal from 'react-bootstrap/lib/Modal';
|
|
||||||
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
|
||||||
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
|
||||||
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
|
||||||
|
|
||||||
import TransferForm from '../ascribe_forms/form_transfer'
|
|
||||||
|
|
||||||
|
|
||||||
let TransferModalButton = React.createClass({
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<OverlayTrigger delay={500} placement="left"
|
|
||||||
overlay={<Tooltip>Transfer the ownership of the artwork</Tooltip>}>
|
|
||||||
<ModalTrigger modal={<TransferModal edition={this.props.edition}
|
|
||||||
currentUser={this.props.currentUser}/>}>
|
|
||||||
<div className="btn btn-ascribe-inv">
|
|
||||||
TRANSFER
|
|
||||||
</div>
|
|
||||||
</ModalTrigger>
|
|
||||||
</OverlayTrigger>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let TransferModal = React.createClass({
|
|
||||||
onRequestHide(e){
|
|
||||||
e.preventDefault();
|
|
||||||
this.props.onRequestHide();
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Modal {...this.props} title="Transfer artwork">
|
|
||||||
<div className="modal-body">
|
|
||||||
<TransferForm edition={this.props.edition}
|
|
||||||
currentUser={this.props.currentUser}
|
|
||||||
onRequestHide={this.onRequestHide}/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
export default TransferModalButton;
|
|
43
js/components/ascribe_modal/modal_unconsign.js
Normal file
43
js/components/ascribe_modal/modal_unconsign.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Modal from 'react-bootstrap/lib/Modal';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||||
|
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
||||||
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
|
||||||
|
import UnConsignForm from '../ascribe_forms/form_unconsign'
|
||||||
|
import ModalMixin from '../../mixins/modal_mixin'
|
||||||
|
|
||||||
|
let UnConsignModalButton = React.createClass({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<OverlayTrigger delay={500} placement="left"
|
||||||
|
overlay={<Tooltip>Unconsign this artwork</Tooltip>}>
|
||||||
|
<ModalTrigger modal={<UnConsignModal edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}/>}>
|
||||||
|
<div className="btn btn-ascribe-inv">
|
||||||
|
UNCONSIGN
|
||||||
|
</div>
|
||||||
|
</ModalTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let UnConsignModal = React.createClass({
|
||||||
|
mixins : [ModalMixin],
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal {...this.props} title="Consign artwork">
|
||||||
|
<div className="modal-body">
|
||||||
|
<UnConsignForm edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
onRequestHide={this.onRequestHide}/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default UnConsignModalButton;
|
43
js/components/ascribe_modal/modal_unconsign_request.js
Normal file
43
js/components/ascribe_modal/modal_unconsign_request.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Modal from 'react-bootstrap/lib/Modal';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||||
|
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
||||||
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
|
||||||
|
import UnConsignRequestForm from '../ascribe_forms/form_unconsign_request'
|
||||||
|
import ModalMixin from '../../mixins/modal_mixin'
|
||||||
|
|
||||||
|
let UnConsignRequestModalButton = React.createClass({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<OverlayTrigger delay={500} placement="left"
|
||||||
|
overlay={<Tooltip>Request to unconsign the artwork</Tooltip>}>
|
||||||
|
<ModalTrigger modal={<UnConsignRequestModal edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}/>}>
|
||||||
|
<div className="btn btn-ascribe-inv">
|
||||||
|
UNCONSIGN REQUEST
|
||||||
|
</div>
|
||||||
|
</ModalTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let UnConsignRequestModal = React.createClass({
|
||||||
|
mixins : [ModalMixin],
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal {...this.props} title="Request to unconsign artwork">
|
||||||
|
<div className="modal-body">
|
||||||
|
<UnConsignRequestForm edition={this.props.edition}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
onRequestHide={this.onRequestHide}/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default UnConsignRequestModalButton;
|
64
js/components/ascribe_modal/modal_wrapper.js
Normal file
64
js/components/ascribe_modal/modal_wrapper.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactAddons from 'react/addons';
|
||||||
|
|
||||||
|
import Modal from 'react-bootstrap/lib/Modal';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||||
|
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
|
||||||
|
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||||
|
|
||||||
|
import ModalMixin from '../../mixins/modal_mixin'
|
||||||
|
|
||||||
|
let ModalWrapper = React.createClass({
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<OverlayTrigger delay={500} placement="left"
|
||||||
|
overlay={<Tooltip>{this.props.tooltip}</Tooltip>}>
|
||||||
|
<ModalTrigger modal={
|
||||||
|
<ModalBody
|
||||||
|
title={this.props.title}
|
||||||
|
editions={this.props.editions}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
handleSuccess={this.props.handleSuccess}
|
||||||
|
>
|
||||||
|
{this.props.children}
|
||||||
|
</ModalBody>
|
||||||
|
}>
|
||||||
|
{this.props.button}
|
||||||
|
</ModalTrigger>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
let ModalBody = React.createClass({
|
||||||
|
mixins : [ModalMixin],
|
||||||
|
|
||||||
|
handleSuccess(){
|
||||||
|
this.props.handleSuccess();
|
||||||
|
this.props.onRequestHide();
|
||||||
|
},
|
||||||
|
renderChildren() {
|
||||||
|
return ReactAddons.Children.map(this.props.children, (child, i) => {
|
||||||
|
return ReactAddons.addons.cloneWithProps(child, {
|
||||||
|
editions: this.props.editions,
|
||||||
|
currentUser: this.props.currentUser,
|
||||||
|
onRequestHide: this.onRequestHide,
|
||||||
|
handleSuccess: this.handleSuccess
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal {...this.props} title={this.props.title}>
|
||||||
|
<div className="modal-body">
|
||||||
|
{this.renderChildren()}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default ModalWrapper;
|
@ -3,6 +3,9 @@ import React from 'react';
|
|||||||
import EditionListStore from '../../stores/edition_list_store';
|
import EditionListStore from '../../stores/edition_list_store';
|
||||||
import EditionListActions from '../../actions/edition_list_actions';
|
import EditionListActions from '../../actions/edition_list_actions';
|
||||||
|
|
||||||
|
import UserActions from '../../actions/user_actions';
|
||||||
|
import UserStore from '../../stores/user_store';
|
||||||
|
|
||||||
import AclButton from '../acl_button';
|
import AclButton from '../acl_button';
|
||||||
import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_selected_editions_widget';
|
import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_selected_editions_widget';
|
||||||
|
|
||||||
@ -20,11 +23,14 @@ let PieceListBulkModal = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
EditionListStore.listen(this.onChange)
|
UserActions.fetchCurrentUser();
|
||||||
|
EditionListStore.listen(this.onChange);
|
||||||
|
UserStore.listen(this.onChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUnmount() {
|
componentDidUnmount() {
|
||||||
EditionListStore.unlisten(this.onChange)
|
EditionListStore.unlisten(this.onChange);
|
||||||
|
UserStore.unlisten(this.onChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
filterForSelected(edition) {
|
filterForSelected(edition) {
|
||||||
@ -75,8 +81,13 @@ let PieceListBulkModal = React.createClass({
|
|||||||
EditionListActions.clearAllEditionSelections();
|
EditionListActions.clearAllEditionSelections();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleSuccess(){
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let availableAcls = this.getAvailableAcls();
|
let availableAcls = this.getAvailableAcls();
|
||||||
|
let selectedEditions = this.fetchSelectedEditionList();
|
||||||
|
|
||||||
if(availableAcls.length > 0) {
|
if(availableAcls.length > 0) {
|
||||||
return (
|
return (
|
||||||
@ -97,10 +108,30 @@ let PieceListBulkModal = React.createClass({
|
|||||||
<p></p>
|
<p></p>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<AclButton availableAcls={availableAcls} action="transfer" actionFunction={this.bulk} />
|
<AclButton
|
||||||
<AclButton availableAcls={availableAcls} action="consign" actionFunction={this.bulk} />
|
availableAcls={availableAcls}
|
||||||
<AclButton availableAcls={availableAcls} action="share" actionFunction={this.bulk} />
|
action="transfer"
|
||||||
<AclButton availableAcls={availableAcls} action="loan" actionFunction={this.bulk} />
|
editions={selectedEditions}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess} />
|
||||||
|
<AclButton
|
||||||
|
availableAcls={availableAcls}
|
||||||
|
action="consign"
|
||||||
|
editions={selectedEditions}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess} />
|
||||||
|
<AclButton
|
||||||
|
availableAcls={availableAcls}
|
||||||
|
action="loan"
|
||||||
|
editions={selectedEditions}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess} />
|
||||||
|
<AclButton
|
||||||
|
availableAcls={availableAcls}
|
||||||
|
action="share"
|
||||||
|
editions={selectedEditions}
|
||||||
|
currentUser={this.state.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ImageViewer from './ascribe_media/image_viewer';
|
|
||||||
import TransferModalButton from './ascribe_modal/modal_transfer';
|
import ResourceViewer from './ascribe_media/resource_viewer';
|
||||||
import ShareModalButton from './ascribe_modal/modal_share';
|
|
||||||
|
import EditionActions from '../actions/edition_actions'
|
||||||
|
import AclButton from './acl_button'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the component that implements display-specific functionality
|
* This is the component that implements display-specific functionality
|
||||||
*/
|
*/
|
||||||
let Edition = React.createClass({
|
let Edition = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
|
let thumbnail = this.props.edition.thumbnail;
|
||||||
|
let mimetype = this.props.edition.digital_work.mime;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="col-md-7">
|
<div className="col-md-7">
|
||||||
<ImageViewer thumbnail={this.props.edition.thumbnail}/>
|
<ResourceViewer thumbnail={thumbnail}
|
||||||
|
mimetype={mimetype}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-5">
|
<div className="col-md-5">
|
||||||
<EditionHeader edition={this.props.edition}/>
|
<EditionHeader edition={this.props.edition}/>
|
||||||
@ -38,6 +45,9 @@ let EditionHeader = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
let EditionDetails = React.createClass({
|
let EditionDetails = React.createClass({
|
||||||
|
handleSuccess(){
|
||||||
|
EditionActions.fetchOne(this.props.edition.id);
|
||||||
|
},
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-detail-header">
|
<div className="ascribe-detail-header">
|
||||||
@ -46,8 +56,20 @@ let EditionDetails = React.createClass({
|
|||||||
<EditionDetailProperty label="id" value={ this.props.edition.bitcoin_id } />
|
<EditionDetailProperty label="id" value={ this.props.edition.bitcoin_id } />
|
||||||
<EditionDetailProperty label="owner" value={ this.props.edition.owner } />
|
<EditionDetailProperty label="owner" value={ this.props.edition.owner } />
|
||||||
<br/>
|
<br/>
|
||||||
<TransferModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>
|
<AclButton
|
||||||
<ShareModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>
|
availableAcls={["transfer"]}
|
||||||
|
action="transfer"
|
||||||
|
editions={[this.props.edition]}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess}
|
||||||
|
/>
|
||||||
|
<AclButton
|
||||||
|
availableAcls={["consign"]}
|
||||||
|
action="consign"
|
||||||
|
editions={[this.props.edition]}
|
||||||
|
currentUser={this.props.currentUser}
|
||||||
|
handleSuccess={this.handleSuccess}
|
||||||
|
/>
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -74,4 +96,3 @@ let EditionDetailProperty = React.createClass({
|
|||||||
|
|
||||||
|
|
||||||
export default Edition;
|
export default Edition;
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ let EditionContainer = React.createClass({
|
|||||||
UserActions.fetchCurrentUser();
|
UserActions.fetchCurrentUser();
|
||||||
UserStore.listen(this.onChange);
|
UserStore.listen(this.onChange);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUnmount() {
|
componentDidUnmount() {
|
||||||
EditionStore.unlisten(this.onChange);
|
EditionStore.unlisten(this.onChange);
|
||||||
UserStore.unlisten(this.onChange);
|
UserStore.unlisten(this.onChange);
|
||||||
|
@ -3,14 +3,15 @@ import AppConstants from './application_constants';
|
|||||||
let apiUrls = {
|
let apiUrls = {
|
||||||
'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/',
|
'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/',
|
||||||
'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/',
|
'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/',
|
||||||
|
|
||||||
'user': AppConstants.baseUrl + 'users/',
|
'user': AppConstants.baseUrl + 'users/',
|
||||||
|
|
||||||
'pieces_list': AppConstants.baseUrl + 'pieces/',
|
'pieces_list': AppConstants.baseUrl + 'pieces/',
|
||||||
'piece': AppConstants.baseUrl + 'pieces/${piece_id}',
|
'piece': AppConstants.baseUrl + 'pieces/${piece_id}',
|
||||||
|
|
||||||
'edition': AppConstants.baseUrl + 'editions/${bitcoin_id}/',
|
'edition': AppConstants.baseUrl + 'editions/${bitcoin_id}/',
|
||||||
'editions_list': AppConstants.baseUrl + 'pieces/${piece_id}/editions/'
|
'editions_list': AppConstants.baseUrl + 'pieces/${piece_id}/editions/',
|
||||||
|
'ownership_loans' : AppConstants.baseUrl + 'ownership/loans/',
|
||||||
|
'ownership_consigns' : AppConstants.baseUrl + 'ownership/consigns/',
|
||||||
|
'ownership_unconsigns' : AppConstants.baseUrl + 'ownership/unconsigns/',
|
||||||
|
'ownership_unconsigns_request' : AppConstants.baseUrl + 'ownership/unconsigns/request/'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default apiUrls;
|
export default apiUrls;
|
||||||
|
24
js/fetchers/ownership_fetcher.js
Normal file
24
js/fetchers/ownership_fetcher.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
|
import AppConstants from '../constants/application_constants';
|
||||||
|
import FetchApiUtils from '../utils/fetch_api_utils';
|
||||||
|
|
||||||
|
|
||||||
|
let OwnershipFetcher = {
|
||||||
|
/**
|
||||||
|
* Fetch one user from the API.
|
||||||
|
* If no arg is supplied, load the current user
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fetchLoanContract(email) {
|
||||||
|
return fetch(AppConstants.baseUrl + 'ownership/loans/contract/?loanee=' + email, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Basic ' + AppConstants.debugCredentialBase64
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
(res) => res.json()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OwnershipFetcher;
|
@ -5,12 +5,15 @@ let AlertMixin = {
|
|||||||
setAlerts(errors){
|
setAlerts(errors){
|
||||||
let alerts = errors.map(
|
let alerts = errors.map(
|
||||||
function(error) {
|
function(error) {
|
||||||
let key = error + this.state.retry;
|
return <AlertDismissable error={error} key={error}/>;
|
||||||
return <AlertDismissable error={error} key={key}/>;
|
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
this.setState({alerts: alerts, retry: this.state.retry + 1});
|
this.setState({alerts: alerts});
|
||||||
|
},
|
||||||
|
clearAlerts(){
|
||||||
|
this.setState({alerts: null});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlertMixin;
|
export default AlertMixin;
|
@ -9,6 +9,7 @@ export const FormMixin = {
|
|||||||
return {
|
return {
|
||||||
submitted: false
|
submitted: false
|
||||||
, status: null
|
, status: null
|
||||||
|
, errors: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -19,7 +20,6 @@ export const FormMixin = {
|
|||||||
.post(this.url(), { body: this.getFormData() })
|
.post(this.url(), { body: this.getFormData() })
|
||||||
.then(response => { this.props.onRequestHide(); })
|
.then(response => { this.props.onRequestHide(); })
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleError(err){
|
handleError(err){
|
||||||
@ -27,12 +27,23 @@ export const FormMixin = {
|
|||||||
for (var input in errors){
|
for (var input in errors){
|
||||||
if (this.refs && this.refs[input] && this.refs[input].state) {
|
if (this.refs && this.refs[input] && this.refs[input].state) {
|
||||||
this.refs[input].setAlerts(errors[input]);
|
this.refs[input].setAlerts(errors[input]);
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({submitted: false});
|
|
||||||
} else {
|
} else {
|
||||||
this.setState({submitted: false, status: response.status});
|
this.setState({errors: this.state.errors.concat(errors[input])});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getBitcoinIds(){
|
||||||
|
return this.props.editions.map(function(edition){
|
||||||
|
return edition.bitcoin_id
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getTitlesString(){
|
||||||
|
return this.props.editions.map(function(edition){
|
||||||
|
return '- \"' + edition.title + ', edition ' + edition.edition_number + '\"\n'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
@ -40,6 +51,13 @@ export const FormMixin = {
|
|||||||
if (this.state.status >= 500){
|
if (this.state.status >= 500){
|
||||||
alert = <AlertDismissable error="Something went wrong, please try again later"/>;
|
alert = <AlertDismissable error="Something went wrong, please try again later"/>;
|
||||||
}
|
}
|
||||||
|
if (this.state.errors.length > 0){
|
||||||
|
alert = this.state.errors.map(
|
||||||
|
function(error) {
|
||||||
|
return <AlertDismissable error={error} key={error}/>;
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{alert}
|
{alert}
|
||||||
|
57
js/mixins/inject_in_head_mixin.js
Normal file
57
js/mixins/inject_in_head_mixin.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
let mapAttr = {
|
||||||
|
link: 'href',
|
||||||
|
source: 'src'
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapExt = {
|
||||||
|
js: 'source',
|
||||||
|
css: 'link'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let InjectInHeadMixin = {
|
||||||
|
/**
|
||||||
|
* Provide functions to inject `<script>` and `<link>` in `<head>`.
|
||||||
|
* Useful when you have to load a huge external library and
|
||||||
|
* you don't want to embed everything inside the build file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
isPresent(tag, src) {
|
||||||
|
let attr = mapAttr[tag];
|
||||||
|
let query = `head > ${tag}[${attr}="${src}"]`;
|
||||||
|
return document.querySelector(query);
|
||||||
|
},
|
||||||
|
|
||||||
|
injectTag(tag, src){
|
||||||
|
console.log(this.foobar);
|
||||||
|
if (InjectInHeadMixin.isPresent(tag, src))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let attr = mapAttr[tag];
|
||||||
|
let element = document.createElement(tag);
|
||||||
|
document.head.appendChild(element);
|
||||||
|
element[attr] = src;
|
||||||
|
},
|
||||||
|
|
||||||
|
injectStylesheet(src) {
|
||||||
|
this.injectTag('link', src);
|
||||||
|
},
|
||||||
|
|
||||||
|
injectScript(src) {
|
||||||
|
this.injectTag('source', src);
|
||||||
|
},
|
||||||
|
|
||||||
|
inject(src) {
|
||||||
|
//debugger;
|
||||||
|
let ext = src.split('.').pop();
|
||||||
|
try {
|
||||||
|
let tag = mapAttr(src);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Cannot inject ${src} in the DOM, cannot guess the tag name from extension ${ext}. Valid extensions are "js" and "css".`);
|
||||||
|
}
|
||||||
|
InjectInHeadMixin.injectTag(tag, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InjectInHeadMixin;
|
11
js/mixins/modal_mixin.js
Normal file
11
js/mixins/modal_mixin.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
let ModalMixin = {
|
||||||
|
onRequestHide(e){
|
||||||
|
if (e)
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onRequestHide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalMixin;
|
@ -4,13 +4,13 @@ import UserAction from '../actions/user_actions';
|
|||||||
|
|
||||||
class UserStore{
|
class UserStore{
|
||||||
constructor() {
|
constructor() {
|
||||||
this.currentUser = {}
|
this.currentUser = {};
|
||||||
this.bindActions(UserAction);
|
this.bindActions(UserAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateCurrentUser(user) {
|
onUpdateCurrentUser(user) {
|
||||||
this.currentUser = user;
|
this.currentUser = user;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default alt.createStore(UserStore);
|
export default alt.createStore(UserStore);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { default as _fetch } from 'isomorphic-fetch';
|
import { default as _fetch } from 'isomorphic-fetch';
|
||||||
|
|
||||||
import { argsToQueryParams } from '../utils/fetch_api_utils';
|
import { argsToQueryParams } from '../utils/fetch_api_utils';
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,9 @@
|
|||||||
"react": "^0.13.2",
|
"react": "^0.13.2",
|
||||||
"react-bootstrap": "~0.22.6",
|
"react-bootstrap": "~0.22.6",
|
||||||
"react-router": "^0.13.3",
|
"react-router": "^0.13.3",
|
||||||
"uglifyjs": "^2.4.10"
|
"uglifyjs": "^2.4.10",
|
||||||
|
"react-bootstrap": "~0.22.6",
|
||||||
|
"react-datepicker": "~0.8.0"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"scriptPreprocessor": "node_modules/babel-jest",
|
"scriptPreprocessor": "node_modules/babel-jest",
|
||||||
|
@ -164,7 +164,8 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-text-ascribe {
|
.input-text-ascribe,
|
||||||
|
.datepicker__input {
|
||||||
border-bottom: 1px solid black;
|
border-bottom: 1px solid black;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
@ -178,6 +179,14 @@
|
|||||||
height: 13em !important;
|
height: 13em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-checkbox-ascribe {
|
||||||
|
text-align: left;
|
||||||
|
line-height: 1.6;
|
||||||
|
width: 90%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* columns of same height styles */
|
/* columns of same height styles */
|
||||||
/* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */
|
/* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */
|
||||||
.row-full-height {
|
.row-full-height {
|
||||||
|
Loading…
Reference in New Issue
Block a user