diff --git a/js/actions/loan_contract_list_actions.js b/js/actions/loan_contract_list_actions.js new file mode 100644 index 00000000..bc5cef82 --- /dev/null +++ b/js/actions/loan_contract_list_actions.js @@ -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); diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js index 80a42a62..ae581fdf 100644 --- a/js/components/password_reset_container.js +++ b/js/components/password_reset_container.js @@ -74,6 +74,7 @@ let PasswordRequestResetForm = React.createClass({ return (
0) { + return ( + + {getLangText('Learn more')} + + }> + + ); + } + return null; + }, + + render() { + return ( + + SEND LOAN REQUEST + } + spinner={ + + + + }> +
+

CONTRACT FORM

+
+ + + + + + + {this.getContracts()} + + + +
+ ); + } +}); + +export default ContractForm; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js new file mode 100644 index 00000000..34f03042 --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js @@ -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 ( + + ); + } +}); + + +export default IkonotvRegisterPiece; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 29012d71..8d7a4aa8 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -19,6 +19,7 @@ import CylandRegisterPiece from './components/cyland/cyland_register_piece'; import CylandPieceList from './components/cyland/cyland_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'; @@ -62,12 +63,12 @@ let ROUTES = { ), 'ikonotv': ( - + - + diff --git a/js/fetchers/ownership_fetcher.js b/js/fetchers/ownership_fetcher.js index 111e3a9a..68ffa264 100644 --- a/js/fetchers/ownership_fetcher.js +++ b/js/fetchers/ownership_fetcher.js @@ -6,12 +6,19 @@ import ApiUrls from '../constants/api_urls'; let OwnershipFetcher = { /** - * Fetch one user from the API. - * If no arg is supplied, load the current user + * Fetch the default, public loan contract of a user from the API. */ fetchLoanContract(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; diff --git a/js/stores/loan_contract_list_store.js b/js/stores/loan_contract_list_store.js new file mode 100644 index 00000000..c4145d28 --- /dev/null +++ b/js/stores/loan_contract_list_store.js @@ -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'); diff --git a/sass/ascribe_form.scss b/sass/ascribe_form.scss index dd4af008..d2802ee8 100644 --- a/sass/ascribe_form.scss +++ b/sass/ascribe_form.scss @@ -13,4 +13,13 @@ margin-top: 0; margin-bottom: 0; color: #616161; +} + +.ascribe-form-wrapper { + width: 80%; + margin: 0 auto; + max-width: 600px; + @media (max-width: 550px) { + width: 100%; + } } \ No newline at end of file