diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js index 6e8a77c3..84713bd9 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -10,9 +10,6 @@ import Row from 'react-bootstrap/lib/Row'; import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece'; -import Property from '../../../../ascribe_forms/property'; -import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; - import WhitelabelActions from '../../../../../actions/whitelabel_actions'; import WhitelabelStore from '../../../../../stores/whitelabel_store'; @@ -136,7 +133,7 @@ let CylandRegisterPiece = React.createClass({ this.transitionTo('piece', {pieceId: this.state.piece.id}); }, - // We need to increase the step to lock the forms that are already filed out + // We need to increase the step to lock the forms that are already filled out incrementStep() { // also increase step let newStep = this.state.step + 1; diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js index 4b7f3dbc..be3bda77 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js @@ -1,17 +1,8 @@ 'use strict'; import React from 'react'; -import Moment from 'moment'; import classNames from 'classnames'; - -import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; - -import LoanForm from '../../../../../ascribe_forms/form_loan'; - -import Property from '../../../../../ascribe_forms/property'; -import InputCheckbox from '../../../../../ascribe_forms/input_checkbox'; - -import ApiUrls from '../../../../../../constants/api_urls'; +import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; import { getLangText } from '../../../../../../utils/lang_utils'; @@ -22,37 +13,30 @@ let IkonotvSubmitButton = React.createClass({ piece: React.PropTypes.object.isRequired }, - getSubmitButton() { - return ( - - ); - }, - render() { + let piece = this.props.piece; + let startFrom = 1; - let today = new Moment(); - let enddate = new Moment(); - enddate.add(1, 'years'); + // In the Ikonotv loan page a user has to complete two steps. + // Since every one of those steps is atomic a user should always be able to continue + // where he left of. + // This is why we start the process form slide 1/2 if the user has already finished + // it in another session. + if(piece && piece.extra_data && Object.keys(piece.extra_data).length > 0) { + startFrom = 1; + } return ( - - - - + + {getLangText('Loan to IkonoTV')} + ); } }); diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_additional_data_form.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_additional_data_form.js new file mode 100644 index 00000000..6a2f8cc5 --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_additional_data_form.js @@ -0,0 +1,134 @@ +'use strict'; + +import React from 'react'; + +import Form from '../../../../../ascribe_forms/form'; +import Property from '../../../../../ascribe_forms/property'; + +import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable'; + +import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader'; + +import ApiUrls from '../../../../../../constants/api_urls'; +import AppConstants from '../../../../../../constants/application_constants'; + +import requests from '../../../../../../utils/requests'; + +import { getLangText } from '../../../../../../utils/lang_utils'; +import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils'; + + +let IkonotvAdditionalDataForm = React.createClass({ + propTypes: { + handleSuccess: React.PropTypes.func.isRequired, + piece: React.PropTypes.object.isRequired, + + disabled: React.PropTypes.bool + }, + + getInitialState() { + return { + isUploadReady: true + }; + }, + + getFormData() { + let extradata = {}; + let formRefs = this.refs.form.refs; + + // Put additional fields in extra data object + Object + .keys(formRefs) + .forEach((fieldName) => { + extradata[fieldName] = formRefs[fieldName].state.value; + }); + + return { + extradata: extradata, + piece_id: this.props.piece.id + }; + + }, + + uploadStarted() { + this.setState({ + isUploadReady: false + }); + }, + + setIsUploadReady(isReady) { + this.setState({ + isUploadReady: isReady + }); + }, + + render() { + if(this.props.piece && this.props.piece.id) { + return ( +
+ {getLangText('Proceed to loan')} + + } + spinner={ +
+ +
+ }> +
+

+ {getLangText('Provide supporting materials')} +

+
+ + + + + + + + + ); + } else { + return ( +
+ +
+ ); + } + } +}); + +export default IkonotvAdditionalDataForm; \ 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..6a2acbb8 --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js @@ -0,0 +1,220 @@ +'use strict'; + +import React from 'react'; +import Moment from 'moment'; +import Router from 'react-router'; + +import Col from 'react-bootstrap/lib/Col'; +import Row from 'react-bootstrap/lib/Row'; + +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 GlobalNotificationModel from '../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; + +import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece'; +import LoanForm from '../../../../ascribe_forms/form_loan'; +import IkonotvAdditionalDataForm from './ascribe_forms/ikonotv_additional_data_form'; + +import SlidesContainer from '../../../../ascribe_slides_container/slides_container'; + +import ApiUrls from '../../../../../constants/api_urls'; + +import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; + +let IkonotvRegisterPiece = React.createClass({ + + propTypes: { + handleSuccess: React.PropTypes.func, + piece: React.PropTypes.object.isRequired + }, + + mixins: [Router.Navigation, Router.State], + + getInitialState(){ + return mergeOptions( + UserStore.getState(), + PieceListStore.getState(), + PieceStore.getState(), + { + step: 0 + }); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); + PieceStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + + let queryParams = this.getQuery(); + + // Since every step of this register process is atomic, + // we may need to enter the process at step 1 or 2. + // If this is the case, we'll need the piece number to complete submission. + // It is encoded in the URL as a queryParam and we're checking for it here. + // + // We're using 'in' here as we want to know if 'piece_id' is present in the url, + // we don't care about the value. + if (queryParams && 'piece_id' in queryParams) { + PieceActions.fetchOne(queryParams.piece_id); + } + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + PieceStore.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){ + + this.refreshPieceList(); + + // also start loading the piece for the next step + if(response && response.piece) { + PieceActions.updatePiece(response.piece); + } + + this.incrementStep(); + + this.refs.slidesContainer.nextSlide(); + }, + + handleAdditionalDataSuccess() { + + // We need to refetch the piece again after submitting the additional data + // since we want it's otherData to be displayed when the user choses to click + // on the browsers back button. + PieceActions.fetchOne(this.state.piece.id); + + this.refreshPieceList(); + + this.incrementStep(); + + this.refs.slidesContainer.nextSlide(); + }, + + handleLoanSuccess(response) { + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + + this.refreshPieceList(); + + PieceActions.fetchOne(this.state.piece.id); + this.transitionTo('piece', {pieceId: this.state.piece.id}); + }, + + // We need to increase the step to lock the forms that are already filled out + incrementStep() { + // also increase step + let newStep = this.state.step + 1; + this.setState({ + step: newStep + }); + }, + + refreshPieceList() { + PieceListActions.fetchPieceList( + this.state.page, + this.state.pageSize, + this.state.searchTerm, + this.state.orderBy, + this.state.orderAsc, + this.state.filterBy + ); + }, + + 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() { + + let today = new Moment(); + let enddate = new Moment(); + enddate.add(1, 'years'); + + return ( + +
+ + + 0} + enableLocalHashing={false} + headerMessage={getLangText('Submit to Cyland Archive')} + submitMessage={getLangText('Submit')} + isFineUploaderActive={this.state.isFineUploaderActive} + handleSuccess={this.handleRegisterSuccess} + onLoggedOut={this.onLoggedOut} /> + + +
+
+ + + 1} + handleSuccess={this.handleAdditionalDataSuccess} + piece={this.state.piece}/> + + +
+
+ + + + + +
+
+ ); + } +}); + +export default IkonotvRegisterPiece; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 25fc1d80..6dd1ed24 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -21,6 +21,7 @@ import CylandPieceList from './components/cyland/cyland_piece_list'; import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list'; import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan'; +import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece'; import IkonotvPieceContainer from './components/ikonotv/ascribe_detail/ikonotv_piece_container'; import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications'; @@ -73,7 +74,7 @@ let ROUTES = { - +