1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-15 09:35:10 +01:00

loan contract form

This commit is contained in:
diminator 2015-08-18 16:24:36 +02:00
parent e862fa39a9
commit e933b334c2
8 changed files with 327 additions and 4 deletions

View File

@ -0,0 +1,27 @@
'use strict';
import alt from '../alt';
import OwnershipFetcher from '../fetchers/ownership_fetcher';
class LoanContractListActions {
constructor() {
this.generateActions(
'updateLoanContractList',
'flushLoanContractList'
);
}
fetchLoanContractList() {
OwnershipFetcher.fetchLoanContractList()
.then((contracts) => {
this.actions.updateLoanContractList(contracts);
})
.catch((err) => {
console.logGlobal(err);
this.actions.updateLoanContractList([]);
});
}
}
export default alt.createActions(LoanContractListActions);

View File

@ -74,6 +74,7 @@ let PasswordRequestResetForm = React.createClass({
return ( return (
<Form <Form
ref="form" ref="form"
className='ascribe-form-wrapper'
url={ApiUrls.users_password_reset_request} url={ApiUrls.users_password_reset_request}
handleSuccess={this.handleSuccess} handleSuccess={this.handleSuccess}
buttons={ buttons={
@ -130,6 +131,7 @@ let PasswordResetForm = React.createClass({
return ( return (
<Form <Form
ref="form" ref="form"
className='ascribe-form-wrapper'
url={ApiUrls.users_password_reset} url={ApiUrls.users_password_reset}
handleSuccess={this.handleSuccess} handleSuccess={this.handleSuccess}
getFormData={this.getFormData} getFormData={this.getFormData}

View File

@ -0,0 +1,135 @@
'use strict';
import React from 'react';
import Property from '../../../../../ascribe_forms/property';
import LoanContractListActions from '../../../../../../actions/loan_contract_list_actions';
import LoanContractListStore from '../../../../../../stores/loan_contract_list_store';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
import Form from '../../../../../ascribe_forms/form';
import ApiUrls from '../../../../../../constants/api_urls';
import { getLangText } from '../../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';
let ContractForm = React.createClass({
getInitialState() {
return mergeOptions(
LoanContractListStore.getState(),
{
selectedContract: 0
}
);
},
componentDidMount() {
LoanContractListStore.listen(this.onChange);
LoanContractListActions.fetchLoanContractList();
},
componentWillUnmount() {
LoanContractListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
onContractChange(event){
this.setState({selectedContract: event.target.selectedIndex});
},
handleSubmitSuccess(response) {
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getContracts() {
if (this.state.contractList && this.state.contractList.length > 0) {
return (
<Property
name='contract'
label={getLangText('Contract Type')}
onChange={this.onContractChange}
footer={
<a
className="pull-right"
href={this.state.contractList[this.state.selectedContract].s3UrlSafe}
target="_blank">
{getLangText('Learn more')}
</a>
}>
<select name="contract">
{this.state.contractList.map((contract, i) => {
return (
<option
name={i}
key={i}
value={ contract.name }>
{ contract.name }
</option>
);
})}
</select>
</Property>);
}
return null;
},
render() {
return (
<Form
className="ascribe-form-bordered ascribe-form-wrapper"
ref='form'
url={ApiUrls.ownership_loans_contract}
handleSuccess={this.props.handleSuccess}
buttons={<button
type="submit"
className="btn ascribe-btn ascribe-btn-login">
SEND LOAN REQUEST
</button>}
spinner={
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</span>
}>
<div className="ascribe-form-header">
<h3>CONTRACT FORM</h3>
</div>
<Property
name='artist_name'
label={getLangText('Artist Name')}>
<input
type="text"
placeholder="(e.g. Andy Warhol)"
required/>
</Property>
<Property
name='artist_email'
label={getLangText('Artist Email')}>
<input
type="email"
placeholder="(e.g. andy@warhol.co.uk)"
required/>
</Property>
{this.getContracts()}
<Property
name='appendix'
label={getLangText('Appendix')}>
<input
type="text"
placeholder="Add an appendix to the contract"
required/>
</Property>
</Form>
);
}
});
export default ContractForm;

View File

@ -0,0 +1,120 @@
'use strict';
import React from 'react';
import Router from 'react-router';
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../stores/whitelabel_store';
import PieceListStore from '../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../actions/piece_list_actions';
import UserStore from '../../../../../stores/user_store';
import UserActions from '../../../../../actions/user_actions';
import PieceStore from '../../../../../stores/piece_store';
import PieceActions from '../../../../../actions/piece_actions';
import ContractForm from './ascribe_forms/ikonotv_contract_form';
import GlobalNotificationModel from '../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../actions/global_notification_actions';
import { getLangText } from '../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../utils/general_utils';
let IkonotvRegisterPiece = React.createClass({
mixins: [Router.Navigation],
getInitialState(){
return mergeOptions(
UserStore.getState(),
PieceListStore.getState(),
PieceStore.getState(),
WhitelabelStore.getState());
},
componentDidMount() {
PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
PieceStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
UserActions.fetchCurrentUser();
WhitelabelActions.fetchWhitelabel();
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
PieceStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
if(this.state.currentUser && this.state.currentUser.email) {
// we should also make the fineuploader component editable again
this.setState({
isFineUploaderActive: true
});
}
},
handleRegisterSuccess(response){
// once the user was able to register a piece successfully, we need to make sure to keep
// the piece list up to date
PieceListActions.fetchPieceList(
this.state.page,
this.state.pageSize,
this.state.searchTerm,
this.state.orderBy,
this.state.orderAsc,
this.state.filterBy
);
// also start loading the piece for the next step
if(response && response.piece) {
PieceActions.updatePiece(response.piece);
}
this.refs.slidesContainer.setSlideNum(1);
},
handleAdditionalDataSuccess() {
this.refs.slidesContainer.setSlideNum(2);
},
handleLoanSuccess(response) {
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
PieceActions.fetchOne(this.state.piece.id);
this.transitionTo('piece', {pieceId: this.state.piece.id});
},
changeSlide() {
// only transition to the login store, if user is not logged in
// ergo the currentUser object is not properly defined
if(this.state.currentUser && !this.state.currentUser.email) {
this.onLoggedOut();
}
},
// basically redirects to the second slide (index: 1), when the user is not logged in
onLoggedOut() {
this.transitionTo('login');
},
render() {
return (
<ContractForm />
);
}
});
export default IkonotvRegisterPiece;

View File

@ -19,6 +19,7 @@ import CylandRegisterPiece from './components/cyland/cyland_register_piece';
import CylandPieceList from './components/cyland/cyland_piece_list'; import CylandPieceList from './components/cyland/cyland_piece_list';
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list'; import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import CCRegisterPiece from './components/cc/cc_register_piece'; import CCRegisterPiece from './components/cc/cc_register_piece';
@ -62,12 +63,12 @@ let ROUTES = {
), ),
'ikonotv': ( 'ikonotv': (
<Route name="app" path={baseUrl} handler={WalletApp}> <Route name="app" path={baseUrl} handler={WalletApp}>
<Route name="landing" path={baseUrl} handler={CylandRegisterPiece} /> <Route name="landing" path={baseUrl} handler={IkonotvRegisterPiece} />
<Route name="login" path="login" handler={LoginContainer} /> <Route name="login" path="login" handler={LoginContainer} />
<Route name="logout" path="logout" handler={LogoutContainer} /> <Route name="logout" path="logout" handler={LogoutContainer} />
<Route name="signup" path="signup" handler={SignupContainer} /> <Route name="signup" path="signup" handler={SignupContainer} />
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} /> <Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
<Route name="register_piece" path="register_piece" handler={CylandRegisterPiece} /> <Route name="register_piece" path="register_piece" handler={IkonotvRegisterPiece} />
<Route name="pieces" path="collection" handler={IkonotvPieceList} /> <Route name="pieces" path="collection" handler={IkonotvPieceList} />
<Route name="piece" path="pieces/:pieceId" handler={CylandPieceContainer} /> <Route name="piece" path="pieces/:pieceId" handler={CylandPieceContainer} />
<Route name="edition" path="editions/:editionId" handler={EditionContainer} /> <Route name="edition" path="editions/:editionId" handler={EditionContainer} />

View File

@ -6,12 +6,19 @@ import ApiUrls from '../constants/api_urls';
let OwnershipFetcher = { let OwnershipFetcher = {
/** /**
* Fetch one user from the API. * Fetch the default, public loan contract of a user from the API.
* If no arg is supplied, load the current user
*/ */
fetchLoanContract(email) { fetchLoanContract(email) {
return requests.get(ApiUrls.ownership_loans_contract + '?loanee=' + email); return requests.get(ApiUrls.ownership_loans_contract + '?loanee=' + email);
},
/**
* Fetch the contracts of the logged-in user from the API.
*/
fetchLoanContractList(){
return requests.get(ApiUrls.ownership_loans_contract);
} }
}; };
export default OwnershipFetcher; export default OwnershipFetcher;

View File

@ -0,0 +1,22 @@
'use strict';
import alt from '../alt';
import LoanContractListActions from '../actions/loan_contract_list_actions';
class LoanContractListStore {
constructor() {
this.contractList = [];
this.bindActions(LoanContractListActions);
}
onUpdateLoanContractList(contractList) {
this.contractList = contractList;
}
onFlushLoanContractList() {
this.contractList = [];
}
}
export default alt.createStore(LoanContractListStore, 'LoanContractListStore');

View File

@ -14,3 +14,12 @@
margin-bottom: 0; margin-bottom: 0;
color: #616161; color: #616161;
} }
.ascribe-form-wrapper {
width: 80%;
margin: 0 auto;
max-width: 600px;
@media (max-width: 550px) {
width: 100%;
}
}