1
0
mirror of https://github.com/ascribe/onion.git synced 2025-02-14 21:10:27 +01:00

Merge remote-tracking branch 'origin/AD-943-add-custom-additional-fields' into AD-943-add-custom-additional-fields

This commit is contained in:
diminator 2015-09-22 17:23:37 +02:00
commit 24b7031c72
9 changed files with 142 additions and 95 deletions

View File

@ -35,27 +35,47 @@ class ContractAgreementListActions {
); );
} }
fetchAvailableContractAgreementList(issuer){ fetchAvailableContractAgreementList(issuer, createContractAgreement) {
return Q.Promise((resolve, reject) => { return Q.Promise((resolve, reject) => {
this.actions.fetchContractAgreementList(issuer, true, null) OwnershipFetcher.fetchContractAgreementList(issuer, true, null)
.then((contractAgreementListAccepted) => { .then((acceptedContractAgreementList) => {
if (!contractAgreementListAccepted) { // if there is at least an accepted contract agreement, we're going to
// fetch pending agreements if no accepted ones // use it
return this.actions.fetchContractAgreementList(issuer, null, true); if(acceptedContractAgreementList.count > 0) {
this.actions.updateContractAgreementList(acceptedContractAgreementList.results);
} else {
// otherwise, we're looking for contract agreements that are still pending
//
// Normally nesting promises, but for this conditional one, it makes sense to not
// overcomplicate the method
OwnershipFetcher.fetchContractAgreementList(issuer, null, true)
.then((pendingContractAgreementList) => {
if(pendingContractAgreementList.count > 0) {
this.actions.updateContractAgreementList(pendingContractAgreementList.results);
} else {
// 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);
}
}
})
.catch((err) => {
console.logGlobal(err);
reject(err);
});
} }
else { })
resolve(contractAgreementListAccepted); .catch((err) => {
}
}).then((contractAgreementListPending) => {
resolve(contractAgreementListPending);
}).catch((err) => {
console.logGlobal(err); console.logGlobal(err);
reject(err); reject(err);
}); });
}); }
);
} }
createContractAgreementFromPublicContract(issuer){ createContractAgreementFromPublicContract(issuer) {
ContractListActions.fetchContractList(null, null, issuer) ContractListActions.fetchContractList(null, null, issuer)
.then((publicContract) => { .then((publicContract) => {
// create an agreement with the public contract if there is one // create an agreement with the public contract if there is one

View File

@ -59,10 +59,13 @@ let LoanForm = React.createClass({
this.getContractAgreementsOrCreatePublic(this.props.email); 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) { componentWillReceiveProps(nextProps) {
// however, it can also be that at the time the component is mounting,
// the email is not defined (because it's asynchronously fetched from the server).
// Then we need to update it as soon as it is included into LoanForm's props.
if(nextProps && nextProps.email && this.props.email !== nextProps.email) { if(nextProps && nextProps.email && this.props.email !== nextProps.email) {
this.getContractAgreementsOrCreatePublic(nextProps.email); this.getContractAgreementsOrCreatePublic(nextProps.email);
} }
@ -80,14 +83,7 @@ let LoanForm = React.createClass({
ContractAgreementListActions.flushContractAgreementList.defer(); ContractAgreementListActions.flushContractAgreementList.defer();
if (email) { if (email) {
// fetch the available contractagreements (pending/accepted) // fetch the available contractagreements (pending/accepted)
ContractAgreementListActions.fetchAvailableContractAgreementList(email).then( ContractAgreementListActions.fetchAvailableContractAgreementList(email, true);
(contractAgreementList) => {
if (!contractAgreementList && this.props.createPublicContractAgreement) {
// for public contracts: fetch the public contract and create a contractagreement if available
ContractAgreementListActions.createContractAgreementFromPublicContract(email);
}
}
);
} }
}, },
@ -119,25 +115,46 @@ let LoanForm = React.createClass({
// we need to define a key on the InputCheckboxes as otherwise // we need to define a key on the InputCheckboxes as otherwise
// react is not rerendering them on a store switch and is keeping // react is not rerendering them on a store switch and is keeping
// the default value of the component (which is in that case true) // the default value of the component (which is in that case true)
let contract = this.state.contractAgreementList[0].contract; let contractAgreement = this.state.contractAgreementList[0];
let contract = contractAgreement.contract;
return ( if(contractAgreement.datetime_accepted) {
<Property return (
name="terms" <Property
className="ascribe-settings-property-collapsible-toggle" name="terms"
style={{paddingBottom: 0}}> hidden={false}
<InputCheckbox className="notification-contract-pdf">
key="terms_explicitly" <embed
defaultChecked={false}> className="loan-form"
<span> src={contract.blob.url_safe}
{getLangText('I agree to the')}&nbsp; alt="pdf"
<a href={contract.blob.url_safe} target="_blank"> pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
{getLangText('terms of ')} {contract.issuer} {/* We still need to send the server information that we're accepting */}
</a> <InputCheckbox
</span> style={{'display': 'none'}}
</InputCheckbox> key="terms_implicitly"
</Property> defaultChecked={true} />
); </Property>
);
} else {
return (
<Property
name="terms"
className="ascribe-settings-property-collapsible-toggle"
style={{paddingBottom: 0}}>
<InputCheckbox
key="terms_explicitly"
defaultChecked={false}>
<span>
{getLangText('I agree to the')}&nbsp;
<a href={contract.blob.url_safe} target="_blank">
{getLangText('terms of ')} {contract.issuer}
</a>
</span>
</InputCheckbox>
</Property>
);
}
} else { } else {
return ( return (
<Property <Property
@ -157,12 +174,11 @@ let LoanForm = React.createClass({
let appendix = this.state.contractAgreementList[0].appendix; let appendix = this.state.contractAgreementList[0].appendix;
if (appendix && appendix.default) { if (appendix && appendix.default) {
return ( return (
<div className='notification-contract-footer'> <Property
<h2>{getLangText('Appendix')}</h2> name='appendix'
<pre> label={getLangText('Appendix')}>
{appendix.default} <pre className="ascribe-pre">{appendix.default}</pre>
</pre> </Property>
</div>
); );
} }
} }
@ -214,7 +230,7 @@ let LoanForm = React.createClass({
name='loanee' name='loanee'
label={getLangText('Loanee Email')} label={getLangText('Loanee Email')}
editable={!this.props.email} editable={!this.props.email}
onBlur={this.handleOnChange} onChange={this.handleOnChange}
overrideForm={!!this.props.email}> overrideForm={!!this.props.email}>
<input <input
value={this.props.email} value={this.props.email}
@ -264,6 +280,8 @@ let LoanForm = React.createClass({
placeholder={getLangText('Enter a message...')} placeholder={getLangText('Enter a message...')}
required={this.props.showPersonalMessage ? 'required' : ''}/> required={this.props.showPersonalMessage ? 'required' : ''}/>
</Property> </Property>
{this.getContractCheckbox()}
{this.getAppendix()}
<Property <Property
name='password' name='password'
label={getLangText('Password')} label={getLangText('Password')}
@ -273,8 +291,6 @@ let LoanForm = React.createClass({
placeholder={getLangText('Enter your password')} placeholder={getLangText('Enter your password')}
required={this.props.showPassword ? 'required' : ''}/> required={this.props.showPassword ? 'required' : ''}/>
</Property> </Property>
{this.getContractCheckbox()}
{this.getAppendix()}
{this.props.children} {this.props.children}
</Form> </Form>
); );

View File

@ -25,7 +25,10 @@ let InputCheckbox = React.createClass({
// provided by Property // provided by Property
disabled: React.PropTypes.bool, disabled: React.PropTypes.bool,
onChange: React.PropTypes.func onChange: React.PropTypes.func,
// can be used to style the component from the outside
style: React.PropTypes.object
}, },
// As HTML inputs, we're setting the default value for an input to checked === false // As HTML inputs, we're setting the default value for an input to checked === false
@ -98,6 +101,7 @@ let InputCheckbox = React.createClass({
return ( return (
<span <span
style={this.props.style}
onClick={this.onChange}> onClick={this.onChange}>
<input <input
type="checkbox" type="checkbox"

View File

@ -19,20 +19,10 @@ let InputTextAreaToggable = React.createClass({
}; };
}, },
componentDidUpdate(prevProps, prevState) { componentDidUpdate() {
// if the components state value was changed during an update, we want to refresh it // If the initial value of state.value is null, we want to set props.defaultValue
// in this component as well as in the parent Property // as a value. In all other cases TextareaAutosize.onChange is updating.handleChange already
if(!this.state.value && this.state.value !== prevState.value) { if(this.state.value === null && this.props.defaultValue) {
this.handleChange({
target: {
value: this.state.value
}
});
}
// Otherwise, if state wasn't defined beforehand and defaultValue is defined from the outside
// we set it as the component's state and update Property by calling handleChange
if(!this.state.value && this.props.defaultValue) {
this.setState({ this.setState({
value: this.props.defaultValue value: this.props.defaultValue
}); });

View File

@ -68,7 +68,7 @@ let IkonotvArtistDetailsForm = React.createClass({
type="submit" type="submit"
className="btn ascribe-btn ascribe-btn-login" className="btn ascribe-btn ascribe-btn-login"
disabled={this.props.disabled}> disabled={this.props.disabled}>
{getLangText('Proceed to artwork details')} {getLangText('Proceed to loan')}
</button> </button>
); );

View File

@ -67,7 +67,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
type="submit" type="submit"
className="btn ascribe-btn ascribe-btn-login" className="btn ascribe-btn ascribe-btn-login"
disabled={this.props.disabled}> disabled={this.props.disabled}>
{getLangText('Proceed to loan')} {getLangText('Proceed to artist details')}
</button> </button>
); );

View File

@ -22,6 +22,8 @@ import GlobalNotificationActions from '../../../../../actions/global_notificatio
import CopyrightAssociationForm from '../../../../ascribe_forms/form_copyright_association'; import CopyrightAssociationForm from '../../../../ascribe_forms/form_copyright_association';
import Property from '../../../../ascribe_forms/property';
import AppConstants from '../../../../../constants/application_constants'; import AppConstants from '../../../../../constants/application_constants';
import { getLangText } from '../../../../../utils/lang_utils'; import { getLangText } from '../../../../../utils/lang_utils';
@ -67,16 +69,11 @@ let IkonotvContractNotifications = React.createClass({
if (blob.mime === 'pdf') { if (blob.mime === 'pdf') {
return ( return (
<div className='notification-contract-pdf'> <div className='notification-contract-pdf'>
<embed src={blob.url_safe} alt="pdf" <embed
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/> height
<div className='notification-contract-pdf-download'> src={blob.url_safe}
<a href={blob.url_safe} target="_blank"> alt="pdf"
<Glyphicon glyph='download-alt'/> pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
<span style={{padding: '0.3em'}}>
Download PDF version
</span>
</a>
</div>
</div> </div>
); );
} }
@ -97,12 +94,11 @@ let IkonotvContractNotifications = React.createClass({
let appendix = notifications.contract_agreement.appendix; let appendix = notifications.contract_agreement.appendix;
if (appendix && appendix.default) { if (appendix && appendix.default) {
return ( return (
<div className='notification-contract-footer'> <Property
<h1>{getLangText('Appendix')}</h1> name='appendix'
<pre> label={getLangText('Appendix')}>
{appendix.default} <pre className="ascribe-pre">{appendix.default}</pre>
</pre> </Property>
</div>
); );
} }
return null; return null;
@ -153,9 +149,12 @@ let IkonotvContractNotifications = React.createClass({
}, },
render() { render() {
if (this.state.contractAgreementListNotifications && if (this.state.contractAgreementListNotifications &&
this.state.contractAgreementListNotifications.length > 0) { this.state.contractAgreementListNotifications.length > 0) {
let notifications = this.state.contractAgreementListNotifications[0];
let blob = notifications.contract_agreement.contract.blob;
return ( return (
<div className='container'> <div className='container'>
<div className='notification-contract-wrapper'> <div className='notification-contract-wrapper'>
@ -168,6 +167,14 @@ let IkonotvContractNotifications = React.createClass({
{this.getContract()} {this.getContract()}
<div className='notification-contract-footer'> <div className='notification-contract-footer'>
{this.getAppendix()} {this.getAppendix()}
<div className='notification-contract-pdf-download'>
<a href={blob.url_safe} target="_blank">
<Glyphicon glyph='download-alt'/>
<span style={{padding: '0.3em'}}>
Download PDF version
</span>
</a>
</div>
{this.getCopyrightAssociationForm()} {this.getCopyrightAssociationForm()}
<p style={{marginTop: '1em'}}> <p style={{marginTop: '1em'}}>
<Button type="submit" onClick={this.handleConfirm}> <Button type="submit" onClick={this.handleConfirm}>

View File

@ -209,10 +209,9 @@ let IkonotvRegisterPiece = React.createClass({
getSlideLoan() { getSlideLoan() {
if (this.canSubmit()) { if (this.canSubmit()) {
let today = new Moment(); let today = new Moment();
let enddate = new Moment(); let enddate = new Moment();
enddate.add(1, 'years'); enddate.add(2, 'years');
return ( return (
<div data-slide-title={getLangText('Loan')}> <div data-slide-title={getLangText('Loan')}>
<Row className="no-margin"> <Row className="no-margin">
@ -224,6 +223,8 @@ let IkonotvRegisterPiece = React.createClass({
email="submissions@ikono.org" email="submissions@ikono.org"
startdate={today} startdate={today}
enddate={enddate} enddate={enddate}
showStartDate={false}
showEndDate={false}
gallery="IkonoTV archive" gallery="IkonoTV archive"
showPersonalMessage={false} showPersonalMessage={false}
createPublicContractAgreement={false} createPublicContractAgreement={false}

View File

@ -1,10 +1,10 @@
.notification-contract-wrapper {
.notification-contract-download { text-align: center;
} }
.notification-contract-wrapper{ .notification-contract-pdf-download {
text-align: center; text-align: right;
margin: 1em 0 1em 0;
} }
.notification-contract-logo { .notification-contract-logo {
@ -29,8 +29,17 @@
border: 1px solid #cccccc; border: 1px solid #cccccc;
width: 100%; width: 100%;
height: 60vh; height: 60vh;
margin-bottom: 0.4em; margin-bottom: 0;
.loan-form {
height: 45vh;
}
} }
.loan-form {
height: 40vh;
}
.notification-contract-pdf-download { .notification-contract-pdf-download {
text-align: left; text-align: left;
margin-left: 1em; margin-left: 1em;
@ -39,7 +48,7 @@
.notification-contract-footer { .notification-contract-footer {
text-align: left; text-align: left;
padding: 1em; padding: 0 0 1em 0;
> h1 { > h1 {
margin-top: 0.4em; margin-top: 0.4em;
font-size: 1.4em; font-size: 1.4em;