mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 09:23:13 +01:00
Merge pull request #47 from ascribe/AD-1149-additional-details
AD-1149 Contract agreement in consign forms
This commit is contained in:
commit
c9949f0cc0
@ -22,8 +22,7 @@ class ContractAgreementListActions {
|
||||
if (contractAgreementList.count > 0) {
|
||||
this.actions.updateContractAgreementList(contractAgreementList.results);
|
||||
resolve(contractAgreementList.results);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
})
|
||||
@ -35,13 +34,13 @@ class ContractAgreementListActions {
|
||||
);
|
||||
}
|
||||
|
||||
fetchAvailableContractAgreementList(issuer, createContractAgreement) {
|
||||
fetchAvailableContractAgreementList(issuer, createPublicContractAgreement) {
|
||||
return Q.Promise((resolve, reject) => {
|
||||
OwnershipFetcher.fetchContractAgreementList(issuer, true, null)
|
||||
.then((acceptedContractAgreementList) => {
|
||||
// if there is at least an accepted contract agreement, we're going to
|
||||
// use it
|
||||
if(acceptedContractAgreementList.count > 0) {
|
||||
if (acceptedContractAgreementList.count > 0) {
|
||||
this.actions.updateContractAgreementList(acceptedContractAgreementList.results);
|
||||
} else {
|
||||
// otherwise, we're looking for contract agreements that are still pending
|
||||
@ -50,15 +49,13 @@ class ContractAgreementListActions {
|
||||
// overcomplicate the method
|
||||
OwnershipFetcher.fetchContractAgreementList(issuer, null, true)
|
||||
.then((pendingContractAgreementList) => {
|
||||
if(pendingContractAgreementList.count > 0) {
|
||||
if (pendingContractAgreementList.count > 0) {
|
||||
this.actions.updateContractAgreementList(pendingContractAgreementList.results);
|
||||
} else {
|
||||
} else if (createPublicContractAgreement) {
|
||||
// if there was neither a pending nor an active contractAgreement
|
||||
// found and createContractAgreement is set to true, we create a
|
||||
// new contract agreement
|
||||
if(createContractAgreement) {
|
||||
this.actions.createContractAgreementFromPublicContract(issuer);
|
||||
}
|
||||
// found and createPublicContractAgreement is set to true, we create a
|
||||
// new public contract agreement
|
||||
this.actions.createContractAgreementFromPublicContract(issuer);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
@ -81,8 +78,7 @@ class ContractAgreementListActions {
|
||||
// create an agreement with the public contract if there is one
|
||||
if (publicContract && publicContract.length > 0) {
|
||||
return this.actions.createContractAgreement(null, publicContract[0]);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/*
|
||||
contractAgreementList in the store is already set to null;
|
||||
*/
|
||||
@ -91,21 +87,17 @@ class ContractAgreementListActions {
|
||||
if (publicContracAgreement) {
|
||||
this.actions.updateContractAgreementList([publicContracAgreement]);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.logGlobal(err);
|
||||
});
|
||||
}).catch(console.logGlobal);
|
||||
}
|
||||
|
||||
createContractAgreement(issuer, contract){
|
||||
return Q.Promise((resolve, reject) => {
|
||||
OwnershipFetcher.createContractAgreement(issuer, contract).then(
|
||||
(contractAgreement) => {
|
||||
resolve(contractAgreement);
|
||||
}
|
||||
).catch((err) => {
|
||||
console.logGlobal(err);
|
||||
reject(err);
|
||||
});
|
||||
OwnershipFetcher
|
||||
.createContractAgreement(issuer, contract).then(resolve)
|
||||
.catch((err) => {
|
||||
console.logGlobal(err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ let EditionActionPanel = React.createClass({
|
||||
isInline={true}>
|
||||
<Property
|
||||
name="bitcoin_id"
|
||||
hidden={true}>
|
||||
expanded={false}>
|
||||
<input
|
||||
type="text"
|
||||
value={edition.bitcoin_id}
|
||||
@ -148,7 +148,7 @@ let EditionActionPanel = React.createClass({
|
||||
isInline={true}>
|
||||
<Property
|
||||
name="bitcoin_id"
|
||||
hidden={true}>
|
||||
expanded={false}>
|
||||
<input
|
||||
type="text"
|
||||
value={edition.bitcoin_id}
|
||||
|
@ -124,8 +124,18 @@ let Form = React.createClass({
|
||||
getFormData() {
|
||||
let data = {};
|
||||
|
||||
for (let ref in this.refs) {
|
||||
data[this.refs[ref].props.name] = this.refs[ref].state.value;
|
||||
for (let refName in this.refs) {
|
||||
const ref = this.refs[refName];
|
||||
|
||||
if (ref.state && 'value' in ref.state) {
|
||||
// An input can also provide an `Object` as a value
|
||||
// which we're going to merge with `data` (overwrites)
|
||||
if(ref.state.value.constructor === Object) {
|
||||
Object.assign(data, ref.state.value);
|
||||
} else {
|
||||
data[ref.props.name] = ref.state.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.props.getFormData === 'function') {
|
||||
@ -238,7 +248,15 @@ let Form = React.createClass({
|
||||
renderChildren() {
|
||||
return ReactAddons.Children.map(this.props.children, (child, i) => {
|
||||
if (child) {
|
||||
return ReactAddons.addons.cloneWithProps(child, {
|
||||
// Since refs will be overwritten by this functions return statement,
|
||||
// we still want to be able to define refs for nested `Form` or `Property`
|
||||
// children, which is why we're upfront simply invoking the callback-ref-
|
||||
// function before overwriting it.
|
||||
if(typeof child.ref === 'function' && this.refs[child.props.name]) {
|
||||
child.ref(this.refs[child.props.name]);
|
||||
}
|
||||
|
||||
return React.cloneElement(child, {
|
||||
handleChange: this.handleChangeChild,
|
||||
ref: child.props.name,
|
||||
key: i,
|
||||
|
@ -6,9 +6,13 @@ import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
|
||||
import InputContractAgreementCheckbox from './input_contract_agreement_checkbox';
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
|
||||
|
||||
import AscribeSpinner from '../ascribe_spinner';
|
||||
|
||||
import AclInformation from '../ascribe_buttons/acl_information';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
@ -21,6 +25,7 @@ let ConsignForm = React.createClass({
|
||||
email: React.PropTypes.string,
|
||||
message: React.PropTypes.string,
|
||||
labels: React.PropTypes.object,
|
||||
createPublicContractAgreement: React.PropTypes.bool,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
@ -30,12 +35,34 @@ let ConsignForm = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
email: this.props.email
|
||||
};
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return this.props.id;
|
||||
},
|
||||
|
||||
handleEmailOnChange(event) {
|
||||
// event.target.value is the submitted email of the consignee
|
||||
this.setState({
|
||||
email: event && event.target && event.target.value || ''
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
const { autoFocusProperty, email, id, handleSuccess, message, labels, url } = this.props;
|
||||
const { email } = this.state;
|
||||
const {
|
||||
autoFocusProperty,
|
||||
createPublicContractAgreement,
|
||||
email: defaultEmail,
|
||||
handleSuccess,
|
||||
id,
|
||||
message,
|
||||
labels,
|
||||
url } = this.props;
|
||||
|
||||
return (
|
||||
<Form
|
||||
@ -64,12 +91,13 @@ let ConsignForm = React.createClass({
|
||||
autoFocus={autoFocusProperty === 'email'}
|
||||
name='consignee'
|
||||
label={labels.email || getLangText('Email')}
|
||||
editable={!email}
|
||||
overrideForm={!!email}>
|
||||
editable={!defaultEmail}
|
||||
onChange={this.handleEmailOnChange}
|
||||
overrideForm={!!defaultEmail}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
placeholder={getLangText('Email of the consignee')}
|
||||
defaultValue={email}
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
@ -84,6 +112,15 @@ let ConsignForm = React.createClass({
|
||||
placeholder={getLangText('Enter a message...')}
|
||||
required />
|
||||
</Property>
|
||||
<Property
|
||||
name='contract_agreement'
|
||||
label={getLangText('Consign Contract')}
|
||||
className="ascribe-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputContractAgreementCheckbox
|
||||
createPublicContractAgreement={createPublicContractAgreement}
|
||||
email={email} />
|
||||
</Property>
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}>
|
||||
|
@ -91,14 +91,14 @@ let CreateContractForm = React.createClass({
|
||||
<Property
|
||||
name='name'
|
||||
label={getLangText('Contract name')}
|
||||
hidden={true}>
|
||||
expanded={false}>
|
||||
<input
|
||||
type="text"
|
||||
value={this.state.contractName}/>
|
||||
</Property>
|
||||
<Property
|
||||
name="is_public"
|
||||
hidden={true}>
|
||||
expanded={false}>
|
||||
<input
|
||||
type="checkbox"
|
||||
value={this.props.isPublic} />
|
||||
|
@ -1,33 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
import InputDate from './input_date';
|
||||
import InputCheckbox from './input_checkbox';
|
||||
|
||||
import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
|
||||
import ContractAgreementListActions from '../../actions/contract_agreement_list_actions';
|
||||
import InputDate from './input_date';
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
import InputContractAgreementCheckbox from './input_contract_agreement_checkbox';
|
||||
|
||||
import AscribeSpinner from '../ascribe_spinner';
|
||||
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import AclInformation from '../ascribe_buttons/acl_information';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
|
||||
|
||||
let LoanForm = React.createClass({
|
||||
propTypes: {
|
||||
loanHeading: React.PropTypes.string,
|
||||
email: React.PropTypes.string,
|
||||
gallery: React.PropTypes.string,
|
||||
startdate: React.PropTypes.object,
|
||||
enddate: React.PropTypes.object,
|
||||
startDate: React.PropTypes.object,
|
||||
endDate: React.PropTypes.object,
|
||||
showPersonalMessage: React.PropTypes.bool,
|
||||
showEndDate: React.PropTypes.bool,
|
||||
showStartDate: React.PropTypes.bool,
|
||||
@ -36,7 +37,11 @@ let LoanForm = React.createClass({
|
||||
id: React.PropTypes.object,
|
||||
message: React.PropTypes.string,
|
||||
createPublicContractAgreement: React.PropTypes.bool,
|
||||
handleSuccess: React.PropTypes.func
|
||||
handleSuccess: React.PropTypes.func,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.object,
|
||||
React.PropTypes.array
|
||||
])
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
@ -45,148 +50,33 @@ let LoanForm = React.createClass({
|
||||
showPersonalMessage: true,
|
||||
showEndDate: true,
|
||||
showStartDate: true,
|
||||
showPassword: true,
|
||||
createPublicContractAgreement: true
|
||||
showPassword: true
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return ContractAgreementListStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
ContractAgreementListStore.listen(this.onChange);
|
||||
this.getContractAgreementsOrCreatePublic(this.props.email);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method needs to be in form_loan as some whitelabel pages (Cyland) load
|
||||
* the loanee's email async!
|
||||
*
|
||||
* SO LEAVE IT IN!
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(nextProps && nextProps.email && this.props.email !== nextProps.email) {
|
||||
this.getContractAgreementsOrCreatePublic(nextProps.email);
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
ContractAgreementListStore.unlisten(this.onChange);
|
||||
return {
|
||||
email: this.props.email || ''
|
||||
};
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
getContractAgreementsOrCreatePublic(email){
|
||||
ContractAgreementListActions.flushContractAgreementList.defer();
|
||||
if (email) {
|
||||
// fetch the available contractagreements (pending/accepted)
|
||||
ContractAgreementListActions.fetchAvailableContractAgreementList(email, true);
|
||||
}
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return mergeOptions(
|
||||
this.props.id,
|
||||
this.getContractAgreementId()
|
||||
);
|
||||
},
|
||||
|
||||
handleOnChange(event) {
|
||||
handleEmailOnChange(event) {
|
||||
// event.target.value is the submitted email of the loanee
|
||||
if(event && event.target && event.target.value && event.target.value.match(/.*@.*\..*/)) {
|
||||
this.getContractAgreementsOrCreatePublic(event.target.value);
|
||||
} else {
|
||||
ContractAgreementListActions.flushContractAgreementList();
|
||||
}
|
||||
this.setState({
|
||||
email: event && event.target && event.target.value || ''
|
||||
});
|
||||
},
|
||||
|
||||
getContractAgreementId() {
|
||||
if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
|
||||
return {'contract_agreement_id': this.state.contractAgreementList[0].id};
|
||||
}
|
||||
return {};
|
||||
handleReset() {
|
||||
this.handleEmailOnChange();
|
||||
},
|
||||
|
||||
getContractCheckbox() {
|
||||
if(this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
|
||||
// we need to define a key on the InputCheckboxes as otherwise
|
||||
// react is not rerendering them on a store switch and is keeping
|
||||
// the default value of the component (which is in that case true)
|
||||
let contractAgreement = this.state.contractAgreementList[0];
|
||||
let contract = contractAgreement.contract;
|
||||
|
||||
if(contractAgreement.datetime_accepted) {
|
||||
return (
|
||||
<Property
|
||||
name="terms"
|
||||
label={getLangText('Loan Contract')}
|
||||
hidden={false}
|
||||
className="notification-contract-pdf">
|
||||
<embed
|
||||
className="loan-form"
|
||||
src={contract.blob.url_safe}
|
||||
alt="pdf"
|
||||
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
|
||||
<a href={contract.blob.url_safe} target="_blank">
|
||||
<span className="glyphicon glyphicon-download" aria-hidden="true"></span> {getLangText('Download contract')}
|
||||
</a>
|
||||
{/* We still need to send the server information that we're accepting */}
|
||||
<InputCheckbox
|
||||
style={{'display': 'none'}}
|
||||
key="terms_implicitly"
|
||||
defaultChecked={true} />
|
||||
</Property>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Property
|
||||
name="terms"
|
||||
className="ascribe-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputCheckbox
|
||||
key="terms_explicitly"
|
||||
defaultChecked={false}>
|
||||
<span>
|
||||
{getLangText('I agree to the')}
|
||||
<a href={contract.blob.url_safe} target="_blank">
|
||||
{getLangText('terms of ')} {contract.issuer}
|
||||
</a>
|
||||
</span>
|
||||
</InputCheckbox>
|
||||
</Property>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<Property
|
||||
name="terms"
|
||||
style={{paddingBottom: 0}}
|
||||
hidden={true}>
|
||||
<InputCheckbox
|
||||
key="terms_implicitly"
|
||||
defaultChecked={true} />
|
||||
</Property>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getAppendix() {
|
||||
if(this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
|
||||
let appendix = this.state.contractAgreementList[0].appendix;
|
||||
if (appendix && appendix.default) {
|
||||
return (
|
||||
<Property
|
||||
name='appendix'
|
||||
label={getLangText('Appendix')}>
|
||||
<pre className="ascribe-pre">{appendix.default}</pre>
|
||||
</Property>
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
getFormData() {
|
||||
return this.props.id;
|
||||
},
|
||||
|
||||
getButtons() {
|
||||
@ -214,14 +104,31 @@ let LoanForm = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { email } = this.state;
|
||||
const {
|
||||
children,
|
||||
createPublicContractAgreement,
|
||||
email: defaultEmail,
|
||||
handleSuccess,
|
||||
gallery,
|
||||
loanHeading,
|
||||
message,
|
||||
showPersonalMessage,
|
||||
endDate,
|
||||
startDate,
|
||||
showEndDate,
|
||||
showStartDate,
|
||||
showPassword,
|
||||
url } = this.props;
|
||||
|
||||
return (
|
||||
<Form
|
||||
className={classnames({'ascribe-form-bordered': this.props.loanHeading})}
|
||||
className={classnames({'ascribe-form-bordered': loanHeading})}
|
||||
ref='form'
|
||||
url={this.props.url}
|
||||
url={url}
|
||||
getFormData={this.getFormData}
|
||||
onReset={this.handleOnChange}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
onReset={this.handleReset}
|
||||
handleSuccess={handleSuccess}
|
||||
buttons={this.getButtons()}
|
||||
spinner={
|
||||
<div className="modal-footer">
|
||||
@ -229,18 +136,18 @@ let LoanForm = React.createClass({
|
||||
<AscribeSpinner color='dark-blue' size='md'/>
|
||||
</p>
|
||||
</div>}>
|
||||
<div className={classnames({'ascribe-form-header': true, 'hidden': !this.props.loanHeading})}>
|
||||
<h3>{this.props.loanHeading}</h3>
|
||||
<div className={classnames({'ascribe-form-header': true, 'hidden': !loanHeading})}>
|
||||
<h3>{loanHeading}</h3>
|
||||
</div>
|
||||
<AclInformation aim={'form'} verbs={['acl_loan']}/>
|
||||
<Property
|
||||
name='loanee'
|
||||
label={getLangText('Loanee Email')}
|
||||
editable={!this.props.email}
|
||||
onChange={this.handleOnChange}
|
||||
overrideForm={!!this.props.email}>
|
||||
editable={!defaultEmail}
|
||||
onChange={this.handleEmailOnChange}
|
||||
overrideForm={!!defaultEmail}>
|
||||
<input
|
||||
value={this.props.email}
|
||||
value={email}
|
||||
type="email"
|
||||
placeholder={getLangText('Email of the loanee')}
|
||||
required/>
|
||||
@ -248,31 +155,31 @@ let LoanForm = React.createClass({
|
||||
<Property
|
||||
name='gallery'
|
||||
label={getLangText('Gallery/exhibition (optional)')}
|
||||
editable={!this.props.gallery}
|
||||
overrideForm={!!this.props.gallery}>
|
||||
editable={!gallery}
|
||||
overrideForm={!!gallery}>
|
||||
<input
|
||||
value={this.props.gallery}
|
||||
value={gallery}
|
||||
type="text"
|
||||
placeholder={getLangText('Gallery/exhibition (optional)')}/>
|
||||
</Property>
|
||||
<Property
|
||||
name='startdate'
|
||||
label={getLangText('Start date')}
|
||||
editable={!this.props.startdate}
|
||||
overrideForm={!!this.props.startdate}
|
||||
hidden={!this.props.showStartDate}>
|
||||
editable={!startDate}
|
||||
overrideForm={!!startDate}
|
||||
expanded={showStartDate}>
|
||||
<InputDate
|
||||
defaultValue={this.props.startdate}
|
||||
defaultValue={startDate}
|
||||
placeholderText={getLangText('Loan start date')} />
|
||||
</Property>
|
||||
<Property
|
||||
name='enddate'
|
||||
editable={!this.props.enddate}
|
||||
overrideForm={!!this.props.enddate}
|
||||
editable={!endDate}
|
||||
overrideForm={!!endDate}
|
||||
label={getLangText('End date')}
|
||||
hidden={!this.props.showEndDate}>
|
||||
expanded={showEndDate}>
|
||||
<InputDate
|
||||
defaultValue={this.props.enddate}
|
||||
defaultValue={endDate}
|
||||
placeholderText={getLangText('Loan end date')} />
|
||||
</Property>
|
||||
<Property
|
||||
@ -280,25 +187,32 @@ let LoanForm = React.createClass({
|
||||
label={getLangText('Personal Message')}
|
||||
editable={true}
|
||||
overrideForm={true}
|
||||
hidden={!this.props.showPersonalMessage}>
|
||||
expanded={showPersonalMessage}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.message}
|
||||
defaultValue={message}
|
||||
placeholder={getLangText('Enter a message...')}
|
||||
required={this.props.showPersonalMessage}/>
|
||||
required={showPersonalMessage}/>
|
||||
</Property>
|
||||
<Property
|
||||
name='contract_agreement'
|
||||
label={getLangText('Loan Contract')}
|
||||
className="ascribe-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputContractAgreementCheckbox
|
||||
createPublicContractAgreement={createPublicContractAgreement}
|
||||
email={email} />
|
||||
</Property>
|
||||
{this.getContractCheckbox()}
|
||||
{this.getAppendix()}
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}
|
||||
hidden={!this.props.showPassword}>
|
||||
expanded={showPassword}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Enter your password')}
|
||||
required={this.props.showPassword ? 'required' : ''}/>
|
||||
required={showPassword ? 'required' : ''}/>
|
||||
</Property>
|
||||
{this.props.children}
|
||||
{children}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ let LoanRequestAnswerForm = React.createClass({
|
||||
url={this.props.url}
|
||||
email={this.state.loanRequest ? this.state.loanRequest.new_owner : null}
|
||||
gallery={this.state.loanRequest ? this.state.loanRequest.gallery : null}
|
||||
startdate={startDate}
|
||||
enddate={endDate}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
showPassword={true}
|
||||
showPersonalMessage={false}
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
@ -76,4 +76,4 @@ let LoanRequestAnswerForm = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
export default LoanRequestAnswerForm;
|
||||
export default LoanRequestAnswerForm;
|
||||
|
@ -21,7 +21,7 @@ import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
|
||||
|
||||
let ContractAgreementForm = React.createClass({
|
||||
let SendContractAgreementForm = React.createClass({
|
||||
propTypes: {
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
@ -55,7 +55,7 @@ let ContractAgreementForm = React.createClass({
|
||||
},
|
||||
|
||||
handleSubmitSuccess() {
|
||||
let notification = 'Contract agreement send';
|
||||
let notification = 'Contract agreement sent';
|
||||
notification = new GlobalNotificationModel(notification, 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
@ -148,4 +148,4 @@ let ContractAgreementForm = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
export default ContractAgreementForm;
|
||||
export default SendContractAgreementForm;
|
201
js/components/ascribe_forms/input_contract_agreement_checkbox.js
Normal file
201
js/components/ascribe_forms/input_contract_agreement_checkbox.js
Normal file
@ -0,0 +1,201 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react/addons';
|
||||
|
||||
import InputCheckbox from './input_checkbox';
|
||||
|
||||
import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
|
||||
import ContractAgreementListActions from '../../actions/contract_agreement_list_actions';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
import { isEmail } from '../../utils/regex_utils';
|
||||
|
||||
|
||||
const InputContractAgreementCheckbox = React.createClass({
|
||||
propTypes: {
|
||||
createPublicContractAgreement: React.PropTypes.bool,
|
||||
email: React.PropTypes.string,
|
||||
|
||||
required: React.PropTypes.bool,
|
||||
|
||||
// provided by Property
|
||||
disabled: React.PropTypes.bool,
|
||||
onChange: React.PropTypes.func,
|
||||
name: React.PropTypes.string,
|
||||
setExpanded: React.PropTypes.func,
|
||||
|
||||
// can be used to style the component from the outside
|
||||
style: React.PropTypes.object
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
createPublicContractAgreement: true
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions(
|
||||
ContractAgreementListStore.getState(),
|
||||
{
|
||||
value: {
|
||||
terms: null,
|
||||
contract_agreement_id: null
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
ContractAgreementListStore.listen(this.onStoreChange);
|
||||
this.getContractAgreementsOrCreatePublic(this.props.email);
|
||||
},
|
||||
|
||||
componentWillReceiveProps({ email: nextEmail }) {
|
||||
const { contractAgreementList } = this.state;
|
||||
|
||||
if (this.props.email !== nextEmail) {
|
||||
if (isEmail(nextEmail)) {
|
||||
this.getContractAgreementsOrCreatePublic(nextEmail);
|
||||
} else if (contractAgreementList && contractAgreementList.length > 0) {
|
||||
ContractAgreementListActions.flushContractAgreementList();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
ContractAgreementListStore.unlisten(this.onStoreChange);
|
||||
},
|
||||
|
||||
onStoreChange(state) {
|
||||
const contractAgreement = this.getContractAgreement(state.contractAgreementList);
|
||||
this.props.setExpanded(!!contractAgreement);
|
||||
|
||||
state = mergeOptions(state, {
|
||||
value: {
|
||||
// If `email` is defined in this component, `getContractAgreementsOrCreatePublic`
|
||||
// is either:
|
||||
//
|
||||
// - fetching a already existing contract agreement; or
|
||||
// - trying to create a contract agreement
|
||||
//
|
||||
// If both attempts result in `contractAgreement` being not defined,
|
||||
// it means that the receiver hasn't defined a contract, which means
|
||||
// a contract agreement cannot be created, which means we don't have to
|
||||
// specify `contract_agreement_id` when sending a request to the server.
|
||||
contract_agreement_id: contractAgreement ? contractAgreement.id : null,
|
||||
// If the receiver hasn't set a contract or the contract was
|
||||
// previously accepted, we set the terms to `true`
|
||||
// as we always need to at least give a boolean value for `terms`
|
||||
// to the API endpoint
|
||||
terms: !contractAgreement || !!contractAgreement.datetime_accepted
|
||||
}
|
||||
});
|
||||
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
onChange(event) {
|
||||
this.setState({
|
||||
value: React.addons.update(this.state.value, {
|
||||
terms: { $set: event.target.value }
|
||||
})
|
||||
});
|
||||
this.props.onChange(event);
|
||||
},
|
||||
|
||||
getContractAgreement(contractAgreementList = this.state.contractAgreementList) {
|
||||
if (contractAgreementList && contractAgreementList.length > 0) {
|
||||
return contractAgreementList[0];
|
||||
}
|
||||
},
|
||||
|
||||
getContractAgreementsOrCreatePublic(email) {
|
||||
ContractAgreementListActions.flushContractAgreementList.defer();
|
||||
|
||||
if (email) {
|
||||
// fetch the available contractagreements (pending/accepted)
|
||||
ContractAgreementListActions.fetchAvailableContractAgreementList(email, this.props.createPublicContractAgreement);
|
||||
}
|
||||
},
|
||||
|
||||
getAppendix() {
|
||||
const contractAgreement = this.getContractAgreement();
|
||||
|
||||
if (contractAgreement &&
|
||||
contractAgreement.appendix &&
|
||||
contractAgreement.appendix.default) {
|
||||
return (
|
||||
<div className="ascribe-property contract-appendix-form">
|
||||
<p><span>{getLangText('Appendix')}</span></p>
|
||||
<pre className="ascribe-pre">{contractAgreement.appendix.default}</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getContractCheckbox() {
|
||||
const contractAgreement = this.getContractAgreement();
|
||||
|
||||
if(contractAgreement) {
|
||||
const {
|
||||
datetime_accepted: datetimeAccepted,
|
||||
contract: {
|
||||
issuer: contractIssuer,
|
||||
blob: { url_safe: contractUrl }
|
||||
}
|
||||
} = contractAgreement;
|
||||
|
||||
if(datetimeAccepted) {
|
||||
return (
|
||||
<div
|
||||
className="notification-contract-pdf"
|
||||
style={{paddingBottom: '1em'}}>
|
||||
<embed
|
||||
className="embed-form"
|
||||
src={contractUrl}
|
||||
alt="pdf"
|
||||
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
|
||||
<a href={contractUrl} target="_blank">
|
||||
<span className="glyphicon glyphicon-download" aria-hidden="true" /> {getLangText('Download contract')}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
const {
|
||||
name,
|
||||
disabled,
|
||||
style } = this.props;
|
||||
|
||||
return (
|
||||
<InputCheckbox
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
onChange={this.onChange}
|
||||
key="terms_explicitly"
|
||||
defaultChecked={false}>
|
||||
<span>
|
||||
{getLangText('I agree to the')}
|
||||
<a href={contractUrl} target="_blank">
|
||||
{getLangText('terms of ')} {contractIssuer}
|
||||
</a>
|
||||
</span>
|
||||
</InputCheckbox>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.getContractCheckbox()}
|
||||
{this.getAppendix()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default InputContractAgreementCheckbox;
|
@ -3,62 +3,69 @@
|
||||
import React from 'react';
|
||||
import ReactAddons from 'react/addons';
|
||||
|
||||
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||
import Panel from 'react-bootstrap/lib/Panel';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
|
||||
|
||||
let Property = React.createClass({
|
||||
propTypes: {
|
||||
hidden: React.PropTypes.bool,
|
||||
const { bool, element, string, oneOfType, func, object, arrayOf } = React.PropTypes;
|
||||
|
||||
autoFocus: React.PropTypes.bool,
|
||||
editable: React.PropTypes.bool,
|
||||
const Property = React.createClass({
|
||||
propTypes: {
|
||||
editable: bool,
|
||||
|
||||
// If we want Form to have a different value for disabled as Property has one for
|
||||
// editable, we need to set overrideForm to true, as it will then override Form's
|
||||
// disabled value for individual Properties
|
||||
overrideForm: React.PropTypes.bool,
|
||||
overrideForm: bool,
|
||||
|
||||
tooltip: React.PropTypes.element,
|
||||
label: React.PropTypes.string,
|
||||
value: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.element
|
||||
label: string,
|
||||
value: oneOfType([
|
||||
string,
|
||||
element
|
||||
]),
|
||||
footer: React.PropTypes.element,
|
||||
handleChange: React.PropTypes.func,
|
||||
ignoreFocus: React.PropTypes.bool,
|
||||
name: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.number
|
||||
]).isRequired,
|
||||
className: React.PropTypes.string,
|
||||
footer: element,
|
||||
handleChange: func,
|
||||
ignoreFocus: bool,
|
||||
name: string.isRequired,
|
||||
className: string,
|
||||
|
||||
onClick: React.PropTypes.func,
|
||||
onChange: React.PropTypes.func,
|
||||
onBlur: React.PropTypes.func,
|
||||
onClick: func,
|
||||
onChange: func,
|
||||
onBlur: func,
|
||||
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
React.PropTypes.element
|
||||
children: oneOfType([
|
||||
arrayOf(element),
|
||||
element
|
||||
]),
|
||||
style: React.PropTypes.object
|
||||
style: object,
|
||||
expanded: bool,
|
||||
checkboxLabel: string,
|
||||
autoFocus: bool
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
editable: true,
|
||||
hidden: false,
|
||||
expanded: true,
|
||||
className: ''
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
const { expanded, ignoreFocus, checkboxLabel } = this.props;
|
||||
|
||||
return {
|
||||
// We're mirroring expanded here as a state
|
||||
// React's docs do NOT consider this an antipattern as long as it's
|
||||
// not a "source of truth"-duplication
|
||||
expanded,
|
||||
|
||||
// When a checkboxLabel is defined in the props, we want to set
|
||||
// `ignoreFocus` to true
|
||||
ignoreFocus: ignoreFocus || checkboxLabel,
|
||||
// Please don't confuse initialValue with react's defaultValue.
|
||||
// initialValue is set by us to ensure that a user can reset a specific
|
||||
// property (after editing) to its initial value
|
||||
@ -70,14 +77,26 @@ let Property = React.createClass({
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.autoFocus) {
|
||||
if(this.props.autoFocus) {
|
||||
this.handleFocus();
|
||||
}
|
||||
},
|
||||
|
||||
componentWillReceiveProps() {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let childInput = this.refs.input;
|
||||
|
||||
// For expanded there are actually three use cases:
|
||||
//
|
||||
// 1. Control its value from the outside completely (do not define `checkboxLabel`)
|
||||
// 2. Let it be controlled from the inside (default value can be set though via `expanded`)
|
||||
// 3. Let it be controlled from a child by using `setExpanded` (`expanded` must not be
|
||||
// set from the outside as a prop then(!!!))
|
||||
//
|
||||
// This handles case 1. and 3.
|
||||
if(nextProps.expanded !== this.props.expanded && nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
|
||||
this.setState({ expanded: nextProps.expanded });
|
||||
}
|
||||
|
||||
// In order to set this.state.value from another component
|
||||
// the state of value should only be set if its not undefined and
|
||||
// actually references something
|
||||
@ -90,13 +109,13 @@ let Property = React.createClass({
|
||||
// from native HTML elements.
|
||||
// To enable developers to create input elements, they can expose a property called value
|
||||
// in their state that will be picked up by property.js
|
||||
} else if(childInput.state && typeof childInput.state.value !== 'undefined') {
|
||||
} else if(childInput && childInput.state && typeof childInput.state.value !== 'undefined') {
|
||||
this.setState({
|
||||
value: childInput.state.value
|
||||
});
|
||||
}
|
||||
|
||||
if(!this.state.initialValue && childInput.props.defaultValue) {
|
||||
if(!this.state.initialValue && childInput && childInput.props.defaultValue) {
|
||||
this.setState({
|
||||
initialValue: childInput.props.defaultValue
|
||||
});
|
||||
@ -148,7 +167,7 @@ let Property = React.createClass({
|
||||
handleFocus() {
|
||||
// if ignoreFocus (bool) is defined, then just ignore focusing on
|
||||
// the property and input
|
||||
if(this.props.ignoreFocus) {
|
||||
if(this.state.ignoreFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -200,7 +219,7 @@ let Property = React.createClass({
|
||||
},
|
||||
|
||||
getClassName() {
|
||||
if(this.props.hidden){
|
||||
if(!this.state.expanded && !this.props.checkboxLabel){
|
||||
return 'is-hidden';
|
||||
}
|
||||
if(!this.props.editable){
|
||||
@ -216,40 +235,92 @@ let Property = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
setExpanded(expanded) {
|
||||
this.setState({ expanded });
|
||||
},
|
||||
|
||||
renderChildren(style) {
|
||||
return ReactAddons.Children.map(this.props.children, (child) => {
|
||||
return ReactAddons.addons.cloneWithProps(child, {
|
||||
style,
|
||||
onChange: this.handleChange,
|
||||
onFocus: this.handleFocus,
|
||||
onBlur: this.handleBlur,
|
||||
disabled: !this.props.editable,
|
||||
ref: 'input',
|
||||
name: this.props.name
|
||||
// Input's props should only be cloned and propagated down the tree,
|
||||
// if the component is actually being shown (!== 'expanded === false')
|
||||
if((this.state.expanded && this.props.checkboxLabel) || !this.props.checkboxLabel) {
|
||||
return ReactAddons.Children.map(this.props.children, (child) => {
|
||||
|
||||
// Since refs will be overriden by this functions return statement,
|
||||
// we still want to be able to define refs for nested `Form` or `Property`
|
||||
// children, which is why we're upfront simply invoking the callback-ref-
|
||||
// function before overriding it.
|
||||
if(typeof child.ref === 'function' && this.refs.input) {
|
||||
child.ref(this.refs.input);
|
||||
}
|
||||
|
||||
return React.cloneElement(child, {
|
||||
style,
|
||||
onChange: this.handleChange,
|
||||
onFocus: this.handleFocus,
|
||||
onBlur: this.handleBlur,
|
||||
disabled: !this.props.editable,
|
||||
ref: 'input',
|
||||
name: this.props.name,
|
||||
setExpanded: this.setExpanded
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getLabelAndErrors() {
|
||||
if(this.props.label || this.state.errors) {
|
||||
return (
|
||||
<p>
|
||||
<span className="pull-left">{this.props.label}</span>
|
||||
<span className="pull-right">{this.state.errors}</span>
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
handleCheckboxToggle() {
|
||||
this.setState({expanded: !this.state.expanded});
|
||||
},
|
||||
|
||||
getCheckbox() {
|
||||
const { checkboxLabel } = this.props;
|
||||
|
||||
if(checkboxLabel) {
|
||||
return (
|
||||
<div
|
||||
className="ascribe-property-collapsible-toggle"
|
||||
onClick={this.handleCheckboxToggle}>
|
||||
<input
|
||||
onChange={this.handleCheckboxToggle}
|
||||
type="checkbox"
|
||||
checked={this.state.expanded}
|
||||
ref="checkboxCollapsible"/>
|
||||
<span className="checkbox">{' ' + checkboxLabel}</span>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let footer = null;
|
||||
let tooltip = <span/>;
|
||||
let style = this.props.style ? mergeOptions({}, this.props.style) : {};
|
||||
let style = Object.assign({}, this.props.style);
|
||||
|
||||
if(this.props.tooltip){
|
||||
tooltip = (
|
||||
<Tooltip>
|
||||
{this.props.tooltip}
|
||||
</Tooltip>);
|
||||
}
|
||||
|
||||
if(this.props.footer){
|
||||
footer = (
|
||||
<div className="ascribe-property-footer">
|
||||
{this.props.footer}
|
||||
</div>);
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if(!this.props.editable) {
|
||||
if (!this.state.expanded) {
|
||||
style.paddingBottom = 0;
|
||||
}
|
||||
if (!this.props.editable) {
|
||||
style.cursor = 'not-allowed';
|
||||
}
|
||||
|
||||
@ -258,19 +329,17 @@ let Property = React.createClass({
|
||||
className={'ascribe-property-wrapper ' + this.getClassName()}
|
||||
onClick={this.handleFocus}
|
||||
style={style}>
|
||||
<OverlayTrigger
|
||||
delay={500}
|
||||
placement="top"
|
||||
overlay={tooltip}>
|
||||
{this.getCheckbox()}
|
||||
<Panel
|
||||
collapsible
|
||||
expanded={this.state.expanded}
|
||||
className="bs-custom-panel">
|
||||
<div className={'ascribe-property ' + this.props.className}>
|
||||
<p>
|
||||
<span className="pull-left">{this.props.label}</span>
|
||||
<span className="pull-right">{this.state.errors}</span>
|
||||
</p>
|
||||
{this.getLabelAndErrors()}
|
||||
{this.renderChildren(style)}
|
||||
{footer}
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</Panel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||
import Panel from 'react-bootstrap/lib/Panel';
|
||||
|
||||
|
||||
let PropertyCollapsile = React.createClass({
|
||||
let PropertyCollapsible = React.createClass({
|
||||
propTypes: {
|
||||
children: React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
checkboxLabel: React.PropTypes.string,
|
||||
@ -93,4 +93,4 @@ let PropertyCollapsile = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
export default PropertyCollapsile;
|
||||
export default PropertyCollapsible;
|
||||
|
@ -292,8 +292,8 @@ let PrizePieceRatings = React.createClass({
|
||||
url={ApiUrls.ownership_loans_pieces_request}
|
||||
email={this.props.currentUser.email}
|
||||
gallery={this.props.piece.prize.name}
|
||||
startdate={today}
|
||||
enddate={endDate}
|
||||
startDate={today}
|
||||
endDate={endDate}
|
||||
showPersonalMessage={true}
|
||||
showPassword={false}
|
||||
handleSuccess={this.handleLoanSuccess} />
|
||||
|
@ -122,7 +122,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='artist_bio'
|
||||
label={getLangText('Artist Biography')}
|
||||
hidden={disabled && !piece.extra_data.artist_bio}>
|
||||
expanded={!disabled || !!piece.extra_data.artist_bio}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.artist_bio}
|
||||
@ -131,7 +131,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='artist_contact_information'
|
||||
label={getLangText('Artist Contact Information')}
|
||||
hidden={disabled && !piece.extra_data.artist_contact_information}>
|
||||
expanded={!disabled || !!piece.extra_data.artist_contact_information}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.artist_contact_information}
|
||||
@ -140,7 +140,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='conceptual_overview'
|
||||
label={getLangText('Conceptual Overview')}
|
||||
hidden={disabled && !piece.extra_data.conceptual_overview}>
|
||||
expanded={!disabled || !!piece.extra_data.conceptual_overview}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.conceptual_overview}
|
||||
@ -149,7 +149,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='medium'
|
||||
label={getLangText('Medium (technical specifications)')}
|
||||
hidden={disabled && !piece.extra_data.medium}>
|
||||
expanded={!disabled || !!piece.extra_data.medium}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.medium}
|
||||
@ -158,7 +158,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='size_duration'
|
||||
label={getLangText('Size / Duration')}
|
||||
hidden={disabled && !piece.extra_data.size_duration}>
|
||||
expanded={!disabled || !!piece.extra_data.size_duration}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.size_duration}
|
||||
@ -167,7 +167,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='display_instructions'
|
||||
label={getLangText('Display instructions')}
|
||||
hidden={disabled && !piece.extra_data.display_instructions}>
|
||||
expanded={!disabled || !!piece.extra_data.display_instructions}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.display_instructions}
|
||||
@ -176,7 +176,7 @@ let CylandAdditionalDataForm = React.createClass({
|
||||
<Property
|
||||
name='additional_details'
|
||||
label={getLangText('Additional details')}
|
||||
hidden={disabled && !piece.extra_data.additional_details}>
|
||||
expanded={!disabled || !!piece.extra_data.additional_details}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={piece.extra_data.additional_details}
|
||||
|
@ -214,8 +214,8 @@ let CylandRegisterPiece = React.createClass({
|
||||
url={ApiUrls.ownership_loans_pieces}
|
||||
email={this.state.whitelabel.user}
|
||||
gallery="Cyland Archive"
|
||||
startdate={today}
|
||||
enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain}
|
||||
startDate={today}
|
||||
endDate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain}
|
||||
showStartDate={false}
|
||||
showEndDate={false}
|
||||
showPersonalMessage={false}
|
||||
|
@ -104,7 +104,7 @@ let IkonotvArtistDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='artist_website'
|
||||
label={getLangText('Artist Website')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.artist_website}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.artist_website}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.artist_website}
|
||||
@ -113,7 +113,7 @@ let IkonotvArtistDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='gallery_website'
|
||||
label={getLangText('Website of related Gallery, Museum, etc.')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.gallery_website}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.gallery_website}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.gallery_website}
|
||||
@ -122,7 +122,7 @@ let IkonotvArtistDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='additional_websites'
|
||||
label={getLangText('Additional Websites/Publications/Museums/Galleries')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.additional_websites}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.additional_websites}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.additional_websites}
|
||||
@ -131,7 +131,7 @@ let IkonotvArtistDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='conceptual_overview'
|
||||
label={getLangText('Short text about the Artist')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.conceptual_overview}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.conceptual_overview}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.conceptual_overview}
|
||||
|
@ -103,7 +103,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='medium'
|
||||
label={getLangText('Medium')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.medium}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.medium}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.medium}
|
||||
@ -112,7 +112,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='size_duration'
|
||||
label={getLangText('Size/Duration')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.size_duration}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.size_duration}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.size_duration}
|
||||
@ -121,7 +121,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='copyright'
|
||||
label={getLangText('Copyright')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.copyright}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.copyright}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.copyright}
|
||||
@ -130,7 +130,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='courtesy_of'
|
||||
label={getLangText('Courtesy of')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.courtesy_of}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.courtesy_of}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.courtesy_of}
|
||||
@ -139,7 +139,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='copyright_of_photography'
|
||||
label={getLangText('Copyright of Photography')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.copyright_of_photography}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.copyright_of_photography}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.copyright_of_photography}
|
||||
@ -148,7 +148,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
|
||||
<Property
|
||||
name='additional_details'
|
||||
label={getLangText('Additional Details about the artwork')}
|
||||
hidden={this.props.disabled && !this.props.piece.extra_data.additional_details}>
|
||||
expanded={!this.props.disabled || !!this.props.piece.extra_data.additional_details}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
defaultValue={this.props.piece.extra_data.additional_details}
|
||||
|
@ -199,10 +199,11 @@ let IkonotvRegisterPiece = React.createClass({
|
||||
|
||||
getSlideLoan() {
|
||||
if (this.canSubmit()) {
|
||||
let today = new Moment();
|
||||
let enddate = new Moment();
|
||||
enddate.add(2, 'years');
|
||||
const {piece, whitelabel} = this.state;
|
||||
let today = new Moment();
|
||||
let endDate = new Moment();
|
||||
endDate.add(2, 'years');
|
||||
|
||||
return (
|
||||
<div data-slide-title={getLangText('Loan')}>
|
||||
<Row className="no-margin">
|
||||
@ -212,8 +213,8 @@ let IkonotvRegisterPiece = React.createClass({
|
||||
id={{piece_id: piece.id}}
|
||||
url={ApiUrls.ownership_loans_pieces}
|
||||
email={whitelabel.user}
|
||||
startdate={today}
|
||||
enddate={enddate}
|
||||
startDate={today}
|
||||
endDate={endDate}
|
||||
showStartDate={false}
|
||||
showEndDate={false}
|
||||
gallery="IkonoTV archive"
|
||||
|
@ -129,7 +129,8 @@ let MarketSubmitButton = React.createClass({
|
||||
handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
|
||||
title={getLangText('Add additional information')}>
|
||||
<MarketAdditionalDataForm
|
||||
pieceId={solePieceId} />
|
||||
pieceId={solePieceId}
|
||||
submitLabel={getLangText('Continue to consignment')} />
|
||||
</ModalWrapper>
|
||||
|
||||
<ModalWrapper
|
||||
|
@ -35,9 +35,16 @@ let MarketAdditionalDataForm = React.createClass({
|
||||
isInline: React.PropTypes.bool,
|
||||
showHeading: React.PropTypes.bool,
|
||||
showNotification: React.PropTypes.bool,
|
||||
submitLabel: React.PropTypes.string,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
submitLabel: getLangText('Register work')
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
const pieceStore = PieceStore.getState();
|
||||
|
||||
@ -123,7 +130,7 @@ let MarketAdditionalDataForm = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const { isInline, handleSuccess, showHeading, showNotification } = this.props;
|
||||
const { isInline, handleSuccess, showHeading, showNotification, submitLabel } = this.props;
|
||||
const { piece } = this.state;
|
||||
let buttons, spinner, heading;
|
||||
|
||||
@ -133,7 +140,7 @@ let MarketAdditionalDataForm = React.createClass({
|
||||
type="submit"
|
||||
className="btn btn-default btn-wide"
|
||||
disabled={!this.state.isUploadReady}>
|
||||
{getLangText('Register work')}
|
||||
{submitLabel}
|
||||
</button>
|
||||
);
|
||||
|
||||
|
@ -25,7 +25,7 @@ import CylandPieceList from './components/cyland/cyland_piece_list';
|
||||
|
||||
import IkonotvLanding from './components/ikonotv/ikonotv_landing';
|
||||
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
|
||||
import ContractAgreementForm from '../../../components/ascribe_forms/form_contract_agreement';
|
||||
import SendContractAgreementForm from '../../../components/ascribe_forms/form_send_contract_agreement';
|
||||
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
|
||||
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
|
||||
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
|
||||
@ -135,7 +135,7 @@ let ROUTES = {
|
||||
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
|
||||
<Route
|
||||
path='request_loan'
|
||||
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractAgreementForm)}
|
||||
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SendContractAgreementForm)}
|
||||
headerTitle='SEND NEW CONTRACT'
|
||||
aclName='acl_create_contractagreement'/>
|
||||
<Route
|
||||
|
7
js/utils/regex_utils.js
Normal file
7
js/utils/regex_utils.js
Normal file
@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
export function isEmail(string) {
|
||||
// This is a bit of a weak test for an email, but you really can't win them all
|
||||
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address
|
||||
return !!string && string.match(/.*@.*\..*/);
|
||||
}
|
@ -31,16 +31,11 @@
|
||||
margin-top: .5em;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.loan-form {
|
||||
margin-top: .5em;
|
||||
&.embed-form {
|
||||
height: 45vh;
|
||||
}
|
||||
}
|
||||
|
||||
.loan-form {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
.notification-contract-pdf-download {
|
||||
text-align: left;
|
||||
margin-left: 1em;
|
||||
@ -69,4 +64,8 @@
|
||||
padding-left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.ascribe-property.contract-appendix-form {
|
||||
padding-left: 0;
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
.panel {
|
||||
/* Here we are overriding bootstrap to show the is-focused background color */
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.ascribe-panel-wrapper {
|
||||
border: 1px solid #ddd;
|
||||
height: 5em;
|
||||
|
Loading…
Reference in New Issue
Block a user