diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js index cd78569d..d52b8d43 100644 --- a/js/actions/piece_actions.js +++ b/js/actions/piece_actions.js @@ -7,7 +7,8 @@ import PieceFetcher from '../fetchers/piece_fetcher'; class PieceActions { constructor() { this.generateActions( - 'updatePiece' + 'updatePiece', + 'updateProperty' ); } diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index ec7ad7a7..3c5b44d2 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -14,6 +14,21 @@ class PieceListActions { } fetchPieceList(page, pageSize, search, orderBy, orderAsc) { + // To prevent flickering on a pagination request, + // we overwrite the piecelist with an empty list before + // pieceListCount === -1 defines the loading state + this.actions.updatePieceList({ + page, + pageSize, + search, + orderBy, + orderAsc, + 'pieceList': [], + 'pieceListCount': -1 + }); + + // afterwards, we can load the list + return new Promise((resolve, reject) => { PieceListFetcher .fetch(page, pageSize, search, orderBy, orderAsc) diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index 4d057c44..150d6934 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -8,7 +8,7 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; -import AccordionListItemCreateEditions from './accordion_list_item_create_editions'; +import CreateEditionsForm from '../ascribe_forms/create_editions_form'; import PieceListActions from '../../actions/piece_list_actions'; import EditionListActions from '../../actions/edition_list_actions'; @@ -35,20 +35,6 @@ let AccordionListItem = React.createClass({ }; }, - componentDidUpdate() { - if(this.props.content.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') { - this.startPolling(); - } - }, - - componentWillUnmount() { - clearInterval(this.state.pollingIntervalIndex); - }, - - onChange(state) { - this.setState(state); - }, - getGlyphicon(){ if (this.props.content.requestAction){ return ( @@ -66,39 +52,32 @@ let AccordionListItem = React.createClass({ }); }, - handleEditionCreationSuccess(response) { - let notification = new GlobalNotificationModel(response.notification, 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); + handleEditionCreationSuccess() { PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0}); this.toggleCreateEditionsDialog(); }, - startPolling() { - // start polling until editions are defined - let pollingIntervalIndex = setInterval(() => { - EditionListActions.fetchEditionList(this.props.content.id) - .then((res) => { - - clearInterval(this.state.pollingIntervalIndex); - - PieceListActions.updatePropertyForPiece({ - pieceId: this.props.content.id, - key: 'num_editions', - value: res.editions[0].num_editions - }); - - EditionListActions.toggleEditionList(this.props.content.id); - - }) - .catch(() => { - /* Ignore and keep going */ - }); - }, 5000); - - this.setState({ - pollingIntervalIndex + onPollingSuccess(pieceId, numEditions) { + PieceListActions.updatePropertyForPiece({ + pieceId, + key: 'num_editions', + value: numEditions }); + + EditionListActions.toggleEditionList(pieceId); + }, + + getCreateEditionsDialog() { + if(this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
+ +
+ ); + } }, render() { @@ -141,7 +120,8 @@ let AccordionListItem = React.createClass({ + toggleCreateEditionsDialog={this.toggleCreateEditionsDialog} + onPollingSuccess={this.onPollingSuccess}/> @@ -150,8 +130,9 @@ let AccordionListItem = React.createClass({ - {this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog ? : null} + {this.getCreateEditionsDialog()} + {/* this.props.children is AccordionListItemTableEditions */} {this.props.children} diff --git a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js deleted file mode 100644 index 30a6efbc..00000000 --- a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -import React from 'react'; - -import Form from '../ascribe_forms/form'; -import Property from '../ascribe_forms/property'; - -import apiUrls from '../../constants/api_urls'; -import { getLangText } from '../../utils/lang_utils'; - -let AccordionListItemCreateEditions = React.createClass({ - - propTypes: { - pieceId: React.PropTypes.number, - handleSuccess: React.PropTypes.func - }, - - getFormData(){ - return { - piece_id: parseInt(this.props.pieceId, 10) - }; - }, - - render() { - return ( -
-
- - - }> - - - -
-
- ); - } -}); - -export default AccordionListItemCreateEditions; \ No newline at end of file diff --git a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js index ba4ece2a..02328382 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js @@ -6,13 +6,16 @@ import classNames from 'classnames'; import EditionListActions from '../../actions/edition_list_actions'; import EditionListStore from '../../stores/edition_list_store'; +import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; + import { getLangText } from '../../utils/lang_utils'; let AccordionListItemEditionWidget = React.createClass({ propTypes: { className: React.PropTypes.string, piece: React.PropTypes.object.isRequired, - toggleCreateEditionsDialog: React.PropTypes.func.isRequired + toggleCreateEditionsDialog: React.PropTypes.func.isRequired, + onPollingSuccess: React.PropTypes.func }, getInitialState() { @@ -55,16 +58,9 @@ let AccordionListItemEditionWidget = React.createClass({ let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false; if(isEditionListOpen) { - if(typeof this.state.editionList[pieceId] === 'undefined') { - return ( - - ); - } else { - return ( - - ); - } - + return ( + + ); } else { return ( @@ -76,23 +72,16 @@ let AccordionListItemEditionWidget = React.createClass({ let piece = this.props.piece; let numEditions = piece.num_editions; - if(numEditions === -1) { + if(numEditions <= 0) { return ( - + ); - } - else if(numEditions === 0) { - return ( - - ); - } - else if(numEditions === 1) { + } else if(numEditions === 1) { let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : ''; return ( diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index 1e20d0d8..e9d2aa2a 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -105,6 +105,20 @@ let AclButton = React.createClass({ } }, + getShareMessage(){ + return ( + ` +${getLangText('Hi')}, + +${getLangText('I am sharing')}: +${this.getTitlesString()} ${getLangText('with you')}. + +${getLangText('Truly yours')}, +${this.props.currentUser.username} + ` + ); + }, + render() { let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; let aclProps = this.actionProperties(); @@ -121,18 +135,6 @@ let AclButton = React.createClass({ { aclProps.form } ); - }, - - getShareMessage(){ - return ( -`${getLangText('Hi')}, - -${getLangText('I am sharing')} : -${this.getTitlesString()}${getLangText('with you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username}` - ); } }); diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index eb3dc720..5fb3b224 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -7,14 +7,20 @@ import UserStore from '../../stores/user_store'; import AclButton from '../ascribe_buttons/acl_button'; import DeleteButton from '../ascribe_buttons/delete_button'; -import CreateEditionButton from '../ascribe_buttons/create_editions_button'; let AclButtonList = React.createClass({ propTypes: { className: React.PropTypes.string, - editions: React.PropTypes.object, + editions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]), availableAcls: React.PropTypes.array, - handleSuccess: React.PropTypes.func + handleSuccess: React.PropTypes.func, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) }, getInitialState() { @@ -69,8 +75,7 @@ let AclButtonList = React.createClass({ handleSuccess={this.props.handleSuccess} /> - + {this.props.children} ); } diff --git a/js/components/ascribe_buttons/create_editions_button.js b/js/components/ascribe_buttons/create_editions_button.js index 4b189db2..63127c68 100644 --- a/js/components/ascribe_buttons/create_editions_button.js +++ b/js/components/ascribe_buttons/create_editions_button.js @@ -1,42 +1,93 @@ 'use strict'; import React from 'react'; -import Router from 'react-router'; - -import Button from 'react-bootstrap/lib/Button'; - -import EditionDeleteForm from '../ascribe_forms/form_delete_edition'; -import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection'; -import ModalWrapper from '../ascribe_modal/modal_wrapper'; -import AccordionListItemCreateEditions from './../ascribe_accordion_list/accordion_list_item_create_editions'; -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils.js' import EditionListActions from '../../actions/edition_list_actions'; +import EditionListStore from '../../stores/edition_list_store'; + +import { getAvailableAcls } from '../../utils/acl_utils'; +import { getLangText } from '../../utils/lang_utils'; + +import classNames from 'classnames'; let CreateEditionsButton = React.createClass({ propTypes: { - piece: React.PropTypes.object.isRequired + label: React.PropTypes.string, + className: React.PropTypes.string, + piece: React.PropTypes.object.isRequired, + toggleCreateEditionsDialog: React.PropTypes.func.isRequired, + onPollingSuccess: React.PropTypes.func }, - mixins: [Router.Navigation], + getInitialState() { + return EditionListStore.getState(); + }, + + componentDidMount() { + EditionListStore.listen(this.onChange); + }, + + componentWillUnmount() { + EditionListStore.unlisten(this.onChange); + clearInterval(this.state.pollingIntervalIndex); + }, + + onChange(state) { + this.setState(state); + }, + + componentDidUpdate() { + if(this.props.piece.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') { + this.startPolling(); + } + }, + + startPolling() { + // start polling until editions are defined + let pollingIntervalIndex = setInterval(() => { + EditionListActions.fetchEditionList(this.props.piece.id) + .then((res) => { + + clearInterval(this.state.pollingIntervalIndex); + this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions); + + }) + .catch(() => { + /* Ignore and keep going */ + }); + }, 5000); + + this.setState({ + pollingIntervalIndex + }); + }, render: function () { - if (this.props.piece.constructor === Array){ + let piece = this.props.piece; + + let availableAcls = getAvailableAcls(piece); + + if (availableAcls.indexOf('editions') < -1 || piece.num_editions > 0){ return null; } - let availableAcls = getAvailableAcls([this.props.piece]); - if (availableAcls.indexOf('editions') === -1){ - return null; + + if(piece.num_editions === 0 && typeof this.state.editionList[piece.id] === 'undefined') { + return ( + + ); + } else { + return ( + + ); } - return ( - - ); } }); diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index ea9b44c3..a47f2148 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -5,7 +5,6 @@ import Router from 'react-router'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; -import Button from 'react-bootstrap/lib/Button'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import UserActions from '../../actions/user_actions'; @@ -22,7 +21,6 @@ import Property from './../ascribe_forms/property'; import EditionDetailProperty from './detail_property'; import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable'; -import EditionHeader from './header'; import EditionFurtherDetails from './further_details'; //import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata'; @@ -38,7 +36,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import apiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; -import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; let Link = Router.Link; @@ -76,7 +73,12 @@ let Edition = React.createClass({ content={this.props.edition}/> - +
+ {this.props.edition.title}
} /> + + +
+ diff --git a/js/components/ascribe_detail/header.js b/js/components/ascribe_detail/header.js deleted file mode 100644 index e9226a85..00000000 --- a/js/components/ascribe_detail/header.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -import React from 'react'; - -import EditionDetailProperty from './detail_property'; - - -let Header = React.createClass({ - propTypes: { - content: React.PropTypes.object - }, - - render() { - var titleHtml =
{this.props.content.title}
; - return ( -
- - - -
-
- ); - } -}); - -export default Header; \ No newline at end of file diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index d37addea..a0fb1dfc 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -10,26 +10,22 @@ import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph import DetailProperty from './detail_property'; import FurtherDetails from './further_details'; + import UserActions from '../../actions/user_actions'; import UserStore from '../../stores/user_store'; +import PieceActions from '../../actions/piece_actions'; + import MediaContainer from './media_container'; -import Header from './header'; +import EditionDetailProperty from './detail_property'; -import Form from './../ascribe_forms/form'; -import Property from './../ascribe_forms/property'; - -import RequestActionForm from './../ascribe_forms/form_request_action'; -import EditionActions from '../../actions/edition_actions'; import AclButtonList from './../ascribe_buttons/acl_button_list'; +import CreateEditionsForm from '../ascribe_forms/create_editions_form'; +import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; - -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import apiUrls from '../../constants/api_urls'; import { getLangText } from '../../utils/lang_utils'; +import { mergeOptions } from '../../utils/general_utils'; /** * This is the component that implements display-specific functionality @@ -41,7 +37,12 @@ let Piece = React.createClass({ }, getInitialState() { - return UserStore.getState(); + return mergeOptions( + UserStore.getState(), + { + showCreateEditionsDialog: false + } + ); }, componentDidMount() { @@ -57,8 +58,40 @@ let Piece = React.createClass({ this.setState(state); }, - render() { + toggleCreateEditionsDialog() { + this.setState({ + showCreateEditionsDialog: !this.state.showCreateEditionsDialog + }); + }, + handleEditionCreationSuccess() { + PieceActions.updateProperty({key: 'num_editions', value: 0}); + this.toggleCreateEditionsDialog(); + }, + + getCreateEditionsDialog() { + if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
+ +
+
+ ); + } else { + return (
); + } + }, + + handlePollingSuccess(pieceId, numEditions) { + PieceActions.updateProperty({ + key: 'num_editions', + value: numEditions + }); + }, + + render() { return ( @@ -66,12 +99,31 @@ let Piece = React.createClass({ content={this.props.piece}/> -
- +
+ {this.props.piece.title}
} /> + + + {this.props.piece.num_editions > 0 ? : null} +
+ +
+ +
+ + + + + + {this.getCreateEditionsDialog()} + -1 @@ -85,42 +137,10 @@ let Piece = React.createClass({ otherData={this.props.piece.other_data} handleSuccess={this.props.loadPiece}/> - ); } }); -let PieceSummary = React.createClass({ - propTypes: { - piece: React.PropTypes.object - }, - getActions(){ - let actions = ( - - - - - ); - return actions; - //return null; - }, - render() { - return ( -
- - {this.getActions()} -
-
- ); - - } -}); - - export default Piece; diff --git a/js/components/ascribe_forms/create_editions_form.js b/js/components/ascribe_forms/create_editions_form.js new file mode 100644 index 00000000..08195756 --- /dev/null +++ b/js/components/ascribe_forms/create_editions_form.js @@ -0,0 +1,62 @@ +'use strict'; + +import React from 'react'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import apiUrls from '../../constants/api_urls'; + +import { getLangText } from '../../utils/lang_utils'; + +let CreateEditionsForm = React.createClass({ + + propTypes: { + handleSuccess: React.PropTypes.func, + pieceId: React.PropTypes.number + }, + + getFormData(){ + return { + piece_id: parseInt(this.props.pieceId, 10) + }; + }, + + handleSuccess(response) { + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + + if(this.props.handleSuccess) { + this.props.handleSuccess(response); + } + }, + + render() { + return ( +
+ + + }> + + + +
+ ); + } +}); + +export default CreateEditionsForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js index 60d45f61..408aaf73 100644 --- a/js/components/ascribe_forms/form_login.js +++ b/js/components/ascribe_forms/form_login.js @@ -97,9 +97,9 @@ let LoginForm = React.createClass({ {getLangText(this.props.submitMessage)} } spinner={ - + }>

{getLangText(this.props.headerMessage)}

diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js new file mode 100644 index 00000000..41d0834f --- /dev/null +++ b/js/components/ascribe_forms/form_register_piece.js @@ -0,0 +1,165 @@ +'use strict'; + +import React from 'react'; + +import AppConstants from '../../constants/application_constants'; + +import Form from './form'; +import Property from './property'; +import FormPropertyHeader from './form_property_header'; + +import apiUrls from '../../constants/api_urls'; + +import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; + +import { getCookie } from '../../utils/fetch_api_utils'; +import { getLangText } from '../../utils/lang_utils'; + + +let RegisterPieceForm = React.createClass({ + getInitialState(){ + return { + digitalWorkKey: null, + isUploadReady: false + }; + }, + + getFormData(){ + return { + digital_work_key: this.state.digitalWorkKey + }; + }, + + submitKey(key){ + this.setState({ + digitalWorkKey: key + }); + }, + + setIsUploadReady(isReady) { + this.setState({ + isUploadReady: isReady + }); + }, + + isReadyForFormSubmission(files) { + files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled'); + if (files.length > 0 && files[0].status === 'upload successful') { + return true; + } else { + return false; + } + }, + + render() { + return ( +
+ {getLangText('Register work')} + } + spinner={ + + + + }> + +

{getLangText('Register your work')}

+
+ + + + + + + + + + + + + {this.props.children} +
+ ); + } +}); + +let FileUploader = React.createClass({ + propTypes: { + setIsUploadReady: React.PropTypes.func, + submitKey: React.PropTypes.func, + isReadyForFormSubmission: React.PropTypes.func, + onClick: React.PropTypes.func, + // editable is used to lock react fine uploader in case + // a user is actually not logged in already to prevent him from droping files + // before login in + editable: React.PropTypes.bool + }, + + render() { + return ( + + ); + } +}); + +export default RegisterPieceForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_signup.js b/js/components/ascribe_forms/form_signup.js index 3477769c..739b10dd 100644 --- a/js/components/ascribe_forms/form_signup.js +++ b/js/components/ascribe_forms/form_signup.js @@ -84,9 +84,9 @@ let SignupForm = React.createClass({ {getLangText(this.props.submitMessage)} } spinner={ - + }>

{getLangText(this.props.headerMessage)}

diff --git a/js/components/coa_verify_container.js b/js/components/coa_verify_container.js index 6afbdfa5..8c2f2e77 100644 --- a/js/components/coa_verify_container.js +++ b/js/components/coa_verify_container.js @@ -68,9 +68,9 @@ let CoaVerifyForm = React.createClass({ {getLangText('Verify your Certificate of Authenticity')} } spinner={ - + }>
{getLangText('Not an ascribe user')}? {getLangText('Sign up')}...
diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js index 4feba36a..478b4252 100644 --- a/js/components/password_reset_container.js +++ b/js/components/password_reset_container.js @@ -82,9 +82,9 @@ let PasswordRequestResetForm = React.createClass({ {getLangText('Reset your password')} } spinner={ - + }> } spinner={ - + }> file.status !== 'deleted' && file.status !== 'canceled'); - if (files.length > 0 && files[0].status === 'upload successful') { - return true; - } else { - return false; - } - }, onLicenseChange(event){ //console.log(this.state.licenses[event.target.selectedIndex].url); this.setState({selectedLicense: event.target.selectedIndex}); @@ -170,59 +135,9 @@ let RegisterPiece = React.createClass( { onFocus={this.changeSlide}> -
- {getLangText('Register work')} - } - spinner={ - - }> - -

{getLangText('Register your work')}

-
- - - - - - - - - - - - + {getLangText('Editions')} @@ -232,7 +147,7 @@ let RegisterPiece = React.createClass( { min={0}/> {this.getLicenses()} - +
@@ -248,54 +163,4 @@ let RegisterPiece = React.createClass( { }); -let FileUploader = React.createClass({ - propTypes: { - setIsUploadReady: React.PropTypes.func, - submitKey: React.PropTypes.func, - isReadyForFormSubmission: React.PropTypes.func, - onClick: React.PropTypes.func, - // editable is used to lock react fine uploader in case - // a user is actually not logged in already to prevent him from droping files - // before login in - editable: React.PropTypes.bool - }, - - render() { - return ( - - ); - } -}); - export default RegisterPiece; diff --git a/js/constants/languages.js b/js/constants/languages.js index c21bd0ad..d718fa69 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -210,6 +210,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', + 'REGISTREE': 'REGISTREE', }, 'de': { 'ID': 'ID', @@ -420,6 +421,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', + 'REGISTREE': 'REGISTREE', }, 'fr': { 'ID': 'ID', @@ -630,6 +632,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'Si votre adresse électronique existe dans notre base de données, vous recevrez un lien de récupération de mot de passe dans quelques minutes.', + 'REGISTREE': 'REGISTREE', } }; diff --git a/js/stores/piece_list_store.js b/js/stores/piece_list_store.js index 63a109ca..22d8d5d6 100644 --- a/js/stores/piece_list_store.js +++ b/js/stores/piece_list_store.js @@ -19,6 +19,7 @@ class PieceListStore { * the number of items the resource actually - without pagination - provides. */ this.pieceList = []; + // -1 specifies that the store is currently loading this.pieceListCount = -1; this.page = 1; this.pageSize = 10; diff --git a/js/stores/piece_store.js b/js/stores/piece_store.js index 5d2651ad..0bebab10 100644 --- a/js/stores/piece_store.js +++ b/js/stores/piece_store.js @@ -13,6 +13,14 @@ class PieceStore { onUpdatePiece(piece) { this.piece = piece; } + + onUpdateProperty({key, value}) { + if(this.piece && key in this.piece) { + this.piece[key] = value; + } else { + throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.'); + } + } } export default alt.createStore(PieceStore, 'PieceStore');