1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-13 16:45:05 +01:00
This commit is contained in:
ddejongh 2015-06-01 13:02:53 +02:00
parent 2c7535a73a
commit d90a4f97db
12 changed files with 270 additions and 29 deletions

View File

@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="build/css/main.css">
<link rel="stylesheet" href="//brick.a.ssl.fastly.net/Source+Sans+Pro:400,600,700,900">
<link rel="stylesheet" href="node_modules/react-datepicker/dist/react-datepicker.css">
</head>
<body>
<div id="main" class="container"></div>

View File

@ -5,46 +5,122 @@ 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 ConsignForm = React.createClass({
let LoanForm = React.createClass({
mixins: [FormMixin],
url() {
return ApiUrls.ownership_consigns
return ApiUrls.ownership_loans
},
componentDidMount(){
this.setState({contract_key: null,
contract_url: null,
loaneeHasContract: false});
},
getFormData() {
return {
bitcoin_id: this.props.edition.bitcoin_id,
consignee: this.refs.consignee.state.value,
consign_message: this.refs.consign_message.state.value,
password: this.refs.password.state.value
loanee: this.refs.loanee.state.value,
gallery_name: this.refs.gallery_name.state.value,
startdate: this.refs.startdate.state.value,
enddate: this.refs.enddate.state.value,
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.props.edition.title;
let username = this.props.currentUser.username;
let message =
`Hi,
I consign \" ${title} \" to you.
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&nbsp;
<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="consign_modal_content" role="form" onSubmit={this.submit}>
<input className="invisible" type="email" name="fake_consignee"/>
<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="consignee"
placeHolder="Consignee email"
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">
<InputText
ref="startdate"
name="startdate"
placeHolder="Loan start date"
required="required"
type="text"
submitted={this.state.submitted}/>
</div>
<div className="col-md-6 form-group">
<InputText
ref="enddate"
name="enddate"
placeHolder="Loan end date"
required="required"
type="text"
submitted={this.state.submitted}/>
</div>
</div>
<InputTextArea
ref="consign_message"
ref="loan_message"
defaultValue={message}
required=""
/>
@ -54,8 +130,9 @@ ${username}`;
required="required"
type="password"
submitted={this.state.submitted}/>
<ButtonSubmitOrClose
text="CONSIGN"
{contract}
<ButtonSubmitOrClose
text="LOAN"
onClose={this.props.onRequestHide}
submitted={this.state.submitted} />
</form>
@ -63,4 +140,4 @@ ${username}`;
}
});
export default ConsignForm;
export default LoanForm;

View 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;

View File

@ -0,0 +1,53 @@
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: '2015-01-01',
alerts: null // needed in AlertMixin
};
},
handleChange(moment_date) {
this.setState({value: moment_date.format("YYYY-MM-DD")});
},
isValidDate: function (str) {
return (
/^[0-9]{4}$/.test(str) &&
moment(str, 'YYYY-MM-DD').isValid()
);
},
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"
onChange={this.handleChange}
/>
);
//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;

View 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;

View File

@ -24,7 +24,8 @@ let InputText = React.createClass({
placeholder={this.props.placeHolder}
required={this.props.required}
type={this.props.type}
onChange={this.handleChange}/>
onChange={this.handleChange}
onBlur={this.props.onBlur}/>
</div>
);

View File

@ -4,18 +4,18 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import ModalTrigger from 'react-bootstrap/lib/ModalTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
import ConsignForm from '../ascribe_forms/form_consign'
import LoanForm from '../ascribe_forms/form_loan'
import ModalMixin from '../../mixins/modal_mixin'
let ConsignModalButton = React.createClass({
let LoanModalButton = React.createClass({
render() {
return (
<OverlayTrigger delay={500} placement="left"
overlay={<Tooltip>Have someone else sell the artwork</Tooltip>}>
<ModalTrigger modal={<ConsignModal edition={this.props.edition}
currentUser={this.props.currentUser}/>}>
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">
CONSIGN
LOAN
</div>
</ModalTrigger>
</OverlayTrigger>
@ -23,16 +23,16 @@ let ConsignModalButton = React.createClass({
}
});
let ConsignModal = React.createClass({
let LoanModal = React.createClass({
mixins : [ModalMixin],
render() {
return (
<Modal {...this.props} title="Consign artwork">
<Modal {...this.props} title="Loan artwork">
<div className="modal-body">
<ConsignForm edition={this.props.edition}
currentUser={this.props.currentUser}
onRequestHide={this.onRequestHide}/>
<LoanForm edition={this.props.edition}
currentUser={this.props.currentUser}
onRequestHide={this.onRequestHide}/>
</div>
</Modal>
)
@ -40,4 +40,4 @@ let ConsignModal = React.createClass({
});
export default ConsignModalButton;
export default LoanModalButton;

View File

@ -1,6 +1,7 @@
import React from 'react';
import ImageViewer from './ascribe_media/image_viewer';
import LoanModalButton from './ascribe_modal/modal_loan';
import ConsignModalButton from './ascribe_modal/modal_consign';
import UnConsignModalButton from './ascribe_modal/modal_unconsign';
import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request';
@ -50,6 +51,7 @@ let EditionDetails = React.createClass({
<EditionDetailProperty label="id" value={ this.props.edition.bitcoin_id } />
<EditionDetailProperty label="owner" value={ this.props.edition.owner } />
<br/>
<LoanModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>
<ConsignModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>
<UnConsignModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>
<UnConsignRequestModalButton edition={ this.props.edition } currentUser={ this.props.currentUser }/>

View File

@ -3,6 +3,7 @@ import AppConstants from './application_constants';
let apiUrls = {
'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/',
'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/',
'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/'

View 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;

View File

@ -34,7 +34,8 @@
"react": "^0.13.2",
"react-router": "^0.13.3",
"uglifyjs": "^2.4.10",
"react-bootstrap": "~0.22.6"
"react-bootstrap": "~0.22.6",
"react-datepicker": "~0.8.0"
},
"jest": {
"scriptPreprocessor": "node_modules/babel-jest",

View File

@ -163,6 +163,14 @@
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 */
/* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */
.row-full-height {