From f0d6eaa950b07c1c6f410af44649c1be1137887a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 29 Jul 2015 15:57:48 +0200 Subject: [PATCH 001/397] update gitignore --- .gitignore | 3 +++ js/constants/application_constants.js | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index 04138bb0..93db0b6a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ lib-cov *.out *.pid *.gz +*.sublime-project +spool-project.sublime-project +*.sublime-workspace pids logs diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 85699a87..014d92a4 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -46,6 +46,13 @@ let constants = { 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/logo.jpeg', 'permissions': ['register', 'edit', 'share', 'del_from_collection'], 'type': 'prize' + }, + { + 'subdomain': 'cyland', + 'name': 'Cyland', + 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/logo.jpeg', + 'permissions': ['register', 'edit', 'share', 'del_from_collection'], + 'type': 'prize' } ], 'defaultDomain': { From 277cd98549f51e1b71ba5ded5b65f2946c09d484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 29 Jul 2015 16:08:30 +0200 Subject: [PATCH 002/397] fix cyland logo --- js/constants/application_constants.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 014d92a4..9c4a3af4 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -49,8 +49,8 @@ let constants = { }, { 'subdomain': 'cyland', - 'name': 'Cyland', - 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/logo.jpeg', + 'name': 'Cyland media art lab', + 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/cyland/logo.gif', 'permissions': ['register', 'edit', 'share', 'del_from_collection'], 'type': 'prize' } From f3e378f2217f9decd067e2934508f5379decd1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 5 Aug 2015 16:49:25 +0200 Subject: [PATCH 003/397] update react-bootstrap first cut --- .../ascribe_buttons/delete_button.js | 11 ++-- js/components/ascribe_modal/ascribe_modal.js | 63 +++++++++++++++++++ js/components/ascribe_modal/modal_wrapper.js | 15 ++--- package.json | 2 +- 4 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 js/components/ascribe_modal/ascribe_modal.js diff --git a/js/components/ascribe_buttons/delete_button.js b/js/components/ascribe_buttons/delete_button.js index a60344df..966154bc 100644 --- a/js/components/ascribe_buttons/delete_button.js +++ b/js/components/ascribe_buttons/delete_button.js @@ -11,10 +11,10 @@ import PieceDeleteForm from '../ascribe_forms/form_delete_piece'; import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection'; import PieceRemoveFromCollectionForm from '../ascribe_forms/form_remove_piece_from_collection'; -import ModalWrapper from '../ascribe_modal/modal_wrapper'; +import AscribeModal from '../ascribe_modal/ascribe_modal'; import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils.js'; +import { getLangText } from '../../utils/lang_utils'; let DeleteButton = React.createClass({ @@ -66,12 +66,11 @@ let DeleteButton = React.createClass({ return null; } return ( - {content} - + ); } }); diff --git a/js/components/ascribe_modal/ascribe_modal.js b/js/components/ascribe_modal/ascribe_modal.js new file mode 100644 index 00000000..d2a55228 --- /dev/null +++ b/js/components/ascribe_modal/ascribe_modal.js @@ -0,0 +1,63 @@ +'use strict'; + +import React from 'react'; + +import Modal from 'react-bootstrap/lib/Modal'; + +let AscribeModal = React.createClass({ + + propTypes: { + trigger: React.PropTypes.element.isRequired, + title: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element, + React.PropTypes.string + ]).isRequired, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]).isRequired, + footer: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element, + React.PropTypes.string + ]).isRequired + }, + + getInitialState(){ + return { + modalBody: null + }; + }, + + close() { + this.setState({ showModal: false }); + }, + + open() { + this.setState({ showModal: true }); + }, + + render() { + + let trigger = React.cloneElement(this.props.trigger, {onClick: this.open}); + + return ( + + {trigger} + + + + {this.props.title} + + + + {this.props.children} + + + + ); + } +}); + +export default AscribeModal; \ No newline at end of file diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js index a8f7b182..a7155e74 100644 --- a/js/components/ascribe_modal/modal_wrapper.js +++ b/js/components/ascribe_modal/modal_wrapper.js @@ -5,7 +5,6 @@ import ReactAddons from 'react/addons'; import Modal from 'react-bootstrap/lib/Modal'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; -import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import ModalMixin from '../../mixins/modal_mixin'; @@ -22,15 +21,11 @@ let ModalWrapper = React.createClass({ getModalTrigger() { return ( - - {this.props.children} - - }> - {this.props.button} - + + {this.props.children} + ); }, diff --git a/package.json b/package.json index 4fdf87fb..0fc9844f 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "q": "^1.4.1", "raven-js": "^1.1.19", "react": "^0.13.2", - "react-bootstrap": "~0.22.6", + "react-bootstrap": "^0.24.3", "react-datepicker": "~0.8.0", "react-progressbar": "^1.1.0", "react-router": "^0.13.3", From 4c88f88d561d979559c9719c17bb5e2f6724d8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 5 Aug 2015 17:32:35 +0200 Subject: [PATCH 004/397] first cut porting and using new react-bootstrap version --- js/components/ascribe_buttons/acl_button.js | 5 +- .../ascribe_buttons/delete_button.js | 10 +- .../ascribe_buttons/submit_to_prize_button.js | 2 +- .../unconsign_request_button.js | 5 +- js/components/ascribe_forms/form_loan.js | 16 +--- js/components/ascribe_modal/ascribe_modal.js | 63 ------------- .../modal_password_request_reset.js | 11 ++- js/components/ascribe_modal/modal_wrapper.js | 94 ++++++++----------- js/mixins/modal_mixin.js | 12 --- 9 files changed, 58 insertions(+), 160 deletions(-) delete mode 100644 js/components/ascribe_modal/ascribe_modal.js delete mode 100644 js/mixins/modal_mixin.js diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index d9423889..f457e48b 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -214,14 +214,13 @@ ${this.props.currentUser.username} return ( {this.sanitizeAction()} } handleSuccess={aclProps.handleSuccess} - title={aclProps.title} - tooltip={aclProps.tooltip}> + title={aclProps.title}> {aclProps.form} ); diff --git a/js/components/ascribe_buttons/delete_button.js b/js/components/ascribe_buttons/delete_button.js index 966154bc..0e811885 100644 --- a/js/components/ascribe_buttons/delete_button.js +++ b/js/components/ascribe_buttons/delete_button.js @@ -11,10 +11,10 @@ import PieceDeleteForm from '../ascribe_forms/form_delete_piece'; import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection'; import PieceRemoveFromCollectionForm from '../ascribe_forms/form_remove_piece_from_collection'; -import AscribeModal from '../ascribe_modal/ascribe_modal'; +import ModalWrapper from '../ascribe_modal/modal_wrapper'; import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils'; +import { getLangText } from '../../utils/lang_utils.js'; let DeleteButton = React.createClass({ @@ -66,14 +66,14 @@ let DeleteButton = React.createClass({ return null; } return ( - {content} - + ); } }); export default DeleteButton; - diff --git a/js/components/ascribe_buttons/submit_to_prize_button.js b/js/components/ascribe_buttons/submit_to_prize_button.js index 3565a3ee..63b71f77 100644 --- a/js/components/ascribe_buttons/submit_to_prize_button.js +++ b/js/components/ascribe_buttons/submit_to_prize_button.js @@ -27,7 +27,7 @@ let SubmitToPrizeButton = React.createClass({ render() { return ( REQUEST UNCONSIGN } handleSuccess={this.props.handleSuccess} - title='Request to Un-Consign' - tooltip='Ask the consignee to return the ownership of the work back to you'> + title='Request to Un-Consign'> {getLangText('CLOSE')} + onClick={this.props.onRequestHide}>{getLangText('CLOSE')}

} spinner={ diff --git a/js/components/ascribe_modal/ascribe_modal.js b/js/components/ascribe_modal/ascribe_modal.js deleted file mode 100644 index d2a55228..00000000 --- a/js/components/ascribe_modal/ascribe_modal.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -import React from 'react'; - -import Modal from 'react-bootstrap/lib/Modal'; - -let AscribeModal = React.createClass({ - - propTypes: { - trigger: React.PropTypes.element.isRequired, - title: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element, - React.PropTypes.string - ]).isRequired, - children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element - ]).isRequired, - footer: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element, - React.PropTypes.string - ]).isRequired - }, - - getInitialState(){ - return { - modalBody: null - }; - }, - - close() { - this.setState({ showModal: false }); - }, - - open() { - this.setState({ showModal: true }); - }, - - render() { - - let trigger = React.cloneElement(this.props.trigger, {onClick: this.open}); - - return ( - - {trigger} - - - - {this.props.title} - - - - {this.props.children} - - - - ); - } -}); - -export default AscribeModal; \ No newline at end of file diff --git a/js/components/ascribe_modal/modal_password_request_reset.js b/js/components/ascribe_modal/modal_password_request_reset.js index fffcb3d7..d941bcce 100644 --- a/js/components/ascribe_modal/modal_password_request_reset.js +++ b/js/components/ascribe_modal/modal_password_request_reset.js @@ -7,9 +7,13 @@ import PasswordResetRequestForm from '../ascribe_forms/form_password_reset_reque import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; -import { getLangText } from '../../utils/lang_utils.js' +import { getLangText } from '../../utils/lang_utils.js'; let PasswordResetRequestModal = React.createClass({ + propTypes: { + button: React.PropTypes.element + }, + handleResetSuccess(){ let notificationText = getLangText('Request successfully sent, check your email'); let notification = new GlobalNotificationModel(notificationText, 'success', 50000); @@ -18,10 +22,9 @@ let PasswordResetRequestModal = React.createClass({ render() { return ( + handleSuccess={this.handleResetSuccess}> ); diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js index a7155e74..05971f3a 100644 --- a/js/components/ascribe_modal/modal_wrapper.js +++ b/js/components/ascribe_modal/modal_wrapper.js @@ -4,87 +4,73 @@ import React from 'react'; import ReactAddons from 'react/addons'; import Modal from 'react-bootstrap/lib/Modal'; -import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; -import Tooltip from 'react-bootstrap/lib/Tooltip'; - -import ModalMixin from '../../mixins/modal_mixin'; let ModalWrapper = React.createClass({ propTypes: { - title: React.PropTypes.string.isRequired, - onRequestHide: React.PropTypes.func, + trigger: React.PropTypes.element.isRequired, + title: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element, + React.PropTypes.string + ]).isRequired, handleSuccess: React.PropTypes.func.isRequired, - button: React.PropTypes.object.isRequired, - children: React.PropTypes.object, - tooltip: React.PropTypes.string + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) }, - getModalTrigger() { - return ( - - {this.props.children} - - ); + getInitialState() { + return { + showModal: false + }; }, - render() { - if(this.props.tooltip) { - return ( - {this.props.tooltip}}> - {this.getModalTrigger()} - - ); - } else { - return ( - - {/* This needs to be some kind of inline-block */} - {this.getModalTrigger()} - - ); - } - } -}); - - -let ModalBody = React.createClass({ - propTypes: { - onRequestHide: React.PropTypes.func, - handleSuccess: React.PropTypes.func, - children: React.PropTypes.object, - title: React.PropTypes.string.isRequired + show() { + this.setState({ + showModal: true + }); }, - mixins: [ModalMixin], + hide() { + this.setState({ + showModal: false + }); + }, handleSuccess(response){ this.props.handleSuccess(response); - this.props.onRequestHide(); + this.hide(); }, renderChildren() { return ReactAddons.Children.map(this.props.children, (child) => { return ReactAddons.addons.cloneWithProps(child, { - onRequestHide: this.props.onRequestHide, + onRequestHide: this.hide, handleSuccess: this.handleSuccess }); }); }, render() { + let trigger = React.cloneElement(this.props.trigger, {onClick: this.show}); + return ( - -
- {this.renderChildren()} -
-
+ + {trigger} + + + + {this.props.title} + + +
+ {this.renderChildren()} +
+
+
); } }); - export default ModalWrapper; diff --git a/js/mixins/modal_mixin.js b/js/mixins/modal_mixin.js deleted file mode 100644 index 6087f32c..00000000 --- a/js/mixins/modal_mixin.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -let ModalMixin = { - onRequestHide(e){ - if (e) { - e.preventDefault(); - } - this.props.onRequestHide(); - } -}; - -export default ModalMixin; \ No newline at end of file From 1ae77d5157fc1b7b63107efe50524e8fb1ae0b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 5 Aug 2015 18:00:44 +0200 Subject: [PATCH 005/397] remove close button from modals --- js/components/ascribe_forms/form_consign.js | 9 ++-- .../ascribe_forms/form_delete_edition.js | 9 ++-- .../ascribe_forms/form_delete_piece.js | 9 ++-- js/components/ascribe_forms/form_loan.js | 9 ++-- .../form_remove_editions_from_collection.js | 6 +-- .../ascribe_forms/form_share_email.js | 11 ++--- .../ascribe_forms/form_submit_to_prize.js | 10 ++--- js/components/ascribe_forms/form_transfer.js | 9 ++-- js/components/ascribe_forms/form_unconsign.js | 9 ++-- .../ascribe_forms/form_unconsign_request.js | 9 ++-- js/components/ascribe_modal/modal_wrapper.js | 3 +- js/components/login_modal_handler.js | 43 ------------------- 12 files changed, 39 insertions(+), 97 deletions(-) delete mode 100644 js/components/login_modal_handler.js diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index 5815efdd..875b6ddd 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -18,7 +18,6 @@ let ConsignForm = React.createClass({ url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -39,11 +38,9 @@ let ConsignForm = React.createClass({

- + type="submit"> + {getLangText('CONSIGN')} +

} spinner={ diff --git a/js/components/ascribe_forms/form_delete_edition.js b/js/components/ascribe_forms/form_delete_edition.js index c05a20bc..87ffd98b 100644 --- a/js/components/ascribe_forms/form_delete_edition.js +++ b/js/components/ascribe_forms/form_delete_edition.js @@ -24,9 +24,12 @@ let EditionDeleteForm = React.createClass({

{getLangText('Are you sure you would like to permanently delete this edition')}?

{getLangText('This is an irrevocable action%s', '.')}

- - +
); diff --git a/js/components/ascribe_forms/form_delete_piece.js b/js/components/ascribe_forms/form_delete_piece.js index 168d9261..31a3e5c9 100644 --- a/js/components/ascribe_forms/form_delete_piece.js +++ b/js/components/ascribe_forms/form_delete_piece.js @@ -28,9 +28,12 @@ let PieceDeleteForm = React.createClass({

{getLangText('Are you sure you would like to permanently delete this piece')}?

{getLangText('This is an irrevocable action%s', '.')}

- - +
); diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index a25189c6..6d768c39 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -23,7 +23,6 @@ let LoanForm = React.createClass({ url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -101,11 +100,9 @@ let LoanForm = React.createClass({

- + type="submit"> + {getLangText('LOAN')} +

} spinner={ diff --git a/js/components/ascribe_forms/form_remove_editions_from_collection.js b/js/components/ascribe_forms/form_remove_editions_from_collection.js index 4ab8fdf7..b69820de 100644 --- a/js/components/ascribe_forms/form_remove_editions_from_collection.js +++ b/js/components/ascribe_forms/form_remove_editions_from_collection.js @@ -25,9 +25,9 @@ let EditionRemoveFromCollectionForm = React.createClass({

{getLangText('Are you sure you would like to remove these editions from your collection')}?

{getLangText('This is an irrevocable action%s', '.')}

- - +
); diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index 881c9683..86f69cd1 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -2,8 +2,6 @@ import React from 'react'; - - import Form from './form'; import Property from './property'; import InputTextAreaToggable from './input_textarea_toggable'; @@ -20,7 +18,6 @@ let ShareForm = React.createClass({ message: React.PropTypes.string, editions: React.PropTypes.array, currentUser: React.PropTypes.object, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -41,11 +38,9 @@ let ShareForm = React.createClass({

- + type="submit"> + SHARE +

} spinner={ diff --git a/js/components/ascribe_forms/form_submit_to_prize.js b/js/components/ascribe_forms/form_submit_to_prize.js index 7f991af3..ff853c01 100644 --- a/js/components/ascribe_forms/form_submit_to_prize.js +++ b/js/components/ascribe_forms/form_submit_to_prize.js @@ -19,10 +19,7 @@ import requests from '../../utils/requests'; let PieceSubmitToPrizeForm = React.createClass({ propTypes: { piece: React.PropTypes.object, - handleSuccess: React.PropTypes.func, - - // this is set by ModalWrapper automatically - onRequestHide: React.PropTypes.func + handleSuccess: React.PropTypes.func }, render() { @@ -36,7 +33,9 @@ let PieceSubmitToPrizeForm = React.createClass({

+ type="submit"> + {getLangText('SUBMIT TO PRIZE')} +

} spinner={ @@ -80,7 +79,6 @@ let PieceSubmitToPrizeForm = React.createClass({

{getLangText('Are you sure you want to submit to the prize?')}

{getLangText('This is an irrevocable action%s', '.')}

- ); } diff --git a/js/components/ascribe_forms/form_transfer.js b/js/components/ascribe_forms/form_transfer.js index 07821475..6ec73d38 100644 --- a/js/components/ascribe_forms/form_transfer.js +++ b/js/components/ascribe_forms/form_transfer.js @@ -21,7 +21,6 @@ let TransferForm = React.createClass({ message: React.PropTypes.string, editions: React.PropTypes.array, currentUser: React.PropTypes.object, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -42,11 +41,9 @@ let TransferForm = React.createClass({

- + type="submit"> + {getLangText('TRANSFER')} +

} spinner={ diff --git a/js/components/ascribe_forms/form_unconsign.js b/js/components/ascribe_forms/form_unconsign.js index d33ccedf..9bc5b4bd 100644 --- a/js/components/ascribe_forms/form_unconsign.js +++ b/js/components/ascribe_forms/form_unconsign.js @@ -18,7 +18,6 @@ let UnConsignForm = React.createClass({ id: React.PropTypes.object, message: React.PropTypes.string, editions: React.PropTypes.array, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -39,11 +38,9 @@ let UnConsignForm = React.createClass({

- + type="submit"> + {getLangText('UNCONSIGN')} +

} spinner={ diff --git a/js/components/ascribe_forms/form_unconsign_request.js b/js/components/ascribe_forms/form_unconsign_request.js index 1978e151..ff4b8978 100644 --- a/js/components/ascribe_forms/form_unconsign_request.js +++ b/js/components/ascribe_forms/form_unconsign_request.js @@ -19,7 +19,6 @@ let UnConsignRequestForm = React.createClass({ url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, - onRequestHide: React.PropTypes.func, handleSuccess: React.PropTypes.func }, @@ -40,11 +39,9 @@ let UnConsignRequestForm = React.createClass({

- + type="submit"> + {getLangText('REQUEST UNCONSIGN')} +

} spinner={ diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js index 05971f3a..f00eee9e 100644 --- a/js/components/ascribe_modal/modal_wrapper.js +++ b/js/components/ascribe_modal/modal_wrapper.js @@ -46,13 +46,14 @@ let ModalWrapper = React.createClass({ renderChildren() { return ReactAddons.Children.map(this.props.children, (child) => { return ReactAddons.addons.cloneWithProps(child, { - onRequestHide: this.hide, handleSuccess: this.handleSuccess }); }); }, render() { + // this adds the onClick method show of modal_wrapper to the trigger component + // which is in most cases a button. let trigger = React.cloneElement(this.props.trigger, {onClick: this.show}); return ( diff --git a/js/components/login_modal_handler.js b/js/components/login_modal_handler.js deleted file mode 100644 index 005fbcd7..00000000 --- a/js/components/login_modal_handler.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -import React from 'react'; - -import Button from 'react-bootstrap/lib/Button'; -import Modal from 'react-bootstrap/lib/Modal'; -import OverlayMixin from 'react-bootstrap/lib/OverlayMixin'; -import { getLangText } from '../utils/lang_utils.js'; - -let LoginModalHandler = React.createClass({ - mixins: [OverlayMixin], - - getInitialState() { - return { - isModalOpen: true - }; - }, - - handleToggle() { - this.setState({ - isModalOpen: !this.state.isModalOpen - }); - }, - - render() { - if(!this.state.isModalOpen || !(this.props.query.login === '')) { - return ; - } - - return ( - -
- This modal is controlled by our custom trigger component. -
-
- -
-
- ); - } -}); - -export default LoginModalHandler; \ No newline at end of file From d66549478f2ae138204c807aa31b0cc9695bfbf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 5 Aug 2015 18:14:49 +0200 Subject: [PATCH 006/397] WIP: Refactor delete editions form --- .../ascribe_buttons/delete_button.js | 7 +- .../ascribe_forms/form_delete_edition.js | 64 +++++++++++++------ .../ascribe_forms/form_piece_extradata.js | 4 +- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/js/components/ascribe_buttons/delete_button.js b/js/components/ascribe_buttons/delete_button.js index 0e811885..b0b64427 100644 --- a/js/components/ascribe_buttons/delete_button.js +++ b/js/components/ascribe_buttons/delete_button.js @@ -26,7 +26,7 @@ let DeleteButton = React.createClass({ mixins: [Router.Navigation], - render: function () { + render() { let availableAcls; let btnDelete; let content; @@ -61,10 +61,11 @@ let DeleteButton = React.createClass({ } btnDelete = ; - } - else { + + } else { return null; } + return ( +
+

+ +

+ + } + spinner={ +
+ +
+ }>

{getLangText('Are you sure you would like to permanently delete this edition')}?

{getLangText('This is an irrevocable action%s', '.')}

-
- -
- +
); } }); diff --git a/js/components/ascribe_forms/form_piece_extradata.js b/js/components/ascribe_forms/form_piece_extradata.js index bbec9dca..cc4ec130 100644 --- a/js/components/ascribe_forms/form_piece_extradata.js +++ b/js/components/ascribe_forms/form_piece_extradata.js @@ -3,7 +3,7 @@ import React from 'react'; import requests from '../../utils/requests'; -import { getLangText } from '../../utils/lang_utils.js' +import { getLangText } from '../../utils/lang_utils.js'; import apiUrls from '../../constants/api_urls'; @@ -20,6 +20,7 @@ let PieceExtraDataForm = React.createClass({ title: React.PropTypes.string, editable: React.PropTypes.bool }, + getFormData(){ let extradata = {}; extradata[this.props.name] = this.refs.form.refs[this.props.name].state.value; @@ -28,6 +29,7 @@ let PieceExtraDataForm = React.createClass({ piece_id: this.props.pieceId }; }, + render() { let defaultValue = this.props.extraData[this.props.name] || ''; if (defaultValue.length === 0 && !this.props.editable){ From dbd0e14a649ca8c824eae0b9191c095c558158ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:09:25 +0200 Subject: [PATCH 007/397] add DELETE http support to form --- js/components/ascribe_forms/form.js | 51 ++++++++++++++++--- js/components/ascribe_forms/form_consign.js | 1 - .../ascribe_forms/form_delete_edition.js | 7 ++- .../ascribe_forms/form_request_action.js | 3 +- js/utils/requests.js | 2 +- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 0f022a0d..23ace605 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -15,13 +15,25 @@ import { mergeOptionsWithDuplicates } from '../../utils/general_utils'; let Form = React.createClass({ propTypes: { url: React.PropTypes.string, + method: React.PropTypes.string, handleSuccess: React.PropTypes.func, getFormData: React.PropTypes.func, children: React.PropTypes.oneOfType([ React.PropTypes.object, React.PropTypes.array ]), - className: React.PropTypes.string + className: React.PropTypes.string, + spinner: React.PropTypes.element, + buttons: React.PropTypes.oneOfType([ + React.PropTypes.element, + React.PropTypes.arrayOf(React.PropTypes.element) + ]) + }, + + getDefaultProps() { + return { + method: 'post' + }; }, getInitialState() { @@ -31,6 +43,7 @@ let Form = React.createClass({ errors: [] }; }, + reset(){ for (let ref in this.refs){ if (typeof this.refs[ref].reset === 'function'){ @@ -39,22 +52,38 @@ let Form = React.createClass({ } this.setState(this.getInitialState()); }, + submit(event){ - if (event) { + + if(event) { event.preventDefault(); } + this.setState({submitted: true}); this.clearErrors(); - let action = (this.httpVerb && this.httpVerb()) || 'post'; - window.setTimeout(() => this[action](), 100); + + // selecting http method based on props + if(this[this.props.method]) { + window.setTimeout(() => this[this.props.method](), 100); + } else { + throw new Error('This HTTP method is not supported by form.js (' + this.props.method + ')'); + } }, - post(){ + + post() { requests .post(this.props.url, { body: this.getFormData() }) .then(this.handleSuccess) .catch(this.handleError); }, + delete() { + requests + .delete(this.props.url, this.getFormData()) + .then(this.handleSuccess) + .catch(this.handleError); + }, + getFormData(){ let data = {}; for (let ref in this.refs){ @@ -70,6 +99,7 @@ let Form = React.createClass({ handleChangeChild(){ this.setState({edited: true}); }, + handleSuccess(response){ if ('handleSuccess' in this.props){ this.props.handleSuccess(response); @@ -79,8 +109,12 @@ let Form = React.createClass({ this.refs[ref].handleSuccess(); } } - this.setState({edited: false, submitted: false}); + this.setState({ + edited: false, + submitted: false + }); }, + handleError(err){ if (err.json) { for (var input in err.json.errors){ @@ -104,6 +138,7 @@ let Form = React.createClass({ } this.setState({submitted: false}); }, + clearErrors(){ for (var ref in this.refs){ if ('clearErrors' in this.refs[ref]){ @@ -112,6 +147,7 @@ let Form = React.createClass({ } this.setState({errors: []}); }, + getButtons() { if (this.state.submitted){ return this.props.spinner; @@ -134,6 +170,7 @@ let Form = React.createClass({ } return buttons; }, + getErrors() { let errors = null; if (this.state.errors.length > 0){ @@ -143,6 +180,7 @@ let Form = React.createClass({ } return errors; }, + renderChildren() { return ReactAddons.Children.map(this.props.children, (child) => { if (child) { @@ -153,6 +191,7 @@ let Form = React.createClass({ } }); }, + render() { let className = 'ascribe-form'; diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index 875b6ddd..9b3f0c9c 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -26,7 +26,6 @@ let ConsignForm = React.createClass({ }, render() { - return (
diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 622aa02f..9bd1b4c9 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -59,8 +59,7 @@ let RequestActionForm = React.createClass({ onClick={this.handleRequest} className='btn btn-default btn-sm ascribe-margin-1px'>{getLangText('ACCEPT')} ); - if (edition.request_action === 'unconsign'){ - console.log(this.props) + if (edition.request_action === 'unconsign') { buttonAccept = ( { let val = params[key]; if (!val) { From a3bfda186aa46af29872e916c1bf586225679867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:15:02 +0200 Subject: [PATCH 008/397] refactor form_delete_piece --- .../ascribe_forms/form_delete_edition.js | 2 + .../ascribe_forms/form_delete_piece.js | 59 ++++++++++++------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/js/components/ascribe_forms/form_delete_edition.js b/js/components/ascribe_forms/form_delete_edition.js index 0cb31703..9eb721f6 100644 --- a/js/components/ascribe_forms/form_delete_edition.js +++ b/js/components/ascribe_forms/form_delete_edition.js @@ -14,6 +14,8 @@ let EditionDeleteForm = React.createClass({ propTypes: { editions: React.PropTypes.arrayOf(React.PropTypes.object), + + // Propagated by ModalWrapper in most cases handleSuccess: React.PropTypes.func }, diff --git a/js/components/ascribe_forms/form_delete_piece.js b/js/components/ascribe_forms/form_delete_piece.js index 31a3e5c9..1ac073fd 100644 --- a/js/components/ascribe_forms/form_delete_piece.js +++ b/js/components/ascribe_forms/form_delete_piece.js @@ -2,40 +2,55 @@ import React from 'react'; -import requests from '../../utils/requests'; +import Form from '../ascribe_forms/form'; + import ApiUrls from '../../constants/api_urls'; -import FormMixin from '../../mixins/form_mixin'; +import AppConstants from '../../constants/application_constants'; + import { getLangText } from '../../utils/lang_utils'; let PieceDeleteForm = React.createClass({ propTypes: { - pieceId: React.PropTypes.number + pieceId: React.PropTypes.number, + + // Propagated by ModalWrapper in most cases + handleSuccess: React.PropTypes.func }, - mixins: [FormMixin], - - url() { - return requests.prepareUrl(ApiUrls.piece, {piece_id: this.props.pieceId}); + getFormData() { + return { + piece_id: this.props.pieceId + }; }, - httpVerb() { - return 'delete'; - }, - - renderForm () { + render() { return ( -
+ +

+ +

+
+ } + spinner={ +
+ +
+ }>

{getLangText('Are you sure you would like to permanently delete this piece')}?

{getLangText('This is an irrevocable action%s', '.')}

-
- -
- + ); } }); From 68f4decaad978d5a0e696293cb69134681d7049f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:23:01 +0200 Subject: [PATCH 009/397] remove FormPropertyHeader --- .../ascribe_forms/create_editions_form.js | 1 - js/components/ascribe_forms/form_consign.js | 1 - .../ascribe_forms/form_delete_piece.js | 1 + js/components/ascribe_forms/form_login.js | 6 ++-- .../ascribe_forms/form_property_header.js | 22 -------------- .../ascribe_forms/form_register_piece.js | 5 ++-- js/components/ascribe_forms/form_signup.js | 5 ++-- js/components/password_reset_container.js | 30 ++++++++++++++----- js/components/register_piece.js | 1 - 9 files changed, 29 insertions(+), 43 deletions(-) delete mode 100644 js/components/ascribe_forms/form_property_header.js diff --git a/js/components/ascribe_forms/create_editions_form.js b/js/components/ascribe_forms/create_editions_form.js index a9c44993..07f9677c 100644 --- a/js/components/ascribe_forms/create_editions_form.js +++ b/js/components/ascribe_forms/create_editions_form.js @@ -13,7 +13,6 @@ 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 diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index 9b3f0c9c..6f85adc2 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -8,7 +8,6 @@ import Form from './form'; import Property from './property'; import InputTextAreaToggable from './input_textarea_toggable'; - import AppConstants from '../../constants/application_constants'; import { getLangText } from '../../utils/lang_utils.js'; diff --git a/js/components/ascribe_forms/form_delete_piece.js b/js/components/ascribe_forms/form_delete_piece.js index 1ac073fd..552c38c0 100644 --- a/js/components/ascribe_forms/form_delete_piece.js +++ b/js/components/ascribe_forms/form_delete_piece.js @@ -9,6 +9,7 @@ import AppConstants from '../../constants/application_constants'; import { getLangText } from '../../utils/lang_utils'; + let PieceDeleteForm = React.createClass({ propTypes: { pieceId: React.PropTypes.number, diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js index 24b0eb93..a28d99cd 100644 --- a/js/components/ascribe_forms/form_login.js +++ b/js/components/ascribe_forms/form_login.js @@ -11,7 +11,6 @@ import UserActions from '../../actions/user_actions'; import Form from './form'; import Property from './property'; -import FormPropertyHeader from './form_property_header'; import apiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; @@ -20,7 +19,6 @@ import { getLangText } from '../../utils/lang_utils'; let LoginForm = React.createClass({ - propTypes: { headerMessage: React.PropTypes.string, submitMessage: React.PropTypes.string, @@ -114,9 +112,9 @@ let LoginForm = React.createClass({
}> - +

{this.props.headerMessage}

- +
diff --git a/js/components/ascribe_forms/form_property_header.js b/js/components/ascribe_forms/form_property_header.js deleted file mode 100644 index 85e027c1..00000000 --- a/js/components/ascribe_forms/form_property_header.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -import React from 'react'; - -let FormPropertyHeader = React.createClass({ - propTypes: { - children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element - ]) - }, - - render() { - return ( -
- {this.props.children} -
- ); - } -}); - -export default FormPropertyHeader; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index 853506f6..627b1b59 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -7,7 +7,6 @@ import UserActions from '../../actions/user_actions'; import Form from './form'; import Property from './property'; -import FormPropertyHeader from './form_property_header'; import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; @@ -110,9 +109,9 @@ let RegisterPieceForm = React.createClass({ }> - +

{this.props.headerMessage}

- +
}> - +

{this.props.headerMessage}

- +
diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js index 20851632..4cda992e 100644 --- a/js/components/password_reset_container.js +++ b/js/components/password_reset_container.js @@ -5,7 +5,6 @@ import Router from 'react-router'; import Form from './ascribe_forms/form'; import Property from './ascribe_forms/property'; -import FormPropertyHeader from './ascribe_forms/form_property_header'; import apiUrls from '../constants/api_urls'; import GlobalNotificationModel from '../models/global_notification_model'; @@ -15,12 +14,15 @@ import { getLangText } from '../utils/lang_utils'; let PasswordResetContainer = React.createClass({ mixins: [Router.Navigation], + getInitialState() { return {isRequested: false}; }, - handleRequestSuccess(email){ + + handleRequestSuccess(email) { this.setState({isRequested: email}); }, + render() { if (this.props.query.email && this.props.query.token) { return ( @@ -57,12 +59,17 @@ let PasswordResetContainer = React.createClass({ }); let PasswordRequestResetForm = React.createClass({ + propTypes: { + handleRequestSuccess: React.PropTypes.func + }, + handleSuccess() { let notificationText = getLangText('If your email address exists in our database, you will receive a password recovery link in a few minutes.'); let notification = new GlobalNotificationModel(notificationText, 'success', 50000); GlobalNotificationActions.appendGlobalNotification(notification); this.props.handleRequestSuccess(this.refs.form.refs.email.state.value); }, + render() { return (
}> - +

{getLangText('Reset your password')}

- +
@@ -99,19 +106,26 @@ let PasswordRequestResetForm = React.createClass({ }); let PasswordResetForm = React.createClass({ + propTypes: { + email: React.PropTypes.string, + token: React.PropTypes.string + }, + mixins: [Router.Navigation], - getFormData(){ + getFormData() { return { email: this.props.email, token: this.props.token }; }, + handleSuccess() { this.transitionTo('pieces'); let notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000); GlobalNotificationActions.appendGlobalNotification(notification); }, + render() { return ( }> - +

{getLangText('Reset the password for')} {this.props.email}

- +
diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 20826b7d..cdea0247 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -23,7 +23,6 @@ import GlobalNotificationActions from '../actions/global_notification_actions'; import Property from './ascribe_forms/property'; import PropertyCollapsible from './ascribe_forms/property_collapsible'; import RegisterPieceForm from './ascribe_forms/form_register_piece'; -//import FormPropertyHeader from './ascribe_forms/form_property_header'; import LoginContainer from './login_container'; import SlidesContainer from './ascribe_slides_container/slides_container'; From 0eb10c6c4b75bea7a05c655c631a29bb33a92bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:31:51 +0200 Subject: [PATCH 010/397] refactor form_remove_editions_from_collection --- .../ascribe_forms/form_piece_extradata.js | 2 +- .../form_remove_editions_from_collection.js | 69 +++++++++++++------ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/js/components/ascribe_forms/form_piece_extradata.js b/js/components/ascribe_forms/form_piece_extradata.js index cc4ec130..644cb908 100644 --- a/js/components/ascribe_forms/form_piece_extradata.js +++ b/js/components/ascribe_forms/form_piece_extradata.js @@ -21,7 +21,7 @@ let PieceExtraDataForm = React.createClass({ editable: React.PropTypes.bool }, - getFormData(){ + getFormData() { let extradata = {}; extradata[this.props.name] = this.refs.form.refs[this.props.name].state.value; return { diff --git a/js/components/ascribe_forms/form_remove_editions_from_collection.js b/js/components/ascribe_forms/form_remove_editions_from_collection.js index b69820de..7c0bee01 100644 --- a/js/components/ascribe_forms/form_remove_editions_from_collection.js +++ b/js/components/ascribe_forms/form_remove_editions_from_collection.js @@ -2,34 +2,63 @@ import React from 'react'; -import { getLangText } from '../../utils/lang_utils.js'; -import requests from '../../utils/requests'; -import apiUrls from '../../constants/api_urls'; -import FormMixin from '../../mixins/form_mixin'; +import Form from './form'; + +import ApiUrls from '../../constants/api_urls'; +import AppConstants from '../../constants/application_constants'; + +import { getLangText } from '../../utils/lang_utils'; let EditionRemoveFromCollectionForm = React.createClass({ + propTypes: { + editions: React.PropTypes.arrayOf(React.PropTypes.object), - mixins: [FormMixin], - - url() { - return requests.prepareUrl(apiUrls.edition_remove_from_collection, {edition_id: this.getBitcoinIds().join()}); - }, - - httpVerb(){ - return 'delete'; + // Propagated by ModalWrapper in most cases + handleSuccess: React.PropTypes.func }, - renderForm () { + getBitcoinIds() { + return this.props.editions.map(function(edition){ + return edition.bitcoin_id; + }); + }, + + // Since this form can be used for either removing a single edition or multiple + // we need to call getBitcoinIds to get the value of edition_id + getFormData() { + return { + edition_id: this.getBitcoinIds().join(',') + }; + }, + + render() { return ( -
+ +

+ +

+
+ } + spinner={ +
+ +
+ }>

{getLangText('Are you sure you would like to remove these editions from your collection')}?

{getLangText('This is an irrevocable action%s', '.')}

-
- -
- + ); } }); From 3624ae874f9d2688b033ff614f784d2dd115ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:42:12 +0200 Subject: [PATCH 011/397] refactor form_remove_piece_from_collection --- .../form_remove_piece_from_collection.js | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/js/components/ascribe_forms/form_remove_piece_from_collection.js b/js/components/ascribe_forms/form_remove_piece_from_collection.js index 905cfcf6..d827c2ee 100644 --- a/js/components/ascribe_forms/form_remove_piece_from_collection.js +++ b/js/components/ascribe_forms/form_remove_piece_from_collection.js @@ -2,38 +2,56 @@ import React from 'react'; -import { getLangText } from '../../utils/lang_utils.js'; -import requests from '../../utils/requests'; -import apiUrls from '../../constants/api_urls'; -import FormMixin from '../../mixins/form_mixin'; +import Form from './form'; + +import ApiUrls from '../../constants/api_urls'; +import AppConstants from '../../constants/application_constants'; + +import { getLangText } from '../../utils/lang_utils'; + let PieceRemoveFromCollectionForm = React.createClass({ - propTypes: { - pieceId: React.PropTypes.number + pieceId: React.PropTypes.number, + + // Propagated by ModalWrapper in most cases + handleSuccess: React.PropTypes.func }, - mixins: [FormMixin], - - url() { - return requests.prepareUrl(apiUrls.piece_remove_from_collection, {piece_id: this.props.pieceId}); - }, - - httpVerb(){ - return 'delete'; + getFormData() { + return { + piece_id: this.props.pieceId + }; }, - renderForm () { + render () { return ( -
+
+

+ +

+
+ } + spinner={ +
+ +
+ }>

{getLangText('Are you sure you would like to remove this piece from your collection')}?

{getLangText('This is an irrevocable action%s', '.')}

-
- - -
- + ); } }); From 04c406a2887a65b1fc7768edcb3ddc8fe79f293e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 6 Aug 2015 10:58:09 +0200 Subject: [PATCH 012/397] minor changes --- js/components/ascribe_forms/form_share_email.js | 2 ++ js/components/ascribe_forms/form_unconsign_request.js | 1 - js/components/ascribe_forms/input_date.js | 3 ++- js/components/ascribe_forms/input_textarea_toggable.js | 1 - 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index 86f69cd1..89884886 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -5,9 +5,11 @@ import React from 'react'; import Form from './form'; import Property from './property'; import InputTextAreaToggable from './input_textarea_toggable'; + import Button from 'react-bootstrap/lib/Button'; import AppConstants from '../../constants/application_constants'; + import { getLangText } from '../../utils/lang_utils.js'; diff --git a/js/components/ascribe_forms/form_unconsign_request.js b/js/components/ascribe_forms/form_unconsign_request.js index ff4b8978..c47b5411 100644 --- a/js/components/ascribe_forms/form_unconsign_request.js +++ b/js/components/ascribe_forms/form_unconsign_request.js @@ -3,7 +3,6 @@ import React from 'react'; import Button from 'react-bootstrap/lib/Button'; -import Alert from 'react-bootstrap/lib/Alert'; import Form from './form'; import Property from './property'; diff --git a/js/components/ascribe_forms/input_date.js b/js/components/ascribe_forms/input_date.js index 32ffb5eb..e77f70b7 100644 --- a/js/components/ascribe_forms/input_date.js +++ b/js/components/ascribe_forms/input_date.js @@ -7,7 +7,8 @@ import DatePicker from 'react-datepicker/dist/react-datepicker'; let InputDate = React.createClass({ propTypes: { submitted: React.PropTypes.bool, - placeholderText: React.PropTypes.string + placeholderText: React.PropTypes.string, + onChange: React.PropTypes.func }, getInitialState() { diff --git a/js/components/ascribe_forms/input_textarea_toggable.js b/js/components/ascribe_forms/input_textarea_toggable.js index fe372bdd..bc70c530 100644 --- a/js/components/ascribe_forms/input_textarea_toggable.js +++ b/js/components/ascribe_forms/input_textarea_toggable.js @@ -5,7 +5,6 @@ import React from 'react'; import TextareaAutosize from 'react-textarea-autosize'; let InputTextAreaToggable = React.createClass({ - propTypes: { editable: React.PropTypes.bool.isRequired, rows: React.PropTypes.number.isRequired, From 67f70357a50e9f006075d9d8cf0cdf83f0740b29 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 7 Aug 2015 11:27:44 +0200 Subject: [PATCH 013/397] jury invitation, revoke, resend MIGRATE! --- js/components/ascribe_panel/action_panel.js | 31 ++-- .../prize/actions/prize_jury_actions.js | 47 +++++- .../prize/components/settings_container.js | 140 +++++++++++++++--- .../whitelabel/prize/constants/api_urls.js | 5 +- .../prize/fetchers/prize_jury_fetcher.js | 14 +- .../prize/stores/prize_jury_store.js | 17 +++ sass/ascribe_button.scss | 9 ++ sass/ascribe_panel.scss | 15 +- sass/main.scss | 5 + 9 files changed, 242 insertions(+), 41 deletions(-) create mode 100644 sass/ascribe_button.scss diff --git a/js/components/ascribe_panel/action_panel.js b/js/components/ascribe_panel/action_panel.js index a63af530..1aaef6f7 100644 --- a/js/components/ascribe_panel/action_panel.js +++ b/js/components/ascribe_panel/action_panel.js @@ -48,20 +48,23 @@ let ActionPanel = React.createClass({ render() { return ( -
-
- {this.props.title} -
-
- - {this.props.content} - - - {this.props.buttons} - +
+
+
+
+
+ {this.props.title} +
+
+ {this.props.content} +
+
+
+
+
+ {this.props.buttons} +
+
); diff --git a/js/components/whitelabel/prize/actions/prize_jury_actions.js b/js/components/whitelabel/prize/actions/prize_jury_actions.js index e2fe1a96..bd0a25af 100644 --- a/js/components/whitelabel/prize/actions/prize_jury_actions.js +++ b/js/components/whitelabel/prize/actions/prize_jury_actions.js @@ -8,7 +8,9 @@ import PrizeJuryFetcher from '../fetchers/prize_jury_fetcher'; class PrizeJuryActions { constructor() { this.generateActions( - 'updatePrizeJury' + 'updatePrizeJury', + 'removePrizeJury', + 'activatePrizeJury' ); } @@ -26,6 +28,49 @@ class PrizeJuryActions { }); }); } + + activateJury(email) { + return Q.Promise((resolve, reject) => { + PrizeJuryFetcher + .activate(email) + .then((res) => { + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } + + revokeJury(email) { + return Q.Promise((resolve, reject) => { + PrizeJuryFetcher + .delete(email) + .then((res) => { + this.actions.removePrizeJury(email); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } + + resendJuryInvitation(email) { + return Q.Promise((resolve, reject) => { + PrizeJuryFetcher + .resend(email) + .then((res) => { + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } } export default alt.createActions(PrizeJuryActions); \ No newline at end of file diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/settings_container.js index fecc1fd0..bd426a9c 100644 --- a/js/components/whitelabel/prize/components/settings_container.js +++ b/js/components/whitelabel/prize/components/settings_container.js @@ -144,36 +144,138 @@ let PrizeJurySettings = React.createClass({ this.refs.form.refs.email.refs.input.getDOMNode().value = null; }, - render() { + handleActivate(event) { + let email = event.target.getAttribute('data-id'); + PrizeJuryActions.activateJury(email).then((response) => { + PrizeJuryActions.fetchJury(); + let notification = new GlobalNotificationModel(response.notification, 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }); + }, + + handleRevoke(event) { + let email = event.target.getAttribute('data-id'); + PrizeJuryActions.revokeJury(email).then((response) => { + let notification = new GlobalNotificationModel(response.notification, 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }); + }, + + handleResend(event) { + let email = event.target.getAttribute('data-id'); + PrizeJuryActions.resendJuryInvitation(email).then((response) => { + let notification = new GlobalNotificationModel(response.notification, 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }); + }, + + getMembersPending() { + return this.state.membersPending.map(function(member, i) { + return ( + + + +
+ }/> + ); + }, this); + }, + getMembersActive() { + return this.state.membersActive.map(function(member, i) { + return ( + + +
+ }/> + ); + + }, this); + }, + getMembersInactive() { + return this.state.membersInactive.map(function(member, i) { + return ( + + + + }/> + ); + + }, this); + }, + getMembers() { let content = (
); if (this.state.members.length > -1) { - content = this.state.members.map(function(member, i) { - return ( - - {getLangText('RESEND INVITATION')} - } - />); - }, this); content = ( -
- {content} +
+ + {this.getMembersActive()} + + + {this.getMembersPending()} + + + {this.getMembersInactive()} +
); } + return content; + }, + render() { return (
@@ -190,7 +292,7 @@ let PrizeJurySettings = React.createClass({
- {content} + {this.getMembers()}
); } diff --git a/js/components/whitelabel/prize/constants/api_urls.js b/js/components/whitelabel/prize/constants/api_urls.js index f9030794..3e7260bb 100644 --- a/js/components/whitelabel/prize/constants/api_urls.js +++ b/js/components/whitelabel/prize/constants/api_urls.js @@ -11,7 +11,10 @@ function getApiUrls(subdomain) { 'piece_submit_to_prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/submit/', 'piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/', 'prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/', - 'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/' + 'jurys': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/', + 'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/', + 'jury_activate': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/activate/', + 'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/' }; } diff --git a/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js index be00e930..1c5b0a0d 100644 --- a/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js +++ b/js/components/whitelabel/prize/fetchers/prize_jury_fetcher.js @@ -5,7 +5,19 @@ import requests from '../../../../utils/requests'; let PrizeJuryFetcher = { fetch() { - return requests.get('jury'); + return requests.get('jurys'); + }, + + activate(email) { + return requests.post('jury_activate', {'email': email}); + }, + + delete(email) { + return requests.delete('jury', {'email': email}); + }, + + resend(email) { + return requests.post('jury_resend', {'email': email}); } }; diff --git a/js/components/whitelabel/prize/stores/prize_jury_store.js b/js/components/whitelabel/prize/stores/prize_jury_store.js index 59a54329..88ed21ac 100644 --- a/js/components/whitelabel/prize/stores/prize_jury_store.js +++ b/js/components/whitelabel/prize/stores/prize_jury_store.js @@ -7,11 +7,28 @@ import PrizeJuryActions from '../actions/prize_jury_actions'; class PrizeJuryStore { constructor() { this.members = []; + this.membersActive = []; + this.membersPending = []; + this.membersInactive = []; this.bindActions(PrizeJuryActions); } onUpdatePrizeJury( members ) { this.members = members; + this.splitJuryMembers(); + } + + onRemovePrizeJury( email ) { + let memberInactive = this.members.filter((item)=> item.email === email ); + this.membersActive = this.membersActive.filter((item)=> item.email !== email ); + this.membersPending = this.membersPending.filter((item)=> item.email !== email ); + this.membersInactive = this.membersInactive.concat(memberInactive); + } + + splitJuryMembers(){ + this.membersActive = this.members.filter((item)=> item.status === 'Invitation accepted' ); + this.membersPending = this.members.filter((item)=> item.status === 'Invitation pending' ); + this.membersInactive = this.members.filter((item)=> item.status === 'Deactivated' ); } } diff --git a/sass/ascribe_button.scss b/sass/ascribe_button.scss new file mode 100644 index 00000000..2b366ab1 --- /dev/null +++ b/sass/ascribe_button.scss @@ -0,0 +1,9 @@ +.ascribe-btn-gray { + border-color: #CCCCCC; + background-color: #CCCCCC; + + &:hover{ + border-color: #AAAAAA; + background-color: #AAAAAA; + } +} \ No newline at end of file diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss index 43f8f15f..8ad4249c 100644 --- a/sass/ascribe_panel.scss +++ b/sass/ascribe_panel.scss @@ -1,13 +1,18 @@ .ascribe-panel-wrapper { - border: 1px solid #F5F5F5; + border: 1px solid #DDD; + padding: 1.4em; + margin: 1em 0 1em 0; } .ascribe-panel-title { - padding: 1em 0 1em 1.5em; + margin-bottom: 0.5em; } .ascribe-panel-content { - padding: .75em 0 .75em 1em; - font-size: 1em; - color: #616161; + font-size: 0.9em; + color: rgba(0,0,0,0.5); +} + +.ascribe-panel-buttons { + margin-top: 0.5em; } \ No newline at end of file diff --git a/sass/main.scss b/sass/main.scss index 5f00d2c9..d2c05afa 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -28,6 +28,7 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'ascribe_slides_container'; @import 'ascribe_form'; @import 'ascribe_panel'; +@import 'ascribe_button'; @import 'whitelabel/index'; @@ -325,6 +326,10 @@ hr { margin-top: 1px; } +.margin-left-2px{ + margin-left: 2px; +} + .spin { display:inline-block; -webkit-animation: spin 1s infinite linear; From 192f776bd82705119d6db06012c76298dac81368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 13:05:50 +0200 Subject: [PATCH 014/397] Filter open edition tables correctly --- js/actions/edition_list_actions.js | 3 +- js/components/acl_proxy.js | 4 +- js/components/ascribe_detail/edition.js | 2 +- .../piece_list_bulk_modal.js | 2 +- js/components/piece_list.js | 45 +++++++++++++++---- js/stores/edition_list_store.js | 20 ++++++--- 6 files changed, 56 insertions(+), 20 deletions(-) diff --git a/js/actions/edition_list_actions.js b/js/actions/edition_list_actions.js index d13882cd..8a0bb5cd 100644 --- a/js/actions/edition_list_actions.js +++ b/js/actions/edition_list_actions.js @@ -13,7 +13,8 @@ class EditionListActions { 'selectEdition', 'clearAllEditionSelections', 'closeAllEditionLists', - 'toggleEditionList' + 'toggleEditionList', + 'applyFilterBy' ); } diff --git a/js/components/acl_proxy.js b/js/components/acl_proxy.js index a04e499d..be0d8466 100644 --- a/js/components/acl_proxy.js +++ b/js/components/acl_proxy.js @@ -36,9 +36,9 @@ let AclProxy = React.createClass({ ); } else { - if(typeof this.props.aclObject[this.props.aclName] === 'undefined') { + /* if(typeof this.props.aclObject[this.props.aclName] === 'undefined') { console.warn('The aclName you\'re filtering for was not present (or undefined) in the aclObject.'); - } + } */ return null; } } diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 25e8a97c..3aabc9e2 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -89,7 +89,7 @@ let Edition = React.createClass({ PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy); - EditionListActions.refreshEditionList(this.props.edition.parent); + EditionListActions.refreshEditionList({pieceId: this.props.edition.parent}); EditionListActions.closeAllEditionLists(); EditionListActions.clearAllEditionSelections(); diff --git a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js index 3642a667..452a9bd8 100644 --- a/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js @@ -81,7 +81,7 @@ let PieceListBulkModal = React.createClass({ this.fetchSelectedPieceEditionList() .forEach((pieceId) => { - EditionListActions.refreshEditionList(pieceId); + EditionListActions.refreshEditionList({pieceId, filterBy: {}}); }); EditionListActions.clearAllEditionSelections(); }, diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 1792b17a..9321c693 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -6,6 +6,9 @@ import Router from 'react-router'; import PieceListStore from '../stores/piece_list_store'; import PieceListActions from '../actions/piece_list_actions'; +import EditionListStore from '../stores/edition_list_store'; +import EditionListActions from '../actions/edition_list_actions'; + import AccordionList from './ascribe_accordion_list/accordion_list'; import AccordionListItem from './ascribe_accordion_list/accordion_list_item'; import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_list_item_table_editions'; @@ -17,6 +20,7 @@ import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar'; import AppConstants from '../constants/application_constants'; +import { mergeOptions } from '../utils/general_utils'; let PieceList = React.createClass({ propTypes: { @@ -27,16 +31,22 @@ let PieceList = React.createClass({ mixins: [Router.Navigation, Router.State], getInitialState() { - return PieceListStore.getState(); + return mergeOptions( + PieceListStore.getState(), + EditionListStore.getState() + ); }, componentDidMount() { let page = this.getQuery().page || 1; + PieceListStore.listen(this.onChange); + EditionListStore.listen(this.onChange); + if (this.state.pieceList.length === 0){ PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy) - .then(PieceListActions.fetchPieceRequestActions()); + .then(PieceListActions.fetchPieceRequestActions()); } }, @@ -49,6 +59,7 @@ let PieceList = React.createClass({ componentWillUnmount() { PieceListStore.unlisten(this.onChange); + EditionListStore.unlisten(this.onChange); }, onChange(state) { @@ -56,13 +67,14 @@ let PieceList = React.createClass({ }, paginationGoToPage(page) { - // if the users clicks a pager of the pagination, - // the site should go to the top - document.body.scrollTop = document.documentElement.scrollTop = 0; - - return () => PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, + return () => { + // if the users clicks a pager of the pagination, + // the site should go to the top + document.body.scrollTop = document.documentElement.scrollTop = 0; + PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy); + }; }, getPagination() { @@ -86,8 +98,24 @@ let PieceList = React.createClass({ }, applyFilterBy(filterBy) { + // first we need to apply the filter on the piece list PieceListActions.fetchPieceList(1, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, filterBy); + this.state.orderBy, this.state.orderAsc, filterBy) + .then(() => { + // but also, we need to filter all the open edition lists + this.state.pieceList + .forEach((piece) => { + // but only if they're actually open + if(this.state.isEditionListOpenForPieceId[piece.id].show) { + EditionListActions.refreshEditionList({ + pieceId: piece.id, + filterBy + }); + } + + }); + }); + // we have to redirect the user always to page one as it could be that there is no page two // for filtered pieces this.transitionTo(this.getPathname(), {page: 1}); @@ -100,7 +128,6 @@ let PieceList = React.createClass({ render() { let loadingElement = (); - return (
{ // reset back to the normal pageSize and page this.editionList[pieceId].page = prevEditionListPage; From b5448b0acb11c4ab93f6abb846f9400254f87102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 13:09:57 +0200 Subject: [PATCH 015/397] wording --- .../piece_list_toolbar_filter_widget.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js index 13bfd9a0..2520c499 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js @@ -80,7 +80,7 @@ let PieceListToolbarFilterWidgetFilter = React.createClass({ title={filterIcon} className="ascribe-piece-list-toolbar-filter-widget">
  • - {getLangText('Show works that')}: + {getLangText('Show works I can')}:
  • {this.props.filterParams.map((param, i) => { let label; @@ -100,7 +100,7 @@ let PieceListToolbarFilterWidgetFilter = React.createClass({ className="filter-widget-item">
    - {getLangText('I can') + ' ' + getLangText(label)} + {getLangText(label)} Date: Fri, 7 Aug 2015 13:18:33 +0200 Subject: [PATCH 016/397] fix minor consistence bug --- js/stores/edition_list_store.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js index f5430d6c..90f48e8f 100644 --- a/js/stores/edition_list_store.js +++ b/js/stores/edition_list_store.js @@ -133,9 +133,17 @@ class EditionListStore { } onToggleEditionList(pieceId) { + this.isEditionListOpenForPieceId[pieceId] = { show: this.isEditionListOpenForPieceId[pieceId] ? !this.isEditionListOpenForPieceId[pieceId].show : true }; + + if(!this.isEditionListOpenForPieceId[pieceId].show) { + // to clear an array, david walsh recommends to just set it's length to zero + // http://davidwalsh.name/empty-array + + this.editionList[pieceId].length = 0; + } } onCloseAllEditionLists() { From bbb0bb15b6e1902f98c8bc8f1d98fa5b96ac84f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 13:20:31 +0200 Subject: [PATCH 017/397] add documentation --- js/stores/edition_list_store.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js index 90f48e8f..87b4df76 100644 --- a/js/stores/edition_list_store.js +++ b/js/stores/edition_list_store.js @@ -138,6 +138,10 @@ class EditionListStore { show: this.isEditionListOpenForPieceId[pieceId] ? !this.isEditionListOpenForPieceId[pieceId].show : true }; + // When loading all editions of a piece, closing the table and then applying the filter + // the merge fails, as the edition list is not refreshed when closed. + // Therefore in the case of a filter application when closed, we need to reload the + // edition list if(!this.isEditionListOpenForPieceId[pieceId].show) { // to clear an array, david walsh recommends to just set it's length to zero // http://davidwalsh.name/empty-array From 6fc7ac8b63b2a78a8a4b639e400a515a87e58255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 13:21:54 +0200 Subject: [PATCH 018/397] remove unneccesary action for edition list actions --- js/actions/edition_list_actions.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js/actions/edition_list_actions.js b/js/actions/edition_list_actions.js index 8a0bb5cd..d13882cd 100644 --- a/js/actions/edition_list_actions.js +++ b/js/actions/edition_list_actions.js @@ -13,8 +13,7 @@ class EditionListActions { 'selectEdition', 'clearAllEditionSelections', 'closeAllEditionLists', - 'toggleEditionList', - 'applyFilterBy' + 'toggleEditionList' ); } From e9c776fec46baa27ed1bd1b8fd34547a0b4d422e Mon Sep 17 00:00:00 2001 From: vrde Date: Fri, 7 Aug 2015 14:23:59 +0200 Subject: [PATCH 019/397] Add "s" to http lol --- js/components/ascribe_detail/media_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_detail/media_container.js b/js/components/ascribe_detail/media_container.js index 2ff5a55d..529817c3 100644 --- a/js/components/ascribe_detail/media_container.js +++ b/js/components/ascribe_detail/media_container.js @@ -46,7 +46,7 @@ let MediaContainer = React.createClass({ } panel={
    -                            {''}
                             
    }/> From f73001a5b8564b6188b4bfa1eac3507f43ae5af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 14:31:37 +0200 Subject: [PATCH 020/397] remove form property header and replace class name definition --- js/components/ascribe_panel/action_panel.js | 13 ++----------- .../prize/components/settings_container.js | 5 ++--- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/js/components/ascribe_panel/action_panel.js b/js/components/ascribe_panel/action_panel.js index 1aaef6f7..0e63999e 100644 --- a/js/components/ascribe_panel/action_panel.js +++ b/js/components/ascribe_panel/action_panel.js @@ -1,7 +1,7 @@ 'use strict'; import React from 'react'; - +import classnames from 'classnames'; let ActionPanel = React.createClass({ propTypes: { @@ -37,18 +37,9 @@ let ActionPanel = React.createClass({ }); }, - getClassName() { - if(this.state.isFocused) { - return 'is-focused'; - } else { - return ''; - } - }, - render() { - return ( -
    +
    diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/settings_container.js index bd426a9c..ca5bbf7e 100644 --- a/js/components/whitelabel/prize/components/settings_container.js +++ b/js/components/whitelabel/prize/components/settings_container.js @@ -14,7 +14,6 @@ import CollapsibleParagraph from '../../../ascribe_collapsible/collapsible_parag import Form from '../../../ascribe_forms/form'; import Property from '../../../ascribe_forms/property'; -import FormPropertyHeader from '../../../ascribe_forms/form_property_header'; import ActionPanel from '../../../ascribe_panel/action_panel'; @@ -279,9 +278,9 @@ let PrizeJurySettings = React.createClass({ handleSuccess={this.handleCreateSuccess} ref='form' buttonSubmitText='INVITE'> - +

    Jury Members

    - +
    From b56ae0e145fb3c807cc35dc76e3d4d74f4fbf71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 14:50:34 +0200 Subject: [PATCH 021/397] fix requestActions requests --- js/components/piece_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 9321c693..78917f61 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -46,7 +46,7 @@ let PieceList = React.createClass({ if (this.state.pieceList.length === 0){ PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy) - .then(PieceListActions.fetchPieceRequestActions()); + .then(() => PieceListActions.fetchPieceRequestActions()); } }, From 3afb036f2434169e86dc642330e10e1a7c5b5da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 15:08:02 +0200 Subject: [PATCH 022/397] rename apiUrls to ApiUrls --- js/components/ascribe_buttons/acl_button.js | 12 ++++++------ .../ascribe_buttons/unconsign_request_button.js | 4 ++-- js/components/ascribe_detail/edition.js | 8 ++++---- js/components/ascribe_detail/further_details.js | 4 ++-- .../ascribe_forms/create_editions_form.js | 4 ++-- js/components/ascribe_forms/form_login.js | 4 ++-- .../ascribe_forms/form_piece_extradata.js | 4 ++-- js/components/ascribe_forms/form_register_piece.js | 6 +++--- js/components/ascribe_forms/form_request_action.js | 14 +++++++------- js/components/ascribe_forms/form_signup.js | 4 ++-- js/components/coa_verify_container.js | 4 ++-- js/components/password_reset_container.js | 6 +++--- js/components/settings_container.js | 12 ++++++------ .../prize/components/settings_container.js | 4 ++-- js/constants/api_urls.js | 6 +++--- js/fetchers/user_fetcher.js | 4 ++-- 16 files changed, 50 insertions(+), 50 deletions(-) diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index f457e48b..5a924a0c 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -14,7 +14,7 @@ import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; import { getLangText } from '../../utils/lang_utils.js'; -import apiUrls from '../../constants/api_urls'; +import ApiUrls from '../../constants/api_urls'; let AclButton = React.createClass({ propTypes: { @@ -42,7 +42,7 @@ let AclButton = React.createClass({ + url={ApiUrls.ownership_consigns}/> ), handleSuccess: this.showNotification }; @@ -55,7 +55,7 @@ let AclButton = React.createClass({ + url={ApiUrls.ownership_unconsigns}/> ), handleSuccess: this.showNotification }; @@ -67,7 +67,7 @@ let AclButton = React.createClass({ + url={ApiUrls.ownership_transfers}/> ), handleSuccess: this.showNotification }; @@ -79,7 +79,7 @@ let AclButton = React.createClass({ form: ( + url={this.isPiece() ? ApiUrls.ownership_loans_pieces : ApiUrls.ownership_loans_editions}/> ), handleSuccess: this.showNotification }; @@ -92,7 +92,7 @@ let AclButton = React.createClass({ + url={this.isPiece() ? ApiUrls.ownership_shares_pieces : ApiUrls.ownership_shares_editions }/> ), handleSuccess: this.showNotification }; diff --git a/js/components/ascribe_buttons/unconsign_request_button.js b/js/components/ascribe_buttons/unconsign_request_button.js index b192ac55..e5e1c661 100644 --- a/js/components/ascribe_buttons/unconsign_request_button.js +++ b/js/components/ascribe_buttons/unconsign_request_button.js @@ -8,7 +8,7 @@ import ModalWrapper from '../ascribe_modal/modal_wrapper'; import UnConsignRequestForm from './../ascribe_forms/form_unconsign_request'; import { getLangText } from '../../utils/lang_utils.js'; -import apiUrls from '../../constants/api_urls'; +import ApiUrls from '../../constants/api_urls'; let UnConsignRequestButton = React.createClass({ @@ -29,7 +29,7 @@ let UnConsignRequestButton = React.createClass({ handleSuccess={this.props.handleSuccess} title='Request to Un-Consign'> 0 && this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer) { withdrawButton = (
    @@ -335,7 +335,7 @@ let EditionPersonalNote = React.createClass({ if (this.props.currentUser.username && true || false) { return ( diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index b4f7d926..c11a5df2 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -5,7 +5,7 @@ import getPrizeApiUrls from '../components/whitelabel/prize/constants/api_urls'; import { update } from '../utils/general_utils'; -let apiUrls = { +let ApiUrls = { 'applications': AppConstants.apiEndpoint + 'applications/', 'application_token_refresh': AppConstants.apiEndpoint + 'applications/refresh_token/', 'blob_digitalworks': AppConstants.apiEndpoint + 'blob/digitalworks/', @@ -63,7 +63,7 @@ export function updateApiUrls(type, subdomain) { if (type === 'prize') { newUrls = getPrizeApiUrls(subdomain); } - update(apiUrls, newUrls); + update(ApiUrls, newUrls); } -export default apiUrls; +export default ApiUrls; diff --git a/js/fetchers/user_fetcher.js b/js/fetchers/user_fetcher.js index a175c644..eca7494d 100644 --- a/js/fetchers/user_fetcher.js +++ b/js/fetchers/user_fetcher.js @@ -1,7 +1,7 @@ 'use strict'; import requests from '../utils/requests'; -import apiUrls from '../constants/api_urls'; +import ApiUrls from '../constants/api_urls'; let UserFetcher = { /** @@ -13,7 +13,7 @@ let UserFetcher = { }, logout() { - return requests.get(apiUrls.users_logout); + return requests.get(ApiUrls.users_logout); } }; From 8275a8d626a6fe1a25afd165ca4de0fa124b6daf Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 7 Aug 2015 15:10:39 +0200 Subject: [PATCH 023/397] prize: permission refactor email: moved cc folders bug fix email: encode email in queryparams --- .../prize/components/settings_container.js | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/settings_container.js index bd426a9c..affae8f2 100644 --- a/js/components/whitelabel/prize/components/settings_container.js +++ b/js/components/whitelabel/prize/components/settings_container.js @@ -18,17 +18,12 @@ import FormPropertyHeader from '../../../ascribe_forms/form_property_header'; import ActionPanel from '../../../ascribe_panel/action_panel'; -import Table from '../../../ascribe_table/table'; -import TableItem from '../../../ascribe_table/table_item'; -import TableItemText from '../../../ascribe_table/table_item_text'; - import GlobalNotificationModel from '../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../actions/global_notification_actions'; import AppConstants from '../../../../constants/application_constants'; import apiUrls from '../../../../constants/api_urls'; -import { ColumnModel} from '../../../ascribe_table/models/table_models'; import { getLangText } from '../../../../utils/lang_utils'; @@ -299,54 +294,4 @@ let PrizeJurySettings = React.createClass({ }); -let PrizesDashboard = React.createClass({ - - getColumnList() { - return [ - new ColumnModel( - (item) => { - return { - 'content': item.name - }; }, - 'name', - getLangText('Name'), - TableItemText, - 6, - false, - null - ), - new ColumnModel( - (item) => { - return { - 'content': item.domain - }; }, - 'domain', - getLangText('Domain'), - TableItemText, - 1, - false, - null - ) - ]; - }, - - render() { - return ( - - {this.state.prizeList.map((item, i) => { - return ( - - ); - })} -
    - ); - } -}); - export default Settings; \ No newline at end of file From 5cef512c0da4517de242ad6d64c33843e50983da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 7 Aug 2015 15:10:47 +0200 Subject: [PATCH 024/397] remove react flow type --- .../react_flow_type/react_flow_type.js | 92 ------------------- 1 file changed, 92 deletions(-) delete mode 100644 js/components/react_flow_type/react_flow_type.js diff --git a/js/components/react_flow_type/react_flow_type.js b/js/components/react_flow_type/react_flow_type.js deleted file mode 100644 index 063eaf1c..00000000 --- a/js/components/react_flow_type/react_flow_type.js +++ /dev/null @@ -1,92 +0,0 @@ -'use strict'; -/** - * This component is essentially a port of https://github.com/simplefocus/FlowType.JS - * to Reactjs in order to not being forced to use jQuery - * - * Author: Tim Daubenschütz - * - * Thanks to the guys at Simple Focus http://simplefocus.com/ - */ - -import React from 'react'; -import ReactAddons from 'react/addons'; - -let FlowType = React.createClass({ - propTypes: { - - // standard FlowTypes.JS options - maximum: React.PropTypes.number, - minimum: React.PropTypes.number, - maxFont: React.PropTypes.number, - minFont: React.PropTypes.number, - fontRatio: React.PropTypes.number, - - // react specific options - children: React.PropTypes.element.isRequired // only supporting one child element at once right now - }, - - getDefaultProps() { - return { - maximum: 9999, - minimum: 1, - maxFont: 9999, - minFont: 1, - fontRatio: 35 - }; - }, - - getInitialState() { - return { - // 32 because that's the default font display size - // doesn't really matter though - fontSize: 0 - }; - }, - - componentDidMount() { - // Make changes upon resize, calculate changes and rerender - this.handleResize(); - window.addEventListener('resize', this.handleResize); - }, - - componentWillUnmount() { - // stop listening to window once the component was unmounted - window.removeEventListener('resize', this.handleResize); - }, - - handleResize() { - let elemWidth = this.refs.flowTypeElement.getDOMNode().offsetWidth; - let width = elemWidth > this.props.maximum ? this.props.maximum : elemWidth < this.props.minimum ? this.props.minimum : elemWidth; - let fontBase = width / this.props.fontRatio; - let fontSize = fontBase > this.props.maxFont ? this.props.maxFont : fontBase < this.props.minFont ? this.props.minFont : fontBase; - - this.setState({ fontSize }); - }, - - // The child the user passes to this component needs to have it's - // style.fontSize property to be updated - renderChildren() { - return ReactAddons.Children.map(this.props.children, (child) => { - return ReactAddons.addons.cloneWithProps(child, { - ref: 'flowTypeFontElement', - - }); - }); - }, - - render() { - return ( -
    - {this.props.children} -
    - ); - } -}); - -export default FlowType; \ No newline at end of file From 36aa5b1891b0d430cebcf2bc6d3dd80ca7aac37f Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 7 Aug 2015 15:54:36 +0200 Subject: [PATCH 025/397] api tokens with panel instead of property --- js/components/settings_container.js | 35 +++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/js/components/settings_container.js b/js/components/settings_container.js index c35fba1e..76a6cf2c 100644 --- a/js/components/settings_container.js +++ b/js/components/settings_container.js @@ -22,6 +22,8 @@ import Form from './ascribe_forms/form'; import Property from './ascribe_forms/property'; import InputCheckbox from './ascribe_forms/input_checkbox'; +import ActionPanel from './ascribe_panel/action_panel'; + import apiUrls from '../constants/api_urls'; import AppConstants from '../constants/application_constants'; import { getLangText } from '../utils/lang_utils'; @@ -339,20 +341,18 @@ let APISettings = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); }, - render() { + getApplications(){ let content = ; if (this.state.applications.length > -1) { content = this.state.applications.map(function(app, i) { return ( - -
    -
    - {'Bearer ' + app.bearer_token.token} -
    -
    + key={i} + title={app.name} + content={'Bearer ' + app.bearer_token.token} + buttons={ +
    -
    - ); + }/> + ); }, this); - content = ( -
    - - {content} -
    - -
    ); } + return content; + }, + render() { + return ( Usage: curl <url> -H 'Authorization: Bearer <token>' - {content} + {this.getApplications()} ); } From b70eb23dc0f16e18edd0e02da1475ba8ee798c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 09:22:39 +0200 Subject: [PATCH 026/397] refactor action panel: mostly css and layout --- .../ascribe_forms/form_request_action.js | 24 +++-- js/components/ascribe_panel/action_panel.js | 21 ++-- .../prize/components/settings_container.js | 64 ++++++++----- sass/ascribe_panel.scss | 96 +++++++++++++++++-- 4 files changed, 153 insertions(+), 52 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 5b7b2556..b50fbb67 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -8,6 +8,7 @@ import ApiUrls from '../../constants/api_urls'; import FormMixin from '../../mixins/form_mixin'; import AclButton from './../ascribe_buttons/acl_button'; +import ActionPanel from '../ascribe_panel/action_panel'; import AppConstants from '../../constants/application_constants'; import { getLangText } from '../../utils/lang_utils.js'; @@ -52,6 +53,17 @@ let RequestActionForm = React.createClass({ }; }, + getContent() { + let edition = this.props.editions[0]; + let message = edition.owner + ' ' + getLangText('requests you') + ' ' + edition.request_action + ' ' + getLangText('this edition%s', '.'); + + return ( + + {message} + + ); + }, + renderForm() { let edition = this.props.editions[0]; let buttonAccept = ( @@ -86,13 +98,13 @@ let RequestActionForm = React.createClass({ ); } + + + return ( - -
    -
    { edition.owner } {getLangText('requests you')} { edition.request_action } {getLangText('this edition%s', '.')}  
    - {buttons} -
    -
    + ); } }); diff --git a/js/components/ascribe_panel/action_panel.js b/js/components/ascribe_panel/action_panel.js index 0e63999e..2ad3a255 100644 --- a/js/components/ascribe_panel/action_panel.js +++ b/js/components/ascribe_panel/action_panel.js @@ -40,21 +40,14 @@ let ActionPanel = React.createClass({ render() { return (
    -
    -
    -
    -
    - {this.props.title} -
    -
    - {this.props.content} -
    -
    +
    +
    + {this.props.content}
    -
    -
    - {this.props.buttons} -
    +
    +
    +
    + {this.props.buttons}
    diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/settings_container.js index 36321424..109da9ae 100644 --- a/js/components/whitelabel/prize/components/settings_container.js +++ b/js/components/whitelabel/prize/components/settings_container.js @@ -174,8 +174,16 @@ let PrizeJurySettings = React.createClass({ +
    + {member.email} +
    +
    + {member.status} +
    +
    + } buttons={
    + content={ +
    +
    + {member.email} +
    +
    + {member.status} +
    + } + buttons={ + }/> ); @@ -223,17 +237,23 @@ let PrizeJurySettings = React.createClass({ - + content={ +
    +
    + {member.email} +
    +
    + {member.status} +
    + } + buttons={ + }/> ); diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss index 8ad4249c..73fe572e 100644 --- a/sass/ascribe_panel.scss +++ b/sass/ascribe_panel.scss @@ -1,18 +1,94 @@ .ascribe-panel-wrapper { border: 1px solid #DDD; - padding: 1.4em; - margin: 1em 0 1em 0; + min-height: 5em; + height: 5em; + + margin-top: 1em; + + > div { + height: 100%; + float: left; + + &:first-child { + width: 60%; + } + + &:nth-child(2) { + width: 40%; + } + } } -.ascribe-panel-title { - margin-bottom: 0.5em; +.ascribe-panel-table { + display:table; + + > .ascribe-panel-content { + display: table-cell; + vertical-align: middle; + } + + @media(max-width:767px) { + &:first-child { + > div { + padding-left: 1em; + } + + } + + &:nth-child(2) { + > div { + padding-right: 1em; + + > button { + float:right; + } + } + } + + } + + @media(min-width:768px) { + &:first-child { + > div { + padding-left: 2em; + } + + } + + &:nth-child(2) { + > div { + padding-right: 2em; + + > button { + float:right; + } + } + } + } } -.ascribe-panel-content { - font-size: 0.9em; - color: rgba(0,0,0,0.5); +@media(max-width:767px) { + .ascribe-panel-title { + font-size: .9em; + } + + .ascribe-panel-subtitle { + font-size: .7em; + color: rgba(0,0,0,0.5); + } + } -.ascribe-panel-buttons { - margin-top: 0.5em; -} \ No newline at end of file +@media(min-width:768px) { + .ascribe-panel-title { + font-size: 1.1em; + } + + .ascribe-panel-subtitle { + font-size: .9em; + color: rgba(0,0,0,0.5); + } +} + + + From a55efc16922ec430dd4849f9e34dffff8d260d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 09:39:32 +0200 Subject: [PATCH 027/397] fix large buttons on sluice landing page --- js/components/whitelabel/prize/components/landing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/whitelabel/prize/components/landing.js b/js/components/whitelabel/prize/components/landing.js index b1b06207..3a5dc47f 100644 --- a/js/components/whitelabel/prize/components/landing.js +++ b/js/components/whitelabel/prize/components/landing.js @@ -46,7 +46,7 @@ let Landing = React.createClass({

    This is the submission page for Sluice_screens ↄc Prize 2015.

    - + Sign up to submit From 3ff401904b7f1caa096839a7fd2425ab23fc9c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 10:10:43 +0200 Subject: [PATCH 028/397] fix submit to prize button --- js/components/ascribe_forms/form_signup.js | 6 +----- .../components/ascribe_buttons/submit_to_prize_button.js | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_forms/form_signup.js b/js/components/ascribe_forms/form_signup.js index a454a7e2..67097b42 100644 --- a/js/components/ascribe_forms/form_signup.js +++ b/js/components/ascribe_forms/form_signup.js @@ -55,10 +55,6 @@ let SignupForm = React.createClass({ } }, - getFormData() { - return this.getQuery(); - }, - handleSuccess(response){ if (response.user) { let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000); @@ -80,7 +76,7 @@ let SignupForm = React.createClass({ className="ascribe-form-bordered" ref='form' url={ApiUrls.users_signup} - getFormData={this.getFormData} + getFormData={this.getQuery} handleSuccess={this.handleSuccess} buttons={
    -
    - ); + }/> + ); }, this); - content = ( -
    -
    - {content} -
    -
    -
    ); } + return content; + }, + render() { + return ( Usage: curl <url> -H 'Authorization: Bearer <token>' - {content} + {this.getApplications()} ); } From c8dc4fa12d182882f88019e1496405f3e3fee28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 11:11:28 +0200 Subject: [PATCH 030/397] adjust action panel usage for applications --- js/components/settings_container.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/js/components/settings_container.js b/js/components/settings_container.js index adab2ba4..d7255731 100644 --- a/js/components/settings_container.js +++ b/js/components/settings_container.js @@ -349,16 +349,26 @@ let APISettings = React.createClass({ +
    + {app.name} +
    +
    + {'Bearer ' + app.bearer_token.token} +
    +
    + } buttons={
    - +
    + +
    }/> ); From d968f02b5930469135e40d13d1664526ffb84278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 11:57:38 +0200 Subject: [PATCH 031/397] refactor request action form --- .../ascribe_forms/form_request_action.js | 149 +++++++++++------- js/components/ascribe_panel/action_panel.js | 5 +- 2 files changed, 94 insertions(+), 60 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index b50fbb67..834ea2d5 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -2,49 +2,50 @@ import React from 'react'; -import Alert from 'react-bootstrap/lib/Alert'; - -import ApiUrls from '../../constants/api_urls'; import FormMixin from '../../mixins/form_mixin'; import AclButton from './../ascribe_buttons/acl_button'; import ActionPanel from '../ascribe_panel/action_panel'; +import Form from './form'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import ApiUrls from '../../constants/api_urls'; -import AppConstants from '../../constants/application_constants'; import { getLangText } from '../../utils/lang_utils.js'; -let RequestActionForm = React.createClass({ - mixins: [FormMixin], - url(e){ - let edition = this.props.editions[0]; - if (e.target.id === 'request_accept'){ - if (edition.request_action === 'consign'){ - return ApiUrls.ownership_consigns_confirm; - } - else if (edition.request_action === 'unconsign'){ - return ApiUrls.ownership_unconsigns; - } - else if (edition.request_action === 'loan'){ - return ApiUrls.ownership_loans_confirm; - } - } - else if(e.target.id === 'request_deny'){ - if (edition.request_action === 'consign') { - return ApiUrls.ownership_consigns_deny; - } - else if (edition.request_action === 'unconsign') { - return ApiUrls.ownership_unconsigns_deny; - } - else if (edition.request_action === 'loan') { - return ApiUrls.ownership_loans_deny; - } - } +let RequestActionForm = React.createClass({ + propTypes: { + editions: React.PropTypes.arrayOf(React.PropTypes.object), + currentUser: React.PropTypes.object, + handleSuccess: React.PropTypes.func }, - handleRequest: function(e){ - e.preventDefault(); - this.submit(e); + getUrls() { + let edition = this.props.editions[0]; + let urls = {}; + + + if (edition.request_action === 'consign'){ + urls.accept = ApiUrls.ownership_consigns_confirm; + urls.deny = ApiUrls.ownership_consigns_deny; + } else if (edition.request_action === 'unconsign'){ + urls.accept = ApiUrls.ownership_unconsigns; + urls.deny = ApiUrls.ownership_unconsigns_deny; + } else if (edition.request_action === 'loan'){ + urls.accept = ApiUrls.ownership_loans_confirm; + urls.deny = ApiUrls.ownership_loans_deny; + } + + return urls; + }, + + getBitcoinIds(){ + return this.props.editions.map(function(edition){ + return edition.bitcoin_id; + }); }, getFormData() { @@ -53,6 +54,19 @@ let RequestActionForm = React.createClass({ }; }, + showNotification(option, action, owner) { + return () => { + let message = getLangText('You have successfully') + ' ' + option + ' ' + action + ' ' + getLangText('to') + ' ' + owner; + + let notification = new GlobalNotificationModel(message, 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + + if(this.props.handleSuccess) { + this.props.handleSuccess(); + } + }; + }, + getContent() { let edition = this.props.editions[0]; let message = edition.owner + ' ' + getLangText('requests you') + ' ' + edition.request_action + ' ' + getLangText('this edition%s', '.'); @@ -64,15 +78,11 @@ let RequestActionForm = React.createClass({ ); }, - renderForm() { + getAcceptButton() { let edition = this.props.editions[0]; - let buttonAccept = ( -
    {getLangText('ACCEPT')} -
    ); - if (edition.request_action === 'unconsign') { - buttonAccept = ( + + if(edition.request_action === 'unconsign') { + return ( ); - } - let buttons = ( - - - {buttonAccept} - - -
    {getLangText('REJECT')}
    -
    -
    - ); - if (this.state.submitted){ - buttons = ( - - - + } else { + return ( + ); } + }, - + getButtonForm() { + let edition = this.props.editions[0]; + let urls = this.getUrls(); + let acceptButton = this.getAcceptButton(); + + return ( +
    +
    + +
    +
    + {acceptButton} +
    +
    + ); + }, + + render() { return ( + buttons={this.getButtonForm()}/> ); } }); diff --git a/js/components/ascribe_panel/action_panel.js b/js/components/ascribe_panel/action_panel.js index 2ad3a255..148ea03d 100644 --- a/js/components/ascribe_panel/action_panel.js +++ b/js/components/ascribe_panel/action_panel.js @@ -6,7 +6,10 @@ import classnames from 'classnames'; let ActionPanel = React.createClass({ propTypes: { title: React.PropTypes.string, - content: React.PropTypes.string, + content: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.element + ]), buttons: React.PropTypes.element, onClick: React.PropTypes.func, ignoreFocus: React.PropTypes.bool From e589925c9d15a99e4dd9daeb94d8f2f066993f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 14:05:35 +0200 Subject: [PATCH 032/397] delete form mixin --- js/mixins/form_mixin.js | 108 ---------------------------------------- 1 file changed, 108 deletions(-) delete mode 100644 js/mixins/form_mixin.js diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js deleted file mode 100644 index c04f52ed..00000000 --- a/js/mixins/form_mixin.js +++ /dev/null @@ -1,108 +0,0 @@ -'use strict'; - -import requests from '../utils/requests'; -import React from 'react'; - -import AlertDismissable from '../components/ascribe_forms/alert'; -import { getLangText } from '../utils/lang_utils.js'; - -export const FormMixin = { - propTypes: { - editions: React.PropTypes.array, - currentUser: React.PropTypes.object - }, - - getInitialState() { - return { - submitted: false, - errors: [] - }; - }, - - submit(e) { - if (e) { - e.preventDefault(); - } - this.setState({submitted: true}); - this.clearErrors(); - let action = (this.httpVerb && this.httpVerb()) || 'post'; - this[action](e); - }, - - post(e){ - requests - .post(this.url(e), { body: this.getFormData() }) - .then(this.handleSuccess) - .catch(this.handleError); - }, - - delete(e){ - requests - .delete(this.url(e)) - .then(this.handleSuccess) - .catch(this.handleError); - }, - - clearErrors(){ - for (var ref in this.refs){ - if ('clearAlerts' in this.refs[ref]){ - this.refs[ref].clearAlerts(); - } - - } - this.setState({errors: []}); - }, - handleSuccess(response){ - if ('handleSuccess' in this.props){ - this.props.handleSuccess(response); - } - - }, - handleError(err){ - if (err.json) { - for (var input in err.json.errors){ - if (this.refs && this.refs[input] && this.refs[input].state) { - this.refs[input].setAlerts( err.json.errors[input]); - } else { - this.setState({errors: this.state.errors.concat(err.json.errors[input])}); - } - } - } - else { - // TODO translate? - this.setState({errors: ['Something went wrong, please try again later']}); - } - this.setState({submitted: false}); - }, - - getBitcoinIds(){ - return this.props.editions.map(function(edition){ - return edition.bitcoin_id; - }); - }, - - getTitlesString(){ - return this.props.editions.map(function(edition){ - return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n'; - }); - }, - - render(){ - let alert = null; - if (this.state.errors.length > 0){ - alert = this.state.errors.map((error) => { - return ; - }); - } - - return ( -
    - {alert} - {this.renderForm()} -
    - ); - } -}; - -export default FormMixin; - From 3137583b0f608538785fabdacd7e522afc14442b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 14:06:01 +0200 Subject: [PATCH 033/397] adjust button choose logic --- .../ascribe_forms/form_request_action.js | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 834ea2d5..7195d721 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -2,8 +2,6 @@ import React from 'react'; -import FormMixin from '../../mixins/form_mixin'; - import AclButton from './../ascribe_buttons/acl_button'; import ActionPanel from '../ascribe_panel/action_panel'; import Form from './form'; @@ -78,7 +76,7 @@ let RequestActionForm = React.createClass({ ); }, - getAcceptButton() { + getAcceptButtonForm() { let edition = this.props.editions[0]; if(edition.request_action === 'unconsign') { @@ -92,11 +90,17 @@ let RequestActionForm = React.createClass({ ); } else { return ( - +
    + +
    ); } }, @@ -105,7 +109,7 @@ let RequestActionForm = React.createClass({ let edition = this.props.editions[0]; let urls = this.getUrls(); - let acceptButton = this.getAcceptButton(); + let acceptButtonForm = this.getAcceptButtonForm(); return (
    @@ -120,13 +124,7 @@ let RequestActionForm = React.createClass({ {getLangText('REJECT')} -
    - {acceptButton} -
    + {acceptButtonForm}
    ); }, From 4b8987dc7cf0bb21f9554da66391111ce7dde765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 14:07:23 +0200 Subject: [PATCH 034/397] add urls --- js/components/ascribe_forms/form_request_action.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 7195d721..519e3a53 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -76,7 +76,7 @@ let RequestActionForm = React.createClass({ ); }, - getAcceptButtonForm() { + getAcceptButtonForm(urls) { let edition = this.props.editions[0]; if(edition.request_action === 'unconsign') { @@ -109,7 +109,7 @@ let RequestActionForm = React.createClass({ let edition = this.props.editions[0]; let urls = this.getUrls(); - let acceptButtonForm = this.getAcceptButtonForm(); + let acceptButtonForm = this.getAcceptButtonForm(urls); return (
    From 5be771f6acb97f93dc23a2ef390c7be5602ded60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 14:15:32 +0200 Subject: [PATCH 035/397] add inline property to form --- js/components/ascribe_detail/edition.js | 3 ++- js/components/ascribe_forms/form.js | 19 +++++++++++++++++-- .../ascribe_forms/form_request_action.js | 4 +++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index a1d9af70..0f1477c0 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -236,7 +236,8 @@ let EditionSummary = React.createClass({ url={ApiUrls.ownership_transfers_withdraw} getFormData={this.getTransferWithdrawData} handleSuccess={this.showNotification} - className='inline'> + className='inline' + isInline={true}> diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index d7e31382..2b956a7e 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -6,6 +6,9 @@ import ReactAddons from 'react/addons'; import Button from 'react-bootstrap/lib/Button'; import AlertDismissable from './alert'; +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + import requests from '../../utils/requests'; import { getLangText } from '../../utils/lang_utils'; @@ -28,7 +31,12 @@ let Form = React.createClass({ buttons: React.PropTypes.oneOfType([ React.PropTypes.element, React.PropTypes.arrayOf(React.PropTypes.element) - ]) + ]), + + // You can use the form for inline requests, like the submit click on a button. + // For the form to then not display the error on top, you need to enable this option. + // It will make use of the GlobalNotification + isInline: React.PropTypes.bool }, getDefaultProps() { @@ -136,7 +144,14 @@ let Form = React.createClass({ } console.logGlobal(err, false, formData); - this.setState({errors: [getLangText('Something went wrong, please try again later')]}); + + if(this.props.isInline) { + let notification = new GlobalNotificationModel(getLangText('Something went wrong, please try again later'), 'danger'); + GlobalNotificationActions.appendGlobalNotification(notification); + } else { + this.setState({errors: [getLangText('Something went wrong, please try again later')]}); + } + } this.setState({submitted: false}); }, diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 519e3a53..dca86da7 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -54,7 +54,7 @@ let RequestActionForm = React.createClass({ showNotification(option, action, owner) { return () => { - let message = getLangText('You have successfully') + ' ' + option + ' ' + action + ' ' + getLangText('to') + ' ' + owner; + let message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; let notification = new GlobalNotificationModel(message, 'success'); GlobalNotificationActions.appendGlobalNotification(notification); @@ -94,6 +94,7 @@ let RequestActionForm = React.createClass({ url={urls.accept} getFormData={this.getFormData} handleSuccess={this.showNotification(getLangText('denied'), edition.request_action, edition.owner)} + isInline={true} className='inline pull-right'>
    ); diff --git a/js/components/ascribe_forms/property_collapsible.js b/js/components/ascribe_forms/property_collapsible.js index ba6c0a1e..03ec404d 100644 --- a/js/components/ascribe_forms/property_collapsible.js +++ b/js/components/ascribe_forms/property_collapsible.js @@ -3,11 +3,9 @@ import React from 'react'; import ReactAddons from 'react/addons'; -import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; - -import classNames from 'classnames'; +import Panel from 'react-bootstrap/lib/Panel'; let PropertyCollapsile = React.createClass({ @@ -17,22 +15,12 @@ let PropertyCollapsile = React.createClass({ tooltip: React.PropTypes.string }, - mixins: [CollapsibleMixin], - getInitialState() { return { show: false }; }, - getCollapsibleDOMNode(){ - return React.findDOMNode(this.refs.panel); - }, - - getCollapsibleDimensionValue(){ - return React.findDOMNode(this.refs.panel).scrollHeight; - }, - handleFocus() { this.refs.checkboxCollapsible.getDOMNode().checked = !this.refs.checkboxCollapsible.getDOMNode().checked; this.setState({ @@ -85,11 +73,14 @@ let PropertyCollapsile = React.createClass({ {this.props.checkboxLabel}
    -
    + +
    {this.renderChildren()} -
    +
    +
    ); } diff --git a/sass/ascribe_edition.scss b/sass/ascribe_edition.scss index ee082a04..fe647e2d 100644 --- a/sass/ascribe_edition.scss +++ b/sass/ascribe_edition.scss @@ -16,33 +16,35 @@ margin-top: 20px; } .ascribe-edition-collapsible-wrapper > div > span { - font-size: 1.2em; - margin-right: .5em; + font-size: 1.2em; + margin-right: .5em; } .ascribe-edition-collapsible-wrapper > div > span:nth-child(2) { - font-size: 0.9em; + font-size: 0.9em; } -.ascribe-edition-collapible-content { - width:100%; +.ascribe-edition-collapsible-content { + width:100%; + background: none; + border: none; } -.coa-file-wrapper{ - display: table; - height: 200px; - overflow: hidden; - margin: 0 auto; - width: 100%; - padding: 1em; +.coa-file-wrapper { + display: table; + height: 200px; + overflow: hidden; + margin: 0 auto; + width: 100%; + padding: 1em; } .coa-file { - display: table-cell; - vertical-align: middle; - border: 1px solid #CCC; - background-color: #F8F8F8; + display: table-cell; + vertical-align: middle; + border: 1px solid #CCC; + background-color: #F8F8F8; } .ascribe-button-list { - margin-top: 1em; + margin-top: 1em; } \ No newline at end of file diff --git a/sass/ascribe_theme.scss b/sass/ascribe_theme.scss index 9eb92a30..da3c921f 100644 --- a/sass/ascribe_theme.scss +++ b/sass/ascribe_theme.scss @@ -2,4 +2,13 @@ .pager li a { color: white; +} + +.panel-default { + border: none; + box-shadow: none; +} + +.panel-body { + padding:0; } \ No newline at end of file From cde6118b8e3bf0f1a6fcb688a089d9dde37df8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 14:57:06 +0200 Subject: [PATCH 039/397] panel styling --- sass/ascribe_theme.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/sass/ascribe_theme.scss b/sass/ascribe_theme.scss index da3c921f..e02b97c6 100644 --- a/sass/ascribe_theme.scss +++ b/sass/ascribe_theme.scss @@ -7,6 +7,7 @@ .panel-default { border: none; box-shadow: none; + margin-bottom: 0; } .panel-body { From 3c752372759929b6ce82d78c0978c682b152127d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 15:10:21 +0200 Subject: [PATCH 040/397] update refactor.md --- docs/refactor-todo.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/refactor-todo.md b/docs/refactor-todo.md index 8554f001..f7a5917b 100644 --- a/docs/refactor-todo.md +++ b/docs/refactor-todo.md @@ -2,16 +2,18 @@ *This should be a living document. So if you have any ideas for refactoring stuff, then feel free to add them to this document* -- Get rid of all Mixins. (making good progress there :)) - Make all standalone components independent from things like global utilities (GeneralUtils is maybe used in table for example) -- Check if all polyfills are appropriately initialized and available: Compare to this - Extract all standalone components to their own folder structure and write application independent tests (+ figure out how to do that in a productive way) (fetch lib especially) -- Refactor forms to generic-declarative form component - Check for mobile compatibility: Is site responsive anywhere? queryParams of the piece_list_store should all be reflected in the url and not a single component each should manipulate the URL bar (refactor pagination, use actions and state) - Refactor string-templating for api_urls - Use classNames plugin instead of if-conditional-classes +# Refactor DONE +- Refactor forms to generic-declarative form component ✓ +- Get rid of all Mixins (inject head is fine) ✓ +- Check if all polyfills are appropriately initialized and available: Compare to this ✓ + ## React-S3-Fineuploader - implementation should enable to define all important methods outside - and: maybe create a utility class for all methods to avoid code duplication From a27415eb864d8591533079367cb03b795f62443d Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 10 Aug 2015 15:23:13 +0200 Subject: [PATCH 041/397] jury dashboard + rating WIP --- .../components/ascribe_detail/piece_container.js | 13 +++++++++++++ package.json | 3 ++- sass/main.scss | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index 8917e6d0..8782f6f0 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -14,6 +14,8 @@ import Property from '../../../../../components/ascribe_forms/property'; import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; +import StarRating from 'react-star-rating'; + /** * This is the component that implements resource/data specific functionality */ @@ -70,6 +72,10 @@ let PrizePieceDetails = React.createClass({ propTypes: { piece: React.PropTypes.object }, + + onRatingClick(event, position, rating, caption, name) { + console.log(rating); + }, render() { if (this.props.piece.prize && this.props.piece.prize.name @@ -79,6 +85,13 @@ let PrizePieceDetails = React.createClass({ title="Prize Details" show={true} defaultExpanded={true}> + {Object.keys(this.props.piece.extra_data).map((data) => { let label = data.replace('_', ' '); diff --git a/package.json b/package.json index 4fdf87fb..9d767930 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,8 @@ "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", "watchify": "^3.1.2", - "yargs": "^3.10.0" + "yargs": "^3.10.0", + "react-star-rating": "~1.3.2" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", diff --git a/sass/main.scss b/sass/main.scss index d2c05afa..c83379b3 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -6,6 +6,7 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'ascribe_variables'; @import 'variables'; @import '../node_modules/bootstrap-sass/assets/stylesheets/bootstrap'; +@import '../node_modules/react-star-rating/dist/css/react-star-rating.min'; @import '../node_modules/react-datepicker/dist/react-datepicker'; @import 'glyphicons-social'; @import 'ascribe_theme'; @@ -381,4 +382,9 @@ hr { > span { font-size: 2em; } +} + +.rating-container .rating-stars { + width: 25px; + color: #000; } \ No newline at end of file From 8ff2dea4dfb9ef900517c43cf0dfa06f932f136c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 10 Aug 2015 15:57:20 +0200 Subject: [PATCH 042/397] refactor: acl buttons message functionality --- js/components/ascribe_buttons/acl_button.js | 87 +++------------------ js/utils/form_utils.js | 51 ++++++++++++ 2 files changed, 62 insertions(+), 76 deletions(-) create mode 100644 js/utils/form_utils.js diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index 5a924a0c..2f5bb7b0 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -13,9 +13,11 @@ import AppConstants from '../../constants/application_constants'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; -import { getLangText } from '../../utils/lang_utils.js'; import ApiUrls from '../../constants/api_urls'; +import { getAclFormMessage } from '../../utils/form_utils'; +import { getLangText } from '../../utils/lang_utils'; + let AclButton = React.createClass({ propTypes: { action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, @@ -34,13 +36,16 @@ let AclButton = React.createClass({ }, actionProperties(){ + + let message = getAclFormMessage(this.props.action, this.getTitlesString(), this.props.currentUser.username); + if (this.props.action === 'acl_consign'){ return { title: getLangText('Consign artwork'), tooltip: getLangText('Have someone else sell the artwork'), form: ( ), @@ -53,7 +58,7 @@ let AclButton = React.createClass({ tooltip: getLangText('Have the owner manage his sales again'), form: ( ), @@ -65,7 +70,7 @@ let AclButton = React.createClass({ tooltip: getLangText('Transfer the ownership of the artwork'), form: ( ), @@ -77,7 +82,7 @@ let AclButton = React.createClass({ title: getLangText('Loan artwork'), tooltip: getLangText('Loan your artwork for a limited period of time'), form: ( ), @@ -90,7 +95,7 @@ let AclButton = React.createClass({ tooltip: getLangText('Share the artwork'), form: ( ), @@ -133,76 +138,6 @@ let AclButton = React.createClass({ } }, -// plz move to transfer form - getTransferMessage(){ - return ( - `${getLangText('Hi')}, - -${getLangText('I transfer ownership of')}: -${this.getTitlesString()} ${getLangText('to you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username} - ` - ); - }, - - // plz move to transfer form - getLoanMessage(){ - return ( - `${getLangText('Hi')}, - -${getLangText('I loan')}: -${this.getTitlesString()} ${getLangText('to you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username} - ` - ); - }, - - // plz move to consign form - getConsignMessage(){ - return ( - `${getLangText('Hi')}, - -${getLangText('I consign')}: -${this.getTitlesString()} ${getLangText('to you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username} - ` - ); - }, - - // plz move to consign form - getUnConsignMessage(){ - return ( - `${getLangText('Hi')}, - -${getLangText('I un-consign')}: -${this.getTitlesString()} ${getLangText('from you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username} - ` - ); - }, - -// plz move to share form - getShareMessage(){ - return ( - `${getLangText('Hi')}, - -${getLangText('I am sharing')}: -${this.getTitlesString()} ${getLangText('with you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username} - ` - ); - }, - // Removes the acl_ prefix and converts to upper case sanitizeAction() { return this.props.action.split('acl_')[1].toUpperCase(); diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js new file mode 100644 index 00000000..3a8861cc --- /dev/null +++ b/js/utils/form_utils.js @@ -0,0 +1,51 @@ +'use strict'; + +import { getLangText } from './lang_utils'; + +/** + * Generates a message for submitting a form + * @param {string} aclName Enum name of a acl + * @param {string} entities Already computed name of entities + * @param {string} senderName Name of the sender + * @return {string} Completed message + */ +export function getAclFormMessage(aclName, entities, senderName) { + let message = ''; + + message += getLangText('Hi'); + message += ',\n\n'; + + if(aclName === 'acl_transfer') { + message += getLangText('I transfer ownership of'); + } else if(aclName === 'acl_consign') { + message += getLangText('I consign'); + } else if(aclName === 'acl_unconsign') { + message += getLangText('I un-consign'); + } else if(aclName === 'acl_loan') { + message += getLangText('I loan'); + } else if(aclName === 'acl_share') { + message += getLangText('I share'); + } else { + throw new Error('Your specified aclName did not match a an acl class.'); + } + + message += ':\n'; + message += entities; + + if(aclName === 'acl_transfer' || aclName === 'acl_loan' || aclName === 'acl_consign') { + message += getLangText('to you'); + } else if(aclName === 'acl_unconsign') { + message += getLangText('from you'); + } else if(aclName === 'acl_share') { + message += getLangText('with you'); + } else { + throw new Error('Your specified aclName did not match a an acl class.'); + } + + message += '\n\n'; + message += getLangText('Truly yours,'); + message += '\n'; + message += senderName; + + return message; +} \ No newline at end of file From 36ca2004ffd732c90f05bf0b2f2e9235e000a0b1 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 10 Aug 2015 17:02:10 +0200 Subject: [PATCH 043/397] rating create and fetch --- .../prize/actions/prize_rating_actions.js | 66 +++++++++++++++++++ .../ascribe_detail/piece_container.js | 36 ++++++++-- .../whitelabel/prize/constants/api_urls.js | 4 +- .../prize/fetchers/prize_rating_fetcher.js | 20 ++++++ .../prize/stores/prize_rating_store.js | 23 +++++++ 5 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 js/components/whitelabel/prize/actions/prize_rating_actions.js create mode 100644 js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js create mode 100644 js/components/whitelabel/prize/stores/prize_rating_store.js diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/actions/prize_rating_actions.js new file mode 100644 index 00000000..536445f8 --- /dev/null +++ b/js/components/whitelabel/prize/actions/prize_rating_actions.js @@ -0,0 +1,66 @@ +'use strict'; + +import alt from '../../../../alt'; +import Q from 'q'; + +import PrizeRatingFetcher from '../fetchers/prize_rating_fetcher'; + +class PrizeRatingActions { + constructor() { + this.generateActions( + 'updatePrizeRatings', + 'updatePrizeRating' + ); + } + + fetch() { + return Q.Promise((resolve, reject) => { + PrizeRatingFetcher + .fetch() + .then((res) => { + this.actions.updatePrizeRatings(res.ratings); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } + + fetchOne(pieceId) { + return Q.Promise((resolve, reject) => { + PrizeRatingFetcher + .fetchOne(pieceId) + .then((res) => { + this.actions.updatePrizeRating(res.rating.rating); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } + + createRating(pieceId, rating) { + return Q.Promise((resolve, reject) => { + PrizeRatingFetcher + .rate(pieceId, rating) + .then((res) => { + this.actions.updatePrizeRating(res.rating.rating); + resolve(res); + }) + .catch((err) => { + console.logGlobal(err); + reject(err); + }); + }); + } + + updateRating(rating) { + this.actions.updatePrizeRating(rating); + } +} + +export default alt.createActions(PrizeRatingActions); \ No newline at end of file diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index 8782f6f0..3a7c3144 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -2,9 +2,14 @@ import React from 'react'; +import StarRating from 'react-star-rating'; + import PieceActions from '../../../../../actions/piece_actions'; import PieceStore from '../../../../../stores/piece_store'; +import PrizeRatingActions from '../../actions/prize_rating_actions'; +import PrizeRatingStore from '../../stores/prize_rating_store'; + import Piece from '../../../../../components/ascribe_detail/piece'; import AppConstants from '../../../../../constants/application_constants'; @@ -14,8 +19,6 @@ import Property from '../../../../../components/ascribe_forms/property'; import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; -import StarRating from 'react-star-rating'; - /** * This is the component that implements resource/data specific functionality */ @@ -73,9 +76,33 @@ let PrizePieceDetails = React.createClass({ piece: React.PropTypes.object }, - onRatingClick(event, position, rating, caption, name) { - console.log(rating); + getInitialState() { + return PrizeRatingStore.getState(); }, + + onChange(state) { + this.setState(state); + }, + + componentDidMount() { + PrizeRatingStore.listen(this.onChange); + PrizeRatingActions.fetchOne(this.props.piece.id); + }, + + componentWillUnmount() { + // Every time we're leaving the piece detail page, + // just reset the piece that is saved in the piece store + // as it will otherwise display wrong/old data once the user loads + // the piece detail a second time + PrizeRatingActions.updateRating({}); + PrizeRatingStore.unlisten(this.onChange); + }, + + onRatingClick(event, args) { + event.preventDefault(); + PrizeRatingActions.createRating(this.props.piece.id, args.rating); + }, + render() { if (this.props.piece.prize && this.props.piece.prize.name @@ -90,6 +117,7 @@ let PrizePieceDetails = React.createClass({ caption="" step={1} size='lg' + rating={this.state.currentRating} onRatingClick={this.onRatingClick} ratingAmount={5} /> diff --git a/js/components/whitelabel/prize/constants/api_urls.js b/js/components/whitelabel/prize/constants/api_urls.js index 3e7260bb..480e8d4f 100644 --- a/js/components/whitelabel/prize/constants/api_urls.js +++ b/js/components/whitelabel/prize/constants/api_urls.js @@ -14,7 +14,9 @@ function getApiUrls(subdomain) { 'jurys': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/', 'jury': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/', 'jury_activate': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/activate/', - 'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/' + 'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/', + 'ratings': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/', + 'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/' }; } diff --git a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js new file mode 100644 index 00000000..91da0051 --- /dev/null +++ b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js @@ -0,0 +1,20 @@ +'use strict'; + +import requests from '../../../../utils/requests'; + + +let PrizeRatingFetcher = { + fetch() { + return requests.get('rating'); + }, + + fetchOne(pieceId) { + return requests.get('rating', {'piece_id': pieceId}); + }, + + rate(pieceId, rating) { + return requests.post('ratings', {body: {'piece_id': pieceId, 'rating': rating}}); + } +}; + +export default PrizeRatingFetcher; diff --git a/js/components/whitelabel/prize/stores/prize_rating_store.js b/js/components/whitelabel/prize/stores/prize_rating_store.js new file mode 100644 index 00000000..4a31501c --- /dev/null +++ b/js/components/whitelabel/prize/stores/prize_rating_store.js @@ -0,0 +1,23 @@ +'use strict'; + +import alt from '../../../../alt'; + +import PrizeRatingActions from '../actions/prize_rating_actions'; + +class PrizeRatingStore { + constructor() { + this.ratings = []; + this.currentRating = null; + this.bindActions(PrizeRatingActions); + } + + onUpdatePrizeRatings( ratings ) { + this.ratings = ratings; + } + + onUpdatePrizeRating( rating ) { + this.currentRating = parseInt(rating, 10); + } +} + +export default alt.createStore(PrizeRatingStore, 'PrizeRatingStore'); \ No newline at end of file From f5b34222a9bcbae6e25c4986938abb2259a960ea Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 10 Aug 2015 17:45:49 +0200 Subject: [PATCH 044/397] remove ratings from master branch --- .../prize/components/ascribe_detail/piece_container.js | 8 -------- package.json | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index 3a7c3144..b6363868 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -112,14 +112,6 @@ let PrizePieceDetails = React.createClass({ title="Prize Details" show={true} defaultExpanded={true}> - {Object.keys(this.props.piece.extra_data).map((data) => { let label = data.replace('_', ' '); diff --git a/package.json b/package.json index 2b05c9df..ddf45059 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-progressbar": "^1.1.0", "react-router": "^0.13.3", "react-router-bootstrap": "~0.16.0", + "react-star-rating": "~1.3.2", "react-textarea-autosize": "^2.2.3", "reactify": "^1.1.0", "shmui": "^0.1.0", @@ -84,8 +85,7 @@ "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", "watchify": "^3.1.2", - "yargs": "^3.10.0", - "react-star-rating": "~1.3.2" + "yargs": "^3.10.0" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", From 58c0ce4c3f8b293b9cf61da4ffc2853e819642b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 11 Aug 2015 10:03:12 +0200 Subject: [PATCH 045/397] fix wording for multiple uploads --- .../ascribe_uploader/file_drag_and_drop_dialog.js | 8 +++++++- js/components/ascribe_uploader/react_s3_fine_uploader.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_uploader/file_drag_and_drop_dialog.js b/js/components/ascribe_uploader/file_drag_and_drop_dialog.js index 306eb6f1..f5399f9c 100644 --- a/js/components/ascribe_uploader/file_drag_and_drop_dialog.js +++ b/js/components/ascribe_uploader/file_drag_and_drop_dialog.js @@ -57,7 +57,13 @@ let FileDragAndDropDialog = React.createClass({ if(this.props.multipleFiles) { return ( - {getLangText('Click or drag to add files')} +

    {getLangText('Drag files here')}

    +

    {getLangText('or')}

    + + {getLangText('choose files to upload')} +
    ); } else { diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index d6d2f939..4b3e48a5 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -160,7 +160,7 @@ var ReactS3FineUploader = React.createClass({ } return name; }, - multiple: false, + multiple: true, defaultErrorMessage: getLangText('Unexpected error. Please contact us if this happens repeatedly.') }; }, From 0cf63fa6c881a6c5817f039b23a686402f46b81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 11 Aug 2015 11:39:58 +0200 Subject: [PATCH 046/397] fix synchronization of files of fineuploader --- .../react_s3_fine_uploader.js | 36 +++++++++---------- sass/ascribe_uploader.scss | 3 ++ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 4b3e48a5..7780ceae 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -435,7 +435,9 @@ var ReactS3FineUploader = React.createClass({ }, onCancel(id) { - this.removeFileWithIdFromFilesToUpload(id); + + // when a upload is canceled, we need to update this components file array + this.setStatusOfFile(id, 'canceled'); let notification = new GlobalNotificationModel(getLangText('File upload canceled'), 'success', 5000); GlobalNotificationActions.appendGlobalNotification(notification); @@ -455,6 +457,7 @@ var ReactS3FineUploader = React.createClass({ }, onProgress(id, name, uploadedBytes, totalBytes) { + let newState = React.addons.update(this.state, { filesToUpload: { [id]: { progress: { $set: (uploadedBytes / totalBytes) * 100} } @@ -498,7 +501,9 @@ var ReactS3FineUploader = React.createClass({ let notification = new GlobalNotificationModel(getLangText('Couldn\'t delete file'), 'danger', 10000); GlobalNotificationActions.appendGlobalNotification(notification); } else { - this.removeFileWithIdFromFilesToUpload(id); + + // To hide the file in this component, we need to set it's status to "deleted" + this.setStatusOfFile(id, 'deleted'); let notification = new GlobalNotificationModel(getLangText('File deleted'), 'success', 5000); GlobalNotificationActions.appendGlobalNotification(notification); @@ -521,7 +526,8 @@ var ReactS3FineUploader = React.createClass({ }, handleDeleteFile(fileId) { - // In some instances (when the file was already uploaded and is just displayed to the user) + // In some instances (when the file was already uploaded and is just displayed to the user + // - for example in the loan contract or additional files dialog) // fineuploader does not register an id on the file (we do, don't be confused by this!). // Since you can only delete a file by its id, we have to implement this method ourselves // @@ -532,7 +538,7 @@ var ReactS3FineUploader = React.createClass({ if(this.state.filesToUpload[fileId].status !== 'online') { // delete file from server this.state.uploader.deleteFile(fileId); - // this is being continues in onDeleteFile, as + // this is being continued in onDeleteFile, as // fineuploaders deleteFile does not return a correct callback or // promise } else { @@ -739,31 +745,23 @@ var ReactS3FineUploader = React.createClass({ this.setState(newState); }, - removeFileWithIdFromFilesToUpload(fileId) { - // also, sync files from state with the ones from fineuploader - let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload)); - - // splice because I can - filesToUpload.splice(fileId, 1); - - // set state - let newState = React.addons.update(this.state, { - filesToUpload: { $set: filesToUpload } - }); - this.setState(newState); - }, - setStatusOfFile(fileId, status) { // also, sync files from state with the ones from fineuploader let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload)); - // splice because I can filesToUpload[fileId].status = status; + // is status is set to deleted or canceled, we also need to reset the progress + // back to zero + if(status === 'deleted' || status === 'canceled') { + filesToUpload[fileId].progress = 0; + } + // set state let newState = React.addons.update(this.state, { filesToUpload: { $set: filesToUpload } }); + this.setState(newState); }, diff --git a/sass/ascribe_uploader.scss b/sass/ascribe_uploader.scss index c96109ed..2aab021a 100644 --- a/sass/ascribe_uploader.scss +++ b/sass/ascribe_uploader.scss @@ -41,6 +41,9 @@ position: relative; display: inline-block; + margin-left: .7em; + margin-right: .7em; + .delete-file { display: block; background-color: black; From d5efd79d1478c518af67118167424be30c1e0453 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 11 Aug 2015 12:06:01 +0200 Subject: [PATCH 047/397] refactored accordion list item: accordion-list-item accordion-list-item-piece < accordion-list-item accordion-list-item-wallet < accordion-list-item-piece accordion-list-item-prize < accordion-list-item-piece --- .../accordion_list_item.js | 189 ++---------------- .../accordion_list_item_piece.js | 76 +++++++ .../accordion_list_item_wallet.js | 156 +++++++++++++++ js/components/piece_list.js | 14 +- .../accordion_list_item_prize.js | 89 +++++++++ .../whitelabel/prize/components/piece_list.js | 3 +- 6 files changed, 350 insertions(+), 177 deletions(-) create mode 100644 js/components/ascribe_accordion_list/accordion_list_item_piece.js create mode 100644 js/components/ascribe_accordion_list/accordion_list_item_wallet.js create mode 100644 js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index 6c07a891..37803ad2 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -3,151 +3,24 @@ import React from 'react'; import Router from 'react-router'; -import Glyphicon from 'react-bootstrap/lib/Glyphicon'; -import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; -import Tooltip from 'react-bootstrap/lib/Tooltip'; - -import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; -import CreateEditionsForm from '../ascribe_forms/create_editions_form'; - -import PieceListActions from '../../actions/piece_list_actions'; -import PieceListStore from '../../stores/piece_list_store'; - -import WhitelabelStore from '../../stores/whitelabel_store'; - -import EditionListActions from '../../actions/edition_list_actions'; - -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import AclProxy from '../acl_proxy'; -import SubmitToPrizeButton from '../whitelabel/prize/components/ascribe_buttons/submit_to_prize_button'; - -import { getLangText } from '../../utils/lang_utils'; -import { mergeOptions } from '../../utils/general_utils'; - -let Link = Router.Link; - let AccordionListItem = React.createClass({ propTypes: { + badge: React.PropTypes.object, className: React.PropTypes.string, - content: React.PropTypes.object, - children: React.PropTypes.object + thumbnail: React.PropTypes.object, + heading: React.PropTypes.object, + subheading: React.PropTypes.object, + subsubheading: React.PropTypes.object, + buttons: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) }, mixins: [Router.Navigation], - getInitialState() { - return mergeOptions( - { - showCreateEditionsDialog: false - }, - PieceListStore.getState(), - WhitelabelStore.getState() - ); - }, - - componentDidMount() { - PieceListStore.listen(this.onChange); - WhitelabelStore.listen(this.onChange); - }, - - componentWillUnmount() { - PieceListStore.unlisten(this.onChange); - WhitelabelStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - getGlyphicon(){ - if (this.props.content.requestAction) { - return ( - {getLangText('You have actions pending in one of your editions')}}> - - ); - } - return null; - }, - - toggleCreateEditionsDialog() { - this.setState({ - showCreateEditionsDialog: !this.state.showCreateEditionsDialog - }); - }, - - handleEditionCreationSuccess() { - PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0}); - - this.toggleCreateEditionsDialog(); - }, - - handleSubmitPrizeSuccess(response) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - - let notification = new GlobalNotificationModel(response.notification, 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - onPollingSuccess(pieceId) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - EditionListActions.toggleEditionList(pieceId); - - let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - getCreateEditionsDialog() { - if (this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) { - return ( -
    - -
    - ); - } - }, - - getLicences() { - // convert this to acl_view_licences later - if (this.state.whitelabel && this.state.whitelabel.name === 'Creative Commons France') { - return ( - - , - - {getLangText('%s license', this.props.content.license_type.code)} - - - ); - } - }, - render() { - let linkData; - - if (this.props.content.num_editions < 1 || !this.props.content.first_edition) { - linkData = { - to: 'piece', - params: { - pieceId: this.props.content.id - } - }; - } else { - linkData = { - to: 'edition', - params: { - editionId: this.props.content.first_edition.bitcoin_id - } - }; - } return (
    @@ -155,52 +28,22 @@ let AccordionListItem = React.createClass({
    - - - + {this.props.thumbnail}
    - -

    {this.props.content.title}

    - - -

    {getLangText('by %s', this.props.content.artist_name)}

    - -
    - {this.props.content.date_created.split('-')[0]} - - - - - - - - {this.getLicences()} -
    + {this.props.heading} + {this.props.subheading} + {this.props.subsubheading} + {this.props.buttons}
    - {this.getGlyphicon()} + {this.props.badge}
    - - {this.getCreateEditionsDialog()} - - {/* this.props.children is AccordionListItemTableEditions */} {this.props.children}
    ); diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js new file mode 100644 index 00000000..65b6454c --- /dev/null +++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js @@ -0,0 +1,76 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import AccordionListItem from './accordion_list_item'; + +import { getLangText } from '../../utils/lang_utils'; + +let Link = Router.Link; + + +let AccordionListItemPiece = React.createClass({ + propTypes: { + className: React.PropTypes.string, + piece: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]), + subsubheading: React.PropTypes.object, + buttons: React.PropTypes.object, + badge: React.PropTypes.object + }, + + mixins: [Router.Navigation], + + getLinkData(){ + let linkData; + + if (this.props.piece.num_editions < 1 || !this.props.piece.first_edition) { + linkData = { + to: 'piece', + params: { + pieceId: this.props.piece.id + } + }; + } else { + linkData = { + to: 'edition', + params: { + editionId: this.props.piece.first_edition.bitcoin_id + } + }; + } + return linkData; + }, + + render() { + return ( + + + } + heading={ + +

    {this.props.piece.title}

    + } + subheading={ +

    + {getLangText('by %s', this.props.piece.artist_name)} +

    + } + subsubheading={this.props.subsubheading} + buttons={this.props.buttons} + badge={this.props.badge} + > + {this.props.children} +
    + ); + } +}); + +export default AccordionListItemPiece; diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js new file mode 100644 index 00000000..3cb557ef --- /dev/null +++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js @@ -0,0 +1,156 @@ +'use strict'; + +import React from 'react'; + +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; +import Tooltip from 'react-bootstrap/lib/Tooltip'; + +import AccordionListItemPiece from './accordion_list_item_piece'; +import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; +import CreateEditionsForm from '../ascribe_forms/create_editions_form'; + +import PieceListActions from '../../actions/piece_list_actions'; +import PieceListStore from '../../stores/piece_list_store'; + +import WhitelabelStore from '../../stores/whitelabel_store'; + +import EditionListActions from '../../actions/edition_list_actions'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import AclProxy from '../acl_proxy'; + +import { getLangText } from '../../utils/lang_utils'; +import { mergeOptions } from '../../utils/general_utils'; + + +let AccordionListItemWallet = React.createClass({ + propTypes: { + className: React.PropTypes.string, + content: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) + }, + + getInitialState() { + return mergeOptions( + { + showCreateEditionsDialog: false + }, + PieceListStore.getState(), + WhitelabelStore.getState() + ); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + WhitelabelStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + getGlyphicon(){ + if (this.props.content.requestAction) { + return ( + {getLangText('You have actions pending in one of your editions')}}> + + ); + } + return null; + }, + + toggleCreateEditionsDialog() { + this.setState({ + showCreateEditionsDialog: !this.state.showCreateEditionsDialog + }); + }, + + handleEditionCreationSuccess() { + PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0}); + + this.toggleCreateEditionsDialog(); + }, + + onPollingSuccess(pieceId) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + EditionListActions.toggleEditionList(pieceId); + + let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getCreateEditionsDialog() { + if (this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
    + +
    + ); + } + }, + + getLicences() { + // convert this to acl_view_licences later + if (this.state.whitelabel && this.state.whitelabel.name === 'Creative Commons France') { + return ( + + , + + {getLangText('%s license', this.props.content.license_type.code)} + + + ); + } + }, + + render() { + + return ( + + {this.props.content.date_created.split('-')[0]} + {this.getLicences()} +
    } + buttons={ +
    + + + +
    } + badge={this.getGlyphicon()}> + {this.getCreateEditionsDialog()} + {/* this.props.children is AccordionListItemTableEditions */} + {this.props.children} + + ); + } +}); + +export default AccordionListItemWallet; diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 78917f61..566921f2 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -10,7 +10,7 @@ import EditionListStore from '../stores/edition_list_store'; import EditionListActions from '../actions/edition_list_actions'; import AccordionList from './ascribe_accordion_list/accordion_list'; -import AccordionListItem from './ascribe_accordion_list/accordion_list_item'; +import AccordionListItemWallet from './ascribe_accordion_list/accordion_list_item_wallet'; import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_list_item_table_editions'; import Pagination from './ascribe_pagination/pagination'; @@ -24,12 +24,19 @@ import { mergeOptions } from '../utils/general_utils'; let PieceList = React.createClass({ propTypes: { + accordionListItemType: React.PropTypes.object, redirectTo: React.PropTypes.string, customSubmitButton: React.PropTypes.element }, mixins: [Router.Navigation, Router.State], + getDefaultProps() { + return { + accordionListItemType: AccordionListItemWallet + }; + }, + getInitialState() { return mergeOptions( PieceListStore.getState(), @@ -128,6 +135,7 @@ let PieceList = React.createClass({ render() { let loadingElement = (); + let AccordionListItemType = this.props.accordionListItemType; return (
    {this.state.pieceList.map((piece, i) => { return ( - - + ); })} diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js new file mode 100644 index 00000000..263d7f08 --- /dev/null +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -0,0 +1,89 @@ +'use strict'; + +import React from 'react'; + +import AccordionListItemPiece from '../../../../ascribe_accordion_list/accordion_list_item_piece'; + +import PieceListActions from '../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../stores/piece_list_store'; + +import WhitelabelStore from '../../../../../stores/whitelabel_store'; + +import GlobalNotificationModel from '../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; + +import AclProxy from '../../../../acl_proxy'; +import SubmitToPrizeButton from './../ascribe_buttons/submit_to_prize_button'; + +import { getLangText } from '../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../utils/general_utils'; + + +let AccordionListItemWallet = React.createClass({ + propTypes: { + className: React.PropTypes.string, + content: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) + }, + + getInitialState() { + return mergeOptions( + PieceListStore.getState(), + WhitelabelStore.getState() + ); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + WhitelabelStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleSubmitPrizeSuccess(response) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { + + return ( + + {this.props.content.date_created.split('-')[0]} +
    } + buttons={ +
    + + + +
    } + > + {this.props.children} + + ); + } +}); + +export default AccordionListItemWallet; diff --git a/js/components/whitelabel/prize/components/piece_list.js b/js/components/whitelabel/prize/components/piece_list.js index 73674e25..230bf7de 100644 --- a/js/components/whitelabel/prize/components/piece_list.js +++ b/js/components/whitelabel/prize/components/piece_list.js @@ -4,7 +4,7 @@ import React from 'react'; import PieceList from '../../../piece_list'; import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; - +import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize'; let PrizePieceList = React.createClass({ render() { @@ -12,6 +12,7 @@ let PrizePieceList = React.createClass({
    Submit to prize From f086bece7156ea6bf9291836bd833f763d051f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 11 Aug 2015 13:10:15 +0200 Subject: [PATCH 048/397] add boilerplate code for wallet application --- js/components/whitelabel/wallet/app.js | 26 ++++++++++++++ js/components/whitelabel/wallet/routes.js | 41 +++++++++++++++++++++++ js/constants/application_constants.js | 2 +- 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 js/components/whitelabel/wallet/app.js create mode 100644 js/components/whitelabel/wallet/routes.js diff --git a/js/components/whitelabel/wallet/app.js b/js/components/whitelabel/wallet/app.js new file mode 100644 index 00000000..06853ba2 --- /dev/null +++ b/js/components/whitelabel/wallet/app.js @@ -0,0 +1,26 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; +import Header from '../../header'; +// import Footer from '../../footer'; +import GlobalNotification from '../../global_notification'; + +let RouteHandler = Router.RouteHandler; + +let WalletApp = React.createClass({ + render() { + return ( +
    +
    +
    + +
    + + +
    + ); + } +}); + +export default WalletApp; diff --git a/js/components/whitelabel/wallet/routes.js b/js/components/whitelabel/wallet/routes.js new file mode 100644 index 00000000..82cc458f --- /dev/null +++ b/js/components/whitelabel/wallet/routes.js @@ -0,0 +1,41 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import LoginContainer from './components/login_container'; +import LogoutContainer from '../../../components/logout_container'; +import SignupContainer from './components/signup_container'; +import PasswordResetContainer from '../../../components/password_reset_container'; +import WalletRegisterPiece from './components/wallet_register_piece'; +import PieceList from '../../piece_list'; +import PieceContainer from '../../ascribe_detail/piece_container'; +import EditionContainer from '../../ascribe_detail/edition_container'; +import SettingsContainer from './components/settings_container'; + +import App from './app'; +import AppConstants from '../../../constants/application_constants'; + +let Route = Router.Route; +let baseUrl = AppConstants.baseUrl; + + +function getRoutes() { + return ( + + + + + + + + + + + + + ); +} + + +export default getRoutes; \ No newline at end of file diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 54d43299..acd2561a 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -52,7 +52,7 @@ let constants = { 'name': 'Cyland media art lab', 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/cyland/logo.gif', 'permissions': ['register', 'edit', 'share', 'del_from_collection'], - 'type': 'prize' + 'type': 'wallet' } ], 'defaultDomain': { From eb6e3cb20a7ead5deedade404017dabb326c15b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 11 Aug 2015 14:47:28 +0200 Subject: [PATCH 049/397] finishing boilerplate for wallet app + prefixing whitelabel specific files --- js/app.js | 1 - ..._container.js => prize_piece_container.js} | 0 .../components/{hero.js => prize_hero.js} | 0 .../{landing.js => prize_landing.js} | 0 ..._container.js => prize_login_container.js} | 0 .../{piece_list.js => prize_piece_list.js} | 0 ...ister_piece.js => prize_register_piece.js} | 0 ...ntainer.js => prize_settings_container.js} | 0 ...container.js => prize_signup_container.js} | 0 .../{api_urls.js => prize_api_urls.js} | 6 +- ...ants.js => prize_application_constants.js} | 4 +- .../whitelabel/prize/{app.js => prize_app.js} | 2 +- .../prize/{routes.js => prize_routes.js} | 16 +++--- .../components/wallet_register_piece.js | 57 +++++++++++++++++++ .../wallet/constants/wallet_api_urls.js | 11 ++++ .../constants/wallet_application_constants.js | 9 +++ .../wallet/{app.js => wallet_app.js} | 0 .../wallet/{routes.js => wallet_routes.js} | 16 +++--- js/constants/api_urls.js | 7 ++- js/routes.js | 5 +- 20 files changed, 109 insertions(+), 25 deletions(-) rename js/components/whitelabel/prize/components/ascribe_detail/{piece_container.js => prize_piece_container.js} (100%) rename js/components/whitelabel/prize/components/{hero.js => prize_hero.js} (100%) rename js/components/whitelabel/prize/components/{landing.js => prize_landing.js} (100%) rename js/components/whitelabel/prize/components/{login_container.js => prize_login_container.js} (100%) rename js/components/whitelabel/prize/components/{piece_list.js => prize_piece_list.js} (100%) rename js/components/whitelabel/prize/components/{register_piece.js => prize_register_piece.js} (100%) rename js/components/whitelabel/prize/components/{settings_container.js => prize_settings_container.js} (100%) rename js/components/whitelabel/prize/components/{signup_container.js => prize_signup_container.js} (100%) rename js/components/whitelabel/prize/constants/{api_urls.js => prize_api_urls.js} (89%) rename js/components/whitelabel/prize/constants/{application_prize_constants.js => prize_application_constants.js} (74%) rename js/components/whitelabel/prize/{app.js => prize_app.js} (95%) rename js/components/whitelabel/prize/{routes.js => prize_routes.js} (73%) create mode 100644 js/components/whitelabel/wallet/components/wallet_register_piece.js create mode 100644 js/components/whitelabel/wallet/constants/wallet_api_urls.js create mode 100644 js/components/whitelabel/wallet/constants/wallet_application_constants.js rename js/components/whitelabel/wallet/{app.js => wallet_app.js} (100%) rename js/components/whitelabel/wallet/{routes.js => wallet_routes.js} (71%) diff --git a/js/app.js b/js/app.js index 81a8fb82..6115a0aa 100644 --- a/js/app.js +++ b/js/app.js @@ -44,7 +44,6 @@ requests.defaults({ }); - class AppGateway { start() { diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js similarity index 100% rename from js/components/whitelabel/prize/components/ascribe_detail/piece_container.js rename to js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js diff --git a/js/components/whitelabel/prize/components/hero.js b/js/components/whitelabel/prize/components/prize_hero.js similarity index 100% rename from js/components/whitelabel/prize/components/hero.js rename to js/components/whitelabel/prize/components/prize_hero.js diff --git a/js/components/whitelabel/prize/components/landing.js b/js/components/whitelabel/prize/components/prize_landing.js similarity index 100% rename from js/components/whitelabel/prize/components/landing.js rename to js/components/whitelabel/prize/components/prize_landing.js diff --git a/js/components/whitelabel/prize/components/login_container.js b/js/components/whitelabel/prize/components/prize_login_container.js similarity index 100% rename from js/components/whitelabel/prize/components/login_container.js rename to js/components/whitelabel/prize/components/prize_login_container.js diff --git a/js/components/whitelabel/prize/components/piece_list.js b/js/components/whitelabel/prize/components/prize_piece_list.js similarity index 100% rename from js/components/whitelabel/prize/components/piece_list.js rename to js/components/whitelabel/prize/components/prize_piece_list.js diff --git a/js/components/whitelabel/prize/components/register_piece.js b/js/components/whitelabel/prize/components/prize_register_piece.js similarity index 100% rename from js/components/whitelabel/prize/components/register_piece.js rename to js/components/whitelabel/prize/components/prize_register_piece.js diff --git a/js/components/whitelabel/prize/components/settings_container.js b/js/components/whitelabel/prize/components/prize_settings_container.js similarity index 100% rename from js/components/whitelabel/prize/components/settings_container.js rename to js/components/whitelabel/prize/components/prize_settings_container.js diff --git a/js/components/whitelabel/prize/components/signup_container.js b/js/components/whitelabel/prize/components/prize_signup_container.js similarity index 100% rename from js/components/whitelabel/prize/components/signup_container.js rename to js/components/whitelabel/prize/components/prize_signup_container.js diff --git a/js/components/whitelabel/prize/constants/api_urls.js b/js/components/whitelabel/prize/constants/prize_api_urls.js similarity index 89% rename from js/components/whitelabel/prize/constants/api_urls.js rename to js/components/whitelabel/prize/constants/prize_api_urls.js index 480e8d4f..8ef92daa 100644 --- a/js/components/whitelabel/prize/constants/api_urls.js +++ b/js/components/whitelabel/prize/constants/prize_api_urls.js @@ -1,8 +1,8 @@ 'use strict'; -import AppPrizeConstants from './application_prize_constants'; +import AppPrizeConstants from './prize_application_constants'; -function getApiUrls(subdomain) { +function getPrizeApiUrls(subdomain) { return { 'pieces_list': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/', 'users_login': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/login/', @@ -20,4 +20,4 @@ function getApiUrls(subdomain) { }; } -export default getApiUrls; +export default getPrizeApiUrls; diff --git a/js/components/whitelabel/prize/constants/application_prize_constants.js b/js/components/whitelabel/prize/constants/prize_application_constants.js similarity index 74% rename from js/components/whitelabel/prize/constants/application_prize_constants.js rename to js/components/whitelabel/prize/constants/prize_application_constants.js index 6026193b..9ba87a37 100644 --- a/js/components/whitelabel/prize/constants/application_prize_constants.js +++ b/js/components/whitelabel/prize/constants/prize_application_constants.js @@ -2,8 +2,8 @@ import AppConstants from '../../../../constants/application_constants'; -let constants = { +let prizeConstants = { prizeApiEndpoint: AppConstants.apiEndpoint + 'prizes/' }; -export default constants; \ No newline at end of file +export default prizeConstants; \ No newline at end of file diff --git a/js/components/whitelabel/prize/app.js b/js/components/whitelabel/prize/prize_app.js similarity index 95% rename from js/components/whitelabel/prize/app.js rename to js/components/whitelabel/prize/prize_app.js index 8876aa8c..137c2cf4 100644 --- a/js/components/whitelabel/prize/app.js +++ b/js/components/whitelabel/prize/prize_app.js @@ -2,7 +2,7 @@ import React from 'react'; import Router from 'react-router'; -import Hero from './components/hero'; +import Hero from './components/prize_hero'; import Header from '../../header'; // import Footer from '../../footer'; import GlobalNotification from '../../global_notification'; diff --git a/js/components/whitelabel/prize/routes.js b/js/components/whitelabel/prize/prize_routes.js similarity index 73% rename from js/components/whitelabel/prize/routes.js rename to js/components/whitelabel/prize/prize_routes.js index 16e57e50..1384d26b 100644 --- a/js/components/whitelabel/prize/routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -3,18 +3,18 @@ import React from 'react'; import Router from 'react-router'; -import Landing from './components/landing'; -import LoginContainer from './components/login_container'; +import Landing from './components/prize_landing'; +import LoginContainer from './components/prize_login_container'; import LogoutContainer from '../../../components/logout_container'; -import SignupContainer from './components/signup_container'; +import SignupContainer from './components/prize_signup_container'; import PasswordResetContainer from '../../../components/password_reset_container'; -import PrizeRegisterPiece from './components/register_piece'; -import PrizePieceList from './components/piece_list'; -import PrizePieceContainer from './components/ascribe_detail/piece_container'; +import PrizeRegisterPiece from './components/prize_register_piece'; +import PrizePieceList from './components/prize_piece_list'; +import PrizePieceContainer from './components/ascribe_detail/prize_piece_container'; import EditionContainer from '../../ascribe_detail/edition_container'; -import SettingsContainer from './components/settings_container'; +import SettingsContainer from './components/prize_settings_container'; -import App from './app'; +import App from './prize_app'; import AppConstants from '../../../constants/application_constants'; let Route = Router.Route; diff --git a/js/components/whitelabel/wallet/components/wallet_register_piece.js b/js/components/whitelabel/wallet/components/wallet_register_piece.js new file mode 100644 index 00000000..6b4d88fa --- /dev/null +++ b/js/components/whitelabel/wallet/components/wallet_register_piece.js @@ -0,0 +1,57 @@ +'use strict'; + +import React from 'react'; +import RegisterPiece from '../../../register_piece'; +import Property from '../../../ascribe_forms/property'; +import InputTextAreaToggable from '../../../ascribe_forms/input_textarea_toggable'; +import InputCheckbox from '../../../ascribe_forms/input_checkbox'; + +import { getLangText } from '../../../../utils/lang_utils'; + + +let WalletRegisterPiece = React.createClass({ + render() { + return ( + + + + + + + + + + + {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + ( + {getLangText('read')} + ) + + + + + ); + } +}); + +export default WalletRegisterPiece; diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js new file mode 100644 index 00000000..60ee8658 --- /dev/null +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -0,0 +1,11 @@ +'use strict'; + +import WalletAppConstants from './wallet_application_constants'; + +function getPrizeApiUrls(subdomain) { + return { + 'pieces_list': WalletAppConstants.walletApiEndpoint + subdomain + '/pieces/' + }; +} + +export default getPrizeApiUrls; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/constants/wallet_application_constants.js b/js/components/whitelabel/wallet/constants/wallet_application_constants.js new file mode 100644 index 00000000..bc0d73fd --- /dev/null +++ b/js/components/whitelabel/wallet/constants/wallet_application_constants.js @@ -0,0 +1,9 @@ +'use strict'; + +import AppConstants from '../../../../constants/application_constants'; + +let walletConstants = { + walletApiEndpoint: AppConstants.apiEndpoint + 'wallets/' +}; + +export default walletConstants; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/app.js b/js/components/whitelabel/wallet/wallet_app.js similarity index 100% rename from js/components/whitelabel/wallet/app.js rename to js/components/whitelabel/wallet/wallet_app.js diff --git a/js/components/whitelabel/wallet/routes.js b/js/components/whitelabel/wallet/wallet_routes.js similarity index 71% rename from js/components/whitelabel/wallet/routes.js rename to js/components/whitelabel/wallet/wallet_routes.js index 82cc458f..3dc07c6d 100644 --- a/js/components/whitelabel/wallet/routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -3,17 +3,17 @@ import React from 'react'; import Router from 'react-router'; -import LoginContainer from './components/login_container'; +import LoginContainer from '../../../components/login_container'; import LogoutContainer from '../../../components/logout_container'; -import SignupContainer from './components/signup_container'; +import SignupContainer from '../../../components/signup_container'; import PasswordResetContainer from '../../../components/password_reset_container'; import WalletRegisterPiece from './components/wallet_register_piece'; -import PieceList from '../../piece_list'; -import PieceContainer from '../../ascribe_detail/piece_container'; -import EditionContainer from '../../ascribe_detail/edition_container'; -import SettingsContainer from './components/settings_container'; +import PieceList from '../../../components/piece_list'; +import PieceContainer from '../../../components/ascribe_detail/piece_container'; +import EditionContainer from '../../../components/ascribe_detail/edition_container'; +import SettingsContainer from '../../../components/settings_container'; -import App from './app'; +import WalletApp from './wallet_app'; import AppConstants from '../../../constants/application_constants'; let Route = Router.Route; @@ -22,7 +22,7 @@ let baseUrl = AppConstants.baseUrl; function getRoutes() { return ( - + diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index c11a5df2..f56879e5 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -1,7 +1,10 @@ 'use strict'; import AppConstants from './application_constants'; -import getPrizeApiUrls from '../components/whitelabel/prize/constants/api_urls'; + +import getPrizeApiUrls from '../components/whitelabel/prize/constants/prize_api_urls'; +import getWalletApiUrls from '../components/whitelabel/wallet/constants/wallet_api_urls'; + import { update } from '../utils/general_utils'; @@ -62,6 +65,8 @@ export function updateApiUrls(type, subdomain) { if (type === 'prize') { newUrls = getPrizeApiUrls(subdomain); + } else if(type === 'wallet') { + newUrls = getWalletApiUrls(subdomain); } update(ApiUrls, newUrls); } diff --git a/js/routes.js b/js/routes.js index f7ea2ea6..4ee71070 100644 --- a/js/routes.js +++ b/js/routes.js @@ -3,7 +3,8 @@ import React from 'react'; import Router from 'react-router'; -import getPrizeRoutes from './components/whitelabel/prize/routes'; +import getPrizeRoutes from './components/whitelabel/prize/prize_routes'; +import getWalletRoutes from './components/whitelabel/wallet/wallet_routes'; import getDefaultRoutes from './components/routes'; import PieceList from './components/piece_list'; @@ -47,6 +48,8 @@ function getRoutes(type) { if (type === 'prize') { routes = getPrizeRoutes(COMMON_ROUTES); + } else if(type === 'wallet') { + routes = getWalletRoutes(COMMON_ROUTES); } else { routes = getDefaultRoutes(COMMON_ROUTES); } From 22727c2703600114703b0e1ab9b95f1bcf7a4155 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 11 Aug 2015 17:12:12 +0200 Subject: [PATCH 050/397] refactored piece container and detail --- .../collapsible_paragraph.js | 2 +- .../ascribe_detail/detail_property.js | 10 +- .../ascribe_detail/media_container.js | 28 +++- js/components/ascribe_detail/piece.js | 147 ++--------------- .../ascribe_detail/piece_container.js | 152 ++++++++++++++++-- js/components/piece_list.js | 2 +- .../accordion_list_item_prize.js | 75 ++++++--- .../ascribe_detail/piece_container.js | 85 ++++++++-- sass/main.scss | 4 + 9 files changed, 312 insertions(+), 193 deletions(-) diff --git a/js/components/ascribe_collapsible/collapsible_paragraph.js b/js/components/ascribe_collapsible/collapsible_paragraph.js index e04e82c2..8b3b3cf4 100644 --- a/js/components/ascribe_collapsible/collapsible_paragraph.js +++ b/js/components/ascribe_collapsible/collapsible_paragraph.js @@ -23,7 +23,7 @@ const CollapsibleParagraph = React.createClass({ getInitialState() { return { - expanded: false + expanded: this.props.defaultExpanded }; }, diff --git a/js/components/ascribe_detail/detail_property.js b/js/components/ascribe_detail/detail_property.js index f220fc98..991226f9 100644 --- a/js/components/ascribe_detail/detail_property.js +++ b/js/components/ascribe_detail/detail_property.js @@ -18,8 +18,8 @@ let DetailProperty = React.createClass({ getDefaultProps() { return { separator: ':', - labelClassName: 'col-xs-3 col-sm-3 col-md-2 col-lg-2', - valueClassName: 'col-xs-9 col-sm-9 col-md-10 col-lg-10' + labelClassName: 'col-xs-3 col-sm-3 col-md-2 col-lg-2 col-xs-height col-bottom ascribe-detail-property-label', + valueClassName: 'col-xs-9 col-sm-9 col-md-10 col-lg-10 col-xs-height col-bottom ascribe-detail-property-value' }; }, @@ -52,11 +52,11 @@ let DetailProperty = React.createClass({ return (
    -
    - { this.props.label + this.props.separator} +
    + { this.props.label } { this.props.separator}
    {value}
    diff --git a/js/components/ascribe_detail/media_container.js b/js/components/ascribe_detail/media_container.js index 529817c3..6ac2f745 100644 --- a/js/components/ascribe_detail/media_container.js +++ b/js/components/ascribe_detail/media_container.js @@ -19,7 +19,33 @@ const EMBED_IFRAME_HEIGHT = { let MediaContainer = React.createClass({ propTypes: { - content: React.PropTypes.object + content: React.PropTypes.object, + refreshObject: React.PropTypes.func + }, + + getInitialState() { + return {timerId: null}; + }, + + componentDidMount() { + if (!this.props.content.digital_work) { + return; + } + let isEncoding = this.props.content.digital_work.isEncoding; + if (this.props.content.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) { + let timerId = window.setInterval(this.props.refreshObject, 10000); + this.setState({timerId: timerId}); + } + }, + + componentWillUpdate() { + if (this.props.content.digital_work.isEncoding === 100) { + window.clearInterval(this.state.timerId); + } + }, + + componentWillUnmount() { + window.clearInterval(this.state.timerId); }, render() { diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index 3fabb055..ed312f5f 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -1,38 +1,14 @@ 'use strict'; import React from 'react'; -import Router from 'react-router'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; -import DetailProperty from './detail_property'; - -import UserActions from '../../actions/user_actions'; -import UserStore from '../../stores/user_store'; - -import PieceListActions from '../../actions/piece_list_actions'; -import PieceListStore from '../../stores/piece_list_store'; - -import EditionListActions from '../../actions/edition_list_actions'; - import PieceActions from '../../actions/piece_actions'; import MediaContainer from './media_container'; -import EditionDetailProperty from './detail_property'; - -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 DeleteButton from '../ascribe_buttons/delete_button'; - -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'; - /** * This is the component that implements display-specific functionality @@ -40,97 +16,16 @@ import { mergeOptions } from '../../utils/general_utils'; let Piece = React.createClass({ propTypes: { piece: React.PropTypes.object, + header: React.PropTypes.object, + subheader: React.PropTypes.object, + buttons: React.PropTypes.object, loadPiece: React.PropTypes.func, children: React.PropTypes.object }, - mixins: [Router.Navigation], - getInitialState() { - return mergeOptions( - UserStore.getState(), - PieceListStore.getState(), - { - showCreateEditionsDialog: false - } - ); - }, - - componentDidMount() { - UserStore.listen(this.onChange); - PieceListStore.listen(this.onChange); - UserActions.fetchCurrentUser(); - }, - - componentWillUnmount() { - UserStore.unlisten(this.onChange); - PieceListStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - toggleCreateEditionsDialog() { - this.setState({ - showCreateEditionsDialog: !this.state.showCreateEditionsDialog - }); - }, - - handleEditionCreationSuccess() { - PieceActions.updateProperty({key: 'num_editions', value: 0}); - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - this.toggleCreateEditionsDialog(); - }, - - handleDeleteSuccess(response) { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - - // since we're deleting a piece, we just need to close - // all editions dialogs and not reload them - EditionListActions.closeAllEditionLists(); - EditionListActions.clearAllEditionSelections(); - - let notification = new GlobalNotificationModel(response.notification, 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - - this.transitionTo('pieces'); - }, - - getCreateEditionsDialog() { - if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { - return ( -
    - -
    -
    - ); - } else { - return (
    ); - } - }, - - handlePollingSuccess(pieceId, numEditions) { - - // we need to refresh the num_editions property of the actual piece we're looking at - PieceActions.updateProperty({ - key: 'num_editions', - value: numEditions - }); - - // as well as its representation in the collection - // btw.: It's not sufficient to just set num_editions to numEditions, since a single accordion - // list item also uses the firstEdition property which we can only get from the server in that case. - // Therefore we need to at least refetch the changed piece from the server or on our case simply all - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); - - let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); + updateObject() { + return PieceActions.fetchOne(this.props.piece.id); }, render() { @@ -138,38 +33,14 @@ let Piece = React.createClass({ -
    -

    {this.props.piece.title}

    -
    - - - {this.props.piece.num_editions > 0 ? : null} -
    -
    -
    - -
    + {this.props.header} + {this.props.subheader} + {this.props.buttons} - - - - - - {this.getCreateEditionsDialog()} {this.props.children} diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 8e3a5750..8625f7a0 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -1,37 +1,59 @@ 'use strict'; import React from 'react'; +import Router from 'react-router'; import PieceActions from '../../actions/piece_actions'; import PieceStore from '../../stores/piece_store'; +import PieceListActions from '../../actions/piece_list_actions'; +import PieceListStore from '../../stores/piece_list_store'; + +import UserActions from '../../actions/user_actions'; +import UserStore from '../../stores/user_store'; + +import EditionListActions from '../../actions/edition_list_actions'; + import Piece from './piece'; import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph'; import FurtherDetails from './further_details'; +import DetailProperty from './detail_property'; + +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 DeleteButton from '../ascribe_buttons/delete_button'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + import AppConstants from '../../constants/application_constants'; +import { mergeOptions } from '../../utils/general_utils'; +import { getLangText } from '../../utils/lang_utils'; /** * This is the component that implements resource/data specific functionality */ let PieceContainer = React.createClass({ - getInitialState() { - return PieceStore.getState(); - }, - onChange(state) { - this.setState(state); - if (!state.piece.digital_work) { - return; - } - let isEncoding = state.piece.digital_work.isEncoding; - if (state.piece.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) { - let timerId = window.setInterval(() => PieceActions.fetchOne(this.props.params.pieceId), 10000); - this.setState({timerId: timerId}); - } + mixins: [Router.Navigation], + + getInitialState() { + return mergeOptions( + UserStore.getState(), + PieceListStore.getState(), + PieceStore.getState(), + { + showCreateEditionsDialog: false + } + ); }, componentDidMount() { + UserStore.listen(this.onChange); + PieceListStore.listen(this.onChange); + UserActions.fetchCurrentUser(); PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); }, @@ -42,21 +64,121 @@ let PieceContainer = React.createClass({ // as it will otherwise display wrong/old data once the user loads // the piece detail a second time PieceActions.updatePiece({}); - window.clearInterval(this.state.timerId); PieceStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + PieceListStore.unlisten(this.onChange); }, + onChange(state) { + this.setState(state); + }, loadPiece() { PieceActions.fetchOne(this.props.params.pieceId); }, + + toggleCreateEditionsDialog() { + this.setState({ + showCreateEditionsDialog: !this.state.showCreateEditionsDialog + }); + }, + + handleEditionCreationSuccess() { + PieceActions.updateProperty({key: 'num_editions', value: 0}); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + this.toggleCreateEditionsDialog(); + }, + + handleDeleteSuccess(response) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + // since we're deleting a piece, we just need to close + // all editions dialogs and not reload them + EditionListActions.closeAllEditionLists(); + EditionListActions.clearAllEditionSelections(); + + let notification = new GlobalNotificationModel(response.notification, 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + + this.transitionTo('pieces'); + }, + + getCreateEditionsDialog() { + if(this.state.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
    + +
    +
    + ); + } else { + return (
    ); + } + }, + + handlePollingSuccess(pieceId, numEditions) { + + // we need to refresh the num_editions property of the actual piece we're looking at + PieceActions.updateProperty({ + key: 'num_editions', + value: numEditions + }); + + // as well as its representation in the collection + // btw.: It's not sufficient to just set num_editions to numEditions, since a single accordion + // list item also uses the firstEdition property which we can only get from the server in that case. + // Therefore we need to at least refetch the changed piece from the server or on our case simply all + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + let notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + render() { if('title' in this.state.piece) { return ( + loadPiece={this.loadPiece} + header={ +
    +

    {this.state.piece.title}

    +
    + + + {this.state.piece.num_editions > 0 ? : null} +
    +
    + } + subheader={ +
    + +
    + } + buttons={ + + + + + }> + {this.getCreateEditionsDialog()} + + + +
    ); + } + else { + // jury and no rating yet + return ( +
    + + Submit your rating + +
    + ); + } + } + // participant + return ( +
    + + + +
    + ); + }, + render() { return ( @@ -68,22 +118,11 @@ let AccordionListItemWallet = React.createClass({
    {this.props.content.date_created.split('-')[0]}
    } - buttons={ -
    - - - -
    } - > + buttons={this.getPrizeButtons()}> {this.props.children} ); } }); -export default AccordionListItemWallet; +export default AccordionListItemPrize; diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index b6363868..a455b1a4 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -7,6 +7,9 @@ import StarRating from 'react-star-rating'; import PieceActions from '../../../../../actions/piece_actions'; import PieceStore from '../../../../../stores/piece_store'; +import PieceListStore from '../../../../../stores/piece_list_store'; +import PieceListActions from '../../../../../actions/piece_list_actions'; + import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; @@ -19,6 +22,10 @@ import Property from '../../../../../components/ascribe_forms/property'; import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; +import DetailProperty from '../../../../ascribe_detail/detail_property'; + +import { mergeOptions } from '../../../../../utils/general_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; /** * This is the component that implements resource/data specific functionality */ @@ -27,10 +34,6 @@ let PieceContainer = React.createClass({ return PieceStore.getState(); }, - onChange(state) { - this.setState(state); - }, - componentDidMount() { PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); @@ -42,10 +45,12 @@ let PieceContainer = React.createClass({ // as it will otherwise display wrong/old data once the user loads // the piece detail a second time PieceActions.updatePiece({}); - PieceStore.unlisten(this.onChange); }, + onChange(state) { + this.setState(state); + }, loadPiece() { PieceActions.fetchOne(this.props.params.pieceId); @@ -56,7 +61,19 @@ let PieceContainer = React.createClass({ return ( + loadPiece={this.loadPiece} + header={ +
    +

    {this.state.piece.title}

    +
    + + +
    +
    + } + subheader={ + + }>
    ); @@ -70,23 +87,22 @@ let PieceContainer = React.createClass({ } }); - -let PrizePieceDetails = React.createClass({ +let PrizePieceRatings = React.createClass({ propTypes: { piece: React.PropTypes.object }, getInitialState() { - return PrizeRatingStore.getState(); - }, - - onChange(state) { - this.setState(state); + return mergeOptions( + PieceListStore.getState(), + PrizeRatingStore.getState() + ); }, componentDidMount() { PrizeRatingStore.listen(this.onChange); PrizeRatingActions.fetchOne(this.props.piece.id); + PieceListStore.listen(this.onChange); }, componentWillUnmount() { @@ -96,11 +112,52 @@ let PrizePieceDetails = React.createClass({ // the piece detail a second time PrizeRatingActions.updateRating({}); PrizeRatingStore.unlisten(this.onChange); + PieceListStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + if (this.refs.rating) { + this.refs.rating.state.ratingCache = { + pos: this.refs.rating.state.pos, + rating: this.state.currentRating, + caption: this.refs.rating.props.caption, + name: this.refs.rating.props.name + }; + } }, onRatingClick(event, args) { event.preventDefault(); - PrizeRatingActions.createRating(this.props.piece.id, args.rating); + PrizeRatingActions.createRating(this.props.piece.id, args.rating).then( + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy) + ); + }, + render(){ + return ( + YOUR VOTE + } + value={ + } + />); + } +}); + +let PrizePieceDetails = React.createClass({ + propTypes: { + piece: React.PropTypes.object }, render() { diff --git a/sass/main.scss b/sass/main.scss index c83379b3..a81f303f 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -387,4 +387,8 @@ hr { .rating-container .rating-stars { width: 25px; color: #000; +} + +.react-rating-caption { + font-size: 1em; } \ No newline at end of file From ac45283968f59b92961eb5ab26dbd38ae84e0355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 11 Aug 2015 17:40:26 +0200 Subject: [PATCH 051/397] first iteration: whitelabel pages depending on customer --- js/app.js | 5 ++- .../cyland_register_piece.js} | 14 +++---- js/components/whitelabel/wallet/wallet_app.js | 1 - .../whitelabel/wallet/wallet_routes.js | 39 ++++++++++++++++--- js/routes.js | 6 +-- 5 files changed, 47 insertions(+), 18 deletions(-) rename js/components/whitelabel/wallet/components/{wallet_register_piece.js => cyland/cyland_register_piece.js} (81%) diff --git a/js/app.js b/js/app.js index 6115a0aa..6dcf58bf 100644 --- a/js/app.js +++ b/js/app.js @@ -65,12 +65,15 @@ class AppGateway { load(settings) { let type = 'default'; + let subdomain = 'www'; + if (settings) { type = settings.type; + subdomain = settings.subdomain; } EventActions.applicationWillBoot(settings); - Router.run(getRoutes(type), Router.HistoryLocation, (App) => { + Router.run(getRoutes(type, subdomain), Router.HistoryLocation, (App) => { React.render( , document.getElementById('main') diff --git a/js/components/whitelabel/wallet/components/wallet_register_piece.js b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js similarity index 81% rename from js/components/whitelabel/wallet/components/wallet_register_piece.js rename to js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js index 6b4d88fa..a5ff79b3 100644 --- a/js/components/whitelabel/wallet/components/wallet_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -1,15 +1,15 @@ 'use strict'; import React from 'react'; -import RegisterPiece from '../../../register_piece'; -import Property from '../../../ascribe_forms/property'; -import InputTextAreaToggable from '../../../ascribe_forms/input_textarea_toggable'; -import InputCheckbox from '../../../ascribe_forms/input_checkbox'; +import RegisterPiece from '../../../../register_piece'; +import Property from '../../../../ascribe_forms/property'; +import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable'; +import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; -import { getLangText } from '../../../../utils/lang_utils'; +import { getLangText } from '../../../../../utils/lang_utils'; -let WalletRegisterPiece = React.createClass({ +let CylandRegisterPiece = React.createClass({ render() { return ( - + - + - ); + ), + 'cc': ( + + + + + + + + + + + + + + ) +}; + + +function getRoutes(commonRoutes, subdomain) { + if(subdomain in ROUTES) { + return ROUTES[subdomain]; + } else { + throw new Error('Subdomain wasn\'t specified in the wallet app.'); + } } diff --git a/js/routes.js b/js/routes.js index 4ee71070..65dfbaac 100644 --- a/js/routes.js +++ b/js/routes.js @@ -43,13 +43,13 @@ const COMMON_ROUTES = ( ); -function getRoutes(type) { +function getRoutes(type, subdomain) { let routes = null; if (type === 'prize') { - routes = getPrizeRoutes(COMMON_ROUTES); + routes = getPrizeRoutes(COMMON_ROUTES, subdomain); } else if(type === 'wallet') { - routes = getWalletRoutes(COMMON_ROUTES); + routes = getWalletRoutes(COMMON_ROUTES, subdomain); } else { routes = getDefaultRoutes(COMMON_ROUTES); } From 8612f73e96ba6290a3ce2c16a0a26daacd3246b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 09:30:24 +0200 Subject: [PATCH 052/397] separate cc register form --- js/components/ascribe_forms/form.js | 1 + js/components/register_piece.js | 36 -------- .../wallet/components/cc/cc_register_piece.js | 85 +++++++++++++++++++ .../wallet/constants/wallet_api_urls.js | 9 +- .../whitelabel/wallet/wallet_routes.js | 8 +- 5 files changed, 94 insertions(+), 45 deletions(-) create mode 100644 js/components/whitelabel/wallet/components/cc/cc_register_piece.js diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 2b956a7e..0b8d9994 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -103,6 +103,7 @@ let Form = React.createClass({ if ('getFormData' in this.props){ data = mergeOptionsWithDuplicates(data, this.props.getFormData()); } + console.log(data); return data; }, diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 94ce4d33..4fbff2b9 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -54,7 +54,6 @@ let RegisterPiece = React.createClass( { getInitialState(){ return mergeOptions( - LicenseStore.getState(), UserStore.getState(), WhitelabelStore.getState(), PieceListStore.getState(), @@ -65,16 +64,13 @@ let RegisterPiece = React.createClass( { }, componentDidMount() { - LicenseActions.fetchLicense(); WhitelabelActions.fetchWhitelabel(); - LicenseStore.listen(this.onChange); PieceListStore.listen(this.onChange); UserStore.listen(this.onChange); WhitelabelStore.listen(this.onChange); }, componentWillUnmount() { - LicenseStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); WhitelabelStore.unlisten(this.onChange); @@ -109,37 +105,6 @@ let RegisterPiece = React.createClass( { this.transitionTo('piece', {pieceId: response.piece.id}); }, - onLicenseChange(event){ - //console.log(this.state.licenses[event.target.selectedIndex].url); - this.setState({selectedLicense: event.target.selectedIndex}); - }, - getLicenses() { - if (this.state.licenses && this.state.licenses.length > 1) { - return ( - {getLangText('Learn more')} - }> - - ); - } - return null; - }, - getSpecifyEditions() { if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) { return ( @@ -192,7 +157,6 @@ let RegisterPiece = React.createClass( { handleSuccess={this.handleSuccess} onLoggedOut={this.onLoggedOut}> {this.props.children} - {this.getLicenses()} {this.getSpecifyEditions()} diff --git a/js/components/whitelabel/wallet/components/cc/cc_register_piece.js b/js/components/whitelabel/wallet/components/cc/cc_register_piece.js new file mode 100644 index 00000000..129c1b0a --- /dev/null +++ b/js/components/whitelabel/wallet/components/cc/cc_register_piece.js @@ -0,0 +1,85 @@ +'use strict'; + +import React from 'react'; +import RegisterPiece from '../../../../register_piece'; +import Property from '../../../../ascribe_forms/property'; + +import LicenseActions from '../../../../../actions/license_actions'; +import LicenseStore from '../../../../../stores/license_store'; + +import { getLangText } from '../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../utils/general_utils'; + +let CCRegisterPiece = React.createClass({ + + getInitialState() { + return mergeOptions( + LicenseStore.getState(), + { + selectedLicense: 0 + } + ); + }, + + componentDidMount() { + LicenseStore.listen(this.onChange); + LicenseActions.fetchLicense(); + }, + + componentWillUnmount() { + LicenseStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + onLicenseChange(event){ + this.setState({selectedLicense: event.target.selectedIndex}); + }, + + getLicenses() { + if (this.state.licenses && this.state.licenses.length > 1) { + return ( + + {getLangText('Learn more')} + + }> + + ); + } + return null; + }, + + render() { + return ( + + {this.getLicenses()} + + ); + } +}); + +export default CCRegisterPiece; diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index 60ee8658..47c05c0a 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -1,11 +1,8 @@ 'use strict'; -import WalletAppConstants from './wallet_application_constants'; - -function getPrizeApiUrls(subdomain) { - return { - 'pieces_list': WalletAppConstants.walletApiEndpoint + subdomain + '/pieces/' - }; +// gets subdomain as a parameter +function getPrizeApiUrls() { + return {}; } export default getPrizeApiUrls; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 487432ee..a0c80c17 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -3,17 +3,19 @@ import React from 'react'; import Router from 'react-router'; +// general components import LoginContainer from '../../../components/login_container'; import LogoutContainer from '../../../components/logout_container'; import SignupContainer from '../../../components/signup_container'; import PasswordResetContainer from '../../../components/password_reset_container'; -import CylandRegisterPiece from './components/cyland/cyland_register_piece'; import PieceList from '../../../components/piece_list'; import PieceContainer from '../../../components/ascribe_detail/piece_container'; import EditionContainer from '../../../components/ascribe_detail/edition_container'; import SettingsContainer from '../../../components/settings_container'; -import RegisterPiece from '../../../components/register_piece'; +// specific components +import CylandRegisterPiece from './components/cyland/cyland_register_piece'; +import CCRegisterPiece from './components/cc/cc_register_piece'; import WalletApp from './wallet_app'; import AppConstants from '../../../constants/application_constants'; @@ -46,7 +48,7 @@ let ROUTES = { - + From 9630d043db757ba7e89d1ae6953a1ba25a303b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 09:52:51 +0200 Subject: [PATCH 053/397] first slide cyland archive submission --- js/components/ascribe_forms/form.js | 1 - js/components/register_piece.js | 6 +- .../cyland/cyland_register_piece.js | 158 +++++++++++++----- 3 files changed, 119 insertions(+), 46 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 0b8d9994..2b956a7e 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -103,7 +103,6 @@ let Form = React.createClass({ if ('getFormData' in this.props){ data = mergeOptionsWithDuplicates(data, this.props.getFormData()); } - console.log(data); return data; }, diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 4fbff2b9..229592b0 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -1,14 +1,11 @@ 'use strict'; import React from 'react'; - import Router from 'react-router'; + import Col from 'react-bootstrap/lib/Col'; import Row from 'react-bootstrap/lib/Row'; -import LicenseActions from '../actions/license_actions'; -import LicenseStore from '../stores/license_store'; - import WhitelabelActions from '../actions/whitelabel_actions'; import WhitelabelStore from '../stores/whitelabel_store'; @@ -20,7 +17,6 @@ import UserStore from '../stores/user_store'; import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationActions from '../actions/global_notification_actions'; -import Property from './ascribe_forms/property'; import PropertyCollapsible from './ascribe_forms/property_collapsible'; import RegisterPieceForm from './ascribe_forms/form_register_piece'; 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 a5ff79b3..a1f76b6e 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -1,55 +1,133 @@ 'use strict'; import React from 'react'; -import RegisterPiece from '../../../../register_piece'; +import Router from 'react-router'; + +import Col from 'react-bootstrap/lib/Col'; +import Row from 'react-bootstrap/lib/Row'; + +import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece'; + import Property from '../../../../ascribe_forms/property'; import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable'; import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; -import { getLangText } from '../../../../../utils/lang_utils'; +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 GlobalNotificationModel from '../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; + +import SlidesContainer from '../../../../ascribe_slides_container/slides_container'; + +import { getLangText } from '../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../utils/general_utils'; let CylandRegisterPiece = React.createClass({ + + getInitialState(){ + return mergeOptions( + UserStore.getState(), + PieceListStore.getState(), + { + selectedLicense: 0, + isFineUploaderActive: false + }); + }, + + mixins: [Router.Navigation], + + componentDidMount() { + PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + UserStore.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 + }); + } + }, + + handleSuccess(response){ + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + + // 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 + ); + + this.transitionTo('piece', {pieceId: response.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 ( - - - - - - - - - - - {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} - ( - {getLangText('read')} - ) - - - - + +
    + + + + + + + {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + ( + {getLangText('read')} + ) + + + + + + +
    +
    + {/* next slide */} +
    +
    ); } }); From c25de71b4bbf9abb63663c0db115074f18cb42ec Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 12 Aug 2015 13:21:05 +0200 Subject: [PATCH 054/397] notes and bug fixes --- .../ascribe_detail/piece_container.js | 107 +++++++++++++++--- .../whitelabel/prize/constants/api_urls.js | 5 +- .../prize/fetchers/prize_rating_fetcher.js | 2 +- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index a455b1a4..b552f073 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -13,6 +13,8 @@ import PieceListActions from '../../../../../actions/piece_list_actions'; import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; +import UserStore from '../../../../../stores/user_store'; + import Piece from '../../../../../components/ascribe_detail/piece'; import AppConstants from '../../../../../constants/application_constants'; @@ -22,8 +24,12 @@ import Property from '../../../../../components/ascribe_forms/property'; import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; +import GlobalNotificationModel from '../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; + import DetailProperty from '../../../../ascribe_detail/detail_property'; +import ApiUrls from '../../../../../constants/api_urls'; import { mergeOptions } from '../../../../../utils/general_utils'; import { getLangText } from '../../../../../utils/lang_utils'; /** @@ -64,6 +70,7 @@ let PieceContainer = React.createClass({ loadPiece={this.loadPiece} header={
    +

    {this.state.piece.title}


    @@ -87,6 +94,21 @@ let PieceContainer = React.createClass({ } }); +let NavigationHeader = React.createClass({ + propTypes: { + piece: React.PropTypes.object + }, + + render() { + return ( +
    + navigation +
    + ); + } +}); + + let PrizePieceRatings = React.createClass({ propTypes: { piece: React.PropTypes.object @@ -95,7 +117,8 @@ let PrizePieceRatings = React.createClass({ getInitialState() { return mergeOptions( PieceListStore.getState(), - PrizeRatingStore.getState() + PrizeRatingStore.getState(), + UserStore.getState() ); }, @@ -103,6 +126,7 @@ let PrizePieceRatings = React.createClass({ PrizeRatingStore.listen(this.onChange); PrizeRatingActions.fetchOne(this.props.piece.id); PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); }, componentWillUnmount() { @@ -113,6 +137,7 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.updateRating({}); PrizeRatingStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); }, onChange(state) { @@ -135,26 +160,72 @@ let PrizePieceRatings = React.createClass({ ); }, render(){ - return ( - YOUR VOTE - } - value={ - } - />); + if (this.state.currentUser && this.state.currentUser.is_jury) { + return ( +
    + YOUR VOTE + } + value={ + + }/> + +
    ); + } + return null; } }); +let PersonalNote = React.createClass({ + propTypes: { + piece: React.PropTypes.object, + currentUser: React.PropTypes.object + }, + showNotification(){ + let notification = new GlobalNotificationModel(getLangText('Jury note saved'), 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { + if (this.props.currentUser.username && true || false) { + return ( + + + + + +
    + + ); + } + return null; + } +}); + + let PrizePieceDetails = React.createClass({ propTypes: { piece: React.PropTypes.object diff --git a/js/components/whitelabel/prize/constants/api_urls.js b/js/components/whitelabel/prize/constants/api_urls.js index 480e8d4f..a62d455b 100644 --- a/js/components/whitelabel/prize/constants/api_urls.js +++ b/js/components/whitelabel/prize/constants/api_urls.js @@ -16,7 +16,10 @@ function getApiUrls(subdomain) { 'jury_activate': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/activate/', 'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/', 'ratings': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/', - 'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/' + 'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/', + 'notes': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/', + 'note': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/${piece_id}/' + }; } diff --git a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js index 91da0051..b7af8845 100644 --- a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js +++ b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js @@ -13,7 +13,7 @@ let PrizeRatingFetcher = { }, rate(pieceId, rating) { - return requests.post('ratings', {body: {'piece_id': pieceId, 'rating': rating}}); + return requests.post('ratings', {body: {'piece_id': pieceId, 'value': rating}}); } }; From d5dc16481081a225be5a419f0a64986634cc1365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 13:34:41 +0200 Subject: [PATCH 055/397] boilerplate for loan process --- .../ascribe_detail/further_details.js | 98 ++------------- .../further_details_fileuploader.js | 95 ++++++++++++++ js/components/ascribe_forms/form_loan.js | 74 ++++++++--- .../cyland_additional_data_form.js | 116 ++++++++++++++++++ .../cyland/cyland_register_piece.js | 73 ++++++++--- js/utils/general_utils.js | 22 ++++ 6 files changed, 360 insertions(+), 118 deletions(-) create mode 100644 js/components/ascribe_detail/further_details_fileuploader.js create mode 100644 js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js index 3a5c0b90..e8bf5d3b 100644 --- a/js/components/ascribe_detail/further_details.js +++ b/js/components/ascribe_detail/further_details.js @@ -5,21 +5,15 @@ import React from 'react'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; - import Form from './../ascribe_forms/form'; -import Property from './../ascribe_forms/property'; import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata'; -import ReactS3FineUploader from './../ascribe_uploader/react_s3_fine_uploader'; import GlobalNotificationModel from '../../models/global_notification_model'; 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 FurtherDetailsFileuploader from './further_details_fileuploader'; let FurtherDetails = React.createClass({ propTypes: { @@ -90,93 +84,21 @@ let FurtherDetails = React.createClass({ editable={this.props.editable} pieceId={this.props.pieceId} extraData={this.props.extraData} /> - +
    + + ); } }); -let FileUploader = React.createClass({ - propTypes: { - pieceId: React.PropTypes.number, - otherData: React.PropTypes.object, - setIsUploadReady: React.PropTypes.func, - submitKey: React.PropTypes.func, - isReadyForFormSubmission: React.PropTypes.func, - editable: React.PropTypes.bool - }, - render() { - // Essentially there a three cases important to the fileuploader - // - // 1. there is no other_data => do not show the fileuploader at all - // 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons - // 3. both other_data and editable are defined or true => show fileuploade with all action buttons - if (!this.props.editable && !this.props.otherData){ - return null; - } - return ( -
    - - - -
    -
    - ); - } -}); export default FurtherDetails; diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js new file mode 100644 index 00000000..5d9cd5fd --- /dev/null +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -0,0 +1,95 @@ +'use strict'; + +import React from 'react'; + +import Property from './../ascribe_forms/property'; + +import ReactS3FineUploader from './../ascribe_uploader/react_s3_fine_uploader'; + +import ApiUrls from '../../constants/api_urls'; +import AppConstants from '../../constants/application_constants'; + +import { getCookie } from '../../utils/fetch_api_utils'; + +let FurtherDetailsFileuploader = React.createClass({ + propTypes: { + pieceId: React.PropTypes.number, + otherData: React.PropTypes.object, + setIsUploadReady: React.PropTypes.func, + submitKey: React.PropTypes.func, + isReadyForFormSubmission: React.PropTypes.func, + editable: React.PropTypes.bool, + multiple: React.PropTypes.bool + }, + + getDefaultProps() { + return { + multiple: false + }; + }, + + render() { + // Essentially there a three cases important to the fileuploader + // + // 1. there is no other_data => do not show the fileuploader at all + // 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons + // 3. both other_data and editable are defined or true => show fileuploade with all action buttons + if (!this.props.editable && !this.props.otherData){ + return null; + } + return ( + + + + ); + } +}); + +export default FurtherDetailsFileuploader; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index f319c363..a96f12b9 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -2,6 +2,8 @@ import React from 'react'; +import classnames from 'classnames'; + import Button from 'react-bootstrap/lib/Button'; import Form from './form'; @@ -20,12 +22,25 @@ import { getLangText } from '../../utils/lang_utils'; let LoanForm = React.createClass({ propTypes: { + fullform: React.PropTypes.bool, + email: React.PropTypes.string, + gallery: React.PropTypes.string, + startdate: React.PropTypes.string, + enddate: React.PropTypes.string, + showPersonalMessage: React.PropTypes.bool, + url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, handleSuccess: React.PropTypes.func }, + getDefaultProps() { + return { + fullform: false + }; + }, + getInitialState() { return LoanContractStore.getState(); }, @@ -87,60 +102,87 @@ let LoanForm = React.createClass({ } }, - render() { + getButtons() { + if(this.props.fullform) { + return ( + + ); + } else { + return ( +
    +

    + +

    +
    + ); + } + }, + render() { return (
    -

    - -

    -
    } + buttons={this.getButtons()} spinner={
    }> +
    +

    Loan

    +
    + onBlur={this.handleOnBlur} + editable={!this.props.email}> + label={getLangText('Gallery/exhibition (optional)')} + editable={!this.props.gallery}> + label={getLangText('Start date')} + hidden={!this.props.startdate}> + label={getLangText('End date')} + hidden={!this.props.enddate}> + editable={true} + hidden={this.props.showPersonalMessage}> { + extradata[fieldName] = formRefs[fieldName].state.value; + }); + + return { + extradata: extradata, + piece_id: this.props.piece.id + }; + }, + + setIsUploadReady(isReady) { + this.setState({ + isUploadReady: isReady + }); + }, + + isReadyForFormSubmission() { + return true; + }, + + render() { + if(this.props.piece && this.props.piece.id) { + return ( + + {getLangText('Proceed to loan')} + + } + spinner={ +
    + +
    + }> + + + + + + + + + ); + } else { + return First register the piece.; + } + } +}); + +export default CylandAdditionalDataForm; \ No newline at end of file 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 a1f76b6e..cb842df9 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -9,7 +9,6 @@ import Row from 'react-bootstrap/lib/Row'; import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece'; import Property from '../../../../ascribe_forms/property'; -import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable'; import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; import PieceListStore from '../../../../../stores/piece_list_store'; @@ -18,36 +17,51 @@ 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 CylandAdditionalDataForm from '../ascribe_forms/cyland_additional_data_form'; + +import LoanForm from '../../../../ascribe_forms/form_loan'; + import SlidesContainer from '../../../../ascribe_slides_container/slides_container'; +import ApiUrls from '../../../../../constants/api_urls'; + import { getLangText } from '../../../../../utils/lang_utils'; -import { mergeOptions } from '../../../../../utils/general_utils'; +import { mergeOptions, dateToString } from '../../../../../utils/general_utils'; +import { getAclFormMessage } from '../../../../../utils/form_utils'; let CylandRegisterPiece = React.createClass({ + mixins: [Router.Navigation], + getInitialState(){ return mergeOptions( UserStore.getState(), PieceListStore.getState(), + PieceStore.getState(), { selectedLicense: 0, isFineUploaderActive: false }); }, - mixins: [Router.Navigation], - componentDidMount() { PieceListStore.listen(this.onChange); UserStore.listen(this.onChange); + PieceStore.listen(this.onChange); + + UserActions.fetchCurrentUser(); }, componentWillUnmount() { PieceListStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); + PieceStore.unlisten(this.onChange); }, onChange(state) { @@ -61,9 +75,7 @@ let CylandRegisterPiece = React.createClass({ } }, - handleSuccess(response){ - let notification = new GlobalNotificationModel(response.notification, 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); + 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 @@ -76,7 +88,16 @@ let CylandRegisterPiece = React.createClass({ this.state.filterBy ); - this.transitionTo('piece', {pieceId: response.piece.id}); + // 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); }, changeSlide() { @@ -93,11 +114,14 @@ let CylandRegisterPiece = React.createClass({ }, render() { + + let today = new Date(); + let datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain = new Date(); + datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain.setFullYear(3000); + return ( -
    +
    {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} - ( + ( {getLangText('read')} ) @@ -125,7 +149,28 @@ let CylandRegisterPiece = React.createClass({
    - {/* next slide */} + + + + + +
    +
    + + + + +
    ); diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 4dfda21d..85472fea 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -178,3 +178,25 @@ function _mergeOptions(obj1, obj2) { export function escapeHTML(s) { return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML; } + +/** + * Converts a date object to a string. + * Taken from: http://stackoverflow.com/a/4929629/1263876 + * @param {date} date a javascript date + * @return {string} a string, in format: DD-MM-YYY + */ +export function dateToString(date) { + var dd = date.getDate(); + var mm = date.getMonth() + 1; //January is 0! + var yyyy = date.getFullYear(); + + if(dd < 10) { + dd = '0' + dd; + } + + if(mm < 10) { + mm = '0' + mm; + } + + return dd + '-' + mm + '-' + yyyy; +} \ No newline at end of file From 1620437c86ace2a7615eb4bf89c03ce366c0fe05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 13:53:17 +0200 Subject: [PATCH 056/397] add defaultValue to inputdate --- js/components/ascribe_forms/form_loan.js | 8 +++---- js/components/ascribe_forms/input_date.js | 9 +++++++- .../cyland/cyland_register_piece.js | 14 +++++++----- js/utils/general_utils.js | 22 ------------------- package.json | 1 + 5 files changed, 21 insertions(+), 33 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index a96f12b9..fe6f1810 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -25,8 +25,8 @@ let LoanForm = React.createClass({ fullform: React.PropTypes.bool, email: React.PropTypes.string, gallery: React.PropTypes.string, - startdate: React.PropTypes.string, - enddate: React.PropTypes.string, + startdate: React.PropTypes.object, + enddate: React.PropTypes.object, showPersonalMessage: React.PropTypes.bool, url: React.PropTypes.string, @@ -167,7 +167,7 @@ let LoanForm = React.createClass({ label={getLangText('Start date')} hidden={!this.props.startdate}> @@ -167,8 +169,8 @@ let CylandRegisterPiece = React.createClass({ url={ApiUrls.ownership_loans_pieces} email="videoarchive@cyland.org" gallery="Cyland Archive" - startdate={dateToString(today)} - enddate={dateToString(datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain)}/> + startdate={today} + enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain}/>
    diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 85472fea..70c94a97 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -177,26 +177,4 @@ function _mergeOptions(obj1, obj2) { */ export function escapeHTML(s) { return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML; -} - -/** - * Converts a date object to a string. - * Taken from: http://stackoverflow.com/a/4929629/1263876 - * @param {date} date a javascript date - * @return {string} a string, in format: DD-MM-YYY - */ -export function dateToString(date) { - var dd = date.getDate(); - var mm = date.getMonth() + 1; //January is 0! - var yyyy = date.getFullYear(); - - if(dd < 10) { - dd = '0' + dd; - } - - if(mm < 10) { - mm = '0' + mm; - } - - return dd + '-' + mm + '-' + yyyy; } \ No newline at end of file diff --git a/package.json b/package.json index ddf45059..8162df06 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "isomorphic-fetch": "^2.0.2", "jest-cli": "^0.4.0", "lodash": "^3.9.3", + "moment": "^2.10.6", "object-assign": "^2.0.0", "q": "^1.4.1", "raven-js": "^1.1.19", From d3bf990ca5dd10928342c1bc4918aaf458fefb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 14:40:44 +0200 Subject: [PATCH 057/397] adjust props --- js/components/ascribe_forms/form_loan.js | 19 ++++++++++--------- .../cyland_additional_data_form.js | 3 +++ .../cyland/cyland_register_piece.js | 7 ++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index fe6f1810..a0202e7f 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -22,7 +22,7 @@ import { getLangText } from '../../utils/lang_utils'; let LoanForm = React.createClass({ propTypes: { - fullform: React.PropTypes.bool, + loanHeading: React.PropTypes.string, email: React.PropTypes.string, gallery: React.PropTypes.string, startdate: React.PropTypes.object, @@ -37,7 +37,8 @@ let LoanForm = React.createClass({ getDefaultProps() { return { - fullform: false + loanHeading: '', + showPersonalMessage: true }; }, @@ -103,7 +104,7 @@ let LoanForm = React.createClass({ }, getButtons() { - if(this.props.fullform) { + if(this.props.loanHeading) { return (
    }> -
    -

    Loan

    +
    +

    {this.props.loanHeading}

    }> +
    +

    Additional Information

    +
    + enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain} + showPersonalMessage={false}/>
    From 0cf5815f42736d27187d7696c46884aa5b741510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 16:11:15 +0200 Subject: [PATCH 058/397] add functionality to make a forwarded process slide container --- js/components/ascribe_forms/form_loan.js | 2 +- .../ascribe_slides_container/slides_container.js | 15 ++++++++++----- js/components/header.js | 2 +- js/components/register_piece.js | 16 +++++++--------- .../ascribe_forms/cyland_additional_data_form.js | 2 +- .../components/cyland/cyland_register_piece.js | 6 ++++-- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index a0202e7f..3fc6bd6e 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -140,7 +140,7 @@ let LoanForm = React.createClass({
    }> -
    +

    {this.props.loanHeading}

    {getLangText('COLLECTION')}; - addNewWork = this.props.showAddWork ? + {getLangText('NEW WORK')} : null; + addNewWork = this.props.showAddWork ? + {getLangText('NEW WORK')} : null; } else { account = {getLangText('LOGIN')}; diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 229592b0..78474f46 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -117,7 +117,8 @@ let RegisterPiece = React.createClass( { } }, - changeSlide() { + // basically redirects to the second slide (index: 1), when the user is not logged in + onLoggedOut() { // 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) { @@ -125,11 +126,6 @@ let RegisterPiece = React.createClass( { } }, - // basically redirects to the second slide (index: 1), when the user is not logged in - onLoggedOut() { - this.refs.slidesContainer.setSlideNum(1); - }, - onLogin() { // once the currentUser object from UserStore is defined (eventually the user was transitioned // to the login form via the slider and successfully logged in), we can direct him back to the @@ -141,10 +137,12 @@ let RegisterPiece = React.createClass( { render() { return ( - +
    + onClick={this.onLoggedOut} + onFocus={this.onLoggedOut}> }>
    -

    Additional Information

    +

    Provide supporting materials

    +
    @@ -139,7 +141,7 @@ let CylandRegisterPiece = React.createClass({ style={{paddingBottom: 0}}> - {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} ( {getLangText('read')} ) From 88423e6757010a8fc20e87c1b9460a5071dabc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 16:26:24 +0200 Subject: [PATCH 059/397] fix scroll overflow --- js/components/register_piece.js | 2 +- js/components/whitelabel/wallet/wallet_app.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 78474f46..1a09e64f 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -137,7 +137,7 @@ let RegisterPiece = React.createClass( { render() { return ( -
    -
    - -
    +
    From 97c298e304d26af80115fac043ac6d1c0f582a33 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 12 Aug 2015 16:47:16 +0200 Subject: [PATCH 060/397] piece navigation prev next WIP --- .../ascribe_detail/detail_property.js | 2 +- .../ascribe_detail/piece_container.js | 61 ++++++++++++++----- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/js/components/ascribe_detail/detail_property.js b/js/components/ascribe_detail/detail_property.js index 991226f9..828ed81a 100644 --- a/js/components/ascribe_detail/detail_property.js +++ b/js/components/ascribe_detail/detail_property.js @@ -17,7 +17,7 @@ let DetailProperty = React.createClass({ getDefaultProps() { return { - separator: ':', + separator: '', labelClassName: 'col-xs-3 col-sm-3 col-md-2 col-lg-2 col-xs-height col-bottom ascribe-detail-property-label', valueClassName: 'col-xs-9 col-sm-9 col-md-10 col-lg-10 col-xs-height col-bottom ascribe-detail-property-value' }; diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index b552f073..069548ce 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -1,6 +1,7 @@ 'use strict'; import React from 'react'; +import Router from 'react-router'; import StarRating from 'react-star-rating'; @@ -32,17 +33,23 @@ import DetailProperty from '../../../../ascribe_detail/detail_property'; import ApiUrls from '../../../../../constants/api_urls'; import { mergeOptions } from '../../../../../utils/general_utils'; import { getLangText } from '../../../../../utils/lang_utils'; + +let Link = Router.Link; + /** * This is the component that implements resource/data specific functionality */ let PieceContainer = React.createClass({ getInitialState() { - return PieceStore.getState(); + return mergeOptions( + PieceStore.getState(), + UserStore.getState() + ); }, componentDidMount() { PieceStore.listen(this.onChange); - PieceActions.fetchOne(this.props.params.pieceId); + UserStore.listen(this.onChange); }, componentWillUnmount() { @@ -52,6 +59,16 @@ let PieceContainer = React.createClass({ // the piece detail a second time PieceActions.updatePiece({}); PieceStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + }, + + componentDidUpdate() { + console.log('call me ') + PieceActions.fetchOne(this.props.params.pieceId); + }, + + shouldComponentUpdate(nextProps, nextState) { + return this.props.params.pieceId !== nextProps.params.pieceId }, onChange(state) { @@ -63,6 +80,7 @@ let PieceContainer = React.createClass({ }, render() { + console.log(this.props) if('title' in this.state.piece) { return ( - +

    {this.state.piece.title}


    @@ -79,7 +99,9 @@ let PieceContainer = React.createClass({
    } subheader={ - + }> @@ -96,13 +118,26 @@ let PieceContainer = React.createClass({ let NavigationHeader = React.createClass({ propTypes: { - piece: React.PropTypes.object + piece: React.PropTypes.object, + currentUser: React.PropTypes.object }, render() { return ( -
    - navigation +
    +
    + + + + + + Next + + + +
    ); } @@ -111,14 +146,14 @@ let NavigationHeader = React.createClass({ let PrizePieceRatings = React.createClass({ propTypes: { - piece: React.PropTypes.object + piece: React.PropTypes.object, + currentUser: React.PropTypes.object }, getInitialState() { return mergeOptions( PieceListStore.getState(), - PrizeRatingStore.getState(), - UserStore.getState() + PrizeRatingStore.getState() ); }, @@ -126,7 +161,6 @@ let PrizePieceRatings = React.createClass({ PrizeRatingStore.listen(this.onChange); PrizeRatingActions.fetchOne(this.props.piece.id); PieceListStore.listen(this.onChange); - UserStore.listen(this.onChange); }, componentWillUnmount() { @@ -137,7 +171,6 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.updateRating({}); PrizeRatingStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); - UserStore.unlisten(this.onChange); }, onChange(state) { @@ -160,7 +193,7 @@ let PrizePieceRatings = React.createClass({ ); }, render(){ - if (this.state.currentUser && this.state.currentUser.is_jury) { + if (this.props.currentUser && this.props.currentUser.is_jury) { return (
    + currentUser={this.props.currentUser}/>
    ); } return null; From 7c0e2312a11fead7e9f014632978d0b98c9062ee Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 12 Aug 2015 17:09:48 +0200 Subject: [PATCH 061/397] revert piece navigation and bug fix in navigation serializer --- .../ascribe_detail/piece_container.js | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index 069548ce..768a18e9 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -49,6 +49,7 @@ let PieceContainer = React.createClass({ componentDidMount() { PieceStore.listen(this.onChange); + PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); }, @@ -62,15 +63,6 @@ let PieceContainer = React.createClass({ UserStore.unlisten(this.onChange); }, - componentDidUpdate() { - console.log('call me ') - PieceActions.fetchOne(this.props.params.pieceId); - }, - - shouldComponentUpdate(nextProps, nextState) { - return this.props.params.pieceId !== nextProps.params.pieceId - }, - onChange(state) { this.setState(state); }, @@ -123,23 +115,27 @@ let NavigationHeader = React.createClass({ }, render() { - return ( -
    -
    - - - - - - Next - - - + if (this.props.currentUser && this.props.currentUser.is_jury && this.props.piece.navigation) { + let nav = this.props.piece.navigation; + return ( +
    +
    + + + + + + Next + + + +
    -
    - ); + ); + } + return null; } }); From 81ff4641c7b04cf9938eef364fbad485cad669d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 12 Aug 2015 17:30:39 +0200 Subject: [PATCH 062/397] fix prev and next button for navigationheader --- .../components/ascribe_detail/piece_container.js | 12 +++++++++--- sass/main.scss | 7 +++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js index 768a18e9..175757d7 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/piece_container.js @@ -63,6 +63,13 @@ let PieceContainer = React.createClass({ UserStore.unlisten(this.onChange); }, + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + onChange(state) { this.setState(state); }, @@ -72,7 +79,6 @@ let PieceContainer = React.createClass({ }, render() { - console.log(this.props) if('title' in this.state.piece) { return (
    - + - + Next diff --git a/sass/main.scss b/sass/main.scss index a81f303f..4071e727 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -391,4 +391,11 @@ hr { .react-rating-caption { font-size: 1em; +} + +.disable-select { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } \ No newline at end of file From 247cca3ee20865e9058b890ac25dcaa84b758175 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 13 Aug 2015 13:28:09 +0200 Subject: [PATCH 063/397] piece rating + navigation OK close prize --- .../accordion_list_item_piece.js | 3 +- .../prize/actions/prize_rating_actions.js | 2 - .../accordion_list_item_prize.js | 7 +- .../ascribe_detail/piece_container.js | 34 ++++---- .../whitelabel/prize/components/landing.js | 77 +++++++++++++++---- .../whitelabel/prize/components/piece_list.js | 36 +++++++-- sass/main.scss | 10 +++ 7 files changed, 126 insertions(+), 43 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js index 65b6454c..e1271b0a 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js @@ -60,7 +60,8 @@ let AccordionListItemPiece = React.createClass({ } subheading={

    - {getLangText('by %s', this.props.piece.artist_name)} + {getLangText('by ')} + {this.props.artistName ? this.props.artistName : this.props.piece.artist_name}

    } subsubheading={this.props.subsubheading} diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/actions/prize_rating_actions.js index 536445f8..e36023a0 100644 --- a/js/components/whitelabel/prize/actions/prize_rating_actions.js +++ b/js/components/whitelabel/prize/actions/prize_rating_actions.js @@ -37,7 +37,6 @@ class PrizeRatingActions { resolve(res); }) .catch((err) => { - console.logGlobal(err); reject(err); }); }); @@ -52,7 +51,6 @@ class PrizeRatingActions { resolve(res); }) .catch((err) => { - console.logGlobal(err); reject(err); }); }); diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 0c41ca57..73c82ca4 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -69,7 +69,7 @@ let AccordionListItemPrize = React.createClass({ // jury and rating available let rating = parseInt(this.props.content.ratings.rating, 10); return ( -
    +
    @@ -121,18 +123,18 @@ let NavigationHeader = React.createClass({ }, render() { - if (this.props.currentUser && this.props.currentUser.is_jury && this.props.piece.navigation) { + if (this.props.currentUser && this.props.piece.navigation) { let nav = this.props.piece.navigation; return (
    -
    diff --git a/js/components/whitelabel/prize/components/piece_list.js b/js/components/whitelabel/prize/components/piece_list.js index 2e570aed..2c838b6d 100644 --- a/js/components/whitelabel/prize/components/piece_list.js +++ b/js/components/whitelabel/prize/components/piece_list.js @@ -3,23 +3,34 @@ import React from 'react'; import PieceList from '../../../piece_list'; +import UserActions from '../../../../actions/user_actions'; +import UserStore from '../../../../stores/user_store'; + import PrizeActions from '../actions/prize_actions'; import PrizeStore from '../stores/prize_store'; import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize'; +import { mergeOptions } from '../../../../utils/general_utils'; + let PrizePieceList = React.createClass({ getInitialState() { - return PrizeStore.getState(); + return mergeOptions( + PrizeStore.getState(), + UserStore.getState() + ); }, componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); PrizeStore.listen(this.onChange); PrizeActions.fetchPrize(); }, componentWillUnmount() { + UserStore.unlisten(this.onChange); PrizeStore.unlisten(this.onChange); }, @@ -43,7 +54,8 @@ let PrizePieceList = React.createClass({
    ); diff --git a/sass/ascribe_piece_list_toolbar.scss b/sass/ascribe_piece_list_toolbar.scss index 44ded8a6..8756adf4 100644 --- a/sass/ascribe_piece_list_toolbar.scss +++ b/sass/ascribe_piece_list_toolbar.scss @@ -14,11 +14,13 @@ .ascribe-input-glyph > .form-group > .input-group { margin-left: 6px; input { + box-shadow: none; + background-color: transparent; border: 1px solid #02b6a3; border-right: 0; } > .input-group-addon { - background-color: white; + background-color: transparent; > .filter-glyph { color: #02b6a3; } diff --git a/sass/main.scss b/sass/main.scss index a657b002..de166b0c 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -80,6 +80,25 @@ hr { font-size: 0.8em; } +.navbar-default .navbar-nav > .active { + a { + background-color: transparent!important; + > span {color: #02b6a3;} + color: #02b6a3; + border-bottom: 1px solid #02b6a3; + + &:hover, &:focus{ + > span {color: #02b6a3;} + color: #02b6a3; + background-color: transparent; + border-bottom: 1px solid #02b6a3; + } + } +} +.navbar-default .navbar-nav > li > a { + border: 1px solid rgba(0,0,0,0); +} + .img-brand { padding: 0; height: 45px; From cf86e352e43f16ee0ebbb43661145b7c977151f5 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 17 Aug 2015 12:18:40 +0200 Subject: [PATCH 070/397] slide breadcrumbs --- .../slides_container.js | 39 +++++++++++++++++-- .../cyland_additional_data_form.js | 16 ++++---- .../cyland/cyland_register_piece.js | 11 +++++- sass/ascribe_slides_container.scss | 28 ++++++++++++- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 72ddfd49..dabb54a0 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -4,11 +4,14 @@ import React from 'react'; import Router from 'react-router'; import ReactAddons from 'react/addons'; +import Col from 'react-bootstrap/lib/Col'; + let State = Router.State; let Navigation = Router.Navigation; let SlidesContainer = React.createClass({ propTypes: { + breadcrumbs: React.PropTypes.arrayOf(React.PropTypes.string), children: React.PropTypes.arrayOf(React.PropTypes.element), forwardProcess: React.PropTypes.bool.isRequired }, @@ -132,6 +135,35 @@ let SlidesContainer = React.createClass({ } }, + renderBreadCrumbs() { + if (this.props.breadcrumbs) { + let numSlides = this.props.breadcrumbs.length; + let columnWidth = Math.floor(12 / numSlides); + return ( + + ); + } + return null; + }, + // Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps // Also, a key is nice to have! renderChildren() { @@ -151,15 +183,16 @@ let SlidesContainer = React.createClass({
    + {this.renderBreadCrumbs()}
    -
    - {this.renderChildren()} -
    +
    + {this.renderChildren()} +
    ); diff --git a/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js index 33b3e4ca..0ae5e22a 100644 --- a/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js @@ -80,14 +80,6 @@ let CylandAdditionalDataForm = React.createClass({

    Provide supporting materials

    - + ); } else { 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 918db052..42c5e14e 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -102,6 +102,13 @@ let CylandRegisterPiece = React.createClass({ this.refs.slidesContainer.setSlideNum(2); }, + handleLoanSuccess(response) { + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + + 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 @@ -124,6 +131,7 @@ let CylandRegisterPiece = React.createClass({ return (
    @@ -173,7 +181,8 @@ let CylandRegisterPiece = React.createClass({ gallery="Cyland Archive" startdate={today} enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain} - showPersonalMessage={false}/> + showPersonalMessage={false} + handleSuccess={this.handleLoanSuccess}/>
    diff --git a/sass/ascribe_slides_container.scss b/sass/ascribe_slides_container.scss index 2bc2d115..773a68bc 100644 --- a/sass/ascribe_slides_container.scss +++ b/sass/ascribe_slides_container.scss @@ -15,4 +15,30 @@ position: relative; min-height: 1px; float:left; -} \ No newline at end of file +} + +.ascribe-breadcrumb-container{ + div:last-child { + .ascribe-breadcrumb { + border-right: 1px solid #EEE; + } + } +} + +.ascribe-breadcrumb { + padding: 1em; + border: 1px solid #EEE; + border-right: 1px solid rgba(0, 0, 0, 0); + margin-bottom: 0.6em; + + .active { + color: #666; + } + a { + color: #DDD; + text-decoration: none; + font-size: 1.1em; + font-style: italic; + } +} + From 0be3e249bb3fdd06722fd06a0f764120ff665dfd Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 17 Aug 2015 13:46:04 +0200 Subject: [PATCH 071/397] breadcrumb style fix --- js/components/ascribe_slides_container/slides_container.js | 2 +- .../wallet/components/cyland/cyland_register_piece.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index dabb54a0..741e43a4 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -148,7 +148,7 @@ let SlidesContainer = React.createClass({
    - {i + 1}. {this.props.breadcrumbs[i]} + {this.props.breadcrumbs[i]} 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 42c5e14e..3026fc6f 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -131,7 +131,7 @@ let CylandRegisterPiece = React.createClass({ return (
    From fc82c866fb3b372140241b822a3b9627f79d3be2 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 17 Aug 2015 20:52:36 +0200 Subject: [PATCH 072/397] cyland refactor whitelabel + cyland app --- .../accordion_list_item_piece.js | 25 +--- .../ascribe_detail/further_details.js | 5 +- .../further_details_fileuploader.js | 6 +- .../ascribe_detail/piece_container.js | 2 +- .../accordion_list_item_prize.js | 2 +- .../prize/constants/prize_api_urls.js | 2 +- js/components/whitelabel/prize/prize_app.js | 2 +- .../cyland_accordion_list_item.js | 93 ++++++++++++ .../ascribe_buttons/cyland_submit_button.js | 54 +++++++ .../ascribe_detail/cyland_piece_container.js | 137 ++++++++++++++++++ .../cyland_additional_data_form.js | 18 +-- .../components/cyland/cyland_piece_list.js | 42 ++++++ .../cyland/cyland_register_piece.js | 14 +- .../wallet/constants/wallet_api_urls.js | 12 +- .../constants/wallet_application_constants.js | 2 +- js/components/whitelabel/wallet/wallet_app.js | 2 +- .../whitelabel/wallet/wallet_routes.js | 7 +- js/constants/application_constants.js | 16 +- 18 files changed, 381 insertions(+), 60 deletions(-) create mode 100644 js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js create mode 100644 js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js create mode 100644 js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js rename js/components/whitelabel/wallet/components/{ => cyland}/ascribe_forms/cyland_additional_data_form.js (85%) create mode 100644 js/components/whitelabel/wallet/components/cyland/cyland_piece_list.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js index e1271b0a..b7e621b8 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js @@ -13,6 +13,7 @@ let Link = Router.Link; let AccordionListItemPiece = React.createClass({ propTypes: { className: React.PropTypes.string, + artistName: React.PropTypes.string, piece: React.PropTypes.object, children: React.PropTypes.oneOfType([ React.PropTypes.arrayOf(React.PropTypes.element), @@ -26,24 +27,12 @@ let AccordionListItemPiece = React.createClass({ mixins: [Router.Navigation], getLinkData(){ - let linkData; - - if (this.props.piece.num_editions < 1 || !this.props.piece.first_edition) { - linkData = { - to: 'piece', - params: { - pieceId: this.props.piece.id - } - }; - } else { - linkData = { - to: 'edition', - params: { - editionId: this.props.piece.first_edition.bitcoin_id - } - }; - } - return linkData; + return { + to: 'piece', + params: { + pieceId: this.props.piece.id + } + }; }, render() { diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js index e8bf5d3b..57c6ebe1 100644 --- a/js/components/ascribe_detail/further_details.js +++ b/js/components/ascribe_detail/further_details.js @@ -20,7 +20,7 @@ let FurtherDetails = React.createClass({ editable: React.PropTypes.bool, pieceId: React.PropTypes.number, extraData: React.PropTypes.object, - otherData: React.PropTypes.object, + otherData: React.PropTypes.arrayOf(React.PropTypes.object), handleSuccess: React.PropTypes.func }, @@ -91,7 +91,8 @@ let FurtherDetails = React.createClass({ isReadyForFormSubmission={this.isReadyForFormSubmission} editable={this.props.editable} pieceId={this.props.pieceId} - otherData={this.props.otherData}/> + otherData={this.props.otherData} + multiple={true}/> diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 5d9cd5fd..7c5525fd 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -14,7 +14,7 @@ import { getCookie } from '../../utils/fetch_api_utils'; let FurtherDetailsFileuploader = React.createClass({ propTypes: { pieceId: React.PropTypes.number, - otherData: React.PropTypes.object, + otherData: React.PropTypes.arrayOf(React.PropTypes.object), setIsUploadReady: React.PropTypes.func, submitKey: React.PropTypes.func, isReadyForFormSubmission: React.PropTypes.func, @@ -37,6 +37,8 @@ let FurtherDetailsFileuploader = React.createClass({ if (!this.props.editable && !this.props.otherData){ return null; } + let otherDataIds = this.props.otherData ? this.props.otherData.map((data)=>{return data.id; }).join() : null; + return ( @@ -63,7 +65,7 @@ let FurtherDetailsFileuploader = React.createClass({ 'X-CSRFToken': getCookie(AppConstants.csrftoken) }, params: { - 'pk': this.props.otherData ? this.props.otherData.id : null + 'pk': otherDataIds }, cors: { expected: true, diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 2b607516..7380ada7 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -148,7 +148,7 @@ let PieceContainer = React.createClass({ loadPiece={this.loadPiece} header={
    -
    +

    {this.state.piece.title}

    diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 73c82ca4..bf6301f0 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -98,7 +98,7 @@ let AccordionListItemPrize = React.createClass({
    + aclName="acl_submit"> +
    {header}
    diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js b/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js new file mode 100644 index 00000000..c523739d --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js @@ -0,0 +1,93 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece'; + +import PieceListActions from '../../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../../stores/piece_list_store'; + +import UserStore from '../../../../../../stores/user_store'; + +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; + +import CylandSubmitButton from '../ascribe_buttons/cyland_submit_button'; +import AclProxy from '../../../../../acl_proxy'; + +import { getLangText } from '../../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../../utils/general_utils'; + + +let CylandAccordionListItem = React.createClass({ + propTypes: { + className: React.PropTypes.string, + content: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) + }, + + getInitialState() { + return mergeOptions( + PieceListStore.getState(), + UserStore.getState() + ); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleSubmitSuccess(response) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getSubmitButtons() { + return ( +
    + + + +
    + ); + }, + + render() { + return ( + + {this.props.content.date_created.split('-')[0]} +
    } + buttons={this.getSubmitButtons()}> + {this.props.children} + + ); + } +}); + +export default CylandAccordionListItem; diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js new file mode 100644 index 00000000..6e2246f8 --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -0,0 +1,54 @@ +'use strict'; + +import React from 'react'; +import classNames from 'classnames'; + +import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; +import PieceSubmitToPrizeForm from '../../../../../ascribe_forms/form_submit_to_prize'; + +import { getLangText } from '../../../../../../utils/lang_utils'; + +let SubmitToPrizeButton = React.createClass({ + propTypes: { + className: React.PropTypes.string, + handleSuccess: React.PropTypes.func, + piece: React.PropTypes.object.isRequired + }, + + getSubmitButton() { + if (this.props.piece.prize) { + return ( + + ); + } + else { + return ( + + ); + } + }, + + render() { + return ( + + + + + ); + } +}); + +export default SubmitToPrizeButton; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js new file mode 100644 index 00000000..d22d8638 --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js @@ -0,0 +1,137 @@ +'use strict'; + +import React from 'react'; + +import PieceActions from '../../../../../../actions/piece_actions'; +import PieceStore from '../../../../../../stores/piece_store'; + +import UserStore from '../../../../../../stores/user_store'; + +import Piece from '../../../../../../components/ascribe_detail/piece'; + +import AppConstants from '../../../../../../constants/application_constants'; + +import Form from '../../../../../../components/ascribe_forms/form'; +import Property from '../../../../../../components/ascribe_forms/property'; +import InputTextAreaToggable from '../../../../../../components/ascribe_forms/input_textarea_toggable'; +import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph'; + +import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader'; +import DetailProperty from '../../../../../ascribe_detail/detail_property'; + +import { mergeOptions } from '../../../../../../utils/general_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; + +/** + * This is the component that implements resource/data specific functionality + */ +let CylandPieceContainer = React.createClass({ + getInitialState() { + return mergeOptions( + PieceStore.getState(), + UserStore.getState() + ); + }, + + componentDidMount() { + PieceStore.listen(this.onChange); + PieceActions.fetchOne(this.props.params.pieceId); + UserStore.listen(this.onChange); + }, + + componentWillUnmount() { + // Every time we're leaving the piece detail page, + // just reset the piece that is saved in the piece store + // as it will otherwise display wrong/old data once the user loads + // the piece detail a second time + PieceActions.updatePiece({}); + PieceStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + }, + + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + + onChange(state) { + this.setState(state); + }, + + loadPiece() { + PieceActions.fetchOne(this.props.params.pieceId); + }, + + render() { + if('title' in this.state.piece) { + return ( + +
    +

    {this.state.piece.title}

    + + +
    +
    + }> + + + ); + } else { + return ( +
    + +
    + ); + } + } +}); + + +let CylandPieceDetails = React.createClass({ + propTypes: { + piece: React.PropTypes.object + }, + + render() { + if (Object.keys(this.props.piece.extra_data).length !== 0){ + return ( + +
    + {Object.keys(this.props.piece.extra_data).map((data) => { + let label = data.replace('_', ' '); + return ( + + + ); + } + )} + +
    + +
    + ); + } + return null; + } +}); + +export default CylandPieceContainer; diff --git a/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js similarity index 85% rename from js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js rename to js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 0ae5e22a..364360c8 100644 --- a/js/components/whitelabel/wallet/components/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -2,19 +2,19 @@ import React from 'react'; -import Form from '../../../../ascribe_forms/form'; -import Property from '../../../../ascribe_forms/property'; +import Form from '../../../../../ascribe_forms/form'; +import Property from '../../../../../ascribe_forms/property'; -import InputTextAreaToggable from '../../../../ascribe_forms/input_textarea_toggable'; +import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable'; -import FurtherDetailsFileuploader from '../../../../ascribe_detail/further_details_fileuploader'; +import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader'; -import ApiUrls from '../../../../../constants/api_urls'; -import AppConstants from '../../../../../constants/application_constants'; +import ApiUrls from '../../../../../../constants/api_urls'; +import AppConstants from '../../../../../../constants/application_constants'; -import requests from '../../../../../utils/requests'; +import requests from '../../../../../../utils/requests'; -import { getLangText } from '../../../../../utils/lang_utils'; +import { getLangText } from '../../../../../../utils/lang_utils'; let CylandAdditionalDataForm = React.createClass({ propTypes: { @@ -107,7 +107,7 @@ let CylandAdditionalDataForm = React.createClass({ editable={true} pieceId={this.props.piece.id} otherData={this.props.piece.other_data} - multiple={false}/> + multiple={true}/> ); } else { diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_piece_list.js b/js/components/whitelabel/wallet/components/cyland/cyland_piece_list.js new file mode 100644 index 00000000..018a3e55 --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/cyland_piece_list.js @@ -0,0 +1,42 @@ +'use strict'; + +import React from 'react'; +import PieceList from '../../../../piece_list'; + +import UserActions from '../../../../../actions/user_actions'; +import UserStore from '../../../../../stores/user_store'; + +import CylandAccordionListItem from './ascribe_accordion_list/cyland_accordion_list_item'; + + +let CylandPieceList = React.createClass({ + getInitialState() { + return UserStore.getState(); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + return ( +
    + +
    + ); + } +}); + +export default CylandPieceList; 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 3026fc6f..b01d648d 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -13,6 +13,9 @@ 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'; + import PieceListStore from '../../../../../stores/piece_list_store'; import PieceListActions from '../../../../../actions/piece_list_actions'; @@ -25,7 +28,7 @@ import PieceActions from '../../../../../actions/piece_actions'; import GlobalNotificationModel from '../../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; -import CylandAdditionalDataForm from '../ascribe_forms/cyland_additional_data_form'; +import CylandAdditionalDataForm from './ascribe_forms/cyland_additional_data_form'; import LoanForm from '../../../../ascribe_forms/form_loan'; @@ -46,6 +49,7 @@ let CylandRegisterPiece = React.createClass({ UserStore.getState(), PieceListStore.getState(), PieceStore.getState(), + WhitelabelStore.getState(), { selectedLicense: 0, isFineUploaderActive: false @@ -56,14 +60,16 @@ let CylandRegisterPiece = React.createClass({ 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) { @@ -105,7 +111,7 @@ let CylandRegisterPiece = React.createClass({ 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}); }, @@ -177,7 +183,7 @@ let CylandRegisterPiece = React.createClass({ message={getAclFormMessage('acl_loan', '\"' + this.state.piece.title + '\"', this.state.currentUser.username)} id={{piece_id: this.state.piece.id}} url={ApiUrls.ownership_loans_pieces} - email="videoarchive@mailinator.com" + email={this.state.whitelabel.user} gallery="Cyland Archive" startdate={today} enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain} diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index 47c05c0a..cd3e4fdb 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -1,8 +1,16 @@ 'use strict'; +import walletConstants from './wallet_application_constants'; + // gets subdomain as a parameter -function getPrizeApiUrls() { +function getWalletApiUrls(subdomain) { + if (subdomain === 'cyland'){ + return { + 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/', + 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' + }; + } return {}; } -export default getPrizeApiUrls; \ No newline at end of file +export default getWalletApiUrls; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/constants/wallet_application_constants.js b/js/components/whitelabel/wallet/constants/wallet_application_constants.js index bc0d73fd..cec456d9 100644 --- a/js/components/whitelabel/wallet/constants/wallet_application_constants.js +++ b/js/components/whitelabel/wallet/constants/wallet_application_constants.js @@ -3,7 +3,7 @@ import AppConstants from '../../../../constants/application_constants'; let walletConstants = { - walletApiEndpoint: AppConstants.apiEndpoint + 'wallets/' + walletApiEndpoint: AppConstants.apiEndpoint + 'whitelabel/' }; export default walletConstants; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js index 15b115d6..27657ff7 100644 --- a/js/components/whitelabel/wallet/wallet_app.js +++ b/js/components/whitelabel/wallet/wallet_app.js @@ -10,7 +10,7 @@ let RouteHandler = Router.RouteHandler; let WalletApp = React.createClass({ render() { return ( -
    +
    diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index a0c80c17..b5821670 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -14,7 +14,10 @@ import EditionContainer from '../../../components/ascribe_detail/edition_contain import SettingsContainer from '../../../components/settings_container'; // specific components +import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piece_container'; import CylandRegisterPiece from './components/cyland/cyland_register_piece'; +import CylandPieceList from './components/cyland/cyland_piece_list'; + import CCRegisterPiece from './components/cc/cc_register_piece'; import WalletApp from './wallet_app'; @@ -34,8 +37,8 @@ let ROUTES = { - - + + diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index acd2561a..530aaece 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -12,7 +12,7 @@ let constants = { 'baseUrl': window.BASE_URL, 'aclList': ['acl_coa', 'acl_consign', 'acl_delete', 'acl_download', 'acl_edit', 'acl_create_editions', 'acl_view_editions', 'acl_loan', 'acl_share', 'acl_transfer', 'acl_unconsign', 'acl_unshare', 'acl_view', - 'acl_withdraw_transfer', 'acl_submit_to_prize'], + 'acl_withdraw_transfer', 'acl_submit'], 'version': 0.1, 'csrftoken': 'csrftoken2', @@ -25,13 +25,6 @@ let constants = { 'type': 'wallet', 'ga': 'UA-60614729-4' }, - { - 'subdomain': 'cc-staging', - 'name': 'Creative Commons France', - 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/public/creativecommons/cc.logo.sm.png', - 'permissions': ['register', 'edit', 'share', 'del_from_collection'], - 'type': 'wallet' - }, { 'subdomain': 'sluice', 'name': 'Sluice Art Fair', @@ -40,13 +33,6 @@ let constants = { 'type': 'prize', 'ga': 'UA-60614729-5' }, - { - 'subdomain': 'sluice-staging', - 'name': 'Sluice Art Fair', - 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/sluice/logo.jpeg', - 'permissions': ['register', 'edit', 'share', 'del_from_collection'], - 'type': 'prize' - }, { 'subdomain': 'cyland', 'name': 'Cyland media art lab', From f77f1d1d5df55c7a9e4d3ec6f3444437dd81470e Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 18 Aug 2015 09:42:28 +0200 Subject: [PATCH 073/397] cyland submit button and form WIP cyland footers --- js/components/whitelabel/prize/prize_app.js | 3 +- .../ascribe_buttons/cyland_submit_button.js | 34 +++---- .../ascribe_forms/cyland_form_submit.js | 89 +++++++++++++++++++ js/components/whitelabel/wallet/wallet_app.js | 3 + 4 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js diff --git a/js/components/whitelabel/prize/prize_app.js b/js/components/whitelabel/prize/prize_app.js index 83dfbfdd..dc95f478 100644 --- a/js/components/whitelabel/prize/prize_app.js +++ b/js/components/whitelabel/prize/prize_app.js @@ -4,7 +4,7 @@ import React from 'react'; import Router from 'react-router'; import Hero from './components/prize_hero'; import Header from '../../header'; -// import Footer from '../../footer'; +import Footer from '../../footer'; import GlobalNotification from '../../global_notification'; let RouteHandler = Router.RouteHandler; @@ -28,6 +28,7 @@ let PrizeApp = React.createClass({
    +
    ); } diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js index 6e2246f8..a19a73c6 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -4,11 +4,11 @@ import React from 'react'; import classNames from 'classnames'; import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; -import PieceSubmitToPrizeForm from '../../../../../ascribe_forms/form_submit_to_prize'; +import CylandPieceSubmitForm from '../ascribe_forms/cyland_form_submit'; import { getLangText } from '../../../../../../utils/lang_utils'; -let SubmitToPrizeButton = React.createClass({ +let CylandSubmitButton = React.createClass({ propTypes: { className: React.PropTypes.string, handleSuccess: React.PropTypes.func, @@ -16,24 +16,12 @@ let SubmitToPrizeButton = React.createClass({ }, getSubmitButton() { - if (this.props.piece.prize) { - return ( - - ); - } - else { - return ( - - ); - } + return ( + + ); }, render() { @@ -41,8 +29,8 @@ let SubmitToPrizeButton = React.createClass({ - + @@ -51,4 +39,4 @@ let SubmitToPrizeButton = React.createClass({ } }); -export default SubmitToPrizeButton; \ No newline at end of file +export default CylandSubmitButton; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js new file mode 100644 index 00000000..bbc5f889 --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js @@ -0,0 +1,89 @@ +'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 InputCheckbox from '../../../../../ascribe_forms/input_checkbox'; + +import Alert from 'react-bootstrap/lib/Alert'; + +import AppConstants from '../../../../../../constants/application_constants'; +import ApiUrls from '../../../../../../constants/api_urls'; + +import { getLangText } from '../../../../../../utils/lang_utils.js'; + +import requests from '../../../../../../utils/requests'; + +let CylandPieceSubmitForm = React.createClass({ + propTypes: { + piece: React.PropTypes.object, + handleSuccess: React.PropTypes.func + }, + + render() { + //return ( + //
    + //

    + // + //

    + //
    } + // spinner={ + //
    + // + //
    }> + // + // + // + // + // + // + // + // + // + // {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} + // ( + // {getLangText('read')} + // ) + // + // + // + // + //

    {getLangText('Are you sure you want to submit to the prize?')}

    + //

    {getLangText('This is an irrevocable action%s', '.')}

    + //
    + // + //); + return null; + } +}); + + +export default CylandPieceSubmitForm; diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js index 27657ff7..311efd5c 100644 --- a/js/components/whitelabel/wallet/wallet_app.js +++ b/js/components/whitelabel/wallet/wallet_app.js @@ -3,6 +3,8 @@ import React from 'react'; import Router from 'react-router'; import Header from '../../header'; +import Footer from '../../footer'; + import GlobalNotification from '../../global_notification'; let RouteHandler = Router.RouteHandler; @@ -15,6 +17,7 @@ let WalletApp = React.createClass({ +
    ); } From eb54e6fff6bd0ab1e00e5bbdcc41853dd0b606d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 18 Aug 2015 10:53:50 +0200 Subject: [PATCH 074/397] refresh piece list after loan --- .../cyland/cyland_register_piece.js | 23 ++++++++++--------- sass/ascribe_slides_container.scss | 1 + 2 files changed, 13 insertions(+), 11 deletions(-) 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 b01d648d..5a17ae94 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -85,17 +85,6 @@ let CylandRegisterPiece = React.createClass({ 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); @@ -111,6 +100,18 @@ let CylandRegisterPiece = React.createClass({ handleLoanSuccess(response) { let notification = new GlobalNotificationModel(response.notification, 'success', 10000); GlobalNotificationActions.appendGlobalNotification(notification); + + // once the user was able to register + loan 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 + ); + PieceActions.fetchOne(this.state.piece.id); this.transitionTo('piece', {pieceId: this.state.piece.id}); }, diff --git a/sass/ascribe_slides_container.scss b/sass/ascribe_slides_container.scss index 773a68bc..4b96017c 100644 --- a/sass/ascribe_slides_container.scss +++ b/sass/ascribe_slides_container.scss @@ -30,6 +30,7 @@ border: 1px solid #EEE; border-right: 1px solid rgba(0, 0, 0, 0); margin-bottom: 0.6em; + background-color: white; .active { color: #666; From 8ae7edaa1ccdeb8677e19a983658f42eca1edd1e Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 18 Aug 2015 12:08:01 +0200 Subject: [PATCH 075/397] ikonotv initial setup --- .../ikonotv_accordion_list_item.js | 93 +++++++++++++++++++ .../ascribe_buttons/ikonotv_submit_button.js | 42 +++++++++ .../components/ikonotv/ikonotv_piece_list.js | 42 +++++++++ .../wallet/constants/wallet_api_urls.js | 6 ++ .../whitelabel/wallet/wallet_routes.js | 14 +++ js/constants/application_constants.js | 7 ++ 6 files changed, 204 insertions(+) create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js new file mode 100644 index 00000000..f89fd46b --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -0,0 +1,93 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece'; + +import PieceListActions from '../../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../../stores/piece_list_store'; + +import UserStore from '../../../../../../stores/user_store'; + +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; + +import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button'; +import AclProxy from '../../../../../acl_proxy'; + +import { getLangText } from '../../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../../utils/general_utils'; + + +let IkonotvAccordionListItem = React.createClass({ + propTypes: { + className: React.PropTypes.string, + content: React.PropTypes.object, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) + }, + + getInitialState() { + return mergeOptions( + PieceListStore.getState(), + UserStore.getState() + ); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + UserStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleSubmitSuccess(response) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getSubmitButtons() { + return ( +
    + + + +
    + ); + }, + + render() { + return ( + + {this.props.content.date_created.split('-')[0]} +
    } + buttons={this.getSubmitButtons()}> + {this.props.children} + + ); + } +}); + +export default IkonotvAccordionListItem; 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 new file mode 100644 index 00000000..0ebf352a --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_buttons/ikonotv_submit_button.js @@ -0,0 +1,42 @@ +'use strict'; + +import React from 'react'; +import classNames from 'classnames'; + +import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; +import CylandPieceSubmitForm from '../ascribe_forms/cyland_form_submit'; + +import { getLangText } from '../../../../../../utils/lang_utils'; + +let IkonotvSubmitButton = React.createClass({ + propTypes: { + className: React.PropTypes.string, + handleSuccess: React.PropTypes.func, + piece: React.PropTypes.object.isRequired + }, + + getSubmitButton() { + return ( + + ); + }, + + render() { + return ( + + + + + ); + } +}); + +export default IkonotvSubmitButton; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js new file mode 100644 index 00000000..e4c83d97 --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js @@ -0,0 +1,42 @@ +'use strict'; + +import React from 'react'; +import PieceList from '../../../../piece_list'; + +import UserActions from '../../../../../actions/user_actions'; +import UserStore from '../../../../../stores/user_store'; + +import IkonotvAccordionListItem from './ascribe_accordion_list/ikonotv_accordion_list_item'; + + +let IkonotvPieceList = React.createClass({ + getInitialState() { + return UserStore.getState(); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + return ( +
    + +
    + ); + } +}); + +export default IkonotvPieceList; diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index cd3e4fdb..56b6121e 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -10,6 +10,12 @@ function getWalletApiUrls(subdomain) { 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' }; } + else if (subdomain === 'ikonotv'){ + return { + 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/', + 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' + }; + } return {}; } diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index b5821670..f2aaf1f7 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -57,6 +57,20 @@ let ROUTES = { + ), + 'ikonotv': ( + + + + + + + + + + + + ) }; diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 530aaece..a1b0a157 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -39,6 +39,13 @@ let constants = { 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/cyland/logo.gif', 'permissions': ['register', 'edit', 'share', 'del_from_collection'], 'type': 'wallet' + }, + { + 'subdomain': 'ikonotv', + 'name': 'IkonoTV', + 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/ikonotv/ikono-logo-black.png', + 'permissions': ['register', 'edit', 'share', 'del_from_collection'], + 'type': 'wallet' } ], 'defaultDomain': { From e862fa39a91a930afb151d8bfa49457f33511047 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 18 Aug 2015 12:36:38 +0200 Subject: [PATCH 076/397] Merge remote-tracking branch 'remotes/origin/AD-803-refactor-acls' into AD-456-ikonotv-branded-page-for-registra Conflicts: web/settings.py --- .../ikonotv/ascribe_buttons/ikonotv_submit_button.js | 5 +---- js/components/whitelabel/wallet/wallet_routes.js | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) 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 0ebf352a..d3f4c0e3 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 @@ -4,7 +4,6 @@ import React from 'react'; import classNames from 'classnames'; import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; -import CylandPieceSubmitForm from '../ascribe_forms/cyland_form_submit'; import { getLangText } from '../../../../../../utils/lang_utils'; @@ -30,9 +29,7 @@ let IkonotvSubmitButton = React.createClass({ trigger={this.getSubmitButton()} handleSuccess={this.props.handleSuccess} title={getLangText('Loan to IkonoTV')}> - + ); diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index f2aaf1f7..29012d71 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -18,6 +18,8 @@ import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piec 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 CCRegisterPiece from './components/cc/cc_register_piece'; import WalletApp from './wallet_app'; @@ -66,7 +68,7 @@ let ROUTES = { - + From ad8be7e34aa01a10b3ad996ac79ff844bf256de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 18 Aug 2015 13:15:22 +0200 Subject: [PATCH 077/397] separate pre-sending form submission functionality --- js/components/ascribe_detail/further_details.js | 13 +++---------- .../ascribe_forms/form_register_piece.js | 13 +++---------- .../ascribe_slides_container/slides_container.js | 5 ++++- .../ascribe_uploader/react_s3_fine_uploader.js | 2 +- .../react_s3_fine_uploader_utils.js | 16 ++++++++++++++++ .../ascribe_forms/cyland_additional_data_form.js | 12 ++++++++++-- 6 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 js/components/ascribe_uploader/react_s3_fine_uploader_utils.js diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js index 57c6ebe1..36e79811 100644 --- a/js/components/ascribe_detail/further_details.js +++ b/js/components/ascribe_detail/further_details.js @@ -15,6 +15,8 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import FurtherDetailsFileuploader from './further_details_fileuploader'; +import { isReadyForFormSubmission } from '../ascribe_uploader/react_s3_fine_uploader_utils'; + let FurtherDetails = React.createClass({ propTypes: { editable: React.PropTypes.bool, @@ -48,15 +50,6 @@ let FurtherDetails = React.createClass({ }); }, - 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 (); return ( @@ -88,7 +81,7 @@ let FurtherDetails = React.createClass({ file.status !== 'deleted' && file.status !== 'canceled'); - if (files.length > 0 && files[0].status === 'upload successful') { - return true; - } else { - return false; - } - }, - render() { let currentUser = this.state.currentUser; let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false; @@ -117,7 +110,7 @@ let RegisterPieceForm = React.createClass({ {this.props.breadcrumbs.map((breadcrumb, i) => { return ( - +
    {this.props.breadcrumbs[i]} diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 7780ceae..90c76667 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -160,7 +160,7 @@ var ReactS3FineUploader = React.createClass({ } return name; }, - multiple: true, + multiple: false, defaultErrorMessage: getLangText('Unexpected error. Please contact us if this happens repeatedly.') }; }, diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js new file mode 100644 index 00000000..dbf62619 --- /dev/null +++ b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js @@ -0,0 +1,16 @@ +'use strict'; + +/** + * Returns a boolean if there has been at least one file uploaded + * successfully without it being deleted or canceled. + * @param {array of files} files provided by react fine uploader + * @return {Boolean} + */ +export function 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; + } +} \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 364360c8..cddabb0c 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -43,6 +43,7 @@ let CylandAdditionalDataForm = React.createClass({ extradata: extradata, piece_id: this.props.piece.id }; + }, setIsUploadReady(isReady) { @@ -51,8 +52,15 @@ let CylandAdditionalDataForm = React.createClass({ }); }, - isReadyForFormSubmission() { - return true; + isReadyForFormSubmission(files) { + let uploadedFiles = files.filter((file) => file.status === 'upload successful'); + let uploadingFiles = files.filter((file) => file.status === 'submitting'); + + if (uploadedFiles.length > 0 && uploadingFiles.length === 0) { + return true; + } else { + return false; + } }, render() { From e88612704f95fc4eca8a1b308b6e206abeedc9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 18 Aug 2015 13:39:06 +0200 Subject: [PATCH 078/397] cyland loan form for accordion list --- .../ascribe_buttons/cyland_submit_button.js | 46 ++++++++-- .../ascribe_forms/cyland_form_submit.js | 89 ------------------- 2 files changed, 41 insertions(+), 94 deletions(-) delete mode 100644 js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js index a19a73c6..2bb35719 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -3,16 +3,42 @@ import React from 'react'; import classNames from 'classnames'; +import Moment from 'moment'; + +import WhitelabelActions from '../../../../../../actions/whitelabel_actions'; +import WhitelabelStore from '../../../../../../stores/whitelabel_store'; + import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; -import CylandPieceSubmitForm from '../ascribe_forms/cyland_form_submit'; +import LoanForm from '../../../../../ascribe_forms/form_loan'; + +import ApiUrls from '../../../../../../constants/api_urls'; import { getLangText } from '../../../../../../utils/lang_utils'; +import { getAclFormMessage } from '../../../../../../utils/form_utils'; let CylandSubmitButton = React.createClass({ propTypes: { className: React.PropTypes.string, handleSuccess: React.PropTypes.func, - piece: React.PropTypes.object.isRequired + piece: React.PropTypes.object.isRequired, + username: React.PropTypes.string + }, + + getInitialState() { + return WhitelabelStore.getState(); + }, + + componentDidMount() { + WhitelabelStore.listen(this.onChange); + WhitelabelActions.fetchWhitelabel(); + }, + + componentWillUnmount() { + WhitelabelStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); }, getSubmitButton() { @@ -25,16 +51,26 @@ let CylandSubmitButton = React.createClass({ }, render() { + let today = new Moment(); + let loanEndDate = new Moment(); + loanEndDate.add(1000, 'years'); + return ( - - ); } }); diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js deleted file mode 100644 index bbc5f889..00000000 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_form_submit.js +++ /dev/null @@ -1,89 +0,0 @@ -'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 InputCheckbox from '../../../../../ascribe_forms/input_checkbox'; - -import Alert from 'react-bootstrap/lib/Alert'; - -import AppConstants from '../../../../../../constants/application_constants'; -import ApiUrls from '../../../../../../constants/api_urls'; - -import { getLangText } from '../../../../../../utils/lang_utils.js'; - -import requests from '../../../../../../utils/requests'; - -let CylandPieceSubmitForm = React.createClass({ - propTypes: { - piece: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - - render() { - //return ( - //
    - //

    - // - //

    - //
    } - // spinner={ - //
    - // - //
    }> - // - // - // - // - // - // - // - // - // - // {' ' + getLangText('I agree to the Terms of Service the art price') + ' '} - // (
    - // {getLangText('read')} - // ) - //
    - // - // - // - //

    {getLangText('Are you sure you want to submit to the prize?')}

    - //

    {getLangText('This is an irrevocable action%s', '.')}

    - //
    - // - //); - return null; - } -}); - - -export default CylandPieceSubmitForm; From e933b334c233810c656e651eaadb17808362e384 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 18 Aug 2015 16:24:36 +0200 Subject: [PATCH 079/397] loan contract form --- js/actions/loan_contract_list_actions.js | 27 ++++ js/components/password_reset_container.js | 2 + .../ascribe_forms/ikonotv_contract_form.js | 135 ++++++++++++++++++ .../ikonotv/ikonotv_register_piece.js | 120 ++++++++++++++++ .../whitelabel/wallet/wallet_routes.js | 5 +- js/fetchers/ownership_fetcher.js | 11 +- js/stores/loan_contract_list_store.js | 22 +++ sass/ascribe_form.scss | 9 ++ 8 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 js/actions/loan_contract_list_actions.js create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_contract_form.js create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js create mode 100644 js/stores/loan_contract_list_store.js 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 From 8a814c287cd6dc85fbd63cb29518ac0e21aabfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 18 Aug 2015 17:57:14 +0200 Subject: [PATCH 080/397] form validation first cut --- js/components/ascribe_forms/form.js | 41 +++++++++++-- .../ascribe_forms/form_register_piece.js | 58 +++++++++++++------ js/components/ascribe_forms/input_checkbox.js | 27 +++++---- js/components/ascribe_forms/property.js | 43 +++++++++++--- .../cyland/cyland_register_piece.js | 3 +- 5 files changed, 131 insertions(+), 41 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 2b956a7e..a9e267d9 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -23,8 +23,8 @@ let Form = React.createClass({ handleSuccess: React.PropTypes.func, getFormData: React.PropTypes.func, children: React.PropTypes.oneOfType([ - React.PropTypes.object, - React.PropTypes.array + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element ]), className: React.PropTypes.string, spinner: React.PropTypes.element, @@ -165,14 +165,43 @@ let Form = React.createClass({ this.setState({errors: []}); }, + checkFormValidity() { + let requiredProps = []; + + Object + .keys(this.refs) + .forEach((refName) => { + if(this.refs[refName].props.required) { + requiredProps.push(this.refs[refName]); + } + }); + + let validProps = requiredProps.filter((property) => property.state.isValid); + + if(requiredProps.length === validProps.length) { + return true; + } else { + return false; + } + + }, + getButtons() { - if (this.state.submitted){ + let buttons = null; + let isFormValid = this.checkFormValidity(); + + if(this.state.submitted) { return this.props.spinner; } - if (this.props.buttons){ - return this.props.buttons; + if(this.props.buttons) { + + buttons = React.cloneElement(this.props.buttons, { + disabled: !isFormValid + }); + + return buttons; } - let buttons = null; + if (this.state.edited){ buttons = ( diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index 6545007c..ef25dd55 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -27,7 +27,10 @@ let RegisterPieceForm = React.createClass({ isFineUploaderActive: React.PropTypes.bool, isFineUploaderEditable: React.PropTypes.bool, enableLocalHashing: React.PropTypes.bool, - children: React.PropTypes.element, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]), onLoggedOut: React.PropTypes.func }, @@ -74,16 +77,11 @@ let RegisterPieceForm = React.createClass({ }); }, - setIsUploadReady(isReady) { - this.setState({ - isUploadReady: isReady - }); - }, - render() { let currentUser = this.state.currentUser; let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false; enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing; + return (
    {this.props.headerMessage}
    + name="digital_work_key" + ignoreFocus={true} + required={true}> + label={getLangText('Artist Name')} + required={true}> + label={getLangText('Title')} + required={true}> + label={getLangText('Year Created')} + required={true}> + style={{paddingBottom: 0}} + required={true}> {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} From 188cca483474e0122fa884fd436c06b6be430f0d Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 19 Aug 2015 09:31:36 +0200 Subject: [PATCH 081/397] ikono register --- .../ikonotv/ikonotv_register_piece.js | 78 +++++-------------- .../whitelabel/wallet/wallet_routes.js | 3 +- 2 files changed, 21 insertions(+), 60 deletions(-) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js index 34f03042..33cc576c 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js @@ -16,6 +16,9 @@ import PieceStore from '../../../../../stores/piece_store'; import PieceActions from '../../../../../actions/piece_actions'; import ContractForm from './ascribe_forms/ikonotv_contract_form'; +import RegisterPieceForm from '../../../../../components/ascribe_forms/form_register_piece'; +import Property from '../../../../../components/ascribe_forms/property'; +import InputCheckbox from '../../../../../components/ascribe_forms/input_checkbox'; import GlobalNotificationModel from '../../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; @@ -31,88 +34,45 @@ let IkonotvRegisterPiece = React.createClass({ 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() { - + if (this.state.currentUser && + this.state.whitelabel && + this.state.whitelabel.user && + this.state.currentUser.email === this.state.whitelabel.user){ + return ( + + ); + } return ( - +
    + +
    ); + } }); diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 8d7a4aa8..435b1695 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -14,6 +14,7 @@ import EditionContainer from '../../../components/ascribe_detail/edition_contain import SettingsContainer from '../../../components/settings_container'; // specific components +import CylandLanding from './components/cyland/cyland_landing'; import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piece_container'; import CylandRegisterPiece from './components/cyland/cyland_register_piece'; import CylandPieceList from './components/cyland/cyland_piece_list'; @@ -34,7 +35,7 @@ let baseUrl = AppConstants.baseUrl; let ROUTES = { 'cyland': ( - + From bc6389935000e28b1f847102f78079a94b5ed79e Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 19 Aug 2015 09:41:28 +0200 Subject: [PATCH 082/397] Revert "form validation first cut" This reverts commit 8a814c287cd6dc85fbd63cb29518ac0e21aabfb3. --- js/components/ascribe_forms/form.js | 41 ++----------- .../ascribe_forms/form_register_piece.js | 58 ++++++------------- js/components/ascribe_forms/input_checkbox.js | 27 ++++----- js/components/ascribe_forms/property.js | 43 +++----------- .../cyland/cyland_register_piece.js | 3 +- 5 files changed, 41 insertions(+), 131 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index a9e267d9..2b956a7e 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -23,8 +23,8 @@ let Form = React.createClass({ handleSuccess: React.PropTypes.func, getFormData: React.PropTypes.func, children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element + React.PropTypes.object, + React.PropTypes.array ]), className: React.PropTypes.string, spinner: React.PropTypes.element, @@ -165,43 +165,14 @@ let Form = React.createClass({ this.setState({errors: []}); }, - checkFormValidity() { - let requiredProps = []; - - Object - .keys(this.refs) - .forEach((refName) => { - if(this.refs[refName].props.required) { - requiredProps.push(this.refs[refName]); - } - }); - - let validProps = requiredProps.filter((property) => property.state.isValid); - - if(requiredProps.length === validProps.length) { - return true; - } else { - return false; - } - - }, - getButtons() { - let buttons = null; - let isFormValid = this.checkFormValidity(); - - if(this.state.submitted) { + if (this.state.submitted){ return this.props.spinner; } - if(this.props.buttons) { - - buttons = React.cloneElement(this.props.buttons, { - disabled: !isFormValid - }); - - return buttons; + if (this.props.buttons){ + return this.props.buttons; } - + let buttons = null; if (this.state.edited){ buttons = ( diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index ef25dd55..6545007c 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -27,10 +27,7 @@ let RegisterPieceForm = React.createClass({ isFineUploaderActive: React.PropTypes.bool, isFineUploaderEditable: React.PropTypes.bool, enableLocalHashing: React.PropTypes.bool, - children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element - ]), + children: React.PropTypes.element, onLoggedOut: React.PropTypes.func }, @@ -77,11 +74,16 @@ let RegisterPieceForm = React.createClass({ }); }, + setIsUploadReady(isReady) { + this.setState({ + isUploadReady: isReady + }); + }, + render() { let currentUser = this.state.currentUser; let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false; enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing; - return ( {this.props.headerMessage}
    + ignoreFocus={true}> + label={getLangText('Artist Name')}> + label={getLangText('Title')}> + label={getLangText('Year Created')}> + style={{paddingBottom: 0}}> {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} From b7e81fb0dd3c70ad733c49c37189bfbd53b82b32 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 19 Aug 2015 13:54:45 +0200 Subject: [PATCH 083/397] cyland landing --- .../wallet/components/cyland/cyland_hero.js | 20 +++++ .../components/cyland/cyland_landing.js | 77 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 js/components/whitelabel/wallet/components/cyland/cyland_hero.js create mode 100644 js/components/whitelabel/wallet/components/cyland/cyland_landing.js diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_hero.js b/js/components/whitelabel/wallet/components/cyland/cyland_hero.js new file mode 100644 index 00000000..b98f407e --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/cyland_hero.js @@ -0,0 +1,20 @@ +'use strict'; + +import React from 'react'; +import constants from '../../../../constants/application_constants'; + + +let Hero = React.createClass({ + render() { + return ( +
    + Sluice Art Prize +
    + ); + } +}); + +export default Hero; diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js new file mode 100644 index 00000000..1512587e --- /dev/null +++ b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js @@ -0,0 +1,77 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; +import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'; + +import UserStore from '../../../../../stores/user_store'; +import UserActions from '../../../../../actions/user_actions'; + +import { mergeOptions } from '../../../../../utils/general_utils'; + + +let CylandLanding = React.createClass({ + + mixins: [Router.Navigation], + + getInitialState() { + return mergeOptions( + UserStore.getState() + ); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + + // if user is already logged in, redirect him to piece list + if(this.state.currentUser && this.state.currentUser.email) { + // FIXME: hack to redirect out of the dispatch cycle + window.setTimeout(() => this.replaceWith('pieces'), 0); + } + }, + + render() { + return ( +
    +
    +
    +
    + +
    +
    +
    +
    + Existing ascribe user? +
    + + Log in + +
    +
    +
    + Do you need an account? +
    + + Sign up + +
    +
    +
    +
    +
    + ); + } +}); + +export default CylandLanding; From 6dab66ec61663dd37f529ead16254f2417850238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 13:56:43 +0200 Subject: [PATCH 084/397] restructure cyland submit button --- .../ascribe_buttons/cyland_submit_button.js | 40 +++---------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js index 2bb35719..8b9a53ef 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -3,18 +3,12 @@ import React from 'react'; import classNames from 'classnames'; -import Moment from 'moment'; +import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; import WhitelabelActions from '../../../../../../actions/whitelabel_actions'; import WhitelabelStore from '../../../../../../stores/whitelabel_store'; -import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper'; -import LoanForm from '../../../../../ascribe_forms/form_loan'; - -import ApiUrls from '../../../../../../constants/api_urls'; - import { getLangText } from '../../../../../../utils/lang_utils'; -import { getAclFormMessage } from '../../../../../../utils/form_utils'; let CylandSubmitButton = React.createClass({ propTypes: { @@ -41,36 +35,14 @@ let CylandSubmitButton = React.createClass({ this.setState(state); }, - getSubmitButton() { + render() { return ( - - ); - }, - - render() { - let today = new Moment(); - let loanEndDate = new Moment(); - loanEndDate.add(1000, 'years'); - - return ( - - - + ); } }); From 406cee5bd3d1c56b86e202850eb9cbd8a1940ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 14:11:03 +0200 Subject: [PATCH 085/397] refactor breadcrumbs to attributes --- .../slides_container.js | 32 ++++++++++++++----- .../cyland/cyland_register_piece.js | 7 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 9a3f2269..95c5859f 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -11,7 +11,6 @@ let Navigation = Router.Navigation; let SlidesContainer = React.createClass({ propTypes: { - breadcrumbs: React.PropTypes.arrayOf(React.PropTypes.string), children: React.PropTypes.arrayOf(React.PropTypes.element), forwardProcess: React.PropTypes.bool.isRequired }, @@ -135,15 +134,31 @@ let SlidesContainer = React.createClass({ } }, - renderBreadCrumbs() { - if (this.props.breadcrumbs) { - let numSlides = this.props.breadcrumbs.length; + extractBreadcrumbs() { + let breadcrumbs = []; + + ReactAddons.Children.map(this.props.children, (child) => { + breadcrumbs.push(child.props['data-slide-title']); + }); + + return breadcrumbs; + }, + + renderBreadcrumbs() { + let breadcrumbs = this.extractBreadcrumbs(); + let numOfChildren = React.Children.count(this.props.children); + + // check if every child/slide has a title, + // otherwise do not display the breadcrumbs at all + if(breadcrumbs.length === numOfChildren) { + let numSlides = breadcrumbs.length; let columnWidth = Math.floor(12 / numSlides); + return (
    - {this.props.breadcrumbs.map((breadcrumb, i) => { + {breadcrumbs.map((breadcrumb, i) => { return (
    - {this.props.breadcrumbs[i]} + {breadcrumb} @@ -163,8 +178,9 @@ let SlidesContainer = React.createClass({
    ); + } else { + return null; } - return null; }, // Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps @@ -186,7 +202,7 @@ let SlidesContainer = React.createClass({
    - {this.renderBreadCrumbs()} + {this.renderBreadcrumbs()}
    -
    +
    -
    +
    -
    +
    Date: Wed, 19 Aug 2015 14:48:22 +0200 Subject: [PATCH 086/397] cyland landing --- .../components/cyland/cyland_landing.js | 31 ++++++++++++++----- js/components/whitelabel/wallet/wallet_app.js | 11 ++++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js index 1512587e..650fd88c 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js @@ -3,6 +3,10 @@ import React from 'react'; import Router from 'react-router'; + +import WhitelabelActions from '../../../../../actions/whitelabel_actions'; +import WhitelabelStore from '../../../../../stores/whitelabel_store'; + import ButtonLink from 'react-router-bootstrap/lib/ButtonLink'; import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'; @@ -18,17 +22,21 @@ let CylandLanding = React.createClass({ getInitialState() { return mergeOptions( - UserStore.getState() + UserStore.getState(), + WhitelabelStore.getState() ); }, componentDidMount() { UserStore.listen(this.onChange); UserActions.fetchCurrentUser(); + WhitelabelStore.listen(this.onChange); + WhitelabelActions.fetchWhitelabel(); }, componentWillUnmount() { UserStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); }, onChange(state) { @@ -46,22 +54,29 @@ let CylandLanding = React.createClass({
    -
    - +
    + +
    + Submissions to Cyland Archive are powered by + + ascribe + + +
    -
    +
    -
    +

    Existing ascribe user? -

    +

    Log in
    -
    +

    Do you need an account? -

    +

    Sign up diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js index 311efd5c..a10593b4 100644 --- a/js/components/whitelabel/wallet/wallet_app.js +++ b/js/components/whitelabel/wallet/wallet_app.js @@ -10,10 +10,19 @@ import GlobalNotification from '../../global_notification'; let RouteHandler = Router.RouteHandler; let WalletApp = React.createClass({ + mixins: [Router.State], + render() { + let header = null; + if (this.isActive('landing') || this.isActive('login') || this.isActive('signup')) { + header = ( +
    ); + } else { + header =
    ; + } return (
    -
    + {header} From 8a88f978c6544dc6fd56632f494926dc03217f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 15:30:48 +0200 Subject: [PATCH 087/397] add start_from parameter to slide container --- .../ascribe_accordion_list/accordion_list.js | 2 +- .../slides_container.js | 71 +++++++++++++++---- js/components/piece_list.js | 2 +- .../ascribe_buttons/cyland_submit_button.js | 6 +- .../ascribe_detail/cyland_piece_container.js | 8 +-- .../cyland_additional_data_form.js | 21 +++++- .../cyland/cyland_register_piece.js | 9 ++- sass/ascribe_accordion_list.scss | 7 +- sass/main.scss | 8 ++- 9 files changed, 102 insertions(+), 32 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list.js b/js/components/ascribe_accordion_list/accordion_list.js index 85084b5f..471ba9d5 100644 --- a/js/components/ascribe_accordion_list/accordion_list.js +++ b/js/components/ascribe_accordion_list/accordion_list.js @@ -28,7 +28,7 @@ let AccordionList = React.createClass({ ); } else { return ( -
    +
    {this.props.loadingElement}
    ); diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 95c5859f..56f1547f 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -21,15 +21,22 @@ let SlidesContainer = React.createClass({ // handle queryParameters let queryParams = this.getQuery(); let slideNum = -1; + let startFrom = -1; if(queryParams && 'slide_num' in queryParams) { slideNum = parseInt(queryParams.slide_num, 10); } // if slide_num is not set, this will be done in componentDidMount + // the query param 'start_from' removes all slide children before the respective number + if(queryParams && 'start_from' in queryParams) { + startFrom = parseInt(queryParams.start_from, 10); + } + return { + slideNum, + startFrom, containerWidth: 0, - slideNum: slideNum, historyLength: window.history.length }; }, @@ -54,9 +61,23 @@ let SlidesContainer = React.createClass({ window.addEventListener('resize', this.handleContainerResize); }, - componentDidUpdate() { - // check if slide_num was defined, and if not then default to 0 + componentWillReceiveProps() { let queryParams = this.getQuery(); + + // also check if start_from was updated + // This applies for example when the user tries to submit a already existing piece + // (starting from slide 1 for example) and then clicking on + NEW WORK + if(queryParams && !('start_from' in queryParams)) { + this.setState({ + startFrom: -1 + }); + } + }, + + componentDidUpdate() { + let queryParams = this.getQuery(); + + // check if slide_num was defined, and if not then default to 0 this.setSlideNum(queryParams.slide_num); }, @@ -137,20 +158,34 @@ let SlidesContainer = React.createClass({ extractBreadcrumbs() { let breadcrumbs = []; - ReactAddons.Children.map(this.props.children, (child) => { - breadcrumbs.push(child.props['data-slide-title']); + ReactAddons.Children.map(this.props.children, (child, i) => { + if(i >= this.state.startFrom) { + breadcrumbs.push(child.props['data-slide-title']); + } }); return breadcrumbs; }, + customChildrenCount() { + let count = 0; + React.Children.forEach(this.props.children, (child, i) => { + if(i >= this.state.startFrom) { + count++; + } + }); + + return count; + }, + renderBreadcrumbs() { let breadcrumbs = this.extractBreadcrumbs(); - let numOfChildren = React.Children.count(this.props.children); + let numOfChildren = this.customChildrenCount(); // check if every child/slide has a title, // otherwise do not display the breadcrumbs at all - if(breadcrumbs.length === numOfChildren) { + // Also, if there is only one child, do not display the breadcrumbs + if(breadcrumbs.length === numOfChildren && breadcrumbs.length > 1 && numOfChildren > 1) { let numSlides = breadcrumbs.length; let columnWidth = Math.floor(12 / numSlides); @@ -187,13 +222,21 @@ let SlidesContainer = React.createClass({ // Also, a key is nice to have! renderChildren() { return ReactAddons.Children.map(this.props.children, (child, i) => { - return ReactAddons.addons.cloneWithProps(child, { - className: 'ascribe-slide', - style: { - width: this.state.containerWidth - }, - key: i - }); + // since the default parameter of startFrom is -1, we do not need to check + // if its actually present in the url bar, as it will just not match + + if(i >= this.state.startFrom) { + return ReactAddons.addons.cloneWithProps(child, { + className: 'ascribe-slide', + style: { + width: this.state.containerWidth + }, + key: i + }); + } else { + // Abortions are bad mkay + return null; + } }); }, diff --git a/js/components/piece_list.js b/js/components/piece_list.js index eac6ca15..14554ea0 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -138,7 +138,7 @@ let PieceList = React.createClass({ this.transitionTo(this.getPathname(), {page: 1}); }, - applyOrderBy(orderBy, orderAsc) { + applyOrderBy(orderBy) { PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, orderBy, this.state.orderAsc, this.state.filterBy); }, diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js index 8b9a53ef..a4c23e41 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -39,7 +39,11 @@ let CylandSubmitButton = React.createClass({ return ( {getLangText('Submit to Cyland')} diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js index d22d8638..c8011fc7 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js @@ -20,11 +20,8 @@ import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_de import DetailProperty from '../../../../../ascribe_detail/detail_property'; import { mergeOptions } from '../../../../../../utils/general_utils'; -import { getLangText } from '../../../../../../utils/lang_utils'; -/** - * This is the component that implements resource/data specific functionality - */ + let CylandPieceContainer = React.createClass({ getInitialState() { return mergeOptions( @@ -106,10 +103,11 @@ let CylandPieceDetails = React.createClass({ show={true} defaultExpanded={true}> - {Object.keys(this.props.piece.extra_data).map((data) => { + {Object.keys(this.props.piece.extra_data).map((data, i) => { let label = data.replace('_', ' '); return ( diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index cddabb0c..95e55fca 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -24,7 +24,7 @@ let CylandAdditionalDataForm = React.createClass({ getInitialState() { return { - isUploadReady: false + isUploadReady: true }; }, @@ -64,6 +64,17 @@ let CylandAdditionalDataForm = React.createClass({ }, render() { + let artistBio = ''; + let conceptualOverview = ''; + + if (Object.keys(this.props.piece).length !== 0 && Object.keys(this.props.piece.extra_data).length !== 0) { + let extraData = this.props.piece.extra_data; + + artistBio = extraData.artist_bio; + conceptualOverview = extraData.conceptual_overview; + } + + if(this.props.piece && this.props.piece.id) { return ( ); } else { - return First register the piece.; + return ( +
    + +
    + ); } } }); 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 4e6fd333..ef1c154e 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -40,9 +40,10 @@ import { getLangText } from '../../../../../utils/lang_utils'; import { mergeOptions } from '../../../../../utils/general_utils'; import { getAclFormMessage } from '../../../../../utils/form_utils'; + let CylandRegisterPiece = React.createClass({ - mixins: [Router.Navigation], + mixins: [Router.Navigation, Router.State], getInitialState(){ return mergeOptions( @@ -63,6 +64,12 @@ let CylandRegisterPiece = React.createClass({ WhitelabelStore.listen(this.onChange); UserActions.fetchCurrentUser(); WhitelabelActions.fetchWhitelabel(); + + let queryParams = this.getQuery(); + + if(queryParams && 'piece_id' in queryParams) { + PieceActions.fetchOne(queryParams.piece_id); + } }, componentWillUnmount() { diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss index f44be250..b040e877 100644 --- a/sass/ascribe_accordion_list.scss +++ b/sass/ascribe_accordion_list.scss @@ -65,7 +65,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro'; overflow: hidden; text-overflow: ellipsis; } - a { + a:not(.btn) { color: #666; } } @@ -79,11 +79,6 @@ $ascribe-accordion-list-font: 'Source Sans Pro'; } } -.ascribe-accordion-list-loading { - padding-top: 30%; - padding-bottom: 30%; -} - .ascribe-accordion-list-loading img { display: block; margin: auto; diff --git a/sass/main.scss b/sass/main.scss index de166b0c..fed435f0 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -427,4 +427,10 @@ hr { &:hover { color: #000; } -} \ No newline at end of file +} + +.ascribe-loading-position { + padding-top: 30%; + padding-bottom: 30%; + text-align: center; +} From 0b4b3fa7273211760dcb58cbc01d5033a5837bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 15:54:13 +0200 Subject: [PATCH 088/397] fix slideContainer broken functionality --- .../ascribe_slides_container/slides_container.js | 10 ++++++++-- .../wallet/components/cyland/cyland_register_piece.js | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 56f1547f..50b6eb82 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -92,6 +92,12 @@ let SlidesContainer = React.createClass({ }); }, + // When the start_from parameter is used, this.setSlideNum can not simply be used anymore. + nextSlide() { + let nextSlide = this.state.slideNum + 1; + this.setSlideNum(nextSlide); + }, + // We let every one from the outsite set the page number of the slider, // though only if the slideNum is actually in the range of our children-list. setSlideNum(slideNum) { @@ -122,7 +128,7 @@ let SlidesContainer = React.createClass({ // if slideNum is within the range of slides and none of the previous cases // where matched, we can actually do transitions - } else if(slideNum >= 0 || slideNum < React.Children.count(this.props.children)) { + } else if(slideNum >= 0 || slideNum < this.customChildrenCount()) { if(slideNum !== this.state.slideNum - 1) { // Bootstrapping the component, getInitialState is called once to save @@ -249,7 +255,7 @@ let SlidesContainer = React.createClass({
    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 ef1c154e..5e96a1e6 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -97,11 +97,11 @@ let CylandRegisterPiece = React.createClass({ PieceActions.updatePiece(response.piece); } - this.refs.slidesContainer.setSlideNum(1); + this.refs.slidesContainer.nextSlide(); }, handleAdditionalDataSuccess() { - this.refs.slidesContainer.setSlideNum(2); + this.refs.slidesContainer.nextSlide(); }, handleLoanSuccess(response) { From d5e8181855f5f8b2190f604344e472a5a0034904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 16:02:10 +0200 Subject: [PATCH 089/397] make cyland submission stateful --- .../ascribe_buttons/cyland_submit_button.js | 9 ++++++++- .../ascribe_forms/cyland_additional_data_form.js | 13 ------------- .../components/cyland/cyland_register_piece.js | 15 ++++++++++----- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js index a4c23e41..ab7723ea 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_buttons/cyland_submit_button.js @@ -36,12 +36,19 @@ let CylandSubmitButton = React.createClass({ }, render() { + let piece = this.props.piece; + let startFrom = 1; + + if(piece && piece.extra_data && Object.keys(piece.extra_data).length > 0) { + startFrom = 2; + } + return ( diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 95e55fca..38eeee7f 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -64,17 +64,6 @@ let CylandAdditionalDataForm = React.createClass({ }, render() { - let artistBio = ''; - let conceptualOverview = ''; - - if (Object.keys(this.props.piece).length !== 0 && Object.keys(this.props.piece.extra_data).length !== 0) { - let extraData = this.props.piece.extra_data; - - artistBio = extraData.artist_bio; - conceptualOverview = extraData.conceptual_overview; - } - - if(this.props.piece && this.props.piece.id) { return ( Date: Wed, 19 Aug 2015 16:03:59 +0200 Subject: [PATCH 090/397] Revert "form validation first cut" Tim: I reverted this commit because I want to keep if for later. We decided to do so because we're of the opinion validation is not a pressing issue right now. This reverts commit 8a814c287cd6dc85fbd63cb29518ac0e21aabfb3. --- js/components/ascribe_forms/form.js | 41 ++----------- .../ascribe_forms/form_register_piece.js | 58 ++++++------------- js/components/ascribe_forms/input_checkbox.js | 27 ++++----- js/components/ascribe_forms/property.js | 43 +++----------- .../cyland/cyland_register_piece.js | 3 +- 5 files changed, 41 insertions(+), 131 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index a9e267d9..2b956a7e 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -23,8 +23,8 @@ let Form = React.createClass({ handleSuccess: React.PropTypes.func, getFormData: React.PropTypes.func, children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element + React.PropTypes.object, + React.PropTypes.array ]), className: React.PropTypes.string, spinner: React.PropTypes.element, @@ -165,43 +165,14 @@ let Form = React.createClass({ this.setState({errors: []}); }, - checkFormValidity() { - let requiredProps = []; - - Object - .keys(this.refs) - .forEach((refName) => { - if(this.refs[refName].props.required) { - requiredProps.push(this.refs[refName]); - } - }); - - let validProps = requiredProps.filter((property) => property.state.isValid); - - if(requiredProps.length === validProps.length) { - return true; - } else { - return false; - } - - }, - getButtons() { - let buttons = null; - let isFormValid = this.checkFormValidity(); - - if(this.state.submitted) { + if (this.state.submitted){ return this.props.spinner; } - if(this.props.buttons) { - - buttons = React.cloneElement(this.props.buttons, { - disabled: !isFormValid - }); - - return buttons; + if (this.props.buttons){ + return this.props.buttons; } - + let buttons = null; if (this.state.edited){ buttons = ( diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index ef25dd55..6545007c 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -27,10 +27,7 @@ let RegisterPieceForm = React.createClass({ isFineUploaderActive: React.PropTypes.bool, isFineUploaderEditable: React.PropTypes.bool, enableLocalHashing: React.PropTypes.bool, - children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element - ]), + children: React.PropTypes.element, onLoggedOut: React.PropTypes.func }, @@ -77,11 +74,16 @@ let RegisterPieceForm = React.createClass({ }); }, + setIsUploadReady(isReady) { + this.setState({ + isUploadReady: isReady + }); + }, + render() { let currentUser = this.state.currentUser; let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false; enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing; - return ( {this.props.headerMessage}
    + ignoreFocus={true}> + label={getLangText('Artist Name')}> + label={getLangText('Title')}> + label={getLangText('Year Created')}> + style={{paddingBottom: 0}}> {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} From 862cd7986c208ccf488e3771f6bf770c3fd9b897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 17:06:14 +0200 Subject: [PATCH 091/397] add lock/disabled functionality to form --- js/components/ascribe_forms/form.js | 6 +++- .../ascribe_forms/form_register_piece.js | 18 ++++++++++-- js/components/ascribe_forms/input_checkbox.js | 28 +++++++++++++++++-- js/components/ascribe_forms/property.js | 20 +++++++++---- sass/ascribe_settings.scss | 2 -- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 2b956a7e..eac91d42 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -33,6 +33,9 @@ let Form = React.createClass({ React.PropTypes.arrayOf(React.PropTypes.element) ]), + // Can be used to freeze the whole form + disabled: React.PropTypes.bool, + // You can use the form for inline requests, like the submit click on a button. // For the form to then not display the error on top, you need to enable this option. // It will make use of the GlobalNotification @@ -203,7 +206,8 @@ let Form = React.createClass({ if (child) { return ReactAddons.addons.cloneWithProps(child, { handleChange: this.handleChangeChild, - ref: child.props.name + ref: child.props.name, + editable: !this.props.disabled }); } }); diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index 6545007c..a47ab00e 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -86,6 +86,7 @@ let RegisterPieceForm = React.createClass({ enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing; return ( @@ -83,7 +105,9 @@ let InputCheckbox = React.createClass({ onChange={this.onChange} checked={this.state.value} defaultChecked={this.props.defaultChecked}/> - + {this.props.children} diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js index 5a72270c..acb38234 100644 --- a/js/components/ascribe_forms/property.js +++ b/js/components/ascribe_forms/property.js @@ -6,6 +6,8 @@ import ReactAddons from 'react/addons'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; +import { mergeOptions } from '../../utils/general_utils'; + let Property = React.createClass({ propTypes: { hidden: React.PropTypes.bool, @@ -167,9 +169,10 @@ let Property = React.createClass({ } }, - renderChildren() { + renderChildren(style) { return ReactAddons.Children.map(this.props.children, (child) => { return ReactAddons.addons.cloneWithProps(child, { + style, onChange: this.handleChange, onFocus: this.handleFocus, onBlur: this.handleBlur, @@ -181,25 +184,32 @@ let Property = React.createClass({ render() { let tooltip = ; - if (this.props.tooltip){ + let style = this.props.style ? mergeOptions({}, this.props.style) : {}; + + if(this.props.tooltip){ tooltip = ( {this.props.tooltip} ); } let footer = null; - if (this.props.footer){ + if(this.props.footer){ footer = (
    {this.props.footer}
    ); } + + if(!this.props.editable) { + style.cursor = 'not-allowed'; + } + return (
    + style={style}> {this.state.errors} { this.props.label} - {this.renderChildren()} + {this.renderChildren(style)} {footer}
    diff --git a/sass/ascribe_settings.scss b/sass/ascribe_settings.scss index e8a57832..ad498646 100644 --- a/sass/ascribe_settings.scss +++ b/sass/ascribe_settings.scss @@ -153,12 +153,10 @@ /* Taken from: http://www.htmllion.com/css3-checkbox.html */ .checkbox { display: inline-block; - cursor: pointer; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: normal; font-size: .9em; - color: rgba(0, 0, 0, .5); vertical-align:middle; > span { From 7e9e187c1881420fcd8e82f47d7e5a73768a1cec Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 19 Aug 2015 17:18:32 +0200 Subject: [PATCH 092/397] bug fix breadcrumbs bug fix sluice landing page bug fix sluice register_piece bug fix ownershiphistory pending --- .../slides_container.js | 2 +- .../prize/components/prize_register_piece.js | 37 +++++++++++++++++-- js/components/whitelabel/prize/prize_app.js | 4 +- js/components/whitelabel/wallet/wallet_app.js | 4 +- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 50b6eb82..f63a895e 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -165,7 +165,7 @@ let SlidesContainer = React.createClass({ let breadcrumbs = []; ReactAddons.Children.map(this.props.children, (child, i) => { - if(i >= this.state.startFrom) { + if(i >= this.state.startFrom && child.props['data-slide-title']) { breadcrumbs.push(child.props['data-slide-title']); } }); diff --git a/js/components/whitelabel/prize/components/prize_register_piece.js b/js/components/whitelabel/prize/components/prize_register_piece.js index 9e240444..1e91cca0 100644 --- a/js/components/whitelabel/prize/components/prize_register_piece.js +++ b/js/components/whitelabel/prize/components/prize_register_piece.js @@ -1,6 +1,10 @@ 'use strict'; import React from 'react'; + +import PrizeActions from '../actions/prize_actions'; +import PrizeStore from '../stores/prize_store'; + import RegisterPiece from '../../../register_piece'; import Property from '../../../ascribe_forms/property'; import InputTextAreaToggable from '../../../ascribe_forms/input_textarea_toggable'; @@ -10,8 +14,26 @@ import { getLangText } from '../../../../utils/lang_utils'; let PrizeRegisterPiece = React.createClass({ + getInitialState() { + return PrizeStore.getState(); + }, + + componentDidMount() { + PrizeStore.listen(this.onChange); + PrizeActions.fetchPrize(); + }, + + componentWillUnmount() { + PrizeStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + render() { - return ( + if (this.state.prize.active){ + return (
    - - ); + ); + } + else { + return ( +
    +
    + The prize is no longer active +
    +
    + ); + } } }); diff --git a/js/components/whitelabel/prize/prize_app.js b/js/components/whitelabel/prize/prize_app.js index dc95f478..dec859fc 100644 --- a/js/components/whitelabel/prize/prize_app.js +++ b/js/components/whitelabel/prize/prize_app.js @@ -23,9 +23,7 @@ let PrizeApp = React.createClass({ return (
    {header} -
    - -
    +
    diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js index a10593b4..2b7faa9a 100644 --- a/js/components/whitelabel/wallet/wallet_app.js +++ b/js/components/whitelabel/wallet/wallet_app.js @@ -14,7 +14,9 @@ let WalletApp = React.createClass({ render() { let header = null; - if (this.isActive('landing') || this.isActive('login') || this.isActive('signup')) { + let subdomain = window.location.host.split('.')[0]; + if ((this.isActive('landing') || this.isActive('login') || this.isActive('signup')) + && (['ikonotv', 'cyland']).indexOf(subdomain) > -1) { header = (
    ); } else { From 495f5600af8fab9ce6c01ae91deda1e75a6e48e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 17:39:25 +0200 Subject: [PATCH 093/397] implement form locking for cyland --- .../ascribe_forms/form_register_piece.js | 10 +++++++--- .../cyland_additional_data_form.js | 7 +++++-- .../cyland/cyland_register_piece.js | 19 ++++++++++++++++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index a47ab00e..3519c976 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -28,7 +28,10 @@ let RegisterPieceForm = React.createClass({ isFineUploaderEditable: React.PropTypes.bool, enableLocalHashing: React.PropTypes.bool, children: React.PropTypes.element, - onLoggedOut: React.PropTypes.func + onLoggedOut: React.PropTypes.func, + + // For this form to work with SlideContainer, we sometimes have to disable it + disabled: React.PropTypes.bool }, getDefaultProps() { @@ -84,9 +87,10 @@ let RegisterPieceForm = React.createClass({ let currentUser = this.state.currentUser; let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false; enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing; + return ( + disabled={!this.state.isUploadReady || this.props.disabled}> {this.props.submitMessage} } spinner={ diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 38eeee7f..397e5d6d 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -19,7 +19,9 @@ import { getLangText } from '../../../../../../utils/lang_utils'; let CylandAdditionalDataForm = React.createClass({ propTypes: { handleSuccess: React.PropTypes.func.isRequired, - piece: React.PropTypes.object.isRequired + piece: React.PropTypes.object.isRequired, + + disabled: React.PropTypes.bool }, getInitialState() { @@ -67,6 +69,7 @@ let CylandAdditionalDataForm = React.createClass({ if(this.props.piece && this.props.piece.id) { return ( + disabled={!this.state.isUploadReady || this.props.disabled}> {getLangText('Proceed to loan')} } 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 1c07bbd1..6e4abead 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -53,7 +53,8 @@ let CylandRegisterPiece = React.createClass({ WhitelabelStore.getState(), { selectedLicense: 0, - isFineUploaderActive: false + isFineUploaderActive: false, + step: 0 }); }, @@ -99,11 +100,16 @@ let CylandRegisterPiece = React.createClass({ PieceActions.updatePiece(response.piece); } + this.incrementStep(); + this.refs.slidesContainer.nextSlide(); }, handleAdditionalDataSuccess() { this.refreshPieceList(); + + this.incrementStep(); + this.refs.slidesContainer.nextSlide(); }, @@ -117,6 +123,15 @@ 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 + incrementStep() { + // also increase step + let newStep = this.state.step + 1; + this.setState({ + step: newStep + }); + }, + refreshPieceList() { PieceListActions.fetchPieceList( this.state.page, @@ -155,6 +170,7 @@ let CylandRegisterPiece = React.createClass({ 0} enableLocalHashing={false} headerMessage={getLangText('Submit to Cyland Archive')} submitMessage={getLangText('Submit')} @@ -182,6 +198,7 @@ let CylandRegisterPiece = React.createClass({ 1} handleSuccess={this.handleAdditionalDataSuccess} piece={this.state.piece}/> From 215f251845a6207a798b66c9d2cee014bfa2ca97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 18:09:37 +0200 Subject: [PATCH 094/397] enable overriding of editable prop for property --- js/components/ascribe_forms/form.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index eac91d42..8522825c 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -207,7 +207,10 @@ let Form = React.createClass({ return ReactAddons.addons.cloneWithProps(child, { handleChange: this.handleChangeChild, ref: child.props.name, - editable: !this.props.disabled + + // We need this in order to make editable be overridable when setting it directly + // on Property + editable: typeof child.props.editable !== 'undefined' ? child.props.editable : !this.props.disabled }); } }); From 689796b115579e29294c8555f66214f3462d3065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 18:23:04 +0200 Subject: [PATCH 095/397] slidecontainer: display lock on progress --- .../slides_container.js | 27 +++++++++++++++++-- .../cyland/cyland_register_piece.js | 6 ++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 50b6eb82..3b0c493e 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -12,11 +12,25 @@ let Navigation = Router.Navigation; let SlidesContainer = React.createClass({ propTypes: { children: React.PropTypes.arrayOf(React.PropTypes.element), - forwardProcess: React.PropTypes.bool.isRequired + forwardProcess: React.PropTypes.bool.isRequired, + + glyphiconClassNames: React.PropTypes.shape({ + pending: React.PropTypes.string, + complete: React.PropTypes.string + }) }, mixins: [State, Navigation], + getDefaultProps() { + return { + glyphiconClassNames: { + pending: 'glyphicon glyphicon-chevron-right', + complete: 'glyphicon glyphicon-lock' + } + }; + }, + getInitialState() { // handle queryParameters let queryParams = this.getQuery(); @@ -200,6 +214,15 @@ let SlidesContainer = React.createClass({
    {breadcrumbs.map((breadcrumb, i) => { + + let glyphiconClassName; + + if(i >= this.state.slideNum) { + glyphiconClassName = this.props.glyphiconClassNames.pending; + } else { + glyphiconClassName = this.props.glyphiconClassNames.completed; + } + return ( {breadcrumb} - +
    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 6e4abead..88a5c305 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -165,7 +165,11 @@ let CylandRegisterPiece = React.createClass({ return ( + forwardProcess={true} + glyphiconClassNames={{ + pending: 'glyphicon glyphicon-chevron-right', + completed: 'glyphicon glyphicon-lock' + }}>
    From 12de8139c23ef3e3abc3c115b29654e293bc6b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 19 Aug 2015 18:36:23 +0200 Subject: [PATCH 096/397] separate breadcrumb functionality into own component --- .../slides_container.js | 54 +++---------- .../slides_container_breadcrumbs.js | 78 +++++++++++++++++++ 2 files changed, 88 insertions(+), 44 deletions(-) create mode 100644 js/components/ascribe_slides_container/slides_container_breadcrumbs.js diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 3b0c493e..ea329ca2 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -6,6 +6,8 @@ import ReactAddons from 'react/addons'; import Col from 'react-bootstrap/lib/Col'; +import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs'; + let State = Router.State; let Navigation = Router.Navigation; @@ -22,15 +24,6 @@ let SlidesContainer = React.createClass({ mixins: [State, Navigation], - getDefaultProps() { - return { - glyphiconClassNames: { - pending: 'glyphicon glyphicon-chevron-right', - complete: 'glyphicon glyphicon-lock' - } - }; - }, - getInitialState() { // handle queryParameters let queryParams = this.getQuery(); @@ -206,41 +199,13 @@ let SlidesContainer = React.createClass({ // otherwise do not display the breadcrumbs at all // Also, if there is only one child, do not display the breadcrumbs if(breadcrumbs.length === numOfChildren && breadcrumbs.length > 1 && numOfChildren > 1) { - let numSlides = breadcrumbs.length; - let columnWidth = Math.floor(12 / numSlides); - return ( -
    -
    -
    - {breadcrumbs.map((breadcrumb, i) => { - - let glyphiconClassName; - - if(i >= this.state.slideNum) { - glyphiconClassName = this.props.glyphiconClassNames.pending; - } else { - glyphiconClassName = this.props.glyphiconClassNames.completed; - } - - return ( - - - - ); - })} -
    -
    -
    + ); } else { return null; @@ -251,9 +216,9 @@ let SlidesContainer = React.createClass({ // Also, a key is nice to have! renderChildren() { return ReactAddons.Children.map(this.props.children, (child, i) => { + // since the default parameter of startFrom is -1, we do not need to check // if its actually present in the url bar, as it will just not match - if(i >= this.state.startFrom) { return ReactAddons.addons.cloneWithProps(child, { className: 'ascribe-slide', @@ -266,6 +231,7 @@ let SlidesContainer = React.createClass({ // Abortions are bad mkay return null; } + }); }, diff --git a/js/components/ascribe_slides_container/slides_container_breadcrumbs.js b/js/components/ascribe_slides_container/slides_container_breadcrumbs.js new file mode 100644 index 00000000..eb3e95f1 --- /dev/null +++ b/js/components/ascribe_slides_container/slides_container_breadcrumbs.js @@ -0,0 +1,78 @@ +'use strict'; + +import React from 'react'; + +import Col from 'react-bootstrap/lib/Col'; + + +// Note: +// +// If we ever need generic breadcrumbs component, we should refactor this +let SlidesContainerBreadcrumbs = React.createClass({ + propTypes: { + breadcrumbs: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, + + slideNum: React.PropTypes.number.isRequired, + numOfSlides: React.PropTypes.number.isRequired, + + containerWidth: React.PropTypes.number.isRequired, + + glyphiconClassNames: React.PropTypes.shape({ + pending: React.PropTypes.string, + complete: React.PropTypes.string + }) + }, + + getDefaultProps() { + return { + glyphiconClassNames: { + pending: 'glyphicon glyphicon-chevron-right', + complete: 'glyphicon glyphicon-lock' + } + }; + }, + + render() { + let breadcrumbs = this.props.breadcrumbs; + let numSlides = breadcrumbs.length; + let columnWidth = Math.floor(12 / numSlides); + + return ( +
    +
    +
    + {breadcrumbs.map((breadcrumb, i) => { + + // Depending on the progress the user has already made, we display different + // glyphicons that can also be specified from the outside + let glyphiconClassName; + + if(i >= this.props.slideNum) { + glyphiconClassName = this.props.glyphiconClassNames.pending; + } else { + glyphiconClassName = this.props.glyphiconClassNames.completed; + } + + return ( + + + + ); + })} +
    +
    +
    + ); + } +}); + +export default SlidesContainerBreadcrumbs; \ No newline at end of file From 1f1a8b776129a1dea36acd20736e2d489822dfce Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 19 Aug 2015 19:12:30 +0200 Subject: [PATCH 097/397] bug fix piece loan acl bug fix piece edit acl DOUBLE MIGRATE --- .../cyland_accordion_list_item.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js b/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js index c523739d..c5a4a976 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_accordion_list/cyland_accordion_list_item.js @@ -70,6 +70,16 @@ let CylandAccordionListItem = React.createClass({ piece={this.props.content} handleSuccess={this.handleSubmitSuccess}/> + + +
    ); }, From 5d4762f9426d74970d481614e64f9e6e5f6fb835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 20 Aug 2015 11:03:00 +0200 Subject: [PATCH 098/397] fix lock functionality bug --- js/components/ascribe_forms/form.js | 2 +- js/components/ascribe_forms/form_loan.js | 6 ++++-- js/components/ascribe_forms/property.js | 7 +++++++ js/components/ascribe_slides_container/slides_container.js | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 8522825c..12e4ebae 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -210,7 +210,7 @@ let Form = React.createClass({ // We need this in order to make editable be overridable when setting it directly // on Property - editable: typeof child.props.editable !== 'undefined' ? child.props.editable : !this.props.disabled + editable: child.props.overrideForm ? child.props.editable : !this.props.disabled }); } }); diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 3fc6bd6e..201ba174 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -147,7 +147,8 @@ let LoanForm = React.createClass({ name='loanee' label={getLangText('Loanee Email')} onBlur={this.handleOnBlur} - editable={!this.props.email}> + editable={!this.props.email} + overrideForm={!this.props.email}> + editable={!this.props.gallery} + overrideForm={!this.props.gallery}> { - if(i >= this.state.startFrom) { + if(i >= this.state.startFrom && child.props['data-slide-title']) { breadcrumbs.push(child.props['data-slide-title']); } }); From 5b2ab6c1e2949a25f4e622f1f8b31f5eae59473b Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 20 Aug 2015 11:32:11 +0200 Subject: [PATCH 099/397] bug fix acls otherdata frontend MIGRATE + loaddate whitelabel --- js/components/ascribe_detail/edition.js | 2 +- js/components/ascribe_detail/further_details.js | 1 - js/components/ascribe_detail/further_details_fileuploader.js | 4 ++-- js/components/ascribe_detail/piece_container.js | 2 +- js/components/whitelabel/wallet/wallet_app.js | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 0f1477c0..89f10bde 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -165,7 +165,7 @@ let Edition = React.createClass({ title={getLangText('Further Details')} show={this.props.edition.acl.acl_edit || Object.keys(this.props.edition.extra_data).length > 0 - || this.props.edition.other_data !== null}> + || this.props.edition.other_data.length > 0}> ); return ( diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 7c5525fd..064b6a77 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -33,8 +33,8 @@ let FurtherDetailsFileuploader = React.createClass({ // // 1. there is no other_data => do not show the fileuploader at all // 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons - // 3. both other_data and editable are defined or true => show fileuploade with all action buttons - if (!this.props.editable && !this.props.otherData){ + // 3. both other_data and editable are defined or true => show fileuploader with all action buttons + if (!this.props.editable && (!this.props.otherData || this.props.otherData.length == 0)){ return null; } let otherDataIds = this.props.otherData ? this.props.otherData.map((data)=>{return data.id; }).join() : null; diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 7380ada7..1552a985 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -183,7 +183,7 @@ let PieceContainer = React.createClass({ title="Further Details" show={this.state.piece.acl.acl_edit || Object.keys(this.state.piece.extra_data).length > 0 - || this.state.piece.other_data !== null} + || this.state.piece.other_data.length > 0} defaultExpanded={true}> ); } else { - header =
    ; + header =
    ; } return (
    From ffdb4847dbd50c5b3419094d54885d4460e9668f Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 20 Aug 2015 14:01:02 +0200 Subject: [PATCH 100/397] piece bitcoin id --- .../ascribe_detail/piece_container.js | 50 +++++++++++++++++++ .../ascribe_detail/prize_piece_container.js | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 1552a985..2c36035b 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -28,6 +28,11 @@ import DeleteButton from '../ascribe_buttons/delete_button'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; +import InputTextAreaToggable from '../ascribe_forms/input_textarea_toggable'; + +import ApiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; import { mergeOptions } from '../../utils/general_utils'; import { getLangText } from '../../utils/lang_utils'; @@ -159,6 +164,7 @@ let PieceContainer = React.createClass({ subheader={
    +
    } buttons={ @@ -192,6 +198,11 @@ let PieceContainer = React.createClass({ otherData={this.state.piece.other_data} handleSuccess={this.loadPiece}/> + { + // + } ); } else { @@ -204,4 +215,43 @@ let PieceContainer = React.createClass({ } }); + +let PersonalNote = React.createClass({ + propTypes: { + piece: React.PropTypes.object, + currentUser: React.PropTypes.object + }, + showNotification(){ + let notification = new GlobalNotificationModel(getLangText('Jury note saved'), 'success'); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { + if (this.props.currentUser.username && true || false) { + return ( + + + + + +
    + + ); + } + return null; + } +}); + + export default PieceContainer; diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index b41703e7..6ce3a852 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -256,7 +256,7 @@ let PersonalNote = React.createClass({ ); } - return nul + return null; } }); From 60db83c626dfaa60d1d863114abd2211c9aead0b Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 20 Aug 2015 14:18:01 +0200 Subject: [PATCH 101/397] cyland detail subheader --- .../cyland/ascribe_detail/cyland_piece_container.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js index c8011fc7..b8877894 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js @@ -19,6 +19,7 @@ import CollapsibleParagraph from '../../../../../../components/ascribe_collapsib import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader'; import DetailProperty from '../../../../../ascribe_detail/detail_property'; +import { getLangText } from '../../../../../../utils/lang_utils'; import { mergeOptions } from '../../../../../../utils/general_utils'; @@ -75,7 +76,14 @@ let CylandPieceContainer = React.createClass({
    - }> + } + subheader={ +
    + + +
    +
    + }> ); From 5c6b753acbea0523f42628a5268326db9a3315d2 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 20 Aug 2015 15:50:30 +0200 Subject: [PATCH 102/397] piece loan history --- js/components/ascribe_detail/edition.js | 34 +++---------------- .../ascribe_detail/history_iterator.js | 33 ++++++++++++++++++ .../ascribe_detail/piece_container.js | 9 +++++ .../ascribe_detail/cyland_piece_container.js | 10 ++++++ 4 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 js/components/ascribe_detail/history_iterator.js diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 89f10bde..7b89c339 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -16,6 +16,7 @@ import PieceListActions from '../../actions/piece_list_actions'; import PieceListStore from '../../stores/piece_list_store'; import EditionListActions from '../../actions/edition_list_actions'; +import HistoryIterator from './history_iterator'; import MediaContainer from './media_container'; @@ -108,8 +109,8 @@ let Edition = React.createClass({
    -

    {this.props.edition.title}


    +

    {this.props.edition.title}


    @@ -130,21 +131,21 @@ let Edition = React.createClass({ 0}> - 0}> - 0}> - @@ -295,31 +296,6 @@ let EditionSummary = React.createClass({ }); -let EditionDetailHistoryIterator = React.createClass({ - propTypes: { - history: React.PropTypes.array - }, - - render() { - return ( -
    - {this.props.history.map((historicalEvent, i) => { - return ( - -
    { historicalEvent[1] }
    -
    - ); - })} -
    -
    - ); - } -}); - let EditionPersonalNote = React.createClass({ propTypes: { edition: React.PropTypes.object, diff --git a/js/components/ascribe_detail/history_iterator.js b/js/components/ascribe_detail/history_iterator.js new file mode 100644 index 00000000..54d11a5b --- /dev/null +++ b/js/components/ascribe_detail/history_iterator.js @@ -0,0 +1,33 @@ +'use strict'; + +import React from 'react'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +let HistoryIterator = React.createClass({ + propTypes: { + history: React.PropTypes.array + }, + + render() { + return ( +
    + {this.props.history.map((historicalEvent, i) => { + return ( + +
    { historicalEvent[1] }
    +
    + ); + })} +
    +
    + ); + } +}); + +export default HistoryIterator; diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 2c36035b..dd638366 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -19,6 +19,7 @@ import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph import FurtherDetails from './further_details'; import DetailProperty from './detail_property'; +import HistoryIterator from './history_iterator'; import AclButtonList from './../ascribe_buttons/acl_button_list'; import CreateEditionsForm from '../ascribe_forms/create_editions_form'; @@ -185,6 +186,14 @@ let PieceContainer = React.createClass({ }> {this.getCreateEditionsDialog()} + + 0}> + + +
    }> + + 0}> + + + ); From 0687f287453635211487ce7de07f4b92ddf461c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 21 Aug 2015 10:04:24 +0200 Subject: [PATCH 103/397] feature list for testing --- docs/feature_list.md | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 docs/feature_list.md diff --git a/docs/feature_list.md b/docs/feature_list.md new file mode 100644 index 00000000..568f7146 --- /dev/null +++ b/docs/feature_list.md @@ -0,0 +1,63 @@ +# Feature list + +This list specifies all features in Onion that ought to be tested before actually pushing live: + +- sign up & email activation +- login +- log out +- form input + + reset + + save + + disabled state +- form checkbox + + reset + + save + + disabled state +- create app + + refresh token +- loan contract + + upload + + download + + delete +- register work + + with edition + + without edition + + correct encoding of video upload +- fineuploader + + upload file + + upload multiple files + + delete file + + cancel upload of file +- create editions + + in piece list + + in piece detail +- all notes in edition/piece detail +- transfer & consign & loan & share & delete + + bulk + + single + + withdraw +- piece list + + filter (also check for correct filtering of opened edition tables) + + order + + search + + pagination + + expandable edition list for piece +- download coa + +## sluice +- hero landing page +- activation email +- submission (also check extra form fields) + + of existing pieces + + newly registered pieces +- rating + + in piece list + + in piece detail +- short listing (not yet implemented) +- piece list + + order by rating + +## Cyland +- hero landing page +- activation email +- submission (check states of submission (1,2,3)) From 433703a470babebc9edd6f5722524f7fea08b7a3 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 21 Aug 2015 10:54:57 +0200 Subject: [PATCH 104/397] moved terms --- js/components/ascribe_forms/form_loan.js | 3 +- .../cyland/cyland_register_piece.js | 34 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 201ba174..ceb3151f 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -28,7 +28,6 @@ let LoanForm = React.createClass({ startdate: React.PropTypes.object, enddate: React.PropTypes.object, showPersonalMessage: React.PropTypes.bool, - url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, @@ -193,7 +192,6 @@ let LoanForm = React.createClass({ placeholder={getLangText('Enter a message...')} required="required"/> - @@ -203,6 +201,7 @@ let LoanForm = React.createClass({ required/> {this.getContractCheckbox()} + {this.props.children} ); } 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 88a5c305..7b4e3fe9 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -161,7 +161,7 @@ let CylandRegisterPiece = React.createClass({ let today = new Moment(); let datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain = new Moment(); datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain.add(1000, 'years'); - + console.log(this.state.piece.id) return ( - - - - {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} - ( - {getLangText('read')} - ) - - - - + onLoggedOut={this.onLoggedOut} />
    @@ -221,7 +207,21 @@ let CylandRegisterPiece = React.createClass({ startdate={today} enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain} showPersonalMessage={false} - handleSuccess={this.handleLoanSuccess}/> + handleSuccess={this.handleLoanSuccess}> + + + + {' ' + getLangText('I agree to the Terms of Service of Cyland Archive') + ' '} + ( + {getLangText('read')} + ) + + + +
    From 30d57a943f0416139bd4a76ca8bfe82ab8beabba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 21 Aug 2015 11:01:13 +0200 Subject: [PATCH 105/397] fix lock form --- .../ascribe_detail/further_details_fileuploader.js | 2 +- js/components/ascribe_forms/form_loan.js | 4 ++-- .../ascribe_forms/cyland_additional_data_form.js | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 7c5525fd..2c9f2854 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -33,7 +33,7 @@ let FurtherDetailsFileuploader = React.createClass({ // // 1. there is no other_data => do not show the fileuploader at all // 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons - // 3. both other_data and editable are defined or true => show fileuploade with all action buttons + // 3. both other_data and editable are defined or true => show fileuploader with all action buttons if (!this.props.editable && !this.props.otherData){ return null; } diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 201ba174..1beac5f9 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -148,7 +148,7 @@ let LoanForm = React.createClass({ label={getLangText('Loanee Email')} onBlur={this.handleOnBlur} editable={!this.props.email} - overrideForm={!this.props.email}> + overrideForm={this.props.email}> + overrideForm={this.props.gallery}> + editable={!this.props.disabled}> + editable={!this.props.disabled}> @@ -115,7 +115,7 @@ let CylandAdditionalDataForm = React.createClass({ submitKey={this.submitKey} setIsUploadReady={this.setIsUploadReady} isReadyForFormSubmission={this.isReadyForFormSubmission} - editable={true} + editable={!this.props.disabled} pieceId={this.props.piece.id} otherData={this.props.piece.other_data} multiple={true}/> From 3b46dbb9f59792f32ce4f022ee329e6a74f0a499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 21 Aug 2015 11:11:31 +0200 Subject: [PATCH 106/397] add upload busy function to fineuploader --- .../ascribe_detail/further_details_fileuploader.js | 2 ++ js/components/ascribe_uploader/react_s3_fine_uploader.js | 6 ++++++ .../cyland/ascribe_forms/cyland_additional_data_form.js | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 2c9f2854..69f7bdc8 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -13,6 +13,7 @@ import { getCookie } from '../../utils/fetch_api_utils'; let FurtherDetailsFileuploader = React.createClass({ propTypes: { + uploadStarted: React.PropTypes.func, pieceId: React.PropTypes.number, otherData: React.PropTypes.arrayOf(React.PropTypes.object), setIsUploadReady: React.PropTypes.func, @@ -43,6 +44,7 @@ let FurtherDetailsFileuploader = React.createClass({ 1) { diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 71b91485..b97d568c 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -48,6 +48,12 @@ let CylandAdditionalDataForm = React.createClass({ }, + uploadStarted() { + this.setState({ + isUploadReady: false + }); + }, + setIsUploadReady(isReady) { this.setState({ isUploadReady: isReady @@ -112,6 +118,7 @@ let CylandAdditionalDataForm = React.createClass({ required="required"/> Date: Fri, 21 Aug 2015 11:29:57 +0200 Subject: [PATCH 107/397] fix locked fields --- js/components/ascribe_forms/form_loan.js | 4 ++-- js/components/ascribe_slides_container/slides_container.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 1beac5f9..e86a5387 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -148,7 +148,7 @@ let LoanForm = React.createClass({ label={getLangText('Loanee Email')} onBlur={this.handleOnBlur} editable={!this.props.email} - overrideForm={this.props.email}> + overrideForm={!!this.props.email}> + overrideForm={!!this.props.gallery}> Date: Fri, 21 Aug 2015 14:07:10 +0200 Subject: [PATCH 108/397] fix disappearing fineuploader in additional data --- .../ascribe_detail/further_details_fileuploader.js | 1 + js/components/ascribe_forms/form.js | 1 + .../wallet/components/cyland/cyland_register_piece.js | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index a6a84416..2b04a210 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -38,6 +38,7 @@ let FurtherDetailsFileuploader = React.createClass({ if (!this.props.editable && (!this.props.otherData || this.props.otherData.length === 0)) { return null; } + let otherDataIds = this.props.otherData ? this.props.otherData.map((data)=>{return data.id; }).join() : null; return ( diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 12e4ebae..54d4f197 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -106,6 +106,7 @@ let Form = React.createClass({ if ('getFormData' in this.props){ data = mergeOptionsWithDuplicates(data, this.props.getFormData()); } + return data; }, 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 7b4e3fe9..489be043 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -106,6 +106,12 @@ let CylandRegisterPiece = React.createClass({ }, 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(); @@ -161,7 +167,7 @@ let CylandRegisterPiece = React.createClass({ let today = new Moment(); let datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain = new Moment(); datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain.add(1000, 'years'); - console.log(this.state.piece.id) + return ( Date: Fri, 21 Aug 2015 15:04:38 +0200 Subject: [PATCH 109/397] public and private note in edition and piece connection in frontend --- js/components/ascribe_detail/edition.js | 35 +++++++--- js/components/ascribe_detail/note.js | 66 ++++++++++++++++++ .../ascribe_detail/piece_container.js | 68 ++++++------------- js/constants/api_urls.js | 6 +- 4 files changed, 117 insertions(+), 58 deletions(-) create mode 100644 js/components/ascribe_detail/note.js diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 7b89c339..a2156eb0 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -37,6 +37,8 @@ import DeleteButton from '../ascribe_buttons/delete_button'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; +import Note from './note'; + import ApiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; @@ -100,7 +102,12 @@ let Edition = React.createClass({ this.transitionTo('pieces'); }, + getId() { + return {'bitcoin_id': this.props.edition.bitcoin_id}; + }, + render() { + console.log(!!this.props.edition.public_note || this.props.edition.acl.acl_edit) return ( @@ -153,13 +160,25 @@ let Edition = React.createClass({ title="Notes" show={(this.state.currentUser.username && true || false) || (this.props.edition.acl.acl_edit || this.props.edition.public_note)}> - - + + + + + +
    + + ); + } + return null; + } +}); + +export default Note \ No newline at end of file diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index dd638366..97cd76c1 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -29,9 +29,7 @@ import DeleteButton from '../ascribe_buttons/delete_button'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; -import Form from '../ascribe_forms/form'; -import Property from '../ascribe_forms/property'; -import InputTextAreaToggable from '../ascribe_forms/input_textarea_toggable'; +import Note from './note'; import ApiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; @@ -146,6 +144,10 @@ let PieceContainer = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); }, + getId() { + return {'id': this.state.piece.id}; + }, + render() { if('title' in this.state.piece) { return ( @@ -193,7 +195,20 @@ let PieceContainer = React.createClass({
    - + + + - { - // - } + ); } else { @@ -224,43 +235,4 @@ let PieceContainer = React.createClass({ } }); - -let PersonalNote = React.createClass({ - propTypes: { - piece: React.PropTypes.object, - currentUser: React.PropTypes.object - }, - showNotification(){ - let notification = new GlobalNotificationModel(getLangText('Jury note saved'), 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - render() { - if (this.props.currentUser.username && true || false) { - return ( -
    - - - - -
    -
    - ); - } - return null; - } -}); - - export default PieceContainer; diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index f56879e5..8e2545e7 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -22,8 +22,10 @@ let ApiUrls = { 'editions': AppConstants.apiEndpoint + 'editions/', // this should be moved to the one below 'editions_list': AppConstants.apiEndpoint + 'pieces/${piece_id}/editions/', 'licenses': AppConstants.apiEndpoint + 'ownership/licenses/', - 'note_notes': AppConstants.apiEndpoint + 'note/notes/', - 'note_edition': AppConstants.apiEndpoint + 'note/edition_notes/', + 'note_private_edition': AppConstants.apiEndpoint + 'note/private/editions/', + 'note_private_piece': AppConstants.apiEndpoint + 'note/private/pieces/', + 'note_public_edition': AppConstants.apiEndpoint + 'note/public/editions/', + 'note_public_piece': AppConstants.apiEndpoint + 'note/public/pieces/', 'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/', 'ownership_consigns_deny': AppConstants.apiEndpoint + 'ownership/consigns/deny/', From 82cc53fdc5a31c1b3195023dba1ed2c4a7a45faa Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 21 Aug 2015 15:53:55 +0200 Subject: [PATCH 110/397] bug fix remove from collection signal --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bb267749..30c9eae9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ lib-cov *.pid *.gz *.sublime-project - +.idea spool-project.sublime-project *.sublime-workspace *.sublime-workspace From 284919f3dbaa1542c7bb3a6d9252cf36c0d102d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 21 Aug 2015 16:14:15 +0200 Subject: [PATCH 111/397] fix bug --- js/components/piece_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 14554ea0..94d2ef96 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -60,7 +60,7 @@ let PieceList = React.createClass({ PieceListStore.listen(this.onChange); EditionListStore.listen(this.onChange); - if (this.state.pieceList.length === 0){ + if (this.state.pieceList.length === 0 || this.state.page !== page){ PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy) .then(() => PieceListActions.fetchPieceRequestActions()); From ea9fb306c4359ca18e2fe8b280e5647c4943e483 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 21 Aug 2015 16:22:08 +0200 Subject: [PATCH 112/397] add request action loan to piece --- js/components/ascribe_detail/edition.js | 79 ------------------------- 1 file changed, 79 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index a2156eb0..c48b729c 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -107,7 +107,6 @@ let Edition = React.createClass({ }, render() { - console.log(!!this.props.edition.public_note || this.props.edition.acl.acl_edit) return ( @@ -315,84 +314,6 @@ let EditionSummary = React.createClass({ }); -let EditionPersonalNote = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - currentUser: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - showNotification(){ - this.props.handleSuccess(); - let notification = new GlobalNotificationModel(getLangText('Private note saved'), 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - render() { - if (this.props.currentUser.username && true || false) { - return ( -
    - - - - -
    -
    - ); - } - return null; - } -}); - -let EditionPublicEditionNote = React.createClass({ - propTypes: { - edition: React.PropTypes.object, - handleSuccess: React.PropTypes.func - }, - showNotification(){ - this.props.handleSuccess(); - let notification = new GlobalNotificationModel(getLangText('Public note saved'), 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - render() { - let isEditable = this.props.edition.acl.acl_edit; - if (isEditable || this.props.edition.public_note){ - return ( -
    - - - - -
    -
    - ); - } - return null; - } -}); - let CoaDetails = React.createClass({ propTypes: { edition: React.PropTypes.object From 33cd23d11eb7fa67d9d5736f98e1f1bb20df7a6c Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 21 Aug 2015 16:38:18 +0200 Subject: [PATCH 113/397] getlangtext --- js/components/ascribe_detail/edition.js | 9 ++++----- js/components/ascribe_detail/note.js | 4 ++-- js/components/ascribe_detail/piece_container.js | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index c48b729c..2675d804 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -25,7 +25,6 @@ import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph import Form from './../ascribe_forms/form'; import Property from './../ascribe_forms/property'; import EditionDetailProperty from './detail_property'; -import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable'; import EditionFurtherDetails from './further_details'; @@ -163,19 +162,19 @@ let Edition = React.createClass({ id={this.getId} label={getLangText('Personal note (private)')} defaultValue={this.props.edition.private_note ? this.props.edition.private_note : null} - placeholder='Enter your comments ...' + placeholder={getLangText('Enter your comments ...')} editable={true} - successMessage='Private note saved' + successMessage={getLangText('Private note saved')} url={ApiUrls.note_private_edition} currentUser={this.state.currentUser}/> diff --git a/js/components/ascribe_detail/note.js b/js/components/ascribe_detail/note.js index e41a3184..b22d9602 100644 --- a/js/components/ascribe_detail/note.js +++ b/js/components/ascribe_detail/note.js @@ -28,8 +28,8 @@ let Note = React.createClass({ return { editable: true, show: true, - placeholder: 'Enter a note', - successMessage: 'Note saved' + placeholder: getLangText('Enter a note'), + successMessage: getLangText('Note saved') }; }, diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 97cd76c1..fa17d82c 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -196,21 +196,21 @@ let PieceContainer = React.createClass({ history={this.state.piece.loan_history} /> 0 || this.state.piece.other_data.length > 0} From 8b6c5e6e0f9467ddbfd5f08ebf803ba5c5db3cbb Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 21 Aug 2015 16:39:06 +0200 Subject: [PATCH 114/397] username boolean --- js/components/ascribe_detail/note.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_detail/note.js b/js/components/ascribe_detail/note.js index b22d9602..0f32e5da 100644 --- a/js/components/ascribe_detail/note.js +++ b/js/components/ascribe_detail/note.js @@ -39,7 +39,7 @@ let Note = React.createClass({ }, render() { - if ((this.props.currentUser.username && true || false) && this.props.show) { + if (!!this.props.currentUser.username && this.props.show) { return (
    Date: Fri, 21 Aug 2015 16:49:04 +0200 Subject: [PATCH 115/397] switch between request action and acl buttons on piece detail page --- .../ascribe_detail/piece_container.js | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index fa17d82c..dc8e5569 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -26,6 +26,8 @@ import CreateEditionsForm from '../ascribe_forms/create_editions_form'; import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; import DeleteButton from '../ascribe_buttons/delete_button'; +import RequestActionForm from '../ascribe_forms/form_request_action'; + import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; @@ -148,6 +150,34 @@ let PieceContainer = React.createClass({ return {'id': this.state.piece.id}; }, + getActions(){ + if (this.state.piece.request_action && this.state.piece.request_action.length > 0) { + return ( + ); + } + else { + return ( + + + + + ); + } + }, render() { if('title' in this.state.piece) { return ( @@ -170,23 +200,7 @@ let PieceContainer = React.createClass({
    } - buttons={ - - - - - }> + buttons={this.getActions()}> {this.getCreateEditionsDialog()} Date: Mon, 24 Aug 2015 10:48:40 +0200 Subject: [PATCH 116/397] request form on piece level bug fix cyland piece endpoint bug fix otherDataUploader editable --- js/components/ascribe_detail/edition.js | 4 +- .../ascribe_detail/further_details.js | 1 + .../further_details_fileuploader.js | 1 + .../ascribe_detail/piece_container.js | 8 ++- .../ascribe_forms/form_request_action.js | 60 +++++++++++-------- js/constants/api_urls.js | 2 + 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 2675d804..9d2af633 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -242,7 +242,9 @@ let EditionSummary = React.createClass({ actions = ( ); } diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js index d206a3be..9fc5bf15 100644 --- a/js/components/ascribe_detail/further_details.js +++ b/js/components/ascribe_detail/further_details.js @@ -82,6 +82,7 @@ let FurtherDetails = React.createClass({ setIsUploadReady={this.setIsUploadReady} isReadyForFormSubmission={isReadyForFormSubmission} editable={this.props.editable} + overrideForm={true} pieceId={this.props.pieceId} otherData={this.props.otherData} multiple={true}/> diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 2b04a210..a6eea898 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -30,6 +30,7 @@ let FurtherDetailsFileuploader = React.createClass({ }, render() { + console.log(this.props) // Essentially there a three cases important to the fileuploader // // 1. there is no other_data => do not show the fileuploader at all diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index dc8e5569..bb528a56 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -151,11 +151,15 @@ let PieceContainer = React.createClass({ }, getActions(){ - if (this.state.piece.request_action && this.state.piece.request_action.length > 0) { + if (this.state.piece && + this.state.piece.request_action && + this.state.piece.request_action.length > 0) { return ( ); } else { diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index cc4ad88a..3b98a637 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -16,40 +16,49 @@ import { getLangText } from '../../utils/lang_utils.js'; let RequestActionForm = React.createClass({ propTypes: { - editions: React.PropTypes.arrayOf(React.PropTypes.object), + pieceOrEditions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]).isRequired, + requestAction: React.PropTypes.string, + requestUser: React.PropTypes.string, currentUser: React.PropTypes.object, handleSuccess: React.PropTypes.func }, + isPiece(){ + return this.props.pieceOrEditions.constructor !== Array; + }, + getUrls() { - let edition = this.props.editions[0]; let urls = {}; - - if (edition.request_action === 'consign'){ + if (this.props.requestAction === 'consign'){ urls.accept = ApiUrls.ownership_consigns_confirm; urls.deny = ApiUrls.ownership_consigns_deny; - } else if (edition.request_action === 'unconsign'){ + } else if (this.props.requestAction === 'unconsign'){ urls.accept = ApiUrls.ownership_unconsigns; urls.deny = ApiUrls.ownership_unconsigns_deny; - } else if (edition.request_action === 'loan'){ + } else if (this.props.requestAction === 'loan' && !this.isPiece()){ urls.accept = ApiUrls.ownership_loans_confirm; urls.deny = ApiUrls.ownership_loans_deny; + } else if (this.props.requestAction === 'loan' && this.isPiece()){ + urls.accept = ApiUrls.ownership_loans_pieces_confirm; + urls.deny = ApiUrls.ownership_loans_pieces_deny; } return urls; }, - getBitcoinIds(){ - return this.props.editions.map(function(edition){ - return edition.bitcoin_id; - }); - }, - - getFormData() { - return { - bitcoin_id: this.getBitcoinIds().join() - }; + getFormData(){ + if (this.isPiece()) { + return {piece_id: this.props.pieceOrEditions.id}; + } + else { + return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){ + return edition.bitcoin_id; + }).join()}; + } }, showNotification(option, action, owner) { @@ -66,8 +75,7 @@ let RequestActionForm = React.createClass({ }, getContent() { - let edition = this.props.editions[0]; - let message = edition.owner + ' ' + getLangText('requests you') + ' ' + edition.request_action + ' ' + getLangText('this edition%s', '.'); + let message = this.props.requestUser + ' ' + getLangText('requests you') + ' ' + this.props.requestAction + ' ' + getLangText('this edition%s', '.'); return ( @@ -77,14 +85,12 @@ let RequestActionForm = React.createClass({ }, getAcceptButtonForm(urls) { - let edition = this.props.editions[0]; - - if(edition.request_action === 'unconsign') { + if(this.props.requestAction === 'unconsign') { return ( ); @@ -93,7 +99,9 @@ let RequestActionForm = React.createClass({ } spinner={ @@ -100,14 +104,14 @@ let ContractForm = React.createClass({ }>
    -

    CONTRACT FORM

    +

    {getLangText('CONTRACT FORM')}

    {this.getContracts()} @@ -124,7 +128,7 @@ let ContractForm = React.createClass({ label={getLangText('Appendix')}>
    From 54ec8295883b9ce6fb89236fe75eb5828050d9a2 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 24 Aug 2015 11:35:35 +0200 Subject: [PATCH 119/397] notes in cyland --- .../ascribe_detail/cyland_piece_container.js | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js index 2da39a72..b9098e13 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_detail/cyland_piece_container.js @@ -17,10 +17,13 @@ import InputTextAreaToggable from '../../../../../../components/ascribe_forms/in import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph'; import HistoryIterator from '../../../../../ascribe_detail/history_iterator'; +import Note from '../../../../../ascribe_detail/note'; import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader'; import DetailProperty from '../../../../../ascribe_detail/detail_property'; +import ApiUrls from '../../../../../../constants/api_urls'; + import { getLangText } from '../../../../../../utils/lang_utils'; import { mergeOptions } from '../../../../../../utils/general_utils'; @@ -39,6 +42,13 @@ let CylandPieceContainer = React.createClass({ UserStore.listen(this.onChange); }, + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + componentWillUnmount() { // Every time we're leaving the piece detail page, // just reset the piece that is saved in the piece store @@ -49,13 +59,6 @@ let CylandPieceContainer = React.createClass({ UserStore.unlisten(this.onChange); }, - componentWillReceiveProps(nextProps) { - if(this.props.params.pieceId !== nextProps.params.pieceId) { - PieceActions.updatePiece({}); - PieceActions.fetchOne(nextProps.params.pieceId); - } - }, - onChange(state) { this.setState(state); }, @@ -64,6 +67,11 @@ let CylandPieceContainer = React.createClass({ PieceActions.fetchOne(this.props.params.pieceId); }, + getId() { + return {'id': this.state.piece.id}; + }, + + render() { if('title' in this.state.piece) { return ( @@ -93,7 +101,20 @@ let CylandPieceContainer = React.createClass({ - + + + ); From 411b7cb010939277ae40a4598162dc701e298507 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 24 Aug 2015 12:11:07 +0200 Subject: [PATCH 120/397] increase otherdata limit to 50MB --- js/components/ascribe_detail/further_details_fileuploader.js | 4 ++-- js/components/settings_container.js | 2 +- js/utils/lang_utils.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js index 8c1023ba..fa1df933 100644 --- a/js/components/ascribe_detail/further_details_fileuploader.js +++ b/js/components/ascribe_detail/further_details_fileuploader.js @@ -43,7 +43,7 @@ let FurtherDetailsFileuploader = React.createClass({ return ( + label="Additional files (max. 50MB per file)"> Date: Mon, 24 Aug 2015 12:20:54 +0200 Subject: [PATCH 121/397] Merge remote-tracking branch 'remotes/origin/master' into AD-661-due-1208-implement-jury-rating-an Conflicts: ownership/test/test_api.py piece/models.py --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index f97308ab..fa5f855e 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -527,7 +527,7 @@ var ReactS3FineUploader = React.createClass({ }, handleDeleteFile(fileId) { - // In some instances (when the file was already uploaded and is just displayed to the user + // In some instances (when the file was already uploaded and is just displayed to the user // - for example in the loan contract or additional files dialog) // fineuploader does not register an id on the file (we do, don't be confused by this!). // Since you can only delete a file by its id, we have to implement this method ourselves From c14ab4dcd438c367552a8a684a595b51259cc5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 24 Aug 2015 13:12:59 +0200 Subject: [PATCH 122/397] fix fineuploader notification bug --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index f97308ab..820cbafb 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -430,7 +430,7 @@ var ReactS3FineUploader = React.createClass({ this.state.uploader.cancelAll(); let fileSizeInMegaBytes = this.props.validation.sizeLimit / 1000000; - let notification = new GlobalNotificationModel(getLangText('Your file is bigger than %d MB', fileSizeInMegaBytes), 'danger', 5000); + let notification = new GlobalNotificationModel(getLangText('Your file is bigger than ' + fileSizeInMegaBytes + 'MB.'), 'danger', 5000); GlobalNotificationActions.appendGlobalNotification(notification); } }, From f54d7bb85c5670c1cb681bda73d62f41a9a0bf17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 24 Aug 2015 13:57:02 +0200 Subject: [PATCH 123/397] fix validation method --- .../react_s3_fine_uploader.js | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 9d66f2e4..a19a2cef 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -229,7 +229,6 @@ var ReactS3FineUploader = React.createClass({ onDeleteComplete: this.onDeleteComplete, onSessionRequestComplete: this.onSessionRequestComplete, onError: this.onError, - onValidate: this.onValidate, onUploadChunk: this.onUploadChunk, onUploadChunkSuccess: this.onUploadChunkSuccess } @@ -425,13 +424,17 @@ var ReactS3FineUploader = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); }, - onValidate(data) { - if(data.size > this.props.validation.sizeLimit) { - this.state.uploader.cancelAll(); + isFileValid(file) { + if(file.size > this.props.validation.sizeLimit) { let fileSizeInMegaBytes = this.props.validation.sizeLimit / 1000000; - let notification = new GlobalNotificationModel(getLangText('Your file is bigger than ' + fileSizeInMegaBytes + 'MB.'), 'danger', 5000); + + let notification = new GlobalNotificationModel(getLangText('A file you submitted is bigger than ' + fileSizeInMegaBytes + 'MB.'), 'danger', 5000); GlobalNotificationActions.appendGlobalNotification(notification); + + return false; + } else { + return true; } }, @@ -581,8 +584,18 @@ var ReactS3FineUploader = React.createClass({ return; } + // validate each submitted file if it fits the file size + let validFiles = []; + for(let i = 0; i < files.length; i++) { + if(this.isFileValid(files[i])) { + validFiles.push(files[i]); + } + } + // override standard files list with only valid files + files = validFiles; + // Call this method to signal the outside component that an upload is in progress - if(this.props.uploadStarted && typeof this.props.uploadStarted === 'function') { + if(this.props.uploadStarted && typeof this.props.uploadStarted === 'function' && files.length > 0) { this.props.uploadStarted(); } From 18634ffe503701bac3ee502958d85f53327f1bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 24 Aug 2015 14:16:13 +0200 Subject: [PATCH 124/397] fix additional files button bug --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 6 ++++-- .../cyland/ascribe_forms/cyland_additional_data_form.js | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index a19a2cef..8ecaf40b 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -709,8 +709,10 @@ var ReactS3FineUploader = React.createClass({ // if we're not hashing the files locally, we're just going to hand them over to fineuploader // to upload them to the server } else { - this.state.uploader.addFiles(files); - this.synchronizeFileLists(files); + if(files.length > 0) { + this.state.uploader.addFiles(files); + this.synchronizeFileLists(files); + } } }, diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index c8dd7f2c..f7946be5 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -61,10 +61,9 @@ let CylandAdditionalDataForm = React.createClass({ }, isReadyForFormSubmission(files) { - let uploadedFiles = files.filter((file) => file.status === 'upload successful'); let uploadingFiles = files.filter((file) => file.status === 'submitting'); - if (uploadedFiles.length > 0 && uploadingFiles.length === 0) { + if (uploadingFiles.length === 0) { return true; } else { return false; From 70c39794b473d91e5138f51d2e00e1b845dcd3e1 Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 24 Aug 2015 15:33:36 +0200 Subject: [PATCH 125/397] sluice judge + average WIP --- .../prize/actions/prize_rating_actions.js | 7 ++- .../ascribe_detail/prize_piece_container.js | 58 +++++++++++++++---- .../prize/constants/prize_api_urls.js | 1 + .../prize/fetchers/prize_rating_fetcher.js | 6 +- .../prize/stores/prize_rating_store.js | 10 +++- 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/actions/prize_rating_actions.js index e36023a0..73569875 100644 --- a/js/components/whitelabel/prize/actions/prize_rating_actions.js +++ b/js/components/whitelabel/prize/actions/prize_rating_actions.js @@ -9,16 +9,17 @@ class PrizeRatingActions { constructor() { this.generateActions( 'updatePrizeRatings', + 'updatePrizeRatingAverage', 'updatePrizeRating' ); } - fetch() { + fetchAverage(pieceId) { return Q.Promise((resolve, reject) => { PrizeRatingFetcher - .fetch() + .fetchAverage(pieceId) .then((res) => { - this.actions.updatePrizeRatings(res.ratings); + this.actions.updatePrizeRatingAverage(res.data); resolve(res); }) .catch((err) => { diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index fd25190f..f49d430d 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -17,6 +17,7 @@ import PrizeRatingStore from '../../stores/prize_rating_store'; import UserStore from '../../../../../stores/user_store'; import Piece from '../../../../../components/ascribe_detail/piece'; +import Note from '../../../../../components/ascribe_detail/note'; import AppConstants from '../../../../../constants/application_constants'; @@ -53,6 +54,15 @@ let PieceContainer = React.createClass({ UserStore.listen(this.onChange); }, + // This is done to update the container when the user clicks on the prev or next + // button to update the URL parameter (and therefore to switch pieces) + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + componentWillUnmount() { // Every time we're leaving the piece detail page, // just reset the piece that is saved in the piece store @@ -63,14 +73,6 @@ let PieceContainer = React.createClass({ UserStore.unlisten(this.onChange); }, - // This is done to update the container when the user clicks on the prev or next - // button to update the URL parameter (and therefore to switch pieces) - componentWillReceiveProps(nextProps) { - if(this.props.params.pieceId !== nextProps.params.pieceId) { - PieceActions.updatePiece({}); - PieceActions.fetchOne(nextProps.params.pieceId); - } - }, onChange(state) { this.setState(state); @@ -167,6 +169,7 @@ let PrizePieceRatings = React.createClass({ componentDidMount() { PrizeRatingStore.listen(this.onChange); PrizeRatingActions.fetchOne(this.props.piece.id); + PrizeRatingActions.fetchAverage(this.props.piece.id); PieceListStore.listen(this.onChange); }, @@ -204,8 +207,35 @@ let PrizePieceRatings = React.createClass({ ); }, + getId() { + return {'piece_id': this.props.piece.id}; + }, + render(){ - if (this.props.currentUser && this.props.currentUser.is_jury) { + if (this.props.currentUser && this.props.currentUser.is_judge && this.state.average) { + return ( + +
    + +
    +
    + {this.state.ratings.map((item) => { + return item.user; + })} +
    +
    ); + } + else if (this.props.currentUser && this.props.currentUser.is_jury) { return (
    - ); } diff --git a/js/components/whitelabel/prize/constants/prize_api_urls.js b/js/components/whitelabel/prize/constants/prize_api_urls.js index 63eb71e7..880a707b 100644 --- a/js/components/whitelabel/prize/constants/prize_api_urls.js +++ b/js/components/whitelabel/prize/constants/prize_api_urls.js @@ -17,6 +17,7 @@ function getPrizeApiUrls(subdomain) { 'jury_resend': AppPrizeConstants.prizeApiEndpoint + subdomain + '/jury/${email}/resend/', 'ratings': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/', 'rating': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/', + 'rating_average': AppPrizeConstants.prizeApiEndpoint + subdomain + '/ratings/${piece_id}/average/', 'notes': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/', 'note': AppPrizeConstants.prizeApiEndpoint + subdomain + '/notes/${piece_id}/' diff --git a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js index b7af8845..eae4f53a 100644 --- a/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js +++ b/js/components/whitelabel/prize/fetchers/prize_rating_fetcher.js @@ -4,8 +4,8 @@ import requests from '../../../../utils/requests'; let PrizeRatingFetcher = { - fetch() { - return requests.get('rating'); + fetchAverage(pieceId) { + return requests.get('rating_average', {'piece_id': pieceId}); }, fetchOne(pieceId) { @@ -13,7 +13,7 @@ let PrizeRatingFetcher = { }, rate(pieceId, rating) { - return requests.post('ratings', {body: {'piece_id': pieceId, 'value': rating}}); + return requests.post('ratings', {body: {'piece_id': pieceId, 'note': rating}}); } }; diff --git a/js/components/whitelabel/prize/stores/prize_rating_store.js b/js/components/whitelabel/prize/stores/prize_rating_store.js index 4a31501c..9b7a2126 100644 --- a/js/components/whitelabel/prize/stores/prize_rating_store.js +++ b/js/components/whitelabel/prize/stores/prize_rating_store.js @@ -8,16 +8,22 @@ class PrizeRatingStore { constructor() { this.ratings = []; this.currentRating = null; + this.average = null; this.bindActions(PrizeRatingActions); } - onUpdatePrizeRatings( ratings ) { + onUpdatePrizeRatings(ratings) { this.ratings = ratings; } - onUpdatePrizeRating( rating ) { + onUpdatePrizeRating(rating) { this.currentRating = parseInt(rating, 10); } + + onUpdatePrizeRatingAverage(data) { + this.average = data.average; + this.ratings = data.ratings; + } } export default alt.createStore(PrizeRatingStore, 'PrizeRatingStore'); \ No newline at end of file From 5688bde3c70e514104f021af18934b9ddebbd8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 24 Aug 2015 16:13:37 +0200 Subject: [PATCH 126/397] update readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6fae0011..270c4a5f 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,11 @@ gulp serve Additionally, to work on the white labeling functionality, you need to edit your `/etc/hosts` file and add: ``` -127.0.0.1 localhost.com -127.0.0.1 cc.localhost.com +127.0.0.1 localhost.com +127.0.0.1 cc.localhost.com +127.0.0.1 cyland.localhost.com +127.0.0.1 ikonotv.localhost.com +127.0.0.1 sluice.localhost.com ``` From 15bcd4ba14745764562f10c11a8e15d21aa62afa Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 25 Aug 2015 10:47:38 +0200 Subject: [PATCH 127/397] average rating cyland bug fix --- .../accordion_list_item_prize.js | 19 ++++- .../ascribe_detail/prize_piece_container.js | 81 ++++++++----------- .../cyland_additional_data_form.js | 2 + .../cyland/cyland_register_piece.js | 9 +++ .../wallet/constants/wallet_api_urls.js | 3 +- sass/main.scss | 11 --- sass/whitelabel/prize/index.scss | 1 + sass/whitelabel/prize/rating.scss | 34 ++++++++ 8 files changed, 96 insertions(+), 64 deletions(-) create mode 100644 sass/whitelabel/prize/rating.scss diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index bf6301f0..8789f641 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -65,17 +65,28 @@ let AccordionListItemPrize = React.createClass({ getPrizeButtons() { if (this.state.currentUser && this.state.currentUser.is_jury){ - if (this.props.content.ratings && this.props.content.ratings.rating){ + if (this.props.content.ratings && + (this.props.content.ratings.rating || this.props.content.ratings.average)){ // jury and rating available - let rating = parseInt(this.props.content.ratings.rating, 10); + let rating = null, + caption = null; + if (this.props.content.ratings.rating){ + rating = parseInt(this.props.content.ratings.rating, 10); + caption = 'Your rating'; + } + else if (this.props.content.ratings.average){ + rating = this.props.content.ratings.average; + caption = 'Average (' + this.props.content.ratings.ratings.length + ' ratings)'; + } + return (
    diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index f49d430d..33cd411a 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -59,6 +59,7 @@ let PieceContainer = React.createClass({ componentWillReceiveProps(nextProps) { if(this.props.params.pieceId !== nextProps.params.pieceId) { PieceActions.updatePiece({}); + console.log('update') PieceActions.fetchOne(nextProps.params.pieceId); } }, @@ -218,19 +219,40 @@ let PrizePieceRatings = React.createClass({ title="Average Rating" show={true} defaultExpanded={true}> -
    - +
    +

    - {this.state.ratings.map((item) => { - return item.user; + {this.state.ratings.map((item, i) => { + let note = item.note ? +
    + note: {item.note} +
    : null; + return ( +
    +
    + + + + {item.user} + {note} +
    +
    + ); })}
    ); @@ -267,43 +289,6 @@ let PrizePieceRatings = React.createClass({ } }); -let PersonalNote = React.createClass({ - propTypes: { - piece: React.PropTypes.object, - currentUser: React.PropTypes.object - }, - showNotification(){ - let notification = new GlobalNotificationModel(getLangText('Jury note saved'), 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - render() { - if (this.props.currentUser && this.props.currentUser.username) { - return ( -
    - - - - -
    -
    - ); - } - return null; - } -}); - let PrizePieceDetails = React.createClass({ propTypes: { diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index f7946be5..9d4ae455 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -105,6 +105,7 @@ let CylandAdditionalDataForm = React.createClass({ @@ -115,6 +116,7 @@ let CylandAdditionalDataForm = React.createClass({ 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 8a092bdf..55620f89 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -77,6 +77,15 @@ let CylandRegisterPiece = React.createClass({ } }, + // This is done to update the container when the user clicks on the prev or next + // button to update the URL parameter (and therefore to switch pieces) + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + componentWillUnmount() { PieceListStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index 56b6121e..c1b101a1 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -7,7 +7,8 @@ function getWalletApiUrls(subdomain) { if (subdomain === 'cyland'){ return { 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/', - 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' + 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/', + 'piece_extradata': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/extradata/' }; } else if (subdomain === 'ikonotv'){ diff --git a/sass/main.scss b/sass/main.scss index fed435f0..a6ab05b3 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -403,17 +403,6 @@ hr { } } -.rating-container .rating-stars { - width: 25px; - color: #02b6a3; -} -#list-rating > a > span > span > .rating-container .rating-stars{ - color: #000; -} - -.react-rating-caption { - font-size: 1em; -} .disable-select { -webkit-user-select: none; diff --git a/sass/whitelabel/prize/index.scss b/sass/whitelabel/prize/index.scss index cc25b7ec..65c4d0c7 100644 --- a/sass/whitelabel/prize/index.scss +++ b/sass/whitelabel/prize/index.scss @@ -1,4 +1,5 @@ @import 'landing'; +@import 'rating'; .ascribe-prize-app { border-radius: 0; diff --git a/sass/whitelabel/prize/rating.scss b/sass/whitelabel/prize/rating.scss new file mode 100644 index 00000000..8ea7c8ba --- /dev/null +++ b/sass/whitelabel/prize/rating.scss @@ -0,0 +1,34 @@ + +.rating-container .rating-stars { + width: 25px; + color: #02b6a3; +} + +#list-rating { + > a > span > span > .rating-container .rating-stars { + color: #000; + } + > span > span > span > .rating-container .rating-stars { + color: #000; + } + > span > span > .rating-container .rating-stars { + color: #000; + } +} +.react-rating-caption { + font-size: 1em; +} + +.rating-list { + margin-left: 1.5em; + font-size: 0.9em; + margin-bottom: 0.3em; + color: #333; +} + +.rating-note { + color: #666; + font-style: italic; + padding: 0.2em; + +} \ No newline at end of file From 2d10887e1b13467d797852019a630844f3381179 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 25 Aug 2015 10:49:49 +0200 Subject: [PATCH 128/397] reset cyland additional data form --- .../cyland/ascribe_forms/cyland_additional_data_form.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index 9d4ae455..f7946be5 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -105,7 +105,6 @@ let CylandAdditionalDataForm = React.createClass({ @@ -116,7 +115,6 @@ let CylandAdditionalDataForm = React.createClass({ From a07b4cc35ce04eb8581b37c368e4d1e1fd8fd6fa Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 25 Aug 2015 11:11:22 +0200 Subject: [PATCH 129/397] reset cyland register form "no votes yet" for judge --- .../ascribe_accordion_list/accordion_list_item_prize.js | 7 +++++++ .../wallet/components/cyland/cyland_register_piece.js | 9 --------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 8789f641..9270efe1 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -94,6 +94,13 @@ let AccordionListItemPrize = React.createClass({
    ); } else { + if (this.state.currentUser.is_judge){ + return ( +
    + No votes yet +
    + ); + } // jury and no rating yet return (
    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 55620f89..8a092bdf 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -77,15 +77,6 @@ let CylandRegisterPiece = React.createClass({ } }, - // This is done to update the container when the user clicks on the prev or next - // button to update the URL parameter (and therefore to switch pieces) - componentWillReceiveProps(nextProps) { - if(this.props.params.pieceId !== nextProps.params.pieceId) { - PieceActions.updatePiece({}); - PieceActions.fetchOne(nextProps.params.pieceId); - } - }, - componentWillUnmount() { PieceListStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); From 5fcee39ed3195243b18b411f71680669976d526a Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 25 Aug 2015 15:19:10 +0200 Subject: [PATCH 130/397] shortlisting enabled up till loan request --- js/components/ascribe_detail/edition.js | 8 +- .../prize/actions/prize_rating_actions.js | 14 +++ .../accordion_list_item_prize.js | 54 ++++++--- .../ascribe_detail/prize_piece_container.js | 109 ++++++++++++------ .../prize/constants/prize_api_urls.js | 1 + .../prize/fetchers/prize_rating_fetcher.js | 4 + .../ascribe_detail/cyland_piece_container.js | 7 +- sass/ascribe_settings.scss | 15 ++- 8 files changed, 147 insertions(+), 65 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 9d2af633..4f4d424c 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -101,10 +101,6 @@ let Edition = React.createClass({ this.transitionTo('pieces'); }, - getId() { - return {'bitcoin_id': this.props.edition.bitcoin_id}; - }, - render() { return ( @@ -159,7 +155,7 @@ let Edition = React.createClass({ show={(this.state.currentUser.username && true || false) || (this.props.edition.acl.acl_edit || this.props.edition.public_note)}> {return {'bitcoin_id': this.props.edition.bitcoin_id}; }} label={getLangText('Personal note (private)')} defaultValue={this.props.edition.private_note ? this.props.edition.private_note : null} placeholder={getLangText('Enter your comments ...')} @@ -168,7 +164,7 @@ let Edition = React.createClass({ url={ApiUrls.note_private_edition} currentUser={this.state.currentUser}/> {return {'bitcoin_id': this.props.edition.bitcoin_id}; }} label={getLangText('Edition note (public)')} defaultValue={this.props.edition.public_note ? this.props.edition.public_note : null} placeholder={getLangText('Enter your comments ...')} diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/actions/prize_rating_actions.js index 73569875..40e24858 100644 --- a/js/components/whitelabel/prize/actions/prize_rating_actions.js +++ b/js/components/whitelabel/prize/actions/prize_rating_actions.js @@ -57,6 +57,20 @@ class PrizeRatingActions { }); } + toggleShortlist(pieceId) { + return Q.Promise((resolve, reject) => { + PrizeRatingFetcher + .select(pieceId) + .then((res) => { + this.actions.updatePrizeRating(res.rating.rating); + resolve(res); + }) + .catch((err) => { + reject(err); + }); + }); + } + updateRating(rating) { this.actions.updatePrizeRating(rating); } diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 9270efe1..0ca54d93 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -4,13 +4,17 @@ import React from 'react'; import Router from 'react-router'; import StarRating from 'react-star-rating'; -import AccordionListItemPiece from '../../../../ascribe_accordion_list/accordion_list_item_piece'; - import PieceListActions from '../../../../../actions/piece_list_actions'; import PieceListStore from '../../../../../stores/piece_list_store'; +import PrizeRatingActions from '../../actions/prize_rating_actions'; + import UserStore from '../../../../../stores/user_store'; +import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; + +import AccordionListItemPiece from '../../../../ascribe_accordion_list/accordion_list_item_piece'; + import GlobalNotificationModel from '../../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; @@ -76,7 +80,7 @@ let AccordionListItemPrize = React.createClass({ } else if (this.props.content.ratings.average){ rating = this.props.content.ratings.average; - caption = 'Average (' + this.props.content.ratings.ratings.length + ' ratings)'; + caption = 'Average of ' + this.props.content.ratings.ratings.length + ' rating(s)'; } return ( @@ -97,7 +101,7 @@ let AccordionListItemPrize = React.createClass({ if (this.state.currentUser.is_judge){ return (
    - No votes yet + Not rated
    ); } @@ -126,22 +130,42 @@ let AccordionListItemPrize = React.createClass({ ); }, + getPrizeBadge(){ + if (this.state.currentUser && this.state.currentUser.is_judge) { + return ( + + { + PrizeRatingActions.toggleShortlist(this.props.content.id).then( + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy) + ); }}/> + + ); + } + return null; + }, + render() { let artistName = this.state.currentUser.is_jury ?
    } - buttons={this.getPrizeButtons()}> - {this.props.children} - +
    + + {this.props.content.date_created.split('-')[0]} +
    } + buttons={this.getPrizeButtons()} + badge={this.getPrizeBadge()}> + {this.props.children} + +
    ); } }); diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 33cd411a..5d990392 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -26,6 +26,8 @@ import Property from '../../../../../components/ascribe_forms/property'; import InputTextAreaToggable from '../../../../../components/ascribe_forms/input_textarea_toggable'; import CollapsibleParagraph from '../../../../../components/ascribe_collapsible/collapsible_paragraph'; +import InputCheckbox from '../../../../ascribe_forms/input_checkbox'; + import GlobalNotificationModel from '../../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../../actions/global_notification_actions'; @@ -81,11 +83,13 @@ let PieceContainer = React.createClass({ loadPiece() { PieceActions.fetchOne(this.props.params.pieceId); + this.setState(this.state); }, render() { if('title' in this.state.piece) { - let artistName = this.state.currentUser.is_jury ? + let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) || + (this.state.currentUser.is_judge && !this.state.piece.selected )) ?
    diff --git a/js/components/nav_routes_links.js b/js/components/nav_routes_links.js new file mode 100644 index 00000000..0e03e0fe --- /dev/null +++ b/js/components/nav_routes_links.js @@ -0,0 +1,65 @@ +'use strict'; + +import React from 'react'; + +import Nav from 'react-bootstrap/lib/Nav'; +import DropdownButton from 'react-bootstrap/lib/DropdownButton'; +import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink'; +import NavItemLink from 'react-router-bootstrap/lib/NavItemLink'; + +import { sanitizeList } from '../utils/general_utils'; + + +let NavRoutesLinks = React.createClass({ + propTypes: { + routes: React.PropTypes.element + }, + + extractLinksFromRoutes(node, i) { + + node = node.props; + + let links = node.children.map((child, j) => { + + // check if this a candidate for a link generation + if(child.props.headerTitle && typeof child.props.headerTitle === 'string') { + + // also check if it is a candidate for generating a dropdown menu + if(child.props.children && child.props.children.length > 0) { + return ( + + {this.extractLinksFromRoutes(child, i++)} + + ); + } else if(i === 1) { + // if the node's child is actually a node of level one (a child of a node), we're + // returning a DropdownButton matching MenuItemLink + return ( + {child.props.headerTitle} + ); + } else if(i === 0) { + return ( + {child.props.headerTitle} + ); + } else { + return null; + } + } else { + return null; + } + }); + + // remove all nulls from the list of generated links + return sanitizeList(links); + }, + + render() { + return ( + + ); + } +}); + +export default NavRoutesLinks; \ 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 index 33cc576c..814b0f01 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js @@ -55,14 +55,14 @@ let IkonotvRegisterPiece = React.createClass({ render() { - if (this.state.currentUser && + /* if (this.state.currentUser && this.state.whitelabel && this.state.whitelabel.user && this.state.currentUser.email === this.state.whitelabel.user){ return ( ); - } + } */ return (
    + ); + } +}); + +export default IkonotvRequestLoan; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js index f31ec429..06bac15f 100644 --- a/js/components/whitelabel/wallet/wallet_app.js +++ b/js/components/whitelabel/wallet/wallet_app.js @@ -7,21 +7,26 @@ import Footer from '../../footer'; import GlobalNotification from '../../global_notification'; +import getRoutes from './wallet_routes'; + let RouteHandler = Router.RouteHandler; let WalletApp = React.createClass({ mixins: [Router.State], render() { - let header = null; let subdomain = window.location.host.split('.')[0]; + let ROUTES = getRoutes(null, subdomain); + + let header = null; if ((this.isActive('landing') || this.isActive('login') || this.isActive('signup')) && (['ikonotv', 'cyland']).indexOf(subdomain) > -1) { header = (
    ); } else { - header =
    ; + header =
    ; } + return (
    {header} diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 435b1695..941c5a9c 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 IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece'; +import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan'; import CCRegisterPiece from './components/cc/cc_register_piece'; @@ -69,6 +70,7 @@ let ROUTES = { + diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 70c94a97..15b0e85f 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -26,6 +26,23 @@ export function sanitize(obj, filterFn) { return obj; } +/** + * Removes all falsy values (undefined, null, false, ...) from a list/array + * @param {array} l the array to sanitize + * @return {array} the sanitized array + */ +export function sanitizeList(l) { + let sanitizedList = []; + + for(let i = 0; i < l.length; i++) { + if(l[i]) { + sanitizedList.push(l[i]); + } + } + + return sanitizedList; +} + /** * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... */ diff --git a/sass/main.scss b/sass/main.scss index fed435f0..229c04c8 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -100,10 +100,9 @@ hr { } .img-brand { - padding: 0; - height: 45px; - margin: 5px 0 5px 0; + height: 60px; } + .truncate { white-space: nowrap; width: 4em; From b2fed6426fa4389fe78e4c2f1cac476a526b899b Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 26 Aug 2015 09:50:38 +0200 Subject: [PATCH 132/397] loan request up till accept --- js/actions/ownership_actions.js | 39 ++++++++ js/components/ascribe_buttons/acl_button.js | 22 ++++- js/components/ascribe_forms/form_loan.js | 19 ++-- .../ascribe_forms/form_loan_request_answer.js | 88 +++++++++++++++++++ .../ascribe_forms/form_request_action.js | 12 +++ .../ascribe_detail/prize_piece_container.js | 65 ++++++++++++-- js/constants/api_urls.js | 1 + js/fetchers/ownership_fetcher.js | 5 +- js/stores/ownership_store.js | 35 ++++++++ js/utils/form_utils.js | 4 +- 10 files changed, 274 insertions(+), 16 deletions(-) create mode 100644 js/actions/ownership_actions.js create mode 100644 js/components/ascribe_forms/form_loan_request_answer.js create mode 100644 js/stores/ownership_store.js diff --git a/js/actions/ownership_actions.js b/js/actions/ownership_actions.js new file mode 100644 index 00000000..5bd04322 --- /dev/null +++ b/js/actions/ownership_actions.js @@ -0,0 +1,39 @@ +'use strict'; + +import alt from '../alt'; +import OwnershipFetcher from '../fetchers/ownership_fetcher'; + + +class OwnershipActions { + constructor() { + this.generateActions( + 'updateLoanPieceRequestList', + 'updateLoanPieceRequest' + ); + } + + fetchLoanRequestList() { + OwnershipFetcher.fetchLoanPieceRequestList() + .then((data) => { + this.actions.updateLoanPieceRequestList(data.loan_requests); + }) + .catch((err) => { + console.logGlobal(err); + this.actions.updateLoanPieceRequestList(null); + }); + } + + fetchLoanRequest(pieceId) { + OwnershipFetcher.fetchLoanPieceRequestList() + .then((data) => { + let loanRequests = data.loan_requests; + this.actions.updateLoanPieceRequest({loanRequests, pieceId}); + }) + .catch((err) => { + console.logGlobal(err); + this.actions.flushLoanPieceRequest(); + }); + } +} + +export default alt.createActions(OwnershipActions); diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index 2f5bb7b0..128ff5fb 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -6,6 +6,7 @@ import ConsignForm from '../ascribe_forms/form_consign'; import UnConsignForm from '../ascribe_forms/form_unconsign'; import TransferForm from '../ascribe_forms/form_transfer'; import LoanForm from '../ascribe_forms/form_loan'; +import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer'; import ShareForm from '../ascribe_forms/form_share_email'; import ModalWrapper from '../ascribe_modal/modal_wrapper'; import AppConstants from '../../constants/application_constants'; @@ -27,6 +28,8 @@ let AclButton = React.createClass({ React.PropTypes.array ]).isRequired, currentUser: React.PropTypes.object, + buttonAcceptName: React.PropTypes.string, + buttonAcceptClassName: React.PropTypes.string, handleSuccess: React.PropTypes.func.isRequired, className: React.PropTypes.string }, @@ -89,6 +92,18 @@ let AclButton = React.createClass({ handleSuccess: this.showNotification }; } + else if (this.props.action === 'acl_loan_request'){ + return { + title: getLangText('Loan artwork'), + tooltip: getLangText('Loan your artwork for a limited period of time'), + form: ( + ), + handleSuccess: this.showNotification + }; + } else if (this.props.action === 'acl_share'){ return { title: getLangText('Share artwork'), @@ -140,17 +155,20 @@ let AclButton = React.createClass({ // Removes the acl_ prefix and converts to upper case sanitizeAction() { + if (this.props.buttonAcceptName) { + return this.props.buttonAcceptName; + } return this.props.action.split('acl_')[1].toUpperCase(); }, render() { let shouldDisplay = this.props.availableAcls[this.props.action]; let aclProps = this.actionProperties(); - + let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : ''; return ( + } diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index f907239f..07c4b77c 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -28,6 +28,9 @@ let LoanForm = React.createClass({ startdate: React.PropTypes.object, enddate: React.PropTypes.object, showPersonalMessage: React.PropTypes.bool, + showEndDate: React.PropTypes.bool, + showStartDate: React.PropTypes.bool, + showPassword: React.PropTypes.bool, url: React.PropTypes.string, id: React.PropTypes.object, message: React.PropTypes.string, @@ -37,7 +40,10 @@ let LoanForm = React.createClass({ getDefaultProps() { return { loanHeading: '', - showPersonalMessage: true + showPersonalMessage: true, + showEndDate: false, + showStartDate: false, + showPassword: true }; }, @@ -155,7 +161,7 @@ let LoanForm = React.createClass({ required/> @@ -167,7 +173,7 @@ let LoanForm = React.createClass({
    } @@ -169,7 +189,8 @@ let PrizePieceRatings = React.createClass({ getInitialState() { return mergeOptions( PieceListStore.getState(), - PrizeRatingStore.getState() + PrizeRatingStore.getState(), + WhitelabelStore.getState() ); }, @@ -178,6 +199,7 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.fetchOne(this.props.piece.id); PrizeRatingActions.fetchAverage(this.props.piece.id); PieceListStore.listen(this.onChange); + WhitelabelStore.listen(this.onChange); }, componentWillUnmount() { @@ -188,6 +210,7 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.updateRating({}); PrizeRatingStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); }, // The StarRating component does not have a property that lets us set @@ -213,6 +236,39 @@ let PrizePieceRatings = React.createClass({ ); }, + getLoanButton(){ + let today = new Moment(); + let endDate = new Moment(); + endDate.add(6, 'months'); + return ( + + SEND LOAN REQUEST + + } + handleSuccess={this.handleLoanRequestSuccess} + title='REQUEST LOAN'> + + ); + }, + + handleLoanRequestSuccess(){}, + refreshPieceData() { PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc, this.state.filterBy); @@ -241,10 +297,7 @@ let PrizePieceRatings = React.createClass({ - {this.props.piece.selected ? - : null} + {this.props.piece.selected ? this.getLoanButton() : null}

    diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index a1ed9a1d..ac495f43 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -32,6 +32,7 @@ let ApiUrls = { 'ownership_loans_pieces': AppConstants.apiEndpoint + 'ownership/loans/pieces/', 'ownership_loans_pieces_confirm': AppConstants.apiEndpoint + 'ownership/loans/pieces/confirm/', 'ownership_loans_pieces_deny': AppConstants.apiEndpoint + 'ownership/loans/pieces/deny/', + 'ownership_loans_pieces_request': AppConstants.apiEndpoint + 'ownership/loans/pieces/request/', 'ownership_loans_editions': AppConstants.apiEndpoint + 'ownership/loans/editions/', 'ownership_loans_confirm': AppConstants.apiEndpoint + 'ownership/loans/editions/confirm/', 'ownership_loans_deny': AppConstants.apiEndpoint + 'ownership/loans/editions/deny/', diff --git a/js/fetchers/ownership_fetcher.js b/js/fetchers/ownership_fetcher.js index 68ffa264..cd68eebf 100644 --- a/js/fetchers/ownership_fetcher.js +++ b/js/fetchers/ownership_fetcher.js @@ -17,8 +17,11 @@ let OwnershipFetcher = { */ fetchLoanContractList(){ return requests.get(ApiUrls.ownership_loans_contract); - } + }, + fetchLoanPieceRequestList(){ + return requests.get(ApiUrls.ownership_loans_pieces_request); + } }; export default OwnershipFetcher; diff --git a/js/stores/ownership_store.js b/js/stores/ownership_store.js new file mode 100644 index 00000000..90c427d2 --- /dev/null +++ b/js/stores/ownership_store.js @@ -0,0 +1,35 @@ +'use strict'; + +import alt from '../alt'; +import OwnershipActions from '../actions/ownership_actions'; + + +class OwnershipStore { + constructor() { + this.loanRequestList = []; + this.loanRequest = null; + this.bindActions(OwnershipActions); + } + + onUpdateLoanPieceRequestList(loanRequests) { + this.loanRequestList = loanRequests; + } + + onUpdateLoanPieceRequest({loanRequests, pieceId}) { + this.loanRequestList = loanRequests; + this.loanRequest = loanRequests.filter((item) => item.piece_id === pieceId.toString()); + if (this.loanRequest.length > 0){ + this.loanRequest = this.loanRequest[0]; + } + else { + this.loanRequest = null; + } + } + + flushLoanPieceRequest(){ + this.loanRequestList = []; + this.loanRequest = null; + } +} + +export default alt.createStore(OwnershipStore, 'OwnershipStore'); diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js index 3a8861cc..7f9cfb07 100644 --- a/js/utils/form_utils.js +++ b/js/utils/form_utils.js @@ -23,6 +23,8 @@ export function getAclFormMessage(aclName, entities, senderName) { message += getLangText('I un-consign'); } else if(aclName === 'acl_loan') { message += getLangText('I loan'); + } else if(aclName === 'acl_loan_request') { + message += getLangText('I request to loan'); } else if(aclName === 'acl_share') { message += getLangText('I share'); } else { @@ -34,7 +36,7 @@ export function getAclFormMessage(aclName, entities, senderName) { if(aclName === 'acl_transfer' || aclName === 'acl_loan' || aclName === 'acl_consign') { message += getLangText('to you'); - } else if(aclName === 'acl_unconsign') { + } else if(aclName === 'acl_unconsign' || aclName === 'acl_loan_request') { message += getLangText('from you'); } else if(aclName === 'acl_share') { message += getLangText('with you'); From ad7e86108ecd578ad7df64d0079010bd4ba41526 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 26 Aug 2015 12:33:06 +0200 Subject: [PATCH 133/397] prize piece serializer with DB rating stats --- .../ascribe_accordion_list/accordion_list_item_prize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js index 0ca54d93..1aafdac2 100644 --- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js +++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js @@ -80,7 +80,7 @@ let AccordionListItemPrize = React.createClass({ } else if (this.props.content.ratings.average){ rating = this.props.content.ratings.average; - caption = 'Average of ' + this.props.content.ratings.ratings.length + ' rating(s)'; + caption = 'Average of ' + this.props.content.ratings.num_ratings + ' rating(s)'; } return ( From e3b85bf808eed869ed65b7c09998064c5f0b3adb Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 26 Aug 2015 12:51:25 +0200 Subject: [PATCH 134/397] removed loadPieceList from shortlist in detail --- .../ascribe_forms/form_loan_request_answer.js | 2 +- .../components/ascribe_detail/prize_piece_container.js | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/js/components/ascribe_forms/form_loan_request_answer.js b/js/components/ascribe_forms/form_loan_request_answer.js index b695213c..e1a0f5db 100644 --- a/js/components/ascribe_forms/form_loan_request_answer.js +++ b/js/components/ascribe_forms/form_loan_request_answer.js @@ -74,7 +74,7 @@ let LoanRequestAnswerForm = React.createClass({ message={''} id={this.props.id} url={this.props.url} - email={""} + email={this.state.loanRequest.new_owner} gallery={this.state.loanRequest.gallery} showPassword={true} showPersonalMessage={false} diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 9e76bdb4..443c22de 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -16,7 +16,6 @@ import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; import UserStore from '../../../../../stores/user_store'; -import WhitelabelStore from '../../../../../stores/whitelabel_store'; import Piece from '../../../../../components/ascribe_detail/piece'; import Note from '../../../../../components/ascribe_detail/note'; @@ -189,8 +188,7 @@ let PrizePieceRatings = React.createClass({ getInitialState() { return mergeOptions( PieceListStore.getState(), - PrizeRatingStore.getState(), - WhitelabelStore.getState() + PrizeRatingStore.getState() ); }, @@ -199,7 +197,6 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.fetchOne(this.props.piece.id); PrizeRatingActions.fetchAverage(this.props.piece.id); PieceListStore.listen(this.onChange); - WhitelabelStore.listen(this.onChange); }, componentWillUnmount() { @@ -210,7 +207,6 @@ let PrizePieceRatings = React.createClass({ PrizeRatingActions.updateRating({}); PrizeRatingStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); - WhitelabelStore.unlisten(this.onChange); }, // The StarRating component does not have a property that lets us set @@ -255,7 +251,7 @@ let PrizePieceRatings = React.createClass({ 'Please accept the loan request to proceed\n\nBest regards,\n\nSluice.'} id={{piece_id: this.props.piece.id}} url={ApiUrls.ownership_loans_pieces_request} - email={this.state.whitelabel.user} + email={this.props.currentUser.email} gallery={this.props.piece.prize.name} startdate={today} enddate={endDate} @@ -270,8 +266,6 @@ let PrizePieceRatings = React.createClass({ handleLoanRequestSuccess(){}, refreshPieceData() { - PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, - this.state.orderBy, this.state.orderAsc, this.state.filterBy); this.props.loadPiece(); }, From bcd6400a78b8d3ae979c4123ed1ba97e3d07f4cd Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 26 Aug 2015 14:50:16 +0200 Subject: [PATCH 135/397] bug fix promises and notifications --- .../prize/actions/prize_rating_actions.js | 2 +- .../ascribe_detail/prize_piece_container.js | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/js/components/whitelabel/prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/actions/prize_rating_actions.js index 40e24858..1e42f8ba 100644 --- a/js/components/whitelabel/prize/actions/prize_rating_actions.js +++ b/js/components/whitelabel/prize/actions/prize_rating_actions.js @@ -62,7 +62,7 @@ class PrizeRatingActions { PrizeRatingFetcher .select(pieceId) .then((res) => { - this.actions.updatePrizeRating(res.rating.rating); + this.actions.updatePrizeRatings(res.data.ratings); resolve(res); }) .catch((err) => { diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 443c22de..712b463f 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -264,9 +264,15 @@ let PrizePieceRatings = React.createClass({ }, handleLoanRequestSuccess(){}, + handleShortlistSuccess(message){ + let notification = new GlobalNotificationModel(message, 'success', 2000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, refreshPieceData() { this.props.loadPiece(); + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); }, render(){ @@ -282,9 +288,17 @@ let PrizePieceRatings = React.createClass({ { - PrizeRatingActions.toggleShortlist(this.props.piece.id).then( - this.refreshPieceData() - ); }}> + PrizeRatingActions.toggleShortlist(this.props.piece.id) + .then( + (res) => { + this.refreshPieceData(); + return res; + }) + .then( + (res) => { + this.handleShortlistSuccess(res.notification); + } + ); }}> Select for the prize From 88b525f35289cd483ffa8db0467287828c1a2f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 25 Aug 2015 17:22:32 +0200 Subject: [PATCH 136/397] change link in accordionlist item dependent on domain --- .../accordion_list_item_piece.js | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js index b7e621b8..d0b16c9f 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js @@ -26,13 +26,24 @@ let AccordionListItemPiece = React.createClass({ mixins: [Router.Navigation], - getLinkData(){ - return { - to: 'piece', - params: { - pieceId: this.props.piece.id - } - }; + getLinkData() { + + if(this.props.piece && this.props.piece.first_edition) { + return { + to: 'edition', + params: { + editionId: this.props.piece.first_edition.bitcoin_id + } + }; + } else { + return { + to: 'piece', + params: { + pieceId: this.props.piece.id + } + }; + } + }, render() { From 1f8c8a7d9eab737a2e6db81e29b6e042bbf34ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 26 Aug 2015 15:41:59 +0200 Subject: [PATCH 137/397] (hopefully) fix auto-fill bug for safari/chrome --- js/components/ascribe_forms/form.js | 29 ++++++++++++++++++++--- js/components/ascribe_forms/form_login.js | 3 +-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js index 54d4f197..d0117251 100644 --- a/js/components/ascribe_forms/form.js +++ b/js/components/ascribe_forms/form.js @@ -39,13 +39,16 @@ let Form = React.createClass({ // You can use the form for inline requests, like the submit click on a button. // For the form to then not display the error on top, you need to enable this option. // It will make use of the GlobalNotification - isInline: React.PropTypes.bool + isInline: React.PropTypes.bool, + + autoComplete: React.PropTypes.string }, getDefaultProps() { return { method: 'post', - buttonSubmitText: 'SAVE' + buttonSubmitText: 'SAVE', + autoComplete: 'off' }; }, @@ -217,6 +220,25 @@ let Form = React.createClass({ }); }, + /** + * All webkit-based browsers are ignoring the attribute autoComplete="off", + * as stated here: http://stackoverflow.com/questions/15738259/disabling-chrome-autofill/15917221#15917221 + * So what we actually have to do is depended on whether or not this.props.autoComplete is set to "on" or "off" + * insert two fake hidden inputs that mock password and username so that chrome/safari is filling those + */ + getFakeAutocompletableInputs() { + if(this.props.autoComplete === 'off') { + return ( + + + + + ); + } else { + return null; + } + }, + render() { let className = 'ascribe-form'; @@ -229,7 +251,8 @@ let Form = React.createClass({ role="form" className={className} onSubmit={this.submit} - autoComplete="on"> + autoComplete={this.props.autoComplete}> + {this.getFakeAutocompletableInputs()} {this.getErrors()} {this.renderChildren()} {this.getButtons()} diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js index a3fd4d33..86a20119 100644 --- a/js/components/ascribe_forms/form_login.js +++ b/js/components/ascribe_forms/form_login.js @@ -101,6 +101,7 @@ let LoginForm = React.createClass({ ref="loginForm" url={ApiUrls.users_login} handleSuccess={this.handleSuccess} + autoComplete="on" buttons={ } handleSuccess={this.handleLoanRequestSuccess} title='REQUEST LOAN'> ); }, - handleLoanRequestSuccess(){}, - handleShortlistSuccess(message){ let notification = new GlobalNotificationModel(message, 'success', 2000); GlobalNotificationActions.appendGlobalNotification(notification); diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss index b040e877..1ef4bef9 100644 --- a/sass/ascribe_accordion_list.scss +++ b/sass/ascribe_accordion_list.scss @@ -152,11 +152,11 @@ span.ascribe-accordion-list-table-toggle { } } -.request-action-batch { +.request-action-badge { position: absolute; top: 0px; right: 0px; - color: #666; + color: $ascribe-color-green; font-size: 1.2em; padding: 0.3em; } diff --git a/sass/whitelabel/prize/rating.scss b/sass/whitelabel/prize/rating.scss index 8ea7c8ba..dfbff05b 100644 --- a/sass/whitelabel/prize/rating.scss +++ b/sass/whitelabel/prize/rating.scss @@ -29,6 +29,6 @@ .rating-note { color: #666; font-style: italic; - padding: 0.2em; + padding: 0.7em; } \ No newline at end of file From 9d7a9bd028a10669533848244b4b7b33c37e8bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 27 Aug 2015 14:34:15 +0200 Subject: [PATCH 151/397] add router/navigation integration into whole project --- js/components/ascribe_app.js | 7 +++--- js/components/header.js | 7 ------ js/components/nav_routes_links.js | 7 ++++-- js/components/routes.js | 25 ------------------- js/components/whitelabel/prize/prize_app.js | 8 +++++- .../whitelabel/prize/prize_routes.js | 4 +-- .../whitelabel/wallet/wallet_routes.js | 14 +++++------ js/routes.js | 17 +++++++++---- 8 files changed, 37 insertions(+), 52 deletions(-) delete mode 100644 js/components/routes.js diff --git a/js/components/ascribe_app.js b/js/components/ascribe_app.js index b4a894a3..789399b0 100644 --- a/js/components/ascribe_app.js +++ b/js/components/ascribe_app.js @@ -6,15 +6,16 @@ import Header from '../components/header'; import Footer from '../components/footer'; import GlobalNotification from './global_notification'; -// let Link = Router.Link; -let RouteHandler = Router.RouteHandler; +import getRoutes from '../routes'; +let RouteHandler = Router.RouteHandler; + let AscribeApp = React.createClass({ render() { return (
    -
    +
    diff --git a/js/components/header.js b/js/components/header.js index 6c2dfac8..4cd8e4b0 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -93,8 +93,6 @@ let Header = React.createClass({ render() { let account = null; let signup = null; - let collection = null; - let addNewWork = null; if (this.state.currentUser.username){ account = ( @@ -103,9 +101,6 @@ let Header = React.createClass({ {getLangText('Log out')} ); - - collection = {getLangText('COLLECTION')}; - addNewWork = this.props.showAddWork ? + {getLangText('NEW WORK')} : null; } else { account = {getLangText('LOGIN')}; @@ -126,8 +121,6 @@ let Header = React.createClass({ diff --git a/js/components/nav_routes_links.js b/js/components/nav_routes_links.js index 0e03e0fe..9a266ba8 100644 --- a/js/components/nav_routes_links.js +++ b/js/components/nav_routes_links.js @@ -16,6 +16,9 @@ let NavRoutesLinks = React.createClass({ }, extractLinksFromRoutes(node, i) { + if(!node) { + return; + } node = node.props; @@ -35,11 +38,11 @@ let NavRoutesLinks = React.createClass({ // if the node's child is actually a node of level one (a child of a node), we're // returning a DropdownButton matching MenuItemLink return ( - {child.props.headerTitle} + {child.props.headerTitle} ); } else if(i === 0) { return ( - {child.props.headerTitle} + {child.props.headerTitle} ); } else { return null; diff --git a/js/components/routes.js b/js/components/routes.js deleted file mode 100644 index 8b230a5a..00000000 --- a/js/components/routes.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -import React from 'react'; -import Router from 'react-router'; - -import App from './ascribe_app'; -import AppConstants from '../constants/application_constants'; - -let Route = Router.Route; -let Redirect = Router.Redirect; -let baseUrl = AppConstants.baseUrl; - - -function getRoutes(commonRoutes) { - return ( - - - - {commonRoutes} - - ); -} - - -export default getRoutes; diff --git a/js/components/whitelabel/prize/prize_app.js b/js/components/whitelabel/prize/prize_app.js index dec859fc..29763ab3 100644 --- a/js/components/whitelabel/prize/prize_app.js +++ b/js/components/whitelabel/prize/prize_app.js @@ -7,6 +7,8 @@ import Header from '../../header'; import Footer from '../../footer'; import GlobalNotification from '../../global_notification'; +import getRoutes from './prize_routes'; + let RouteHandler = Router.RouteHandler; let PrizeApp = React.createClass({ @@ -14,10 +16,14 @@ let PrizeApp = React.createClass({ render() { let header = null; + let subdomain = window.location.host.split('.')[0]; + + let ROUTES = getRoutes(null, subdomain); + if (this.isActive('landing') || this.isActive('login') || this.isActive('signup')) { header = ; } else { - header =
    ; + header =
    ; } return ( diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js index 1384d26b..a389cb83 100644 --- a/js/components/whitelabel/prize/prize_routes.js +++ b/js/components/whitelabel/prize/prize_routes.js @@ -29,8 +29,8 @@ function getRoutes() { - - + + diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 941c5a9c..a315bf3d 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -41,8 +41,8 @@ let ROUTES = { - - + + @@ -56,8 +56,8 @@ let ROUTES = { - - + + @@ -70,9 +70,9 @@ let ROUTES = { - - - + + + diff --git a/js/routes.js b/js/routes.js index 65dfbaac..f76e4b45 100644 --- a/js/routes.js +++ b/js/routes.js @@ -5,7 +5,8 @@ import Router from 'react-router'; import getPrizeRoutes from './components/whitelabel/prize/prize_routes'; import getWalletRoutes from './components/whitelabel/wallet/wallet_routes'; -import getDefaultRoutes from './components/routes'; + +import App from './components/ascribe_app'; import PieceList from './components/piece_list'; import PieceContainer from './components/ascribe_detail/piece_container'; @@ -23,19 +24,25 @@ import RegisterPiece from './components/register_piece'; import PrizesDashboard from './components/ascribe_prizes_dashboard/prizes_dashboard'; +import AppConstants from './constants/application_constants'; + let Route = Router.Route; +let Redirect = Router.Redirect; +let baseUrl = AppConstants.baseUrl; const COMMON_ROUTES = ( - + + + - + + - @@ -51,7 +58,7 @@ function getRoutes(type, subdomain) { } else if(type === 'wallet') { routes = getWalletRoutes(COMMON_ROUTES, subdomain); } else { - routes = getDefaultRoutes(COMMON_ROUTES); + routes = COMMON_ROUTES; } return routes; From 64d23f82dffae7fdd92f2028c00810ba68f6cd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 27 Aug 2015 14:47:33 +0200 Subject: [PATCH 152/397] refactoring of the general architecture --- .../components/ikonotv/ikonotv_landing.js | 13 +++ .../ikonotv/ikonotv_register_piece.js | 80 ------------------- .../whitelabel/wallet/wallet_routes.js | 7 +- 3 files changed, 17 insertions(+), 83 deletions(-) create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js delete mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js new file mode 100644 index 00000000..9893da0d --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js @@ -0,0 +1,13 @@ +'use strict'; + +import React from 'react'; + +let IkonotvLanding = React.createClass({ + render() { + return ( + This is a landing page placeholder + ); + } +}); + +export default IkonotvLanding; \ 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 deleted file mode 100644 index 814b0f01..00000000 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js +++ /dev/null @@ -1,80 +0,0 @@ -'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 RegisterPieceForm from '../../../../../components/ascribe_forms/form_register_piece'; -import Property from '../../../../../components/ascribe_forms/property'; -import InputCheckbox from '../../../../../components/ascribe_forms/input_checkbox'; - -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(), - WhitelabelStore.getState()); - }, - - componentDidMount() { - UserStore.listen(this.onChange); - WhitelabelStore.listen(this.onChange); - UserActions.fetchCurrentUser(); - WhitelabelActions.fetchWhitelabel(); - }, - - componentWillUnmount() { - UserStore.unlisten(this.onChange); - WhitelabelStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - - render() { - /* if (this.state.currentUser && - this.state.whitelabel && - this.state.whitelabel.user && - this.state.currentUser.email === this.state.whitelabel.user){ - return ( - - ); - } */ - return ( -
    - -
    - ); - - } -}); - - -export default IkonotvRegisterPiece; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index a315bf3d..133d66ac 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -12,13 +12,14 @@ import PieceList from '../../../components/piece_list'; import PieceContainer from '../../../components/ascribe_detail/piece_container'; import EditionContainer from '../../../components/ascribe_detail/edition_container'; import SettingsContainer from '../../../components/settings_container'; +import RegisterPiece from '../../../components/register_piece'; -// specific components import CylandLanding from './components/cyland/cyland_landing'; import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piece_container'; import CylandRegisterPiece from './components/cyland/cyland_register_piece'; import CylandPieceList from './components/cyland/cyland_piece_list'; +import IkonotvLanding from './components/ikonotv/ikonotv_landing'; import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list'; import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece'; import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan'; @@ -65,13 +66,13 @@ let ROUTES = { ), 'ikonotv': ( - + - + From 65148e24de68c91e1fe817d4d6fca0ebaa1c341a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 27 Aug 2015 14:56:49 +0200 Subject: [PATCH 153/397] remove contract form from ikonotv codebase and integrate it into ascribe-core --- .../contract_form.js} | 18 +++++++++--------- .../components/ikonotv/ikonotv_request_loan.js | 2 +- .../whitelabel/wallet/wallet_routes.js | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) rename js/components/{whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_contract_form.js => ascribe_forms/contract_form.js} (86%) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_contract_form.js b/js/components/ascribe_forms/contract_form.js similarity index 86% rename from js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_contract_form.js rename to js/components/ascribe_forms/contract_form.js index 2d56ac6f..91f1d487 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_forms/ikonotv_contract_form.js +++ b/js/components/ascribe_forms/contract_form.js @@ -2,20 +2,20 @@ import React from 'react'; -import Property from '../../../../../ascribe_forms/property'; +import Property from './property'; -import LoanContractListActions from '../../../../../../actions/loan_contract_list_actions'; -import LoanContractListStore from '../../../../../../stores/loan_contract_list_store'; +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 GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; -import Form from '../../../../../ascribe_forms/form'; +import Form from './form'; -import ApiUrls from '../../../../../../constants/api_urls'; +import ApiUrls from '../../constants/api_urls'; -import { getLangText } from '../../../../../../utils/lang_utils'; -import { mergeOptions } from '../../../../../../utils/general_utils'; +import { getLangText } from '../../utils/lang_utils'; +import { mergeOptions } from '../../utils/general_utils'; let ContractForm = React.createClass({ diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js index 78f8b3b4..e9c61f51 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js @@ -2,7 +2,7 @@ import React from 'react'; -import ContractForm from './ascribe_forms/ikonotv_contract_form'; +import ContractForm from '../../../../../components/ascribe_forms/contract_form'; let IkonotvRequestLoan = React.createClass({ diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 133d66ac..d5937710 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -21,7 +21,6 @@ import CylandPieceList from './components/cyland/cyland_piece_list'; import IkonotvLanding from './components/ikonotv/ikonotv_landing'; import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list'; -import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece'; import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan'; import CCRegisterPiece from './components/cc/cc_register_piece'; From 86efb66663404e335f27ff94da1df19154e5ce3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 27 Aug 2015 17:33:51 +0200 Subject: [PATCH 154/397] add collapsible appendix to send contract form --- js/components/ascribe_forms/contract_form.js | 24 ++++++++++--------- .../whitelabel/wallet/wallet_routes.js | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/js/components/ascribe_forms/contract_form.js b/js/components/ascribe_forms/contract_form.js index 91f1d487..5b811cf6 100644 --- a/js/components/ascribe_forms/contract_form.js +++ b/js/components/ascribe_forms/contract_form.js @@ -2,8 +2,6 @@ import React from 'react'; -import Property from './property'; - import LoanContractListActions from '../../actions/loan_contract_list_actions'; import LoanContractListStore from '../../stores/loan_contract_list_store'; @@ -11,6 +9,9 @@ import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; import Form from './form'; +import Property from './property'; +import PropertyCollapsible from './property_collapsible'; +import InputTextAreaToggable from './input_textarea_toggable'; import ApiUrls from '../../constants/api_urls'; @@ -96,7 +97,7 @@ let ContractForm = React.createClass({ buttons={} spinner={ @@ -104,7 +105,7 @@ let ContractForm = React.createClass({ }>
    -

    {getLangText('CONTRACT FORM')}

    +

    {getLangText('Contract form')}

    {this.getContracts()} - - - + checkboxLabel={getLangText('Add appendix to the contract')}> + {getLangText('Appendix')} + + ); } diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index d5937710..6836ec66 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -70,7 +70,7 @@ let ROUTES = { - + From 8e5c04140f1a09be10196c946ccebde6deaa59d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 27 Aug 2015 18:11:47 +0200 Subject: [PATCH 155/397] add vendor prefixes for slide container --- .../ascribe_slides_container/slides_container.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 4ac4d57a..8b098ef6 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -241,6 +241,16 @@ let SlidesContainer = React.createClass({ }, render() { + + let translateXValue = 'translateX(' + (-1) * this.state.containerWidth * this.state.slideNum + 'px)'; + + /* + According to the react documentation, + all browser vendor prefixes need to be upper cases in the beginning except for + the Microsoft one *bigfuckingsurprise* + https://facebook.github.io/react/tips/inline-styles.html + */ + return (
    {this.renderChildren()} From 9a9aa68ca9ecd4774aa19a0f92026bfc28a75b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 11:13:28 +0200 Subject: [PATCH 156/397] fix lazy evalutaion of loan form --- js/components/ascribe_forms/form_loan.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index f9b866a3..276ff492 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -68,8 +68,12 @@ let LoanForm = React.createClass({ return this.props.id; }, - handleOnBlur(event) { - LoanContractActions.fetchLoanContract(event.target.value); + handleOnChange(event) { + let potentialEmail = event.target.value; + + if(potentialEmail.match(/.*@.*/)) { + LoanContractActions.fetchLoanContract(potentialEmail); + } }, getContractCheckbox() { @@ -151,7 +155,7 @@ let LoanForm = React.createClass({ Date: Fri, 28 Aug 2015 12:11:29 +0200 Subject: [PATCH 157/397] add: Loan form for Ikonotv --- .../ikonotv_accordion_list_item.js | 17 ++++---- .../ascribe_buttons/ikonotv_submit_button.js | 41 +++++++++++++++++-- .../wallet/constants/wallet_api_urls.js | 4 +- .../whitelabel/wallet/wallet_routes.js | 5 ++- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js index 2be45ce3..ecab34fb 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -14,8 +14,11 @@ import GlobalNotificationModel from '../../../../../../models/global_notificatio import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button'; + import AclProxy from '../../../../../acl_proxy'; +import AclButton from '../../../../../ascribe_buttons/acl_button'; + import { getLangText } from '../../../../../../utils/lang_utils'; import { mergeOptions } from '../../../../../../utils/general_utils'; @@ -61,16 +64,10 @@ let IkonotvAccordionListItem = React.createClass({ getSubmitButtons() { return ( -
    - - - -
    + ); }, 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 d3f4c0e3..ae5ba094 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,10 +1,18 @@ '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 { getLangText } from '../../../../../../utils/lang_utils'; let IkonotvSubmitButton = React.createClass({ @@ -24,16 +32,43 @@ let IkonotvSubmitButton = React.createClass({ }, render() { + + let today = new Moment(); + let enddate = new Moment(); + enddate.add(1, 'years'); + return ( - + title={getLangText('Loan to IkonoTV archive')}> + + + + + {' ' + getLangText('I agree to the Terms of Service of IkonoTV Archive') + ' '} + ( + {getLangText('read')} + ) + + + + ); } }); -export default IkonotvSubmitButton; \ No newline at end of file +export default IkonotvSubmitButton; diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index c1b101a1..22d4017e 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -13,8 +13,8 @@ function getWalletApiUrls(subdomain) { } else if (subdomain === 'ikonotv'){ return { - 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/', - 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' + 'pieces_list': walletConstants.walletApiEndpoint + 'cyland' + '/pieces/', + 'piece': walletConstants.walletApiEndpoint + 'cyland' + '/pieces/${piece_id}/' }; } return {}; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 6836ec66..9532299c 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -65,12 +65,13 @@ let ROUTES = { ), 'ikonotv': ( - + + - + From 2c26aab8cc262803353d89d6da71d7280c63d206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 12:20:36 +0200 Subject: [PATCH 158/397] add exception for loaning a piece for ikonotv --- js/components/ascribe_detail/piece_container.js | 5 ++++- js/components/whitelabel/wallet/constants/wallet_api_urls.js | 4 ++-- js/components/whitelabel/wallet/wallet_routes.js | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 3739a508..2c6da4a9 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -84,8 +84,11 @@ let PieceContainer = React.createClass({ IT SHOULD BE REMOVED AND REPLACED WITH A BETTER SOLUTION ASAP! + ALSO, WE ENABLED THE LOAN BUTTON FOR IKONOTV TO LET THEM LOAN ON A PIECE LEVEL + */ - if(state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { + let subdomain = window.location.host.split('.')[0]; + if(subdomain !== 'ikonotv' && state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { let pieceState = mergeOptions({}, state.piece); pieceState.acl.acl_loan = false; diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js index 22d4017e..c1b101a1 100644 --- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js +++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js @@ -13,8 +13,8 @@ function getWalletApiUrls(subdomain) { } else if (subdomain === 'ikonotv'){ return { - 'pieces_list': walletConstants.walletApiEndpoint + 'cyland' + '/pieces/', - 'piece': walletConstants.walletApiEndpoint + 'cyland' + '/pieces/${piece_id}/' + 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/', + 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/' }; } return {}; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 9532299c..ec5b9787 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -74,7 +74,7 @@ let ROUTES = { - + From e9d0311f589a5f96ecdf492419870af130fa31ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 12:33:00 +0200 Subject: [PATCH 159/397] custom ikonotv piece page --- .../ascribe_detail/piece_container.js | 1 + .../ikonotv_accordion_list_item.js | 2 +- .../ascribe_buttons/ikonotv_submit_button.js | 2 +- .../ascribe_detail/ikonotv_piece_container.js | 165 ++++++++++++++++++ .../whitelabel/wallet/wallet_routes.js | 4 +- 5 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 2c6da4a9..62fc9b11 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -205,6 +205,7 @@ let PieceContainer = React.createClass({ ); } }, + render() { if('title' in this.state.piece) { return ( diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js index ecab34fb..8a4ed893 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -65,7 +65,7 @@ let IkonotvAccordionListItem = React.createClass({ getSubmitButtons() { return ( ); 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 ae5ba094..a73871dd 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 @@ -25,7 +25,7 @@ let IkonotvSubmitButton = React.createClass({ getSubmitButton() { return ( ); diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js new file mode 100644 index 00000000..d88f42a5 --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js @@ -0,0 +1,165 @@ +'use strict'; + +import React from 'react'; + +import PieceActions from '../../../../../../actions/piece_actions'; +import PieceStore from '../../../../../../stores/piece_store'; +import PieceListActions from '../../../../../../actions/piece_list_actions'; +import UserStore from '../../../../../../stores/user_store'; + +import Piece from '../../../../../../components/ascribe_detail/piece'; + +import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions'; +import AclButtonList from '../../../../../ascribe_buttons/acl_button_list'; +import DeleteButton from '../../../../../ascribe_buttons/delete_button'; + +import CollapsibleParagraph from '../../../../../../components/ascribe_collapsible/collapsible_paragraph'; + +import IkonotvSubmitButton from '../ascribe_buttons/ikonotv_submit_button'; + +import HistoryIterator from '../../../../../ascribe_detail/history_iterator'; + +import DetailProperty from '../../../../../ascribe_detail/detail_property'; + + +import GlobalNotificationModel from '../../../../../../models/global_notification_model'; +import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; + + +import AppConstants from '../../../../../../constants/application_constants'; + +import { getLangText } from '../../../../../../utils/lang_utils'; +import { mergeOptions } from '../../../../../../utils/general_utils'; + + +let IkonotvPieceContainer = React.createClass({ + getInitialState() { + return mergeOptions( + PieceStore.getState(), + UserStore.getState() + ); + }, + + componentDidMount() { + PieceStore.listen(this.onChange); + PieceActions.fetchOne(this.props.params.pieceId); + UserStore.listen(this.onChange); + }, + + componentWillReceiveProps(nextProps) { + if(this.props.params.pieceId !== nextProps.params.pieceId) { + PieceActions.updatePiece({}); + PieceActions.fetchOne(nextProps.params.pieceId); + } + }, + + componentWillUnmount() { + // Every time we're leaving the piece detail page, + // just reset the piece that is saved in the piece store + // as it will otherwise display wrong/old data once the user loads + // the piece detail a second time + PieceActions.updatePiece({}); + PieceStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + loadPiece() { + PieceActions.fetchOne(this.props.params.pieceId); + }, + + handleSubmitSuccess(response) { + PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search, + this.state.orderBy, this.state.orderAsc, this.state.filterBy); + + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getActions(){ + if (this.state.piece && + this.state.piece.request_action && + this.state.piece.request_action.length > 0) { + return ( + + ); + } + else { + + // This is just because we're inserting a custom acl_loan button + let availableAcls; + + if(this.state.piece && this.state.piece.acl && typeof this.state.piece.acl.acl_loan !== 'undefined') { + // make a copy to not have side effects + availableAcls = mergeOptions({}, this.state.piece.acl); + availableAcls.acl_loan = false; + } + + return ( + + + + + ); + } + }, + + render() { + if('title' in this.state.piece) { + return ( + +
    +

    {this.state.piece.title}

    + + +
    +
    + } + subheader={ +
    + + +
    +
    + } + buttons={this.getActions()}> + + 0}> + + + + ); + } else { + return ( +
    + +
    + ); + } + } +}); + +export default IkonotvPieceContainer; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index ec5b9787..40f092d6 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -19,9 +19,9 @@ import CylandPieceContainer from './components/cyland/ascribe_detail/cyland_piec import CylandRegisterPiece from './components/cyland/cyland_register_piece'; import CylandPieceList from './components/cyland/cyland_piece_list'; -import IkonotvLanding from './components/ikonotv/ikonotv_landing'; import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list'; import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan'; +import IkonotvPieceContainer from './components/ikonotv/ascribe_detail/ikonotv_piece_container'; import CCRegisterPiece from './components/cc/cc_register_piece'; @@ -74,7 +74,7 @@ let ROUTES = { - + From 5219dd5cf711c07e79c81c2a5d036f1e828644e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 12:40:00 +0200 Subject: [PATCH 160/397] fix bug + enable contract --- .../ikonotv/ascribe_buttons/ikonotv_submit_button.js | 2 +- .../ikonotv/ascribe_detail/ikonotv_piece_container.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) 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 a73871dd..40d65a2b 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 @@ -58,7 +58,7 @@ let IkonotvSubmitButton = React.createClass({ {' ' + getLangText('I agree to the Terms of Service of IkonoTV Archive') + ' '} - ( + ( {getLangText('read')} ) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js index d88f42a5..bc84249f 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js @@ -4,7 +4,10 @@ import React from 'react'; import PieceActions from '../../../../../../actions/piece_actions'; import PieceStore from '../../../../../../stores/piece_store'; + import PieceListActions from '../../../../../../actions/piece_list_actions'; +import PieceListStore from '../../../../../../stores/piece_list_store'; + import UserStore from '../../../../../../stores/user_store'; import Piece from '../../../../../../components/ascribe_detail/piece'; @@ -36,7 +39,8 @@ let IkonotvPieceContainer = React.createClass({ getInitialState() { return mergeOptions( PieceStore.getState(), - UserStore.getState() + UserStore.getState(), + PieceListStore.getState() ); }, @@ -44,6 +48,7 @@ let IkonotvPieceContainer = React.createClass({ PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); + PieceListStore.listen(this.onChange); }, componentWillReceiveProps(nextProps) { @@ -61,6 +66,7 @@ let IkonotvPieceContainer = React.createClass({ PieceActions.updatePiece({}); PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); + PieceListStore.unlisten(this.onChange); }, onChange(state) { @@ -143,7 +149,6 @@ let IkonotvPieceContainer = React.createClass({
    } buttons={this.getActions()}> - 0}> From d40b671b45aea0ad539d2285d703e8473284acd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 12:48:48 +0200 Subject: [PATCH 161/397] remove ikonotv boilerplate landing page --- .../wallet/components/ikonotv/ikonotv_landing.js | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js deleted file mode 100644 index 9893da0d..00000000 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_landing.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -import React from 'react'; - -let IkonotvLanding = React.createClass({ - render() { - return ( - This is a landing page placeholder - ); - } -}); - -export default IkonotvLanding; \ No newline at end of file From 680cc8572fa62fed84acf6ce82d20f052859e744 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 28 Aug 2015 13:52:58 +0200 Subject: [PATCH 162/397] ikonotv acl_submit --- .../ikonotv_accordion_list_item.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js index 8a4ed893..267b09f1 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -64,10 +64,14 @@ let IkonotvAccordionListItem = React.createClass({ getSubmitButtons() { return ( - + + + ); }, From 1b730573c7a8e6d26a893bb71a3f515cb561fe7c Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 28 Aug 2015 13:58:24 +0200 Subject: [PATCH 163/397] ikonotv acl_submitted + refactor --- .../ikonotv_accordion_list_item.js | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js index 267b09f1..bb47af0f 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -64,14 +64,26 @@ let IkonotvAccordionListItem = React.createClass({ getSubmitButtons() { return ( - - - +
    + + + + + + +
    ); }, From 02e105d2b80b2771c488c730191872cbcd75e886 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 28 Aug 2015 14:00:50 +0200 Subject: [PATCH 164/397] text refactor --- .../ascribe_accordion_list/ikonotv_accordion_list_item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js index bb47af0f..c0a239cb 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_accordion_list/ikonotv_accordion_list_item.js @@ -79,7 +79,7 @@ let IkonotvAccordionListItem = React.createClass({ From 52ae348e57d759683caf88f9aa6b16786f7046fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 14:07:29 +0200 Subject: [PATCH 165/397] dynamic acl for acl_submit --- js/components/ascribe_detail/piece_container.js | 5 +---- .../ascribe_detail/ikonotv_piece_container.js | 15 ++++++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 62fc9b11..b4ec2bf2 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -84,11 +84,8 @@ let PieceContainer = React.createClass({ IT SHOULD BE REMOVED AND REPLACED WITH A BETTER SOLUTION ASAP! - ALSO, WE ENABLED THE LOAN BUTTON FOR IKONOTV TO LET THEM LOAN ON A PIECE LEVEL - */ - let subdomain = window.location.host.split('.')[0]; - if(subdomain !== 'ikonotv' && state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { + if(state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { let pieceState = mergeOptions({}, state.piece); pieceState.acl.acl_loan = false; diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js index bc84249f..8980f6b4 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js @@ -28,6 +28,7 @@ import DetailProperty from '../../../../../ascribe_detail/detail_property'; import GlobalNotificationModel from '../../../../../../models/global_notification_model'; import GlobalNotificationActions from '../../../../../../actions/global_notification_actions'; +import AclProxy from '../../../../../acl_proxy'; import AppConstants from '../../../../../../constants/application_constants'; @@ -99,7 +100,7 @@ let IkonotvPieceContainer = React.createClass({ } else { - // This is just because we're inserting a custom acl_loan button + //We need to disable the normal acl_loan because we're inserting a custom acl_loan button let availableAcls; if(this.state.piece && this.state.piece.acl && typeof this.state.piece.acl.acl_loan !== 'undefined') { @@ -114,10 +115,14 @@ let IkonotvPieceContainer = React.createClass({ availableAcls={availableAcls} editions={this.state.piece} handleSuccess={this.loadPiece}> - + + + From ddfc8b9621808521e2209d4f0b2a2fe9239218f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 14:27:02 +0200 Subject: [PATCH 166/397] minor fixes --- js/components/ascribe_detail/piece_container.js | 2 ++ .../wallet/components/cyland/cyland_register_piece.js | 2 ++ .../ikonotv/ascribe_detail/ikonotv_piece_container.js | 1 + 3 files changed, 5 insertions(+) diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index b4ec2bf2..7297825d 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -84,6 +84,8 @@ let PieceContainer = React.createClass({ IT SHOULD BE REMOVED AND REPLACED WITH A BETTER SOLUTION ASAP! + ALSO, WE ENABLED THE LOAN BUTTON FOR IKONOTV TO LET THEM LOAN ON A PIECE LEVEL + */ if(state && state.piece && state.piece.acl && typeof state.piece.acl.acl_loan !== 'undefined') { 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 8a092bdf..d1363a51 100644 --- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js +++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js @@ -216,6 +216,8 @@ let CylandRegisterPiece = React.createClass({ gallery="Cyland Archive" startdate={today} enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain} + showStartDate={false} + showEndDate={false} showPersonalMessage={false} handleSuccess={this.handleLoanSuccess}> Date: Fri, 28 Aug 2015 15:24:32 +0200 Subject: [PATCH 167/397] request actions first cut --- js/actions/piece_list_actions.js | 2 +- .../accordion_list_item_wallet.js | 5 +- js/components/piece_list.js | 26 +++++++ .../ascribe_detail/prize_piece_container.js | 1 - js/stores/piece_list_store.js | 21 +++++- sass/ascribe_accordion_list.scss | 2 +- sass/ascribe_global_action.scss | 73 +++++++++++++++++++ sass/main.scss | 1 + 8 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 sass/ascribe_global_action.scss diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 1ebe7f42..d1ff363c 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -55,7 +55,7 @@ class PieceListActions { PieceListFetcher .fetchRequestActions() .then((res) => { - this.actions.updatePieceListRequestActions(res.piece_ids); + this.actions.updatePieceListRequestActions(res); }) .catch((err) => console.logGlobal(err)); } diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js index f7bca334..178a7db4 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js @@ -61,12 +61,13 @@ let AccordionListItemWallet = React.createClass({ }, getGlyphicon(){ - if (this.props.content.requestAction && this.props.content.requestAction.length > 0) { + if ((this.props.content.request_action && this.props.content.request_action.length > 0) || + (this.props.content.request_action_editions)){ return ( {getLangText('You have actions pending in one of your editions')}}> + overlay={{getLangText('You have actions pending')}}> ); } diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 79f1471c..185b0f05 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -147,8 +147,34 @@ let PieceList = React.createClass({ render() { let loadingElement = (); let AccordionListItemType = this.props.accordionListItemType; + + let pieceActions = null; + if (this.state.requestActions && this.state.requestActions.pieces){ + pieceActions = this.state.requestActions.pieces.map((item) => { + return ( +
    + test +
    ); + }); + } + let editionActions = null; + if (this.state.requestActions && this.state.requestActions.editions){ + for (let pieceId in this.state.requestActions.editions) { + editionActions = this.state.requestActions.editions[pieceId].map((item) => { + return ( +
    + test +
    ); + }); + } + } + return (
    +
    + {pieceActions} + {editionActions} +
    { - piece.requestAction = requestActions.indexOf(piece.id) > -1; - }); + onUpdatePieceListRequestActions(res) { + this.requestActions.pieces = res.piece_actions; + this.requestActions.editions = res.edition_actions; + for (let pieceId in res.edition_actions){ + try { + this.onUpdatePropertyForPiece({ + pieceId: parseInt(pieceId, 10), + key: 'request_action_editions', + value: res.edition_actions[pieceId] + }); + } + catch(err) { + console.warn('couldnt match request action with piecelist, maybe on other page'); + } + + } } onUpdatePropertyForPiece({pieceId, key, value}) { diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss index 1ef4bef9..6f809b27 100644 --- a/sass/ascribe_accordion_list.scss +++ b/sass/ascribe_accordion_list.scss @@ -158,7 +158,7 @@ span.ascribe-accordion-list-table-toggle { right: 0px; color: $ascribe-color-green; font-size: 1.2em; - padding: 0.3em; + padding: 0.8em; } .ascribe-accordion-list-item-edition-widget { diff --git a/sass/ascribe_global_action.scss b/sass/ascribe_global_action.scss new file mode 100644 index 00000000..bcc3f50d --- /dev/null +++ b/sass/ascribe_global_action.scss @@ -0,0 +1,73 @@ +.ascribe-global-action-wrapper { + position: fixed; + width: 100%; + height:3.5em; + left:0; + top:0; + z-index: 2000; + display:table; +} + +.ascribe-global-action { + width: 40%; + margin: 1px auto; + text-align: center; + padding: 1em; + color: black; + border: 1px solid #cccccc; + background-color: white; +} + +.ascribe-global-notification-off { + bottom: -3.5em; +} + +.ascribe-global-notification-on { + bottom: 0; +} + +.ascribe-global-notification > div, .ascribe-global-notification-bubble > div { + display:table-cell; + vertical-align: middle; + font-size: 1.25em; + font-family: 'Source Sans Pro'; + text-align: right; + padding-right: 3em; +} + +.ascribe-global-notification-bubble > div { + padding: .75em 1.5em .75em 1.5em; +} + +.ascribe-global-notification-bubble { + position: fixed; + bottom: 3em; + right: -50em; + + display:table; + + height: 3.5em; + + background-color: #212121; + border-radius: 2px; + + color: white; + + transition: 1s right ease; +} + +.ascribe-global-notification-bubble-off { + right: -100em; +} + +.ascribe-global-notification-bubble-on { + right: 3.5em; +} + +.ascribe-global-notification-danger { + background-color: #d9534f; +} + +.ascribe-global-notification-success { + background-color: rgba(2, 182, 163, 1); +} \ No newline at end of file diff --git a/sass/main.scss b/sass/main.scss index a6ab05b3..34bf42b1 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -22,6 +22,7 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'ascribe_media_player'; @import 'ascribe_uploader'; @import 'ascribe_footer'; +@import 'ascribe_global_action'; @import 'ascribe_global_notification'; @import 'ascribe_piece_register'; @import 'offset_right'; From 848321a3f3efbfafebd5e180a783064d1cb7c7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 15:29:30 +0200 Subject: [PATCH 168/397] fix nav links on logged out user --- js/components/header.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/components/header.js b/js/components/header.js index 4cd8e4b0..0863624f 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -91,8 +91,9 @@ let Header = React.createClass({ }, render() { - let account = null; - let signup = null; + let account; + let signup; + let navRoutesLinks; if (this.state.currentUser.username){ account = ( @@ -101,6 +102,7 @@ let Header = React.createClass({ {getLangText('Log out')} ); + navRoutesLinks = ; } else { account = {getLangText('LOGIN')}; @@ -124,7 +126,7 @@ let Header = React.createClass({ {account} {signup} - + {navRoutesLinks}
    From 02ed21fef5679ff0c51b1152765e918af25e06e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 15:29:30 +0200 Subject: [PATCH 169/397] fix nav links on logged out user --- js/components/header.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/components/header.js b/js/components/header.js index 4cd8e4b0..0863624f 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -91,8 +91,9 @@ let Header = React.createClass({ }, render() { - let account = null; - let signup = null; + let account; + let signup; + let navRoutesLinks; if (this.state.currentUser.username){ account = ( @@ -101,6 +102,7 @@ let Header = React.createClass({ {getLangText('Log out')} ); + navRoutesLinks = ; } else { account = {getLangText('LOGIN')}; @@ -124,7 +126,7 @@ let Header = React.createClass({ {account} {signup} - + {navRoutesLinks}
    From d9f3f2a9d7871f6e04e977c28349ce1b1dbe3e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 15:55:39 +0200 Subject: [PATCH 170/397] rename contract_form to form_contract --- .../ascribe_forms/{contract_form.js => form_contract.js} | 0 .../wallet/components/ikonotv/ikonotv_request_loan.js | 2 +- js/components/whitelabel/wallet/wallet_routes.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename js/components/ascribe_forms/{contract_form.js => form_contract.js} (100%) diff --git a/js/components/ascribe_forms/contract_form.js b/js/components/ascribe_forms/form_contract.js similarity index 100% rename from js/components/ascribe_forms/contract_form.js rename to js/components/ascribe_forms/form_contract.js diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js index e9c61f51..db74db3b 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_request_loan.js @@ -2,7 +2,7 @@ import React from 'react'; -import ContractForm from '../../../../../components/ascribe_forms/contract_form'; +import ContractForm from '../../../../../components/ascribe_forms/form_contract'; let IkonotvRequestLoan = React.createClass({ diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 40f092d6..1a32f46f 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -71,7 +71,7 @@ let ROUTES = { - + From dd20afff9090de307aa8026336d1b0d639fd3b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 28 Aug 2015 16:18:10 +0200 Subject: [PATCH 171/397] rename LoanContract to Contract --- ...ontract_actions.js => contract_actions.js} | 16 +++++------ js/actions/contract_list_actions.js | 27 +++++++++++++++++++ js/actions/loan_contract_list_actions.js | 27 ------------------- js/components/ascribe_forms/form_contract.js | 14 +++++----- js/components/ascribe_forms/form_loan.js | 14 +++++----- js/constants/api_urls.js | 2 +- js/fetchers/ownership_fetcher.js | 10 +++---- js/stores/contract_list_store.js | 22 +++++++++++++++ ...an_contract_store.js => contract_store.js} | 12 ++++----- js/stores/loan_contract_list_store.js | 22 --------------- 10 files changed, 83 insertions(+), 83 deletions(-) rename js/actions/{loan_contract_actions.js => contract_actions.js} (75%) create mode 100644 js/actions/contract_list_actions.js delete mode 100644 js/actions/loan_contract_list_actions.js create mode 100644 js/stores/contract_list_store.js rename js/stores/{loan_contract_store.js => contract_store.js} (56%) delete mode 100644 js/stores/loan_contract_list_store.js diff --git a/js/actions/loan_contract_actions.js b/js/actions/contract_actions.js similarity index 75% rename from js/actions/loan_contract_actions.js rename to js/actions/contract_actions.js index cc7e5a5b..83a788b8 100644 --- a/js/actions/loan_contract_actions.js +++ b/js/actions/contract_actions.js @@ -4,27 +4,27 @@ import alt from '../alt'; import OwnershipFetcher from '../fetchers/ownership_fetcher'; -class LoanContractActions { +class ContractActions { constructor() { this.generateActions( - 'updateLoanContract', - 'flushLoanContract' + 'updateContract', + 'flushContract' ); } fetchLoanContract(email) { if(email.match(/.+\@.+\..+/)) { - OwnershipFetcher.fetchLoanContract(email) + OwnershipFetcher.fetchContract(email) .then((contracts) => { if (contracts && contracts.length > 0) { - this.actions.updateLoanContract({ + this.actions.updateContract({ contractKey: contracts[0].s3Key, contractUrl: contracts[0].s3Url, contractEmail: email }); } else { - this.actions.updateLoanContract({ + this.actions.updateContract({ contractKey: null, contractUrl: null, contractEmail: null @@ -33,7 +33,7 @@ class LoanContractActions { }) .catch((err) => { console.logGlobal(err); - this.actions.updateLoanContract({ + this.actions.updateContract({ contractKey: null, contractUrl: null, contractEmail: null @@ -45,4 +45,4 @@ class LoanContractActions { } } -export default alt.createActions(LoanContractActions); +export default alt.createActions(ContractActions); diff --git a/js/actions/contract_list_actions.js b/js/actions/contract_list_actions.js new file mode 100644 index 00000000..f4257d37 --- /dev/null +++ b/js/actions/contract_list_actions.js @@ -0,0 +1,27 @@ +'use strict'; + +import alt from '../alt'; +import OwnershipFetcher from '../fetchers/ownership_fetcher'; + + +class ContractListActions { + constructor() { + this.generateActions( + 'updateContractList', + 'flushContractList' + ); + } + + fetchContractList() { + OwnershipFetcher.fetchContractList() + .then((contracts) => { + this.actions.updateContractList(contracts); + }) + .catch((err) => { + console.logGlobal(err); + this.actions.updateContractList([]); + }); + } +} + +export default alt.createActions(ContractListActions); diff --git a/js/actions/loan_contract_list_actions.js b/js/actions/loan_contract_list_actions.js deleted file mode 100644 index bc5cef82..00000000 --- a/js/actions/loan_contract_list_actions.js +++ /dev/null @@ -1,27 +0,0 @@ -'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/ascribe_forms/form_contract.js b/js/components/ascribe_forms/form_contract.js index 5b811cf6..d4e58c79 100644 --- a/js/components/ascribe_forms/form_contract.js +++ b/js/components/ascribe_forms/form_contract.js @@ -2,8 +2,8 @@ import React from 'react'; -import LoanContractListActions from '../../actions/loan_contract_list_actions'; -import LoanContractListStore from '../../stores/loan_contract_list_store'; +import ContractListActions from '../../actions/contract_list_actions'; +import ContractListStore from '../../stores/contract_list_store'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; @@ -26,7 +26,7 @@ let ContractForm = React.createClass({ getInitialState() { return mergeOptions( - LoanContractListStore.getState(), + ContractListStore.getState(), { selectedContract: 0 } @@ -34,12 +34,12 @@ let ContractForm = React.createClass({ }, componentDidMount() { - LoanContractListStore.listen(this.onChange); - LoanContractListActions.fetchLoanContractList(); + ContractListStore.listen(this.onChange); + ContractListActions.fetchContractList(); }, componentWillUnmount() { - LoanContractListStore.unlisten(this.onChange); + ContractListStore.unlisten(this.onChange); }, onChange(state) { @@ -92,7 +92,7 @@ let ContractForm = React.createClass({
    Date: Fri, 28 Aug 2015 15:56:08 +0200 Subject: [PATCH 172/397] Get rid of ascribe-btn-gray --- .../prize/components/prize_settings_container.js | 6 +++--- sass/ascribe_button.scss | 9 --------- sass/ascribe_variables.scss | 1 - sass/main.scss | 1 - sass/variables.scss | 2 +- 5 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 sass/ascribe_button.scss diff --git a/js/components/whitelabel/prize/components/prize_settings_container.js b/js/components/whitelabel/prize/components/prize_settings_container.js index f81e7078..3c48f254 100644 --- a/js/components/whitelabel/prize/components/prize_settings_container.js +++ b/js/components/whitelabel/prize/components/prize_settings_container.js @@ -190,7 +190,7 @@ let PrizeJurySettings = React.createClass({ {getLangText('RESEND')}
    @@ -234,7 +234,7 @@ let BitcoinWalletSettings = React.createClass({ } }); -let LoanContractSettings = React.createClass({ +let ContractSettings = React.createClass({ propTypes: { defaultExpanded: React.PropTypes.bool }, @@ -242,7 +242,7 @@ let LoanContractSettings = React.createClass({ render() { return ( @@ -266,14 +266,14 @@ let FileUploader = React.createClass({ fileClass: 'contract' }} createBlobRoutine={{ - url: ApiUrls.ownership_loans_contract + url: ApiUrls.ownership_contract }} validation={{ itemLimit: 100000, sizeLimit: '50000000' }} session={{ - endpoint: ApiUrls.ownership_loans_contract, + endpoint: ApiUrls.ownership_contract, customHeaders: { 'X-CSRFToken': getCookie(AppConstants.csrftoken) }, From ea52927eece978eca8f4ba7c8ad6b79147d0da54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 31 Aug 2015 11:33:44 +0200 Subject: [PATCH 174/397] rename uploading routes --- js/components/settings_container.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/settings_container.js b/js/components/settings_container.js index 44a24db9..d5821b7a 100644 --- a/js/components/settings_container.js +++ b/js/components/settings_container.js @@ -266,14 +266,14 @@ let FileUploader = React.createClass({ fileClass: 'contract' }} createBlobRoutine={{ - url: ApiUrls.ownership_contract + url: ApiUrls.blob_otherdatas }} validation={{ itemLimit: 100000, sizeLimit: '50000000' }} session={{ - endpoint: ApiUrls.ownership_contract, + endpoint: ApiUrls.blob_otherdatas, customHeaders: { 'X-CSRFToken': getCookie(AppConstants.csrftoken) }, From 7e1815bb1fb5c8328c07c028c700e1d0d38af789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 31 Aug 2015 16:36:24 +0200 Subject: [PATCH 175/397] refactor account settings into multiple files --- .../ascribe_settings/account_settings.js | 144 +++++++ .../ascribe_settings/api_settings.js | 124 ++++++ .../bitcoin_wallet_settings.js | 72 ++++ .../ascribe_settings/contract_settings.js | 79 ++++ .../ascribe_settings/settings_container.js | 36 ++ js/components/piece_list.js | 1 + js/components/settings_container.js | 408 ------------------ .../components/prize_settings_container.js | 2 +- .../whitelabel/wallet/wallet_routes.js | 2 +- js/routes.js | 2 +- 10 files changed, 459 insertions(+), 411 deletions(-) create mode 100644 js/components/ascribe_settings/account_settings.js create mode 100644 js/components/ascribe_settings/api_settings.js create mode 100644 js/components/ascribe_settings/bitcoin_wallet_settings.js create mode 100644 js/components/ascribe_settings/contract_settings.js create mode 100644 js/components/ascribe_settings/settings_container.js delete mode 100644 js/components/settings_container.js diff --git a/js/components/ascribe_settings/account_settings.js b/js/components/ascribe_settings/account_settings.js new file mode 100644 index 00000000..b4d46b2d --- /dev/null +++ b/js/components/ascribe_settings/account_settings.js @@ -0,0 +1,144 @@ +'use strict'; + +import React from 'react'; + +import UserStore from '../../stores/user_store'; +import UserActions from '../../actions/user_actions'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; +import InputCheckbox from '../ascribe_forms/input_checkbox'; +import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph'; + +import ApiUrls from '../../constants/api_urls'; +import AppConstants from '../../constants/application_constants'; + +import { getLangText } from '../../utils/lang_utils'; + +let AccountSettings = React.createClass({ + getInitialState() { + return UserStore.getState(); + }, + + componentDidMount() { + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + }, + + componentWillUnmount() { + UserStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleSuccess(){ + UserActions.fetchCurrentUser(); + let notification = new GlobalNotificationModel(getLangText('Settings succesfully updated'), 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getFormDataProfile(){ + return {'email': this.state.currentUser.email}; + }, + + render() { + let content = ; + let profile = null; + + if (this.state.currentUser.username) { + content = ( + + + + + + + +
    + + ); + profile = ( +
    + + + + {' ' + getLangText('Enable hash option, e.g. slow connections or to keep piece private')} + + + +
    + {/* + + */} +
    + ); + } + return ( + + {content} + {profile} + {/*
    + + + +
    +
    */} +
    + ); + } +}); + +export default AccountSettings; \ No newline at end of file diff --git a/js/components/ascribe_settings/api_settings.js b/js/components/ascribe_settings/api_settings.js new file mode 100644 index 00000000..7908b42a --- /dev/null +++ b/js/components/ascribe_settings/api_settings.js @@ -0,0 +1,124 @@ +'use strict'; + +import React from 'react'; + +import ApplicationStore from '../../stores/application_store'; +import ApplicationActions from '../../actions/application_actions'; + +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import ActionPanel from '../ascribe_panel/action_panel'; +import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph'; + +import ApiUrls from '../../constants/api_urls'; +import AppConstants from '../../constants/application_constants'; + +import { getLangText } from '../../utils/lang_utils'; + + +let APISettings = React.createClass({ + propTypes: { + defaultExpanded: React.PropTypes.bool + }, + + getInitialState() { + return ApplicationStore.getState(); + }, + + componentDidMount() { + ApplicationStore.listen(this.onChange); + ApplicationActions.fetchApplication(); + }, + + componentWillUnmount() { + ApplicationStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + handleCreateSuccess() { + ApplicationActions.fetchApplication(); + let notification = new GlobalNotificationModel(getLangText('Application successfully created'), 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + handleTokenRefresh(event) { + let applicationName = event.target.getAttribute('data-id'); + ApplicationActions.refreshApplicationToken(applicationName); + + let notification = new GlobalNotificationModel(getLangText('Token refreshed'), 'success', 2000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + getApplications(){ + let content = ; + + if (this.state.applications.length > -1) { + content = this.state.applications.map(function(app, i) { + return ( + +
    + {app.name} +
    +
    + {'Bearer ' + app.bearer_token.token} +
    +
    + } + buttons={ +
    +
    + +
    +
    + }/> + ); + }, this); + } + return content; + }, + + render() { + return ( + +
    + + + +
    +
    +
    +                    Usage: curl <url> -H 'Authorization: Bearer <token>'
    +                
    + {this.getApplications()} +
    + ); + } +}); + +export default APISettings; \ No newline at end of file diff --git a/js/components/ascribe_settings/bitcoin_wallet_settings.js b/js/components/ascribe_settings/bitcoin_wallet_settings.js new file mode 100644 index 00000000..18646d75 --- /dev/null +++ b/js/components/ascribe_settings/bitcoin_wallet_settings.js @@ -0,0 +1,72 @@ +'use strict'; + +import React from 'react'; + +import WalletSettingsStore from '../../stores/wallet_settings_store'; +import WalletSettingsActions from '../../actions/wallet_settings_actions'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph'; + +import AppConstants from '../../constants/application_constants'; + +import { getLangText } from '../../utils/lang_utils'; + + +let BitcoinWalletSettings = React.createClass({ + propTypes: { + defaultExpanded: React.PropTypes.bool + }, + + getInitialState() { + return WalletSettingsStore.getState(); + }, + + componentDidMount() { + WalletSettingsStore.listen(this.onChange); + WalletSettingsActions.fetchWalletSettings(); + }, + + componentWillUnmount() { + WalletSettingsStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + let content = ; + + if (this.state.walletSettings.btc_public_key) { + content = ( +
    + +
    {this.state.walletSettings.btc_public_key}
    +
    + +
    {this.state.walletSettings.btc_root_address}
    +
    +
    +
    ); + } + return ( + + {content} + + ); + } +}); + +export default BitcoinWalletSettings; \ No newline at end of file diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js new file mode 100644 index 00000000..1730fe08 --- /dev/null +++ b/js/components/ascribe_settings/contract_settings.js @@ -0,0 +1,79 @@ +'use strict'; + +import React from 'react'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph'; + +import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; + +import AppConstants from '../../constants/application_constants'; +import ApiUrls from '../../constants/api_urls'; + +import { getCookie } from '../../utils/fetch_api_utils'; +import { getLangText } from '../../utils/lang_utils'; + + +let ContractSettings = React.createClass({ + propTypes: { + defaultExpanded: React.PropTypes.bool + }, + + render() { + return ( + +
    + + + +
    +
    +
    + ); + } +}); + +export default ContractSettings; \ No newline at end of file diff --git a/js/components/ascribe_settings/settings_container.js b/js/components/ascribe_settings/settings_container.js new file mode 100644 index 00000000..485b26d7 --- /dev/null +++ b/js/components/ascribe_settings/settings_container.js @@ -0,0 +1,36 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; + +import AccountSettings from './account_settings'; +import BitcoinWalletSettings from './bitcoin_wallet_settings'; +import ContractSettings from './contract_settings'; +import APISettings from './api_settings'; + + +let SettingsContainer = React.createClass({ + propTypes: { + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element]) + }, + + mixins: [Router.Navigation], + + render() { + return ( +
    + + {this.props.children} + + + +
    +
    +
    + ); + } +}); + +export default SettingsContainer; diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 79f1471c..02286374 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -60,6 +60,7 @@ let PieceList = React.createClass({ PieceListStore.listen(this.onChange); EditionListStore.listen(this.onChange); + let orderBy = this.props.orderBy ? this.props.orderBy : this.state.orderBy; if (this.state.pieceList.length === 0 || this.state.page !== page){ PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, diff --git a/js/components/settings_container.js b/js/components/settings_container.js deleted file mode 100644 index d5821b7a..00000000 --- a/js/components/settings_container.js +++ /dev/null @@ -1,408 +0,0 @@ -'use strict'; - -import React from 'react'; -import Router from 'react-router'; - -import UserActions from '../actions/user_actions'; -import UserStore from '../stores/user_store'; - -import WalletSettingsActions from '../actions/wallet_settings_actions'; -import WalletSettingsStore from '../stores/wallet_settings_store'; - -import ApplicationActions from '../actions/application_actions'; -import ApplicationStore from '../stores/application_store'; - -import GlobalNotificationModel from '../models/global_notification_model'; -import GlobalNotificationActions from '../actions/global_notification_actions'; - -import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader'; - -import CollapsibleParagraph from './ascribe_collapsible/collapsible_paragraph'; -import Form from './ascribe_forms/form'; -import Property from './ascribe_forms/property'; -import InputCheckbox from './ascribe_forms/input_checkbox'; - -import ActionPanel from './ascribe_panel/action_panel'; - -import ApiUrls from '../constants/api_urls'; -import AppConstants from '../constants/application_constants'; - -import { getLangText } from '../utils/lang_utils'; -import { getCookie } from '../utils/fetch_api_utils'; - -let SettingsContainer = React.createClass({ - propTypes: { - children: React.PropTypes.oneOfType([ - React.PropTypes.arrayOf(React.PropTypes.element), - React.PropTypes.element]) - }, - - mixins: [Router.Navigation], - - render() { - return ( -
    - - {this.props.children} - - - -
    -
    -
    - ); - } -}); - - -let AccountSettings = React.createClass({ - getInitialState() { - return UserStore.getState(); - }, - - componentDidMount() { - UserStore.listen(this.onChange); - UserActions.fetchCurrentUser(); - }, - - componentWillUnmount() { - UserStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - handleSuccess(){ - UserActions.fetchCurrentUser(); - let notification = new GlobalNotificationModel(getLangText('Settings succesfully updated'), 'success', 5000); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - getFormDataProfile(){ - return {'email': this.state.currentUser.email}; - }, - - render() { - let content = ; - let profile = null; - - if (this.state.currentUser.username) { - content = ( -
    - - - - - - -
    -
    - ); - profile = ( -
    - - - - {' ' + getLangText('Enable hash option, e.g. slow connections or to keep piece private')} - - - -
    - {/* - - */} -
    - ); - } - return ( - - {content} - {profile} - {/*
    - - - -
    -
    */} -
    - ); - } -}); - - - -let BitcoinWalletSettings = React.createClass({ - - propTypes: { - defaultExpanded: React.PropTypes.bool - }, - - getInitialState() { - return WalletSettingsStore.getState(); - }, - - componentDidMount() { - WalletSettingsStore.listen(this.onChange); - WalletSettingsActions.fetchWalletSettings(); - }, - - componentWillUnmount() { - WalletSettingsStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - render() { - let content = ; - if (this.state.walletSettings.btc_public_key) { - content = ( -
    - -
    {this.state.walletSettings.btc_public_key}
    -
    - -
    {this.state.walletSettings.btc_root_address}
    -
    -
    -
    ); - } - return ( - - {content} - - ); - } -}); - -let ContractSettings = React.createClass({ - propTypes: { - defaultExpanded: React.PropTypes.bool - }, - - render() { - return ( - - - - ); - } -}); - -let FileUploader = React.createClass({ - propTypes: { - }, - - render() { - return ( -
    - - - -
    -
    - ); - } -}); - -let APISettings = React.createClass({ - propTypes: { - defaultExpanded: React.PropTypes.bool - }, - - getInitialState() { - return ApplicationStore.getState(); - }, - - componentDidMount() { - ApplicationStore.listen(this.onChange); - ApplicationActions.fetchApplication(); - }, - - componentWillUnmount() { - ApplicationStore.unlisten(this.onChange); - }, - - onChange(state) { - this.setState(state); - }, - - handleCreateSuccess() { - ApplicationActions.fetchApplication(); - let notification = new GlobalNotificationModel(getLangText('Application successfully created'), 'success', 5000); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - handleTokenRefresh(event) { - let applicationName = event.target.getAttribute('data-id'); - ApplicationActions.refreshApplicationToken(applicationName); - - let notification = new GlobalNotificationModel(getLangText('Token refreshed'), 'success', 2000); - GlobalNotificationActions.appendGlobalNotification(notification); - }, - - getApplications(){ - let content = ; - if (this.state.applications.length > -1) { - content = this.state.applications.map(function(app, i) { - return ( - -
    - {app.name} -
    -
    - {'Bearer ' + app.bearer_token.token} -
    -
    - } - buttons={ -
    -
    - -
    -
    - }/> - ); - }, this); - } - return content; - }, - - render() { - return ( - -
    - - - -
    -
    -
    -                    Usage: curl <url> -H 'Authorization: Bearer <token>'
    -                
    - {this.getApplications()} -
    - ); - } -}); - -export default SettingsContainer; diff --git a/js/components/whitelabel/prize/components/prize_settings_container.js b/js/components/whitelabel/prize/components/prize_settings_container.js index f81e7078..86d0f77d 100644 --- a/js/components/whitelabel/prize/components/prize_settings_container.js +++ b/js/components/whitelabel/prize/components/prize_settings_container.js @@ -9,7 +9,7 @@ import PrizeStore from '../stores/prize_store'; import PrizeJuryActions from '../actions/prize_jury_actions'; import PrizeJuryStore from '../stores/prize_jury_store'; -import SettingsContainer from '../../../settings_container'; +import SettingsContainer from '../../../ascribe_settings/settings_container'; import CollapsibleParagraph from '../../../ascribe_collapsible/collapsible_paragraph'; import Form from '../../../ascribe_forms/form'; diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 1a32f46f..1c4ef4a7 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -11,7 +11,7 @@ import PasswordResetContainer from '../../../components/password_reset_container import PieceList from '../../../components/piece_list'; import PieceContainer from '../../../components/ascribe_detail/piece_container'; import EditionContainer from '../../../components/ascribe_detail/edition_container'; -import SettingsContainer from '../../../components/settings_container'; +import SettingsContainer from '../../../components/ascribe_settings/settings_container'; import RegisterPiece from '../../../components/register_piece'; import CylandLanding from './components/cyland/cyland_landing'; diff --git a/js/routes.js b/js/routes.js index f76e4b45..2762052b 100644 --- a/js/routes.js +++ b/js/routes.js @@ -17,7 +17,7 @@ import LogoutContainer from './components/logout_container'; import SignupContainer from './components/signup_container'; import PasswordResetContainer from './components/password_reset_container'; -import SettingsContainer from './components/settings_container'; +import SettingsContainer from './components/ascribe_settings/settings_container'; import CoaVerifyContainer from './components/coa_verify_container'; import RegisterPiece from './components/register_piece'; From 55948bc9ba0ba964b038db8181721ebd5a786d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 31 Aug 2015 16:57:16 +0200 Subject: [PATCH 176/397] integrate unfilteredPieceListCount into piece list store and list --- js/actions/piece_list_actions.js | 10 ++++++---- js/components/piece_list.js | 2 +- js/stores/piece_list_store.js | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 1ebe7f42..2fd15c04 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -25,8 +25,9 @@ class PieceListActions { orderBy, orderAsc, filterBy, - 'pieceList': [], - 'pieceListCount': -1 + pieceList: [], + pieceListCount: -1, + unfilteredPieceListCount: -1 }); // afterwards, we can load the list @@ -42,8 +43,9 @@ class PieceListActions { orderBy, orderAsc, filterBy, - 'pieceList': res.pieces, - 'pieceListCount': res.count + pieceList: res.pieces, + pieceListCount: res.count, + unfilteredPieceListCount: res.unfiltered_count }); resolve(); }) diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 79f1471c..466f3ad3 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -69,7 +69,7 @@ let PieceList = React.createClass({ }, componentDidUpdate() { - if (this.props.redirectTo && this.state.pieceListCount === 0) { + if (this.props.redirectTo && this.state.unfilteredPieceListCount === 0) { // FIXME: hack to redirect out of the dispatch cycle window.setTimeout(() => this.transitionTo(this.props.redirectTo), 0); } diff --git a/js/stores/piece_list_store.js b/js/stores/piece_list_store.js index c1622d99..bc2bba24 100644 --- a/js/stores/piece_list_store.js +++ b/js/stores/piece_list_store.js @@ -21,6 +21,7 @@ class PieceListStore { this.pieceList = []; // -1 specifies that the store is currently loading this.pieceListCount = -1; + this.unfilteredPieceListCount = -1; this.page = 1; this.pageSize = 10; this.search = ''; @@ -30,13 +31,14 @@ class PieceListStore { this.bindActions(PieceListActions); } - onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount, filterBy }) { + onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount, unfilteredPieceListCount, filterBy }) { this.page = page; this.pageSize = pageSize; this.search = search; this.orderAsc = orderAsc; this.orderBy = orderBy; this.pieceListCount = pieceListCount; + this.unfilteredPieceListCount = unfilteredPieceListCount; this.filterBy = filterBy; /** From 96fdb598f76f65229fa800cbab6cac2dbc6e5682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 31 Aug 2015 17:29:43 +0200 Subject: [PATCH 177/397] change api endpoints to contractblobs --- js/components/ascribe_forms/form_contract.js | 2 +- js/components/ascribe_settings/contract_settings.js | 4 ++-- js/components/ascribe_uploader/react_s3_fine_uploader.js | 3 +++ js/constants/api_urls.js | 3 ++- js/fetchers/ownership_fetcher.js | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/js/components/ascribe_forms/form_contract.js b/js/components/ascribe_forms/form_contract.js index d4e58c79..4c51e7a3 100644 --- a/js/components/ascribe_forms/form_contract.js +++ b/js/components/ascribe_forms/form_contract.js @@ -92,7 +92,7 @@ let ContractForm = React.createClass({
    Date: Mon, 31 Aug 2015 18:05:14 +0200 Subject: [PATCH 179/397] disable browsersync ghostmode by default --- gulpfile.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 236bd88c..c7816a3a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -48,8 +48,7 @@ var config = { }, filesToWatch: [ 'build/css/*.css', - 'build/js/*.js', - 'node_modules/react-s3-fine_uploader/*.js' + 'build/js/*.js' ] }; @@ -73,6 +72,8 @@ gulp.task('js:build', function() { gulp.task('serve', ['browser-sync', 'run-server', 'sass:build', 'sass:watch', 'copy'], function() { bundle(true); + + // opens the browser window with the correct url, which is localhost.com opn('http://www.localhost.com:3000'); }); @@ -95,7 +96,8 @@ gulp.task('browser-sync', function() { files: config.filesToWatch, proxy: 'http://localhost:4000', port: 3000, - open: false + open: false, // does not open the browser-window anymore (handled manually) + ghostMode: false }); }); From 99af814492c78aa053cc0a7d8bcf8087a99d92fe Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 31 Aug 2015 19:04:44 +0200 Subject: [PATCH 180/397] Lint scss --- .scss-lint.yml | 224 ++++++++++++++++ sass/ascribe_accordion_list.scss | 150 ++++++----- sass/ascribe_edition.scss | 46 ++-- sass/ascribe_footer.scss | 58 ++-- sass/ascribe_form.scss | 23 +- sass/ascribe_global_notification.scss | 49 ++-- sass/ascribe_login.scss | 127 ++++----- sass/ascribe_media_player.scss | 77 +++--- sass/ascribe_panel.scss | 19 +- sass/ascribe_piece_list_bulk_modal.scss | 27 +- sass/ascribe_piece_list_toolbar.scss | 36 ++- sass/ascribe_piece_register.scss | 21 +- sass/ascribe_settings.scss | 170 ++++++------ sass/ascribe_slides_container.scss | 25 +- sass/ascribe_table.scss | 44 ++- sass/ascribe_textarea.scss | 25 +- sass/ascribe_theme.scss | 8 +- sass/ascribe_uploader.scss | 145 +++++----- sass/ascribe_variables.scss | 2 +- sass/main.scss | 268 +++++++++++-------- sass/offset_right.scss | 340 ++++++++++++++---------- sass/variables.scss | 12 +- 22 files changed, 1117 insertions(+), 779 deletions(-) create mode 100644 .scss-lint.yml diff --git a/.scss-lint.yml b/.scss-lint.yml new file mode 100644 index 00000000..6d4fd6ba --- /dev/null +++ b/.scss-lint.yml @@ -0,0 +1,224 @@ +linters: + BangFormat: + enabled: true + space_before_bang: true + space_after_bang: false + + BemDepth: + enabled: false + max_elements: 1 + + BorderZero: + enabled: true + convention: zero # or `none` + + ColorKeyword: + enabled: true + + ColorVariable: + enabled: true + + Comment: + enabled: true + + DebugStatement: + enabled: true + + DeclarationOrder: + enabled: true + + DisableLinterReason: + enabled: false + + DuplicateProperty: + enabled: true + + ElsePlacement: + enabled: true + style: same_line # or 'new_line' + + EmptyLineBetweenBlocks: + enabled: true + ignore_single_line_blocks: true + + EmptyRule: + enabled: true + + ExtendDirective: + enabled: false + + FinalNewline: + enabled: true + present: true + + HexLength: + enabled: true + style: short # or 'long' + + HexNotation: + enabled: true + style: lowercase # or 'uppercase' + + HexValidation: + enabled: true + + IdSelector: + enabled: true + + ImportantRule: + enabled: true + + ImportPath: + enabled: true + leading_underscore: false + filename_extension: false + + Indentation: + enabled: true + allow_non_nested_indentation: false + character: space # or 'tab' + width: 4 + + LeadingZero: + enabled: true + style: exclude_zero # or 'include_zero' + + MergeableSelector: + enabled: true + force_nesting: true + + NameFormat: + enabled: true + allow_leading_underscore: true + convention: hyphenated_lowercase # or 'camel_case', or 'snake_case', or a regex pattern + + NestingDepth: + enabled: true + max_depth: 3 + ignore_parent_selectors: false + + PlaceholderInExtend: + enabled: true + + PropertyCount: + enabled: false + include_nested: false + max_properties: 10 + + PropertySortOrder: + enabled: true + ignore_unspecified: false + min_properties: 2 + separate_groups: false + + PropertySpelling: + enabled: true + extra_properties: [] + + PropertyUnits: + enabled: true + global: [ + 'ch', 'em', 'ex', 'rem', # Font-relative lengths + 'cm', 'in', 'mm', 'pc', 'pt', 'px', 'q', # Absolute lengths + 'vh', 'vw', 'vmin', 'vmax', # Viewport-percentage lengths + 'deg', 'grad', 'rad', 'turn', # Angle + 'ms', 's', # Duration + 'Hz', 'kHz', # Frequency + 'dpi', 'dpcm', 'dppx', # Resolution + '%'] # Other + properties: {} + + QualifyingElement: + enabled: true + allow_element_with_attribute: false + allow_element_with_class: false + allow_element_with_id: false + + SelectorDepth: + enabled: true + max_depth: 3 + + SelectorFormat: + enabled: true + convention: hyphenated_lowercase # or 'strict_BEM', or 'hyphenated_BEM', or 'snake_case', or 'camel_case', or a regex pattern + + Shorthand: + enabled: true + allowed_shorthands: [1, 2, 3] + + SingleLinePerProperty: + enabled: true + allow_single_line_rule_sets: true + + SingleLinePerSelector: + enabled: true + + SpaceAfterComma: + enabled: true + + SpaceAfterPropertyColon: + enabled: true + style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned' + + SpaceAfterPropertyName: + enabled: true + + SpaceAfterVariableName: + enabled: true + + SpaceAroundOperator: + enabled: true + style: one_space # or 'no_space' + + SpaceBeforeBrace: + enabled: true + style: space # or 'new_line' + allow_single_line_padding: false + + SpaceBetweenParens: + enabled: true + spaces: 0 + + StringQuotes: + enabled: true + style: single_quotes # or double_quotes + + TrailingSemicolon: + enabled: true + + TrailingWhitespace: + enabled: true + + TrailingZero: + enabled: false + + TransitionAll: + enabled: false + + UnnecessaryMantissa: + enabled: true + + UnnecessaryParentReference: + enabled: true + + UrlFormat: + enabled: true + + UrlQuotes: + enabled: true + + VariableForProperty: + enabled: false + properties: [] + + VendorPrefix: + enabled: false + identifier_list: base + additional_identifiers: [] + excluded_identifiers: [] + + ZeroUnit: + enabled: true + + Compass::*: + enabled: false diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss index 1ef4bef9..4b4186eb 100644 --- a/sass/ascribe_accordion_list.scss +++ b/sass/ascribe_accordion_list.scss @@ -1,5 +1,4 @@ $ascribe-accordion-list-item-height: 8em; -$ascribe-accordion-list-font: 'Source Sans Pro'; .ascribe-accordion-list { padding-left: 15px; @@ -11,68 +10,77 @@ $ascribe-accordion-list-font: 'Source Sans Pro'; border: 1px solid black; height: $ascribe-accordion-list-item-height; - padding-left:0; - padding-right:0; + padding-left: 0; + padding-right: 0; margin-top: 1.5em; + overflow: hidden; + + border-radius: 1px; + border-left: .1em solid rgba(0, 0, 0, .2); + border-right: .1em solid rgba(0, 0, 0, .2); + border-top: .1em solid rgba(0, 0, 0, .2); + border-bottom: .1em solid rgba(0, 0, 0, .2); + &::first-child { - margin-top:0; + margin-top: 0; } - overflow:hidden; - - border-left: 0.1em solid rgba(0,0,0,.2); - border-right: 0.1em solid rgba(0,0,0,.2); - border-top: 0.1em solid rgba(0,0,0,.2); - border-radius: 1px; - border-bottom: 0.1em solid rgba(0,0,0,.2); .wrapper { - &:hover{ - background-color: rgba(2, 182, 163, 0.05); + height: 100%; + width: 100%; + + &:hover { + background-color: rgba(2, 182, 163, .05); } - width:100%; - height:100%; + // ToDo: Include media queries for thumbnail .thumbnail-wrapper { - width: 110px; + cursor: pointer; height: 110px; - padding:0; - cursor: pointer; + padding: 0; text-align: center; + width: 110px; + img { - max-width: 100%; max-height: 100%; + max-width: 100%; } + &::before { - content: ' '; - display: inline-block; - vertical-align: middle; /* vertical alignment of the inline element */ - height: 100%; - } + content: ' '; + display: inline-block; + height: 100%; + vertical-align: middle; // vertical alignment of the inline element + } } + h1 { - margin: .1em 0 .1em 0; + cursor: pointer; font-size: 2.2em; - cursor: pointer; - white-space: nowrap; + margin: .1em 0; overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; } + h3 { - font-size: 1.3em; - margin: .2em 0 .3em 0; cursor: pointer; - white-space: nowrap; + font-size: 1.3em; + margin: .2em 0 .3em; overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; } + a:not(.btn) { color: #666; } + } } .accordion-list-item-header { - margin-top:.65em; + margin-top: .65em; > a { text-decoration: none; @@ -85,46 +93,47 @@ $ascribe-accordion-list-font: 'Source Sans Pro'; } .ascribe-accordion-list-item-table { - font-size: .9em; - text-align: center; background-color: white; - - //border-bottom-left-radius: 1px; - //border-bottom-right-radius: 1px; - border-bottom: 0.1em solid rgba(0,0,0,.15); - border-left: 0.1em solid rgba(0,0,0,.2); - border-right: 0.1em solid rgba(0,0,0,.2); + border-bottom: .1em solid rgba(0, 0, 0, .15); + border-left: .1em solid rgba(0, 0, 0, .2); + border-right: .1em solid rgba(0, 0, 0, .2); + font-size: .9em; padding: 0; + text-align: center; + thead:first-child { + border-bottom: 1px solid rgba(0, 0, 0, .05); + border-left: 3px solid rgba(0, 0, 0, 0); + tr:first-child { - border: none! important; + border: none !important; th { + border: none !important; padding-left: 10px; - border: none! important; } } - border-left: 3px solid rgba(0,0,0,0); - //border-top: 1px solid rgba(0,0,0,.1); - border-bottom: 1px solid rgba(0,0,0,.05); } + tbody { tr { + border-bottom: 1px solid rgba(0, 0, 0, .03); + border-left: 3px solid rgba(0, 0, 0, 0); padding: 1em; - &:hover{ + + &:hover { background-color: rgba(2, 182, 163, 0.05); border-left: 3px solid rgba(2, 182, 163, 0.4); } - border-left: 3px solid rgba(0,0,0,0); - border-bottom: 1px solid rgba(0,0,0,.03); - td { - border: none! important; - a { - color: #444 - } + td { + border: none !important; + a { + color: #444; + } } } - tr{ + + tr { td:first-child { margin-left: 10px; } @@ -132,48 +141,51 @@ $ascribe-accordion-list-font: 'Source Sans Pro'; } } -span.ascribe-accordion-list-table-toggle { - -webkit-user-select: none; - -moz-user-select: none; +.ascribe-accordion-list-table-toggle { -khtml-user-select: none; + -moz-user-select: none; -ms-user-select: none; - + -webkit-user-select: none; + &:hover { color: $ascribe-color-green; - cursor:pointer; + cursor: pointer; } } .ascribe-accordion-list-table-list { margin-bottom: .5em; - th, td { - font-size:.85em; - text-align: center; + + th, + td { + font-size: .85em; + text-align: center; } } .request-action-badge { - position: absolute; - top: 0px; - right: 0px; color: $ascribe-color-green; font-size: 1.2em; - padding: 0.3em; + padding: .3em; + position: absolute; + right: 0; + top: 0; } .ascribe-accordion-list-item-edition-widget { cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; -khtml-user-select: none; + -moz-user-select: none; -ms-user-select: none; + -webkit-user-select: none; &:hover { color: $ascribe-color-green; } + .glyphicon { + font-size: .8em; top: 1px !important; - font-size: 0.8em; } -} \ No newline at end of file +} diff --git a/sass/ascribe_edition.scss b/sass/ascribe_edition.scss index fe647e2d..f86f74e2 100644 --- a/sass/ascribe_edition.scss +++ b/sass/ascribe_edition.scss @@ -5,46 +5,48 @@ .ascribe-edition-collapsible-wrapper { vertical-align: bottom; - width:100%; -} - -.ascribe-edition-collapsible-wrapper > div:first-child { width: 100%; - cursor: pointer; - background-color: rgba(0,0,0,0); - padding: 0 10px 10px 0; - margin-top: 20px; -} -.ascribe-edition-collapsible-wrapper > div > span { - font-size: 1.2em; - margin-right: .5em; -} -.ascribe-edition-collapsible-wrapper > div > span:nth-child(2) { - font-size: 0.9em; + + > div:first-child { + background-color: rgba(0, 0, 0, 0); + cursor: pointer; + margin-top: 20px; + padding: 0 10px 10px 0; + width: 100%; + } + + > div > span { + font-size: 1.2em; + margin-right: .5em; + } + + > div > span:nth-child(2) { + font-size: .9em; + } } .ascribe-edition-collapsible-content { - width:100%; background: none; - border: none; + border: 0; + width: 100%; } .coa-file-wrapper { display: table; height: 200px; - overflow: hidden; margin: 0 auto; - width: 100%; + overflow: hidden; padding: 1em; + width: 100%; } .coa-file { + background-color: #F8F8F8; + border: 1px solid #CCC; display: table-cell; vertical-align: middle; - border: 1px solid #CCC; - background-color: #F8F8F8; } .ascribe-button-list { margin-top: 1em; -} \ No newline at end of file +} diff --git a/sass/ascribe_footer.scss b/sass/ascribe_footer.scss index e51443be..fe52b798 100644 --- a/sass/ascribe_footer.scss +++ b/sass/ascribe_footer.scss @@ -1,17 +1,32 @@ .ascribe-footer { text-align: center; -} -.ascribe-footer hr { - border: 0; - border-top: 1px solid #eee; - background-color: rgba(0,0,0,0); - margin-bottom: 0 !important; -} + hr { + background-color: rgba(0, 0, 0, 0); + border-top: 1px solid #eee; + border: 0; + margin-bottom: 0 !important; + } + + .btn-ascribe-landing { + margin-top: 2em; + } + + .social-icons-wrapper { + margin-top: 1em; + + a { + color: #424242; + font-size: 1.3em; + margin-left: 1em; + } + + a:hover { + color: #48DACB; + } + } -.ascribe-footer .btn-ascribe-landing { - margin-top: 2em; } .ascribe-footer-statement { @@ -21,7 +36,8 @@ margin-top: 0; } -.ascribe-footer-statement a, .ascribe-footer-sub-statement a { +.ascribe-footer-statement a, +.ascribe-footer-sub-statement a { color: #424242; } @@ -30,23 +46,7 @@ margin-bottom: 2.5em; } -.ascribe-footer-statement a, .ascribe-footer-sub-statement a { - color: #424242; +.ascribe-footer-statement a:hover, +.ascribe-footer-sub-statement a:hover { + color: #48dacb; } -.ascribe-footer-statement a:hover, .ascribe-footer-sub-statement a:hover { - color: #48DACB; -} - -.ascribe-footer .social-icons-wrapper { - margin-top: 1em; -} - -.ascribe-footer .social-icons-wrapper a { - color: #424242; - margin-left: 1em; - font-size: 1.3em; -} - -.ascribe-footer .social-icons-wrapper a:hover { - color: #48DACB; -} \ No newline at end of file diff --git a/sass/ascribe_form.scss b/sass/ascribe_form.scss index d2802ee8..41e17de1 100644 --- a/sass/ascribe_form.scss +++ b/sass/ascribe_form.scss @@ -1,25 +1,26 @@ .ascribe-form-bordered { - border: 1px solid #F5F5F5; + border: 1px solid #f5f5f5; } .ascribe-form-header { - padding-bottom: 0; - margin-bottom: 0; background-color: white; -} - -.ascribe-form-header > h3 { - padding: .75em 0 .75em 1em; - margin-top: 0; margin-bottom: 0; - color: #616161; + padding-bottom: 0; + + > h3 { + color: #616161; + margin-bottom: 0; + margin-top: 0; + padding: .75em 0 .75em 1em; + } } .ascribe-form-wrapper { - width: 80%; margin: 0 auto; max-width: 600px; + width: 80%; + @media (max-width: 550px) { width: 100%; } -} \ No newline at end of file +} diff --git a/sass/ascribe_global_notification.scss b/sass/ascribe_global_notification.scss index 527b1f06..5286a32c 100644 --- a/sass/ascribe_global_notification.scss +++ b/sass/ascribe_global_notification.scss @@ -1,14 +1,12 @@ .ascribe-global-notification { - position: fixed; - background-color: #212121; color: white; + display: table; + height: 3.5em; + left: 0; + position: fixed; + transition: .2s bottom cubic-bezier(.77, 0, .175, 1); width: 100%; - height:3.5em; - left:0; - display:table; - - transition: .2s bottom cubic-bezier(0.77, 0, 0.175, 1); } .ascribe-global-notification-off { @@ -19,34 +17,29 @@ bottom: 0; } -.ascribe-global-notification > div, .ascribe-global-notification-bubble > div { - display:table-cell; - vertical-align: middle; - font-size: 1.25em; - font-family: 'Source Sans Pro'; - text-align: right; - padding-right: 3em; -} - +.ascribe-global-notification > div, .ascribe-global-notification-bubble > div { - padding: .75em 1.5em .75em 1.5em; + display: table-cell; + font-size: 1.25em; + padding-right: 3em; + text-align: right; + vertical-align: middle; } .ascribe-global-notification-bubble { - position: fixed; - bottom: 3em; - right: -50em; - - display:table; - - height: 3.5em; - background-color: #212121; border-radius: 2px; - + bottom: 3em; color: white; - + display: table; + height: 3.5em; + position: fixed; + right: -50em; transition: 1s right ease; + + > div { + padding: .75em 1.5em; + } } .ascribe-global-notification-bubble-off { @@ -63,4 +56,4 @@ .ascribe-global-notification-success { background-color: rgba(2, 182, 163, 1); -} \ No newline at end of file +} diff --git a/sass/ascribe_login.scss b/sass/ascribe_login.scss index 9ff2857f..9060fee5 100644 --- a/sass/ascribe_login.scss +++ b/sass/ascribe_login.scss @@ -2,84 +2,91 @@ $break-small: 764px; .ascribe-btn-login { - padding: 0.5em; - font-weight: 500; - text-align: center; - background-color: rgba(2, 182, 163, 1); - color: white; - font-size: 1.2em; - border-radius: 0; - width: 100%; - border:none; - //margin-left: 1.2em; - - &:hover { - color: white; - background-color: rgba(2, 182, 163, 0.8); + background-color: rgba(2, 182, 163, 1); border: none; - } - &:active, &:focus { + border-radius: 0; color: white; - background-color: rgba(2, 182, 163, 0.6); - border: none; - } + font-size: 1.2em; + font-weight: 500; + padding: .5em; + text-align: center; + width: 100%; + //margin-left: 1.2em; - &[disabled] { - opacity: .3; - } + &:hover { + background-color: rgba(2, 182, 163, .8); + border: 0; + color: white; + } + + &:active, + &:focus { + background-color: rgba(2, 182, 163, .6); + border: 0; + color: white; + } + + &[disabled] { + opacity: .3; + } } -.ascribe-btn-login-spinner{ - background-color: rgba(2, 182, 163, 0.4); - padding: 0.4em; - img { - height: 1.6em; - } - &:hover { - background-color: rgba(2, 182, 163, 0.4); - } - &:active, &:focus { - background-color: rgba(2, 182, 163, 0.4); - } +.ascribe-btn-login-spinner { + background-color: rgba(2, 182, 163, .4); + padding: .4em; + + img { + height: 1.6em; + } + + &:hover { + background-color: rgba(2, 182, 163, .4); + } + + &:active, + &:focus { + background-color: rgba(2, 182, 163, .4); + } } .ascribe-login-wrapper { - width: 80%; - margin: 0 auto; - max-width: 600px; - @media screen and (max-width: $break-small) { - width: 100%; - } + margin: 0 auto; + max-width: 600px; + width: 80%; + + @media screen and (max-width: $break-small) { + width: 100%; + } } .ascribe-login-text { - font-size: 0.8em; - padding: 0 0 1em 0; - margin-left: 0.4em; - margin-top: 1.5em; - color: rgba(0, 0, 0, 0.6); + color: rgba(0, 0, 0, .6); + font-size: .8em; + margin-left: .4em; + margin-top: 1.5em; + padding: 0 0 1em; } .ascribe-login-header { - font-size: 2em; - margin-left: 0.8em; + font-size: 2em; + margin-left: .8em; } .ascribe-form { - hr { - color: rgba(0, 0, 0, 0.05); - border: none; - height: 1px; - background-color: rgba(0, 0, 0, 0.05); - margin-top: 0; - } + hr { + background-color: rgba(0, 0, 0, .05); + border: 0; + color: rgba(0, 0, 0, .05); + height: 1px; + margin-top: 0; + } } %vertical-align { - position: relative; - top: 50%; - -webkit-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} \ No newline at end of file + position: relative; + top: 50%; + -ms-transform: translateY(-50%); + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} diff --git a/sass/ascribe_media_player.scss b/sass/ascribe_media_player.scss index f3b87618..6a70ad4d 100644 --- a/sass/ascribe_media_player.scss +++ b/sass/ascribe_media_player.scss @@ -3,35 +3,35 @@ video, img { - max-width: 100%; - max-height: 640px; - width: auto; - height: auto; display: block; + height: auto; margin: 0 auto; + max-height: 640px; + max-width: 100%; + width: auto; } .media-other { - font-size: 500%; color: #cccccc; + font-size: 500%; } .audiojs { + background-image: none; margin: 50px auto; - background-image: none; - } + * { + box-sizing: content-box; + } - .audiojs * { - box-sizing: content-box; - } + .loaded { + background-color: $ascribe-color-green; + background-image: none; + } - .audiojs .loaded { - background-color: $ascribe-color-green; - background-image: none; - } - .audiojs .progress { - background-color: rgba(255,255,255,0.8); - background-image: none; + .progress { + background-color: rgba(255, 255, 255, .8); + background-image: none; + } } .video-js, @@ -44,12 +44,13 @@ } .vjs-fullscreen { - padding-top: 0px; + padding-top: 0; + + video { + max-height: 100%; + } } - .vjs-fullscreen video { - max-height: 100%; - } .vjs-default-skin .vjs-play-progress, .vjs-default-skin .vjs-volume-level { @@ -57,41 +58,35 @@ } .vjs-default-skin .vjs-big-play-button { - border-radius: 6px; - -o-border-radius: 6px; + background-color: rgba(0, 0, 0, .8); + border: 0; -moz-border-radius: 6px; + -o-border-radius: 6px; -webkit-border-radius: 6px; - - box-shadow: none; - -o-box-shadow: none; + border-radius: 6px; -moz-box-shadow: none; + -o-box-shadow: none; -webkit-box-shadow: none; - - width: 100px; + box-shadow: none; height: 60px; - top: 50%; left: 50%; margin: -30px -50px; - - border: none; - - background-color: rgba(0,0,0,.8); + top: 50%; + width: 100px; } .vjs-default-skin:hover .vjs-big-play-button, .vjs-default-skin .vjs-big-play-button:focus { + background-color: rgba(0, 0, 0, .9); border-color: #fff; - background-color: rgba(0,0,0,.9); - - box-shadow: none; - -o-box-shadow: none; -moz-box-shadow: none; + -o-box-shadow: none; -webkit-box-shadow: none; - - transition: all 0s; - -o-transition: all 0s; + box-shadow: none; -moz-transition: all 0s; + -o-transition: all 0s; -webkit-transition: all 0s; + transition: all 0s; } .vjs-default-skin .vjs-big-play-button:before { @@ -108,7 +103,7 @@ } .vjs-default-skin .vjs-control-bar { - background-color: rgba(0,0,0,.7); + background-color: rgba(0, 0, 0, .7); } } diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss index 73fe572e..9d53b911 100644 --- a/sass/ascribe_panel.scss +++ b/sass/ascribe_panel.scss @@ -1,13 +1,12 @@ .ascribe-panel-wrapper { - border: 1px solid #DDD; - min-height: 5em; + border: 1px solid #ddd; height: 5em; - margin-top: 1em; + min-height: 5em; > div { - height: 100%; float: left; + height: 100%; &:first-child { width: 60%; @@ -20,7 +19,7 @@ } .ascribe-panel-table { - display:table; + display: table; > .ascribe-panel-content { display: table-cell; @@ -32,7 +31,6 @@ > div { padding-left: 1em; } - } &:nth-child(2) { @@ -40,7 +38,7 @@ padding-right: 1em; > button { - float:right; + float: right; } } } @@ -52,7 +50,6 @@ > div { padding-left: 2em; } - } &:nth-child(2) { @@ -60,7 +57,7 @@ padding-right: 2em; > button { - float:right; + float: right; } } } @@ -73,8 +70,8 @@ } .ascribe-panel-subtitle { + color: rgba(0, 0, 0, .5); font-size: .7em; - color: rgba(0,0,0,0.5); } } @@ -85,8 +82,8 @@ } .ascribe-panel-subtitle { + color: rgba(0, 0, 0, .5); font-size: .9em; - color: rgba(0,0,0,0.5); } } diff --git a/sass/ascribe_piece_list_bulk_modal.scss b/sass/ascribe_piece_list_bulk_modal.scss index 1811982b..4af61e1f 100644 --- a/sass/ascribe_piece_list_bulk_modal.scss +++ b/sass/ascribe_piece_list_bulk_modal.scss @@ -1,20 +1,17 @@ .ascribe-piece-list-bulk-modal { - position: fixed; - top:0; - left: 3%; - width:94%; - - background-color: #FAFAFA; - - border-left: 0.1em solid #E0E0E0; - border-right: 0.1em solid #E0E0E0; - border-top: 0.1em solid #E0E0E0; + background-color: #fafafa; + border-bottom: .2em solid #e0e0e0; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; - border-bottom: 0.2em solid #E0E0E0; - z-index:1000; - + border-left: .1em solid #e0e0e0; + border-right: .1em solid #e0e0e0; + border-top: .1em solid #e0e0e0; + left: 3%; padding-bottom: 1em; + position: fixed; + top: 0; + width: 94%; + z-index: 1000; } @media(min-width:1174px){ @@ -25,6 +22,6 @@ } .piece-list-bulk-modal-clear-all { + cursor: pointer; text-decoration: underline; - cursor:pointer; -} \ No newline at end of file +} diff --git a/sass/ascribe_piece_list_toolbar.scss b/sass/ascribe_piece_list_toolbar.scss index 8756adf4..aeec1bff 100644 --- a/sass/ascribe_piece_list_toolbar.scss +++ b/sass/ascribe_piece_list_toolbar.scss @@ -6,6 +6,7 @@ .search-bar { max-width: 200px; + input { height: 33px; } @@ -13,37 +14,45 @@ .ascribe-input-glyph > .form-group > .input-group { margin-left: 6px; + input { - box-shadow: none; background-color: transparent; border: 1px solid #02b6a3; border-right: 0; + box-shadow: none; } + > .input-group-addon { background-color: transparent; + > .filter-glyph { color: #02b6a3; } + border: 1px solid #02b6a3; border-left: 0; } } .ascribe-piece-list-toolbar-filter-widget { + button { - background-color: rgba(0,0,0,0); + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); color: #02b6a3; - border: 1px solid rgba(0,0,0,0); padding: 6px 4px 6px 8px; - &:hover, &:active { + + &:hover, + &:active { background-color: #02b6a3 !important; - color: white; border: 1px solid #02b6a3 !important; + color: white; } .caret { display: none; } } + .filter-widget-item { > a { @@ -53,23 +62,22 @@ } .checkbox-line { - position: relative; height: 25px; + position: relative; span { - position: absolute; - left: 9px; - top: 3px; cursor: pointer; - + left: 9px; margin-right: 10px; + position: absolute; + top: 3px; } input { - position: absolute; - top: 2px; - right: 9px; margin-left: 10px; + position: absolute; + right: 9px; + top: 2px; } } -} \ No newline at end of file +} diff --git a/sass/ascribe_piece_register.scss b/sass/ascribe_piece_register.scss index 1e4c0fa6..5bc6c3d7 100644 --- a/sass/ascribe_piece_register.scss +++ b/sass/ascribe_piece_register.scss @@ -2,15 +2,16 @@ $break-small: 764px; $break-medium: 991px; .ascribe-row { - @media screen and (max-width: $break-medium) { - max-width: 600px; - } - @media screen and (min-width: $break-medium) { - max-width: 1200px; - } - margin: 0 auto; + @media screen and (max-width: $break-medium) { + max-width: 600px; + } + @media screen and (min-width: $break-medium) { + max-width: 1200px; + } + margin: 0 auto; + + > div { + padding-left: 0; + } } -.ascribe-row > div { - padding-left: 0; -} \ No newline at end of file diff --git a/sass/ascribe_settings.scss b/sass/ascribe_settings.scss index 624b8a3b..c47ddb67 100644 --- a/sass/ascribe_settings.scss +++ b/sass/ascribe_settings.scss @@ -1,98 +1,108 @@ -.settings-container{ - max-width: 600px; +.settings-container { margin: auto; + max-width: 600px; } .ascribe-settings-wrapper { - width: 100%; - text-align: center; - padding-bottom: 1em; - background-color: white; - - border-left: 3px solid rgba(0,0,0,0); + border-left: 3px solid rgba(0, 0, 0, 0); + padding-bottom: 1em; + text-align: center; + width: 100%; &div:last-of-type { - border-bottom: 1px solid rgba(0,0,0,.05); + border-bottom: 1px solid rgba(0, 0, 0, .05); } - &:hover{ - border-left: 3px solid rgba(2, 182, 163, 0.4); + + &:hover { + border-left: 3px solid rgba(2, 182, 163, .4); } } -.is-hidden{ - display: none; +.is-hidden { + display: none; } .is-focused { - background-color: rgba(2, 182, 163, 0.05); + background-color: rgba(2, 182, 163, .05); border-left: 3px solid rgba(2, 182, 163, 1) !important; } .is-error { - background-color: rgba(169, 68, 66, 0.05); + background-color: rgba(169, 68, 66, .05); border-left: 3px solid rgba(169, 68, 66, 1); + > div { > span { color: rgba(169, 68, 66, 1); - font-size: 0.9em; + font-size: .9em; margin-right: 1em; } - > input, > textarea { + + > input, + > textarea { color: #666; } } - &:hover{ + &:hover { border-left: 3px solid rgba(169, 68, 66, 1); } } .is-fixed { cursor: default; + > div { cursor: default; + > span { cursor: default; } - > input, > div, > pre, > textarea { - cursor: default; + + > input, + > div, + > pre, + > textarea { color: #666; + cursor: default; } } } .ascribe-settings-property { + border-top: 1px solid rgba(0, 0, 0, .05); + cursor: pointer; display: inline-block; - width: 100%; - text-align: left; - border-top: 1px solid rgba(0,0,0,.05); - - padding-top: 1em; padding-left: 1.5em; padding-right: 1.5em; + padding-top: 1em; + text-align: left; + width: 100%; - cursor:pointer; - - > input, > div, > span:not(.glyphicon), > pre, > textarea, > select { + > div, + > input, + > pre, + > select, + > span:not(.glyphicon), + > textarea { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } - + > span { + color: rgba(0, 0, 0, .5); + font-size: .9em; font-weight: normal; - font-size: 0.9em; - color: rgba(0,0,0,.5); } > div { - /* margin-top: 10px; */ > div:not(.file-drag-and-drop div) { - padding-left: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: normal; - font-size: 1.1em; - cursor: default; - color: rgba(0, 0, 0, .5); + color: rgba(0, 0, 0, .5); + cursor: default; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 1.1em; + font-weight: normal; + padding-left: 0; } } @@ -100,29 +110,34 @@ margin-top: 0 !important; } - > input, > pre, > textarea, > select, .datepicker__input { - font-weight: 400; - font-size: 1.1em; - width:100%; - margin-top: .5em; + > input, + > pre, + > textarea, + > select, + .datepicker__input { + background-color: rgba(0, 0, 0, 0); border: 0; - background-color: rgba(0,0,0,0); - color: rgba(0,0,0,.8); - padding-left: 0; box-shadow: none; + color: rgba(0, 0, 0, .8); + font-size: 1.1em; + font-weight: 400; + margin-top: .5em; + padding-left: 0; + width: 100%; &:focus { - border:0; - outline:0; + border: 0; box-shadow: none; + outline: 0; } &::selection { + background-color: rgba(0, 0, 0, 1); color: white; - background-color: rgba(0,0,0,1); } } + .datepicker__input { padding: 0; } @@ -135,78 +150,75 @@ } .ascribe-property-footer { - font-size: 0.8em; + font-size: .8em; margin-top: 10px; width: 100%; } .ascribe-settings-property-collapsible-toggle { - text-align: left; + border-top: 1px solid rgba(0, 0, 0, .05); display: inline-block; + padding: .5em 1.5em; + text-align: left; width: 100%; - border-top: 1px solid rgba(0,0,0,.05); - - padding: .5em 1.5em .5em 1.5em; } .ascribe-checkbox-wrapper{ - .checkbox > span {color: black;} + .checkbox > span { + color: black; + } } .ascribe-settings-property-collapsible-toggle, .ascribe-checkbox-wrapper { + cursor: pointer; - cursor:pointer; - - /* Taken from: http://www.htmllion.com/css3-checkbox.html */ + // Taken from: http://www.htmllion.com/css3-checkbox.html .checkbox { display: inline-block; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: normal; font-size: .9em; - vertical-align:middle; + font-weight: normal; + vertical-align: middle; > span { + left: 5px; position: relative; top: 1px; - left: 5px; - -webkit-user-select: none; - -moz-user-select: none; -khtml-user-select: none; + -moz-user-select: none; -ms-user-select: none; + -webkit-user-select: none; } } - input[type=checkbox] { - display:none; + [type=checkbox] { + display: none; } .checkbox:before { + background-color: white; + border: 1px solid rgba(0, 0, 0, .5); + border-radius: 1px; + color: #f3f3f3; content: ""; display: inline-block; - width: 17px; height: 17px; - vertical-align:middle; - background-color: white; - color: #f3f3f3; text-align: center; - - border-radius: 1px; - border: 1px solid rgba(0, 0, 0, .5); + vertical-align: middle; + width: 17px; } - input[type=checkbox]:checked + .checkbox:before { - line-height: .8; - + [type=checkbox]:checked + .checkbox:before { + color: rgba(2, 182, 163, 1); content: "\2713"; font-size: 20px; - color: rgba(2, 182, 163, 1); + line-height: .8; } } -.ascribe-checkbox-badge{ +.ascribe-checkbox-badge { > span > span { margin-top: 0; } -} \ No newline at end of file +} diff --git a/sass/ascribe_slides_container.scss b/sass/ascribe_slides_container.scss index 4b96017c..c213e15b 100644 --- a/sass/ascribe_slides_container.scss +++ b/sass/ascribe_slides_container.scss @@ -5,41 +5,42 @@ padding-right: 0; } -.ascribe-sliding-container { - transition: transform 1s cubic-bezier(0.23, 1, 0.32, 1); +.ascribe-sliding-container { padding-left: 0; padding-right: 0; + transition: transform 1s cubic-bezier(.23, 1, .32, 1); } .ascribe-slide { - position: relative; + float: left; min-height: 1px; - float:left; + position: relative; } -.ascribe-breadcrumb-container{ +.ascribe-breadcrumb-container { div:last-child { .ascribe-breadcrumb { - border-right: 1px solid #EEE; + border-right: 1px solid #eee; } } } .ascribe-breadcrumb { - padding: 1em; - border: 1px solid #EEE; - border-right: 1px solid rgba(0, 0, 0, 0); - margin-bottom: 0.6em; background-color: white; + border: 1px solid #eee; + border-right: 1px solid rgba(0, 0, 0, 0); + margin-bottom: .6em; + padding: 1em; .active { color: #666; } + a { - color: #DDD; - text-decoration: none; + color: #ddd; font-size: 1.1em; font-style: italic; + text-decoration: none; } } diff --git a/sass/ascribe_table.scss b/sass/ascribe_table.scss index 225c27ca..c4b82a29 100644 --- a/sass/ascribe_table.scss +++ b/sass/ascribe_table.scss @@ -1,11 +1,11 @@ .ascribe-table { - margin-bottom:0; + margin-bottom: 0; font-size: 1.1em; } -/*This is aligning the first checkbox in pieclist detail with all the other ones*/ +// This is aligning the first checkbox in pieclist detail with all the other ones .table > thead:first-child > tr:first-child > th { - padding-left:0; + padding-left: 0; } @@ -14,38 +14,36 @@ } .ascribe-table-header-column > span { - display: table-cell; - vertical-align: middle; - font-family: 'Source Sans Pro'; - font-weight: 600; color: #424242; + display: table-cell; + font-weight: 600; + vertical-align: middle; } .ascribe-table-item-column { - font-family: 'Source Sans Pro'; + display: table-cell; font-size: .8em; - height:3em; + height: 3em; vertical-align: middle; - display: table-cell; -} -.ascribe-table-item-column > * { - display: table-cell; - vertical-align: middle; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} + > * { + display: table-cell; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: middle; + white-space: nowrap; + } -.ascribe-table-item-column > span > input { - margin-top:10px; - margin-left:2px; + > span > input { + margin-left: 2px; + margin-top: 10px; + } } .ascribe-table-item-selected { - background-color: rgba(2, 182, 163, 0.5); + background-color: rgba(2, 182, 163, .5); } .ascribe-table-item-selectable { cursor: default; -} \ No newline at end of file +} diff --git a/sass/ascribe_textarea.scss b/sass/ascribe_textarea.scss index 2d368dbf..bcd0502a 100644 --- a/sass/ascribe_textarea.scss +++ b/sass/ascribe_textarea.scss @@ -1,24 +1,23 @@ .ascribe-textarea { - border: none; + border: 0; box-shadow: none; margin-bottom: 1em; } .ascribe-textarea-editable:hover { - //border: 1px solid #AAA;; - border: none; + border: 0; } -.ascribe-pre{ - word-break: break-word; - white-space: pre-wrap; - white-space: -moz-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; - font-family: inherit; - text-align: justify; +.ascribe-pre { background-color: white; - border: none; + border: 0; + font-family: inherit; + margin: 0; padding: 0; - margin:0; + text-align: justify; + white-space: -moz-pre-wrap; + white-space: -o-pre-wrap; + white-space: -pre-wrap; + white-space: pre-wrap; + word-break: break-word; } diff --git a/sass/ascribe_theme.scss b/sass/ascribe_theme.scss index e02b97c6..5f1dd563 100644 --- a/sass/ascribe_theme.scss +++ b/sass/ascribe_theme.scss @@ -1,15 +1,15 @@ -/* All bootstrap overwrites should take place in this file */ +// All bootstrap overwrites should take place in this file .pager li a { color: white; } .panel-default { - border: none; + border: 0; box-shadow: none; margin-bottom: 0; } .panel-body { - padding:0; -} \ No newline at end of file + padding: 0; +} diff --git a/sass/ascribe_uploader.scss b/sass/ascribe_uploader.scss index 2aab021a..f7120fe7 100644 --- a/sass/ascribe_uploader.scss +++ b/sass/ascribe_uploader.scss @@ -1,21 +1,26 @@ .file-drag-and-drop { - display: block; - outline: 1px dashed #9E9E9E; - vertical-align: middle; - text-align: center; - height: auto; - background-color: #FEFEFE; - overflow: auto; - margin-top: 1em; - + background-color: #fefefe; cursor: default !important; + display: block; + height: auto; + margin-top: 1em; + outline: 1px dashed #9e9e9e; + overflow: auto; + padding: 1.5em 0; + text-align: center; + vertical-align: middle; - padding: 1.5em 0 1.5em 0; + .file-drag-and-drop-dialog > p:first-child { + font-size: 1.5em !important; + margin-bottom: 0; + margin-top: 0; + padding-bottom: 0; + } } .inactive-dropzone { + background-color: rgba(0, 0, 0, 0) !important; cursor: default !important; - background-color: rgba(0,0,0,0) !important; outline: 0; } @@ -25,44 +30,34 @@ } .btn { - margin: 0 1em 0 1em; + margin: 0 1em; } } -.file-drag-and-drop .file-drag-and-drop-dialog > p:first-child { - font-size: 1.5em !important; - - margin-top: 0; - margin-bottom: 0; - padding-bottom: 0; -} .file-drag-and-drop-position { - position: relative; display: inline-block; - margin-left: .7em; margin-right: .7em; + position: relative; .delete-file { - display: block; background-color: black; - - width: 20px; + border-radius: 1em; + cursor: pointer; + display: block; height: 20px; position: absolute; right: -7px; - top: -7px; - border-radius: 1em; text-align: center; - - cursor: pointer; + top: -7px; + width: 20px; span { color: white; - top: 1; - left: 0; font-size: .8em; + left: 0; + top: 1px; &:hover { color: $brand-danger; @@ -73,68 +68,74 @@ .file-drag-and-drop-preview-table-wrapper { display: table; - height:94px; - width:104px; + height: 94px; + width: 104px; } .file-drag-and-drop-preview { - overflow:hidden; - cursor: default; - background-color: #EEEEEE; + background-color: #eeeeee; border: 1px solid #616161; + cursor: default; + overflow: hidden; } .file-drag-and-drop-preview-image { - display: table; - height:104px; - width:104px; - overflow:hidden; border: 1px solid #616161; + display: table; + height: 104px; + overflow: hidden; text-align: center; -} + width: 104px; -.file-drag-and-drop-preview-image .action-file { - font-size: 2.5em; - margin-top: .6em; - color: white; - text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; - cursor: pointer; + .action-file { + color: white; + cursor: pointer; + font-size: 2.5em; + margin-top: .6em; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; - &:link, &:visited, &:hover, &:active { - text-decoration: none; - } + &:link, + &:visited, + &:hover, + &:active { + text-decoration: none; + } - &:hover { - color: #d9534f; + &:hover { + color: #d9534f; + } } } -.file-drag-and-drop-preview-other .action-file { - position: relative; - top: .3em; - margin-top: 0; - font-size: 2.5em; - color: white; - text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; - cursor: pointer; - - &:link, &:visited, &:hover, &:active { - text-decoration: none; - } - - &:hover { - color: #d9534f; - } -} .file-drag-and-drop-preview-other { display: table-cell; text-align: center; vertical-align: middle; -} + .action-file { + color: white; + cursor: pointer; + font-size: 2.5em; + margin-top: 0; + position: relative; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + top: .3em; -.file-drag-and-drop-preview-other span:not(:first-child) { - display: block; - margin-top: .5em; + &:link, + &:visited, + &:hover, + &:active { + text-decoration: none; + } + + &:hover { + color: #d9534f; + } + + span:not(:first-child) { + display: block; + margin-top: .5em; + } + } } diff --git a/sass/ascribe_variables.scss b/sass/ascribe_variables.scss index 761cbfc3..2af5c6d3 100644 --- a/sass/ascribe_variables.scss +++ b/sass/ascribe_variables.scss @@ -1,3 +1,3 @@ $ascribe-color-green: rgba(2, 182, 163, 1); -$ascribe-brand-danger: #FC535F; +$ascribe-brand-danger: #fc535f; diff --git a/sass/main.scss b/sass/main.scss index 8a4f1306..b8587635 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -33,9 +33,11 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'whitelabel/index'; -html, body { +html, +body { + background-color: #fdfdfd; + font-family: 'Source Sans Pro'; height: 100%; - background-color: #FDFDFD; } html { @@ -43,8 +45,8 @@ html { } .ascribe-default-app { - padding-top: 70px; overflow-x: hidden; + padding-top: 70px; } hr { @@ -59,154 +61,182 @@ hr { display: none; } -.no-margin{ +.no-margin { margin: 0; + margin-left: 0; + margin-right: 0; } -.no-padding{ + +.no-padding { padding: 0; } -.inline{ + +.inline { display: inline; } .navbar-default { - border: none; - border-left:0; - border-right:0; + border: 0; + border-color: #ccc; + border-left: 0; + border-right: 0; + border-top: 0; + font-size: .8em; margin-bottom: 1.5em; - border-top:0; - border-color: #CCC; - font-size: 0.8em; -} -.navbar-default .navbar-nav > .active { - a { - background-color: transparent!important; - > span {color: #02b6a3;} - color: #02b6a3; - border-bottom: 1px solid #02b6a3; + .navbar-nav > li > a { + border: 1px solid rgba(0, 0, 0, 0); + } - &:hover, &:focus{ - > span {color: #02b6a3;} - color: #02b6a3; - background-color: transparent; + .navbar-nav > .active { + a { + background-color: transparent !important; border-bottom: 1px solid #02b6a3; + color: #02b6a3; + + > span { + color: #02b6a3; + } + + &:hover, + &:focus { + background-color: transparent; + border-bottom: 1px solid #02b6a3; + color: #02b6a3; + + > span { + color: #02b6a3; + } + } } } } -.navbar-default .navbar-nav > li > a { - border: 1px solid rgba(0,0,0,0); -} + + .img-brand { - padding: 0; height: 45px; - margin: 5px 0 5px 0; + margin: 5px 0; + padding: 0; } + .truncate { - white-space: nowrap; - width: 4em; overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; + width: 4em; + @media only screen and (min-width: 400px) { width: 8em; } + @media only screen and (min-width: 600px) { width: 12em; } + @media only screen and (min-width: 1000px) { width: 14em; } + @media only screen and (min-width: 1200px) { width: 16em; } + @media only screen and (min-width: 1400px) { width: 18em; } } + .navbar-right { margin-right: 0; } .clear-paddings { - padding-left:0; - padding-right:0; + padding-left: 0; + padding-right: 0; } .clear-margins { - margin-top:0; - margin-bottom:0; + margin-bottom: 0; + margin-top: 0; } .ascribe-color { color: $ascribe-color-green; } -.ascribe-subheader{ +.ascribe-subheader { padding-bottom: 10px; margin-top: -10px; + a { - cursor: pointer; - font-size: 0.8em; color: #222; + cursor: pointer; + font-size: .8em; } } -.tooltip-inner{ +.tooltip-inner { + background-color: #fcfafa; + border: 1px solid; + border-radius: 0; + color: #000; max-width: 300px; padding: 3px 8px; - color: #000; text-align: center; text-decoration: none; - background-color: #FCFAFA; - border-radius: 0; - border: 1px solid; } -/* Taken from http://stackoverflow.com/a/20548578 */ +// Taken from http://stackoverflow.com/a/20548578 .vcenter { display: inline-block; - vertical-align: middle; float: none; + vertical-align: middle; } -.filter-glyph{ + +.filter-glyph { color: white; } -.no-margin { - margin-right: 0; - margin-left: 0; -} -.btn-delete{ - background-color: rgba(0,0,0,0); + +.btn-delete { + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0); color: #888; - border: 1px solid rgba(0,0,0,0); - &:hover{ + + &:hover { border: 1px solid $ascribe-brand-danger; } } -.btn-ascribe, .btn-ascribe-inv { + +.btn-ascribe, +.btn-ascribe-inv { border: 1px solid #444; - line-height: 2em; - margin-right: 1px; - margin-left: 0 !important; - font-family: sans-serif !important; border-radius: 0 !important; + font-family: sans-serif !important; + line-height: 2em; + margin-left: 0 !important; + margin-right: 1px; } -.btn-ascribe, .btn-ascribe-inv:active, .btn-ascribe-inv:hover { +.btn-ascribe, +.btn-ascribe-inv:active, +.btn-ascribe-inv:hover { + background-color: #fff; color: #222 !important; - background-color: #FFF; } -.btn-ascribe:active, .btn-ascribe:hover, .btn-ascribe-inv { - color: #FFF !important; +.btn-ascribe:active, +.btn-ascribe:hover, +.btn-ascribe-inv { background-color: #444; + color: #fff !important; } -.btn-ascribe-inv:disabled, .btn-ascribe-inv:focus { - color: #444 !important; +.btn-ascribe-inv:disabled, +.btn-ascribe-inv:focus { background-color: #BBB !important; border: 1px solid #444 !important; + color: #444 !important; } .btn-ascribe-sm { @@ -214,24 +244,29 @@ hr { line-height: 1.3em; } -.btn-ascribe-green, .btn-ascribe-green-inv { - border: 1px solid #48DACB; +.btn-ascribe-green, +.btn-ascribe-green-inv { + border: 1px solid #48dacb; + border-radius: 0 !important; + font-family: sans-serif !important; line-height: 2em; margin-left: 0 !important; - font-family: sans-serif !important; - border-radius: 0 !important; } -.btn-ascribe-green, .btn-ascribe-green-inv:active, .btn-ascribe-green-inv:hover { - background-color: #FFF; - border: 1px solid rgba(2, 182, 163, 0.5); +.btn-ascribe-green, +.btn-ascribe-green-inv:active, +.btn-ascribe-green-inv:hover { + background-color: #fff; + border: 1px solid rgba(2, 182, 163, .5); color: rgba(2, 182, 163, 0.5); } -.btn-ascribe-green:active, .btn-ascribe-green:hover, .btn-ascribe-green-inv { - border: 1px solid rgba(2, 182, 163, 0.5); +.btn-ascribe-green:active, +.btn-ascribe-green:hover, +.btn-ascribe-green-inv { + background-color: rgba(2, 182, 163, .5); + border: 1px solid rgba(2, 182, 163, .5); color: white; - background-color: rgba(2, 182, 163, 0.5); } .ascribe-detail-title { @@ -240,33 +275,34 @@ hr { } .ascribe-detail-property { - padding-bottom: 0.4em; + padding-bottom: .4em; } .ascribe-detail-property-label { - font-size: 0.8em; + font-size: .8em; } .ascribe-detail-property-value { - /* white-space: nowrap; - overflow: hidden; */ text-overflow: ellipsis; } -::-webkit-input-placeholder { /* WebKit browsers */ - font-size: 0.9em; +::-webkit-input-placeholder { // WebKit browsers + font-size: .9em; font-style: italic; } -:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ - font-size: 0.9em; + +:-moz-placeholder { // Mozilla Firefox 4 to 18 + font-size: .9em; font-style: italic; } -::-moz-placeholder { /* Mozilla Firefox 19+ */ - font-size: 0.9em; + +::-moz-placeholder { // Mozilla Firefox 19+ + font-size: .9em; font-style: italic; } -:-ms-input-placeholder { /* Internet Explorer 10+ */ - font-size: 0.9em; + +:-ms-input-placeholder { // Internet Explorer 10+ + font-size: .9em; font-style: italic; } @@ -275,15 +311,15 @@ hr { } .input-checkbox-ascribe { - text-align: left; line-height: 1.6; - width: 90%; margin-left: 1.6em; margin-right: auto; + text-align: left; + width: 90%; } -/* columns of same height styles */ -/* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */ +// columns of same height styles +// http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height .row-full-height { height: 100%; } @@ -295,9 +331,9 @@ hr { .row-same-height { display: table; - width: 100%; - /* fix overflow */ + // fix overflow table-layout: fixed; + width: 100%; } .col-xs-height { @@ -326,7 +362,7 @@ hr { } } -/* vertical alignment styles */ +// vertical alignment styles .col-top { vertical-align: top; @@ -350,40 +386,44 @@ hr { } .spin { - display:inline-block; - -webkit-animation: spin 1s infinite linear; -moz-animation: spin 1s infinite linear; - -o-animation: spin 1s infinite linear; -ms-animation: spin 1s infinite linear; + -o-animation: spin 1s infinite linear; + -webkit-animation: spin 1s infinite linear; animation: spin 1s infinite linear; - -webkit-transform-origin: 55% 70%; -moz-transform-origin: 55% 70%; -o-transform-origin: 55% 70%; + -webkit-transform-origin: 55% 70%; + display: inline-block; transform-origin: 55% 70%; width: 10px; height: 10px; } @-webkit-keyframes spin { -0% { -webkit-transform: rotate(0deg);} -100% { -webkit-transform: rotate(360deg);} + 0% { -webkit-transform: rotate(0deg);} + 100% { -webkit-transform: rotate(360deg);} } + @-moz-keyframes spin { -0% { -moz-transform: rotate(0deg); } -100% { -moz-transform: rotate(360deg);} + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(360deg);} } + @-o-keyframes spin { -0% { -o-transform: rotate(0deg);} -100% { -o-transform: rotate(360deg);} + 0% { -o-transform: rotate(0deg);} + 100% { -o-transform: rotate(360deg);} } + @-ms-keyframes spin { -0% { -ms-transform: rotate(0deg);} -100% { -ms-transform: rotate(360deg);} + 0% { -ms-transform: rotate(0deg);} + 100% { -ms-transform: rotate(360deg);} } + @-keyframes spin { -0% { transform: rotate(0deg); } -100% { transform: rotate(360deg);} -} + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg);} +} .btn-default { .glyph-ascribe-spool { @@ -392,9 +432,8 @@ hr { } .fullpage-spinner { - padding-top: 30%; padding-bottom: 30%; - + padding-top: 30%; text-align: center; > span { @@ -404,21 +443,22 @@ hr { .disable-select { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -webkit-user-select: none; user-select: none; } .link-ascribe { color: #666; + &:hover { color: #000; } } .ascribe-loading-position { - padding-top: 30%; padding-bottom: 30%; + padding-top: 30%; text-align: center; } diff --git a/sass/offset_right.scss b/sass/offset_right.scss index f844ce20..a90e2078 100644 --- a/sass/offset_right.scss +++ b/sass/offset_right.scss @@ -1,164 +1,214 @@ -/* Taken from: http://stackoverflow.com/a/27501063/1263876 */ +// Taken from: http://stackoverflow.com/a/27501063/1263876 .col-xs-offset-right-12 { - margin-right: 100%; -} -.col-xs-offset-right-11 { - margin-right: 91.66666667%; -} -.col-xs-offset-right-10 { - margin-right: 83.33333333%; -} -.col-xs-offset-right-9 { - margin-right: 75%; -} -.col-xs-offset-right-8 { - margin-right: 66.66666667%; -} -.col-xs-offset-right-7 { - margin-right: 58.33333333%; -} -.col-xs-offset-right-6 { - margin-right: 50%; -} -.col-xs-offset-right-5 { - margin-right: 41.66666667%; -} -.col-xs-offset-right-4 { - margin-right: 33.33333333%; -} -.col-xs-offset-right-3 { - margin-right: 25%; -} -.col-xs-offset-right-2 { - margin-right: 16.66666667%; -} -.col-xs-offset-right-1 { - margin-right: 8.33333333%; -} -.col-xs-offset-right-0 { - margin-right: 0; -} -@media (min-width: 768px) { - .col-sm-offset-right-12 { margin-right: 100%; - } - .col-sm-offset-right-11 { +} + +.col-xs-offset-right-11 { margin-right: 91.66666667%; - } - .col-sm-offset-right-10 { +} + +.col-xs-offset-right-10 { margin-right: 83.33333333%; - } - .col-sm-offset-right-9 { +} + +.col-xs-offset-right-9 { margin-right: 75%; - } - .col-sm-offset-right-8 { +} + +.col-xs-offset-right-8 { margin-right: 66.66666667%; - } - .col-sm-offset-right-7 { +} + +.col-xs-offset-right-7 { margin-right: 58.33333333%; - } - .col-sm-offset-right-6 { +} + +.col-xs-offset-right-6 { margin-right: 50%; - } - .col-sm-offset-right-5 { +} + +.col-xs-offset-right-5 { margin-right: 41.66666667%; - } - .col-sm-offset-right-4 { +} + +.col-xs-offset-right-4 { margin-right: 33.33333333%; - } - .col-sm-offset-right-3 { +} + +.col-xs-offset-right-3 { margin-right: 25%; - } - .col-sm-offset-right-2 { +} + +.col-xs-offset-right-2 { margin-right: 16.66666667%; - } - .col-sm-offset-right-1 { +} + +.col-xs-offset-right-1 { margin-right: 8.33333333%; - } - .col-sm-offset-right-0 { +} + +.col-xs-offset-right-0 { margin-right: 0; - } +} + +@media (min-width: 768px) { + .col-sm-offset-right-12 { + margin-right: 100%; + } + + .col-sm-offset-right-11 { + margin-right: 91.66666667%; + } + + .col-sm-offset-right-10 { + margin-right: 83.33333333%; + } + + .col-sm-offset-right-9 { + margin-right: 75%; + } + + .col-sm-offset-right-8 { + margin-right: 66.66666667%; + } + + .col-sm-offset-right-7 { + margin-right: 58.33333333%; + } + + .col-sm-offset-right-6 { + margin-right: 50%; + } + + .col-sm-offset-right-5 { + margin-right: 41.66666667%; + } + + .col-sm-offset-right-4 { + margin-right: 33.33333333%; + } + + .col-sm-offset-right-3 { + margin-right: 25%; + } + + .col-sm-offset-right-2 { + margin-right: 16.66666667%; + } + + .col-sm-offset-right-1 { + margin-right: 8.33333333%; + } + + .col-sm-offset-right-0 { + margin-right: 0; + } } @media (min-width: 992px) { - .col-md-offset-right-12 { - margin-right: 100%; - } - .col-md-offset-right-11 { - margin-right: 91.66666667%; - } - .col-md-offset-right-10 { - margin-right: 83.33333333%; - } - .col-md-offset-right-9 { - margin-right: 75%; - } - .col-md-offset-right-8 { - margin-right: 66.66666667%; - } - .col-md-offset-right-7 { - margin-right: 58.33333333%; - } - .col-md-offset-right-6 { - margin-right: 50%; - } - .col-md-offset-right-5 { - margin-right: 41.66666667%; - } - .col-md-offset-right-4 { - margin-right: 33.33333333%; - } - .col-md-offset-right-3 { - margin-right: 25%; - } - .col-md-offset-right-2 { - margin-right: 16.66666667%; - } - .col-md-offset-right-1 { - margin-right: 8.33333333%; - } - .col-md-offset-right-0 { - margin-right: 0; - } + .col-md-offset-right-12 { + margin-right: 100%; + } + + .col-md-offset-right-11 { + margin-right: 91.66666667%; + } + + .col-md-offset-right-10 { + margin-right: 83.33333333%; + } + + .col-md-offset-right-9 { + margin-right: 75%; + } + + .col-md-offset-right-8 { + margin-right: 66.66666667%; + } + + .col-md-offset-right-7 { + margin-right: 58.33333333%; + } + + .col-md-offset-right-6 { + margin-right: 50%; + } + + .col-md-offset-right-5 { + margin-right: 41.66666667%; + } + + .col-md-offset-right-4 { + margin-right: 33.33333333%; + } + + .col-md-offset-right-3 { + margin-right: 25%; + } + + .col-md-offset-right-2 { + margin-right: 16.66666667%; + } + + .col-md-offset-right-1 { + margin-right: 8.33333333%; + } + + .col-md-offset-right-0 { + margin-right: 0; + } } + @media (min-width: 1200px) { - .col-lg-offset-right-12 { - margin-right: 100%; - } - .col-lg-offset-right-11 { - margin-right: 91.66666667%; - } - .col-lg-offset-right-10 { - margin-right: 83.33333333%; - } - .col-lg-offset-right-9 { - margin-right: 75%; - } - .col-lg-offset-right-8 { - margin-right: 66.66666667%; - } - .col-lg-offset-right-7 { - margin-right: 58.33333333%; - } - .col-lg-offset-right-6 { - margin-right: 50%; - } - .col-lg-offset-right-5 { - margin-right: 41.66666667%; - } - .col-lg-offset-right-4 { - margin-right: 33.33333333%; - } - .col-lg-offset-right-3 { - margin-right: 25%; - } - .col-lg-offset-right-2 { - margin-right: 16.66666667%; - } - .col-lg-offset-right-1 { - margin-right: 8.33333333%; - } - .col-lg-offset-right-0 { - margin-right: 0; - } -} \ No newline at end of file + .col-lg-offset-right-12 { + margin-right: 100%; + } + + .col-lg-offset-right-11 { + margin-right: 91.66666667%; + } + + .col-lg-offset-right-10 { + margin-right: 83.33333333%; + } + + .col-lg-offset-right-9 { + margin-right: 75%; + } + + .col-lg-offset-right-8 { + margin-right: 66.66666667%; + } + + .col-lg-offset-right-7 { + margin-right: 58.33333333%; + } + + .col-lg-offset-right-6 { + margin-right: 50%; + } + + .col-lg-offset-right-5 { + margin-right: 41.66666667%; + } + + .col-lg-offset-right-4 { + margin-right: 33.33333333%; + } + + .col-lg-offset-right-3 { + margin-right: 25%; + } + + .col-lg-offset-right-2 { + margin-right: 16.66666667%; + } + + .col-lg-offset-right-1 { + margin-right: 8.33333333%; + } + + .col-lg-offset-right-0 { + margin-right: 0; + } +} diff --git a/sass/variables.scss b/sass/variables.scss index 6a3571e2..909440c9 100644 --- a/sass/variables.scss +++ b/sass/variables.scss @@ -51,14 +51,14 @@ $font-family-base: $font-family-sans-serif !default; $font-size-base: 14px !default; $font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px -$font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px +$font-size-small: ceil(($font-size-base * .85)) !default; // ~12px $font-size-h1: floor(($font-size-base * 2.6)) !default; // ~36px $font-size-h2: floor(($font-size-base * 2.15)) !default; // ~30px $font-size-h3: ceil(($font-size-base * 1.7)) !default; // ~24px $font-size-h4: ceil(($font-size-base * 1.25)) !default; // ~18px $font-size-h5: $font-size-base !default; -$font-size-h6: ceil(($font-size-base * 0.85)) !default; // ~12px +$font-size-h6: ceil(($font-size-base * .85)) !default; // ~12px //** Unit-less `line-height` for use in components like buttons. $line-height-base: 1.428571429 !default; // 20/14 @@ -234,7 +234,7 @@ $cursor-disabled: not-allowed !default; //** Background for the dropdown menu. $dropdown-bg: #fff !default; //** Dropdown menu `border-color`. -$dropdown-border: rgba(0,0,0,.15) !default; +$dropdown-border: rgba(0, 0, 0, .15) !default; //** Dropdown menu `border-color` **for IE8**. $dropdown-fallback-border: #ccc !default; //** Divider color for between dropdown items. @@ -541,7 +541,7 @@ $popover-bg: #fff !default; //** Popover maximum width $popover-max-width: 276px !default; //** Popover border color -$popover-border-color: rgba(0,0,0,.2) !default; +$popover-border-color: rgba(0, 0, 0, .2) !default; //** Popover fallback border color $popover-fallback-border-color: #ccc !default; @@ -556,7 +556,7 @@ $popover-arrow-color: $popover-bg !default; //** Popover outer arrow width $popover-arrow-outer-width: ($popover-arrow-width + 1) !default; //** Popover outer arrow color -$popover-arrow-outer-color: fade_in($popover-border-color, 0.05) !default; +$popover-arrow-outer-color: fade_in($popover-border-color, .05) !default; //** Popover outer arrow fallback color $popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default; @@ -804,7 +804,7 @@ $breadcrumb-separator: "/" !default; // //## -$carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default; +$carousel-text-shadow: 0 1px 2px rgba(0, 0, 0, .6) !default; $carousel-control-color: #fff !default; $carousel-control-width: 15% !default; From b6fc0e931de3d6328d6fd222b51c63d907c8c963 Mon Sep 17 00:00:00 2001 From: vrde Date: Mon, 31 Aug 2015 19:13:09 +0200 Subject: [PATCH 181/397] Update readme with doc on how to install the linter --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 270c4a5f..a3258576 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ Additionally, to work on the white labeling functionality, you need to edit your ``` -Code Conventions -================ +JavaScript Code Conventions +=========================== For this project, we're using: * 4 Spaces @@ -42,6 +42,15 @@ For this project, we're using: * We don't use camel case for file naming but in everything Javascript related * We use `let` instead of `var`: [SA Post](http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword) + +SCSS Code Conventions +===================== +Install [lint-scss](https://github.com/brigade/scss-lint), check the [editor integration docs](https://github.com/brigade/scss-lint#editor-integration) to integrate the lint in your editor. + +Some interesting links: +* [Improving Sass code quality on theguardian.com](https://www.theguardian.com/info/developer-blog/2014/may/13/improving-sass-code-quality-on-theguardiancom) + + Testing =============== We're using Facebook's jest to do testing as it integrates nicely with react.js as well. @@ -127,4 +136,4 @@ Moar stuff - [24ways.org: JavaScript Modules the ES6 Way](http://24ways.org/2014/javascript-modules-the-es6-way/) - [Babel: Learn ES6](https://babeljs.io/docs/learn-es6/) - [egghead's awesome reactjs and flux tutorials](https://egghead.io/) -- [Crockford's genious Javascript: The Good Parts (Tim has a copy)](http://www.amazon.de/JavaScript-Parts-Working-Shallow-Grain/dp/0596517742) \ No newline at end of file +- [Crockford's genious Javascript: The Good Parts (Tim has a copy)](http://www.amazon.de/JavaScript-Parts-Working-Shallow-Grain/dp/0596517742) From f83300e597b6126b13a62da662ccd9356d78516d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Sep 2015 09:34:29 +0200 Subject: [PATCH 182/397] incorporate pr feedback --- js/components/ascribe_slides_container/slides_container.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 8b098ef6..8b800377 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -241,8 +241,8 @@ let SlidesContainer = React.createClass({ }, render() { - - let translateXValue = 'translateX(' + (-1) * this.state.containerWidth * this.state.slideNum + 'px)'; + let spacing = this.state.containerWidth * this.state.slideNum; + let translateXValue = 'translateX(' + (-1) * spacing + 'px)'; /* According to the react documentation, From b5b1e3610992110a5abf75a6f61f332657279d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Sep 2015 14:00:06 +0200 Subject: [PATCH 183/397] nested collapsible paragraphs --- .scss-lint.yml | 4 +- .../collapsible_paragraph.js | 4 +- .../ascribe_settings/contract_settings.js | 93 ++++++++++--------- .../components/prize_settings_container.js | 2 +- sass/ascribe_collapsible.scss | 33 +++++++ sass/ascribe_edition.scss | 28 ------ sass/main.scss | 1 + 7 files changed, 88 insertions(+), 77 deletions(-) create mode 100644 sass/ascribe_collapsible.scss diff --git a/.scss-lint.yml b/.scss-lint.yml index 6d4fd6ba..61b1c624 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -48,7 +48,7 @@ linters: enabled: false FinalNewline: - enabled: true + enabled: false present: true HexLength: @@ -106,7 +106,7 @@ linters: max_properties: 10 PropertySortOrder: - enabled: true + enabled: false ignore_unspecified: false min_properties: 2 separate_groups: false diff --git a/js/components/ascribe_collapsible/collapsible_paragraph.js b/js/components/ascribe_collapsible/collapsible_paragraph.js index 8b3b3cf4..a5c884e5 100644 --- a/js/components/ascribe_collapsible/collapsible_paragraph.js +++ b/js/components/ascribe_collapsible/collapsible_paragraph.js @@ -38,14 +38,14 @@ const CollapsibleParagraph = React.createClass({ if(this.props.show) { return (
    -
    +
    {text} {this.props.title}
    + className="ascribe-collapsible-content"> {this.props.children}
    diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js index d2928457..bba04754 100644 --- a/js/components/ascribe_settings/contract_settings.js +++ b/js/components/ascribe_settings/contract_settings.js @@ -27,50 +27,55 @@ let ContractSettings = React.createClass({ title={getLangText('Contract Settings')} show={true} defaultExpanded={this.props.defaultExpanded}> - - - - -
    - + +
    + + + +
    +
    +
    ); } diff --git a/js/components/whitelabel/prize/components/prize_settings_container.js b/js/components/whitelabel/prize/components/prize_settings_container.js index e0c30d46..e6a53bbb 100644 --- a/js/components/whitelabel/prize/components/prize_settings_container.js +++ b/js/components/whitelabel/prize/components/prize_settings_container.js @@ -265,7 +265,7 @@ let PrizeJurySettings = React.createClass({ if (this.state.members.length > -1) { content = ( -
    +
    div:first-child { + background-color: rgba(0, 0, 0, 0); + cursor: pointer; + margin-top: 20px; + padding: 0 10px 10px 0; + width: 100%; + } + + > div > span { + font-size: 1.2em; + margin-right: .5em; + } + + > div > span:nth-child(2) { + font-size: .9em; + } +} + +.ascribe-collapsible-content { + background: none; + border: 0; + width: 100%; + + /* Shrink the size of the headline for a nested element */ + .ascribe-collapsible-wrapper > div:first-child { + padding-left: 1em; + font-size: 90%; + } +} \ No newline at end of file diff --git a/sass/ascribe_edition.scss b/sass/ascribe_edition.scss index f86f74e2..9fa30387 100644 --- a/sass/ascribe_edition.scss +++ b/sass/ascribe_edition.scss @@ -3,34 +3,6 @@ margin-bottom: 1em; } -.ascribe-edition-collapsible-wrapper { - vertical-align: bottom; - width: 100%; - - > div:first-child { - background-color: rgba(0, 0, 0, 0); - cursor: pointer; - margin-top: 20px; - padding: 0 10px 10px 0; - width: 100%; - } - - > div > span { - font-size: 1.2em; - margin-right: .5em; - } - - > div > span:nth-child(2) { - font-size: .9em; - } -} - -.ascribe-edition-collapsible-content { - background: none; - border: 0; - width: 100%; -} - .coa-file-wrapper { display: table; height: 200px; diff --git a/sass/main.scss b/sass/main.scss index 510599bd..6ec1d37d 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -29,6 +29,7 @@ $BASE_URL: '<%= BASE_URL %>'; @import 'ascribe_slides_container'; @import 'ascribe_form'; @import 'ascribe_panel'; +@import 'ascribe_collapsible'; @import 'whitelabel/index'; From b4abe7a24569f1a30f16d99f5d64fe31c31d23a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Sep 2015 14:42:09 +0200 Subject: [PATCH 184/397] generic form submission determination for fineuploader --- .../ascribe_detail/further_details.js | 4 +- .../ascribe_forms/form_create_contract.js | 102 ++++++++++++++++++ .../ascribe_forms/form_register_piece.js | 6 +- .../ascribe_settings/contract_settings.js | 63 +---------- .../react_s3_fine_uploader_utils.js | 44 +++++--- .../cyland_additional_data_form.js | 14 +-- 6 files changed, 145 insertions(+), 88 deletions(-) create mode 100644 js/components/ascribe_forms/form_create_contract.js diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js index 9fc5bf15..863ed491 100644 --- a/js/components/ascribe_detail/further_details.js +++ b/js/components/ascribe_detail/further_details.js @@ -15,7 +15,7 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import FurtherDetailsFileuploader from './further_details_fileuploader'; -import { isReadyForFormSubmission } from '../ascribe_uploader/react_s3_fine_uploader_utils'; +import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils'; let FurtherDetails = React.createClass({ propTypes: { @@ -80,7 +80,7 @@ let FurtherDetails = React.createClass({ + {getLangText('Create new contract')} + + } + spinner={ + + + + }> + + + + + + + + ); + } +}); + +export default CreateContractForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index 3519c976..c6a28626 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -16,7 +16,7 @@ import ApiUrls from '../../constants/api_urls'; import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; import { mergeOptions } from '../../utils/general_utils'; -import { isReadyForFormSubmission } from '../ascribe_uploader/react_s3_fine_uploader_utils'; +import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils'; let RegisterPieceForm = React.createClass({ @@ -115,7 +115,7 @@ let RegisterPieceForm = React.createClass({ - -
    - - - -
    -
    -
    + defaultExpanded={true}> + {/* this should be this.props.defaultExpanded */} +
    ); } diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js index dbf62619..dbbfd63f 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js @@ -1,16 +1,34 @@ 'use strict'; -/** - * Returns a boolean if there has been at least one file uploaded - * successfully without it being deleted or canceled. - * @param {array of files} files provided by react fine uploader - * @return {Boolean} - */ -export function 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; +export const formSubmissionValidation = { + /** + * Returns a boolean if there has been at least one file uploaded + * successfully without it being deleted or canceled. + * @param {array of files} files provided by react fine uploader + * @return {boolean} + */ + atLeastOneUploadedFile(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; + } + }, + + /** + * File submission for the form is optional, but if the user decides to submit a file + * the form is not ready until there are no more files currently uploading. + * @param {array of files} files files provided by react fine uploader + * @return {boolean} [description] + */ + fileOptional(files) { + let uploadingFiles = files.filter((file) => file.status === 'submitting'); + + if (uploadingFiles.length === 0) { + return true; + } else { + return false; + } } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js index f7946be5..13e731ef 100644 --- a/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js +++ b/js/components/whitelabel/wallet/components/cyland/ascribe_forms/cyland_additional_data_form.js @@ -15,6 +15,8 @@ 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 CylandAdditionalDataForm = React.createClass({ propTypes: { @@ -60,16 +62,6 @@ let CylandAdditionalDataForm = React.createClass({ }); }, - isReadyForFormSubmission(files) { - let uploadingFiles = files.filter((file) => file.status === 'submitting'); - - if (uploadingFiles.length === 0) { - return true; - } else { - return false; - } - }, - render() { if(this.props.piece && this.props.piece.id) { return ( @@ -122,7 +114,7 @@ let CylandAdditionalDataForm = React.createClass({ uploadStarted={this.uploadStarted} submitKey={this.submitKey} setIsUploadReady={this.setIsUploadReady} - isReadyForFormSubmission={this.isReadyForFormSubmission} + isReadyForFormSubmission={formSubmissionValidation.fileOptional} editable={!this.props.disabled} pieceId={this.props.piece.id} otherData={this.props.piece.other_data} From bfaf4886a49d13e803eaf7ac7da85541f58da9eb Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 1 Sep 2015 14:45:14 +0200 Subject: [PATCH 185/397] notifications unoptimized --- .../ascribe_detail/edition_container.js | 9 ++ js/components/global_action.js | 43 ++++++++ js/components/header.js | 98 ++++++++++++++++++- js/components/piece_list.js | 27 +---- js/stores/piece_list_store.js | 16 +-- sass/ascribe_global_action.scss | 64 ++---------- sass/ascribe_notification_list.scss | 65 ++++++++++++ sass/main.scss | 1 + 8 files changed, 226 insertions(+), 97 deletions(-) create mode 100644 js/components/global_action.js create mode 100644 sass/ascribe_notification_list.scss diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js index 15086434..62efa709 100644 --- a/js/components/ascribe_detail/edition_container.js +++ b/js/components/ascribe_detail/edition_container.js @@ -34,6 +34,15 @@ let EditionContainer = React.createClass({ EditionActions.fetchOne(this.props.params.editionId); }, + // This is done to update the container when the user clicks on the prev or next + // button to update the URL parameter (and therefore to switch pieces) + componentWillReceiveProps(nextProps) { + if(this.props.params.editionId !== nextProps.params.editionId) { + EditionActions.updateEdition({}); + EditionActions.fetchOne(nextProps.params.editionId); + } + }, + componentWillUnmount() { // Every time we're leaving the edition detail page, // just reset the edition that is saved in the edition store diff --git a/js/components/global_action.js b/js/components/global_action.js new file mode 100644 index 00000000..80df0c75 --- /dev/null +++ b/js/components/global_action.js @@ -0,0 +1,43 @@ +'use strict'; + +import React from 'react'; + +let GlobalAction = React.createClass({ + propTypes: { + requestActions: React.PropTypes.object + }, + + render() { + let pieceActions = null; + if (this.props.requestActions && this.props.requestActions.pieces){ + pieceActions = this.props.requestActions.pieces.map((item) => { + return ( +
    + {item} +
    ); + }); + } + let editionActions = null; + if (this.props.requestActions && this.props.requestActions.editions){ + editionActions = Object.keys(this.props.requestActions.editions).map((pieceId) => { + return this.props.requestActions.editions[pieceId].map((item) => { + return ( +
    + {item} +
    ); + }); + }); + } + + if (pieceActions || editionActions) { + return ( +
    + {pieceActions} + {editionActions} +
    ); + } + return null; + } +}); + +export default GlobalAction; \ No newline at end of file diff --git a/js/components/header.js b/js/components/header.js index 0863624f..7cd0e455 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -3,6 +3,8 @@ import React from 'react'; import Router from 'react-router'; +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; + import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; @@ -10,6 +12,8 @@ import WhitelabelActions from '../actions/whitelabel_actions'; import WhitelabelStore from '../stores/whitelabel_store'; import EventActions from '../actions/event_actions'; +import PieceListStore from '../stores/piece_list_store'; + import Nav from 'react-bootstrap/lib/Nav'; import Navbar from 'react-bootstrap/lib/Navbar'; import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav'; @@ -25,6 +29,8 @@ import NavRoutesLinks from './nav_routes_links'; import { mergeOptions } from '../utils/general_utils'; import { getLangText } from '../utils/lang_utils'; +let Link = Router.Link; + let Header = React.createClass({ propTypes: { @@ -41,7 +47,11 @@ let Header = React.createClass({ }, getInitialState() { - return mergeOptions(WhitelabelStore.getState(), UserStore.getState()); + return mergeOptions( + WhitelabelStore.getState(), + UserStore.getState(), + PieceListStore.getState() + ); }, componentDidMount() { @@ -49,11 +59,13 @@ let Header = React.createClass({ UserStore.listen(this.onChange); WhitelabelActions.fetchWhitelabel(); WhitelabelStore.listen(this.onChange); + PieceListStore.listen(this.onChange); }, componentWillUnmount() { UserStore.unlisten(this.onChange); WhitelabelStore.unlisten(this.onChange); + PieceListStore.unlisten(this.onChange); }, getLogo(){ @@ -90,6 +102,34 @@ let Header = React.createClass({ } }, + getNotifications() { + if (this.state.requestActions && this.state.requestActions.length > 0) { + return ( + + + + ({this.state.requestActions.length}) + + } + className="notification-menu"> + {this.state.requestActions.map((pieceOrEdition, i) => { + return ( + + + ); + }) + } + + ); + } + return null; + }, + render() { let account; let signup; @@ -100,7 +140,7 @@ let Header = React.createClass({ {getLangText('Account Settings')} {getLangText('Log out')} - + ); navRoutesLinks = ; } @@ -122,6 +162,7 @@ let Header = React.createClass({ {this.getPoweredBy()} + {navRoutesLinks} @@ -175,57 +141,4 @@ let Header = React.createClass({ } }); -let NotificationListItem = React.createClass({ - propTypes: { - pieceOrEdition: React.PropTypes.object - }, - - getLinkData() { - - if(this.props.pieceOrEdition && this.props.pieceOrEdition.bitcoin_id) { - return { - to: 'edition', - params: { - editionId: this.props.pieceOrEdition.bitcoin_id - } - }; - } else { - return { - to: 'piece', - params: { - pieceId: this.props.pieceOrEdition.id - } - }; - } - - }, - - render() { - if (this.props.pieceOrEdition) { - return ( - -
    -
    -
    - -
    -
    -
    -

    {this.props.pieceOrEdition.title}

    -
    by {this.props.pieceOrEdition.artist_name}
    -
    - { - this.props.pieceOrEdition.request_action.map((requestAction) => { - return 'Pending ' + requestAction.action + ' request'; - }) - } -
    -
    -
    - ); - } - return null; - } -}); - export default Header; diff --git a/js/components/header_notification.js b/js/components/header_notification.js new file mode 100644 index 00000000..c838e346 --- /dev/null +++ b/js/components/header_notification.js @@ -0,0 +1,122 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; +import DropdownButton from 'react-bootstrap/lib/DropdownButton'; +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import MenuItem from 'react-bootstrap/lib/MenuItem'; + +import Nav from 'react-bootstrap/lib/Nav'; + +import PieceListStore from '../stores/piece_list_store'; + +import { mergeOptions } from '../utils/general_utils'; +import { getLangText } from '../utils/lang_utils'; + +let Link = Router.Link; + + +let HeaderNotifications = React.createClass({ + + getInitialState() { + return mergeOptions( + PieceListStore.getState() + ); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + }, + + componentWillUnmount() { + PieceListStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + if (this.state.requestActions && this.state.requestActions.length > 0) { + return ( + + ); + } + return null; + } +}); + +let NotificationListItem = React.createClass({ + propTypes: { + pieceOrEdition: React.PropTypes.object + }, + + getLinkData() { + + if(this.props.pieceOrEdition && this.props.pieceOrEdition.parent) { + return { + to: 'edition', + params: { + editionId: this.props.pieceOrEdition.bitcoin_id + } + }; + } else { + return { + to: 'piece', + params: { + pieceId: this.props.pieceOrEdition.id + } + }; + } + + }, + + render() { + if (this.props.pieceOrEdition) { + return ( + +
    +
    +
    + +
    +
    +
    +

    {this.props.pieceOrEdition.title}

    +
    by {this.props.pieceOrEdition.artist_name}
    +
    + { + this.props.pieceOrEdition.request_action.map((requestAction) => { + return 'Pending ' + requestAction.action + ' request'; + }) + } +
    +
    +
    + ); + } + return null; + } +}); + +export default HeaderNotifications; From 71c438ee599fa96b1c74542ab432b753c3d3dd98 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 1 Sep 2015 18:38:24 +0200 Subject: [PATCH 189/397] close notifications dropdown after click --- js/components/header.js | 4 +++- js/components/header_notification.js | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/js/components/header.js b/js/components/header.js index 6876885c..dcf3c475 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -102,7 +102,9 @@ let Header = React.createClass({ let navRoutesLinks; if (this.state.currentUser.username){ account = ( - + {getLangText('Account Settings')} {getLangText('Log out')} diff --git a/js/components/header_notification.js b/js/components/header_notification.js index c838e346..9222c0c4 100644 --- a/js/components/header_notification.js +++ b/js/components/header_notification.js @@ -36,6 +36,27 @@ let HeaderNotifications = React.createClass({ this.setState(state); }, + onSelected(event) { + /* + This is a hack to make the dropdown close after clicking on an item + The function just need to be defined + + from https://github.com/react-bootstrap/react-bootstrap/issues/368: + + @jvillasante - Have you tried to use onSelect with the DropdownButton? + I don't have a working example that is exactly like yours, + but I just noticed that the Dropdown closes when I've attached an event handler to OnSelect: + + + + onSelected: function(e) { + // doesn't need to have functionality (necessarily) ... just wired up + } + Internally, a call to DropdownButton.setDropDownState(false) is made which will hide the dropdown menu. + So, you should be able to call that directly on the DropdownButton instance as well if needed. + */ + }, + render() { if (this.state.requestActions && this.state.requestActions.length > 0) { return ( @@ -48,7 +69,8 @@ let HeaderNotifications = React.createClass({ ({this.state.requestActions.length}) } - className="notification-menu"> + className="notification-menu" + onSelect={this.onSelected}> {this.state.requestActions.map((pieceOrEdition, i) => { return ( From bf5d1de635fea9d55ee6cc5ec49a17374dec9dfc Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 1 Sep 2015 19:14:48 +0200 Subject: [PATCH 190/397] update notification on request action --- .../ascribe_forms/form_request_action.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 5ca7db6c..2448720a 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -6,6 +6,8 @@ import AclButton from './../ascribe_buttons/acl_button'; import ActionPanel from '../ascribe_panel/action_panel'; import Form from './form'; +import PieceListActions from '../../actions/piece_list_actions'; + import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; @@ -71,12 +73,18 @@ let RequestActionForm = React.createClass({ let notification = new GlobalNotificationModel(message, 'success'); GlobalNotificationActions.appendGlobalNotification(notification); - if(this.props.handleSuccess) { - this.props.handleSuccess(); - } + this.handleSuccess(); + }; }, + handleSuccess() { + PieceListActions.fetchPieceRequestActions(); + if(this.props.handleSuccess) { + this.props.handleSuccess(); + } + }, + getContent() { let pieceOrEditionStr = this.isPiece() ? getLangText('this work%s', '.') : getLangText('this edition%s', '.'); let message = this.props.requestUser + ' ' + getLangText('requests you') + ' ' + this.props.requestAction + ' ' + pieceOrEditionStr; @@ -99,7 +107,7 @@ let RequestActionForm = React.createClass({ buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px' pieceOrEditions={this.props.pieceOrEditions} currentUser={this.props.currentUser} - handleSuccess={this.props.handleSuccess} /> + handleSuccess={this.handleSuccess} /> ); } else if(this.props.requestAction === 'loan_request') { return ( @@ -110,7 +118,7 @@ let RequestActionForm = React.createClass({ buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px' pieceOrEditions={this.props.pieceOrEditions} currentUser={this.props.currentUser} - handleSuccess={this.props.handleSuccess} /> + handleSuccess={this.handleSuccess} /> ); } else { return ( From 07ce180ff7a69a4d826e6326336ee897bc56ab5a Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 2 Sep 2015 13:57:41 +0200 Subject: [PATCH 191/397] contract form POST --- js/components/ascribe_forms/form_create_contract.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_forms/form_create_contract.js b/js/components/ascribe_forms/form_create_contract.js index 1b3fcfd6..416ae0e5 100644 --- a/js/components/ascribe_forms/form_create_contract.js +++ b/js/components/ascribe_forms/form_create_contract.js @@ -18,14 +18,20 @@ let CreateContractForm = React.createClass({ getInitialState() { return { - digitalWorkKey: null, + contractKey: null, isUploadReady: false }; }, + getFormData(){ + return { + blob: this.state.contractKey + }; + }, + submitKey(key) { this.setState({ - digitalWorkKey: key + contractKey: key }); }, @@ -39,6 +45,7 @@ let CreateContractForm = React.createClass({ return (
    Date: Wed, 2 Sep 2015 14:02:23 +0200 Subject: [PATCH 192/397] contract list add --- js/components/ascribe_detail/edition.js | 1 - .../ascribe_detail/edition_container.js | 3 ++ .../ascribe_settings/contract_settings.js | 31 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 696e5057..49175851 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -305,7 +305,6 @@ let EditionSummary = React.createClass({
    ); - } }); diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js index 15086434..3be63974 100644 --- a/js/components/ascribe_detail/edition_container.js +++ b/js/components/ascribe_detail/edition_container.js @@ -9,6 +9,8 @@ import Edition from './edition'; import AppConstants from '../../constants/application_constants'; + + /** * This is the component that implements resource/data specific functionality */ @@ -50,6 +52,7 @@ let EditionContainer = React.createClass({ }, render() { + console.log(this.state); if('title' in this.state.edition) { return ( {/* this should be this.props.defaultExpanded */} - + + {this.state.contractList} + + + + ); } From 19726560ba707a7fdbebe6db95b96c93380348c6 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 2 Sep 2015 14:39:32 +0200 Subject: [PATCH 193/397] bitbucket test --- ...contract.js => form_contract_agreement.js} | 28 +++++++++---------- .../ikonotv/ikonotv_request_loan.js | 4 +-- js/constants/api_urls.js | 1 + 3 files changed, 16 insertions(+), 17 deletions(-) rename js/components/ascribe_forms/{form_contract.js => form_contract_agreement.js} (85%) diff --git a/js/components/ascribe_forms/form_contract.js b/js/components/ascribe_forms/form_contract_agreement.js similarity index 85% rename from js/components/ascribe_forms/form_contract.js rename to js/components/ascribe_forms/form_contract_agreement.js index 4c51e7a3..747bdfa4 100644 --- a/js/components/ascribe_forms/form_contract.js +++ b/js/components/ascribe_forms/form_contract_agreement.js @@ -19,7 +19,7 @@ import { getLangText } from '../../utils/lang_utils'; import { mergeOptions } from '../../utils/general_utils'; -let ContractForm = React.createClass({ +let ContractAgreementForm = React.createClass({ propTypes: { handleSuccess: React.PropTypes.func }, @@ -55,8 +55,13 @@ let ContractForm = React.createClass({ GlobalNotificationActions.appendGlobalNotification(notification); }, + getFormData(){ + return {'appendix': {'default': this.refs.form.refs.appendix.value}} + }, + getContracts() { - if (this.state.contractList && this.state.contractList.length > 0) { + if (this.state.contractList && this.state.contractList.count > 0) { + let contractList = this.state.contractList.results; return ( {getLangText('Learn more')} }> - - + ); } }); diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index b056ee03..6e43b8ef 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -27,6 +27,7 @@ let ApiUrls = { 'note_private_piece': AppConstants.apiEndpoint + 'note/private/pieces/', 'note_public_edition': AppConstants.apiEndpoint + 'note/public/editions/', 'note_public_piece': AppConstants.apiEndpoint + 'note/public/pieces/', + 'ownership_contract_agreements': AppConstants.apiEndpoint + 'ownership/contract_agreements/', 'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/', 'ownership_consigns_deny': AppConstants.apiEndpoint + 'ownership/consigns/deny/', From a8610fa1082fc6d3d961f025a6fd2596abea75f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 2 Sep 2015 15:56:27 +0200 Subject: [PATCH 194/397] change ikono contract --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 3 ++- .../ikonotv/ascribe_buttons/ikonotv_submit_button.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 8ecaf40b..a1f76086 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -125,7 +125,8 @@ var ReactS3FineUploader = React.createClass({ bucket: 'ascribe0' }, request: { - endpoint: 'https://ascribe0.s3.amazonaws.com', + endpoint: 'https://www.ascribe.io.global.prod.fastly.net', + //endpoint: 'https://ascribe0.s3.amazonaws.com', accessKey: 'AKIAIVCZJ33WSCBQ3QDA' }, uploadSuccess: { 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 40d65a2b..41b47a82 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 @@ -58,7 +58,7 @@ let IkonotvSubmitButton = React.createClass({ {' ' + getLangText('I agree to the Terms of Service of IkonoTV Archive') + ' '} - ( + ( {getLangText('read')} ) From 7f39c62130d3633422f59d40be6ff2f44ce6ad77 Mon Sep 17 00:00:00 2001 From: diminator Date: Wed, 2 Sep 2015 16:34:43 +0200 Subject: [PATCH 195/397] create contract and agreement --- .../ascribe_forms/form_contract_agreement.js | 2 +- js/components/ascribe_forms/form_create_contract.js | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_forms/form_contract_agreement.js b/js/components/ascribe_forms/form_contract_agreement.js index 747bdfa4..1d9f7c72 100644 --- a/js/components/ascribe_forms/form_contract_agreement.js +++ b/js/components/ascribe_forms/form_contract_agreement.js @@ -56,7 +56,7 @@ let ContractAgreementForm = React.createClass({ }, getFormData(){ - return {'appendix': {'default': this.refs.form.refs.appendix.value}} + return {'appendix': {'default': this.refs.form.refs.appendix.state.value}}; }, getContracts() { diff --git a/js/components/ascribe_forms/form_create_contract.js b/js/components/ascribe_forms/form_create_contract.js index 416ae0e5..a5f719e2 100644 --- a/js/components/ascribe_forms/form_create_contract.js +++ b/js/components/ascribe_forms/form_create_contract.js @@ -5,6 +5,9 @@ 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 ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader'; import AppConstants from '../../constants/application_constants'; @@ -41,11 +44,18 @@ let CreateContractForm = React.createClass({ }); }, + handleCreateSuccess(response) { + let notification = new GlobalNotificationModel(getLangText('Contract %s successfully created', response.name), 'success', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }, + + render() { return ( Date: Wed, 2 Sep 2015 17:36:01 +0200 Subject: [PATCH 196/397] Remove unused ButtonSubmitOrClose and styles --- .../ascribe_buttons/button_submit.js | 27 ---------------- .../ascribe_buttons/button_submit_close.js | 32 ------------------- sass/lib/buttons.scss | 0 sass/main.scss | 13 ++------ 4 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 js/components/ascribe_buttons/button_submit.js delete mode 100644 js/components/ascribe_buttons/button_submit_close.js create mode 100644 sass/lib/buttons.scss diff --git a/js/components/ascribe_buttons/button_submit.js b/js/components/ascribe_buttons/button_submit.js deleted file mode 100644 index ef5999cd..00000000 --- a/js/components/ascribe_buttons/button_submit.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -import React from 'react'; - -let ButtonSubmitOrClose = React.createClass({ - propTypes: { - submitted: React.PropTypes.bool.isRequired, - text: React.PropTypes.string.isRequired - }, - - render() { - if (this.props.submitted){ - return ( -
    - -
    - ); - } - return ( -
    - -
    - ); - } -}); - -export default ButtonSubmitOrClose; diff --git a/js/components/ascribe_buttons/button_submit_close.js b/js/components/ascribe_buttons/button_submit_close.js deleted file mode 100644 index 11d3c0a4..00000000 --- a/js/components/ascribe_buttons/button_submit_close.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -import React from 'react'; - -import AppConstants from '../../constants/application_constants'; -import { getLangText } from '../../utils/lang_utils.js' - -let ButtonSubmitOrClose = React.createClass({ - propTypes: { - submitted: React.PropTypes.bool.isRequired, - text: React.PropTypes.string.isRequired, - onClose: React.PropTypes.func.isRequired - }, - - render() { - if (this.props.submitted){ - return ( -
    - -
    - ); - } - return ( -
    - - -
    - ); - } -}); - -export default ButtonSubmitOrClose; diff --git a/sass/lib/buttons.scss b/sass/lib/buttons.scss new file mode 100644 index 00000000..e69de29b diff --git a/sass/main.scss b/sass/main.scss index e8d708e3..6f17792a 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -184,31 +184,22 @@ hr { border: 1px solid $ascribe-brand-danger; } } -.btn-ascribe, .btn-ascribe-inv { +.btn-ascribe { border: 1px solid #444; line-height: 2em; margin-right: 1px; margin-left: 0 !important; font-family: sans-serif !important; border-radius: 0 !important; -} - -.btn-ascribe, .btn-ascribe-inv:active, .btn-ascribe-inv:hover { color: #222 !important; background-color: #FFF; } -.btn-ascribe:active, .btn-ascribe:hover, .btn-ascribe-inv { +.btn-ascribe:active, .btn-ascribe:hover { color: #FFF !important; background-color: #444; } -.btn-ascribe-inv:disabled, .btn-ascribe-inv:focus { - color: #444 !important; - background-color: #BBB !important; - border: 1px solid #444 !important; -} - .btn-ascribe-sm { font-size: 12px; line-height: 1.3em; From edcd8e57a4f511c192e7bda5c985e1aced98e752 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 3 Sep 2015 14:15:00 +0200 Subject: [PATCH 197/397] notification app notification refactor in onion - split by piece/edition --- js/actions/notification_actions.js | 34 +++++ .../ascribe_detail/edition_container.js | 1 - js/components/header.js | 33 ++++- js/components/header_notification.js | 129 +++++++++++++----- js/components/piece_list.js | 3 +- js/constants/api_urls.js | 3 +- js/fetchers/notification_fetcher.js | 17 +++ js/stores/notification_store.js | 26 ++++ sass/ascribe_notification_list.scss | 28 +++- 9 files changed, 231 insertions(+), 43 deletions(-) create mode 100644 js/actions/notification_actions.js create mode 100644 js/fetchers/notification_fetcher.js create mode 100644 js/stores/notification_store.js diff --git a/js/actions/notification_actions.js b/js/actions/notification_actions.js new file mode 100644 index 00000000..06fce61f --- /dev/null +++ b/js/actions/notification_actions.js @@ -0,0 +1,34 @@ +'use strict'; + +import alt from '../alt'; + +import NotificationFetcher from '../fetchers/notification_fetcher'; + +class NotificationActions { + constructor() { + this.generateActions( + 'updatePieceListNotifications', + 'updateEditionListNotifications' + ); + } + + fetchPieceListNotifications() { + NotificationFetcher + .fetchPieceListNotifications() + .then((res) => { + this.actions.updatePieceListNotifications(res); + }) + .catch((err) => console.logGlobal(err)); + } + + fetchEditionListNotifications() { + NotificationFetcher + .fetchEditionListNotifications() + .then((res) => { + this.actions.updateEditionListNotifications(res); + }) + .catch((err) => console.logGlobal(err)); + } +} + +export default alt.createActions(NotificationActions); diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js index 78b1e477..a19f67b9 100644 --- a/js/components/ascribe_detail/edition_container.js +++ b/js/components/ascribe_detail/edition_container.js @@ -61,7 +61,6 @@ let EditionContainer = React.createClass({ }, render() { - console.log(this.state); if('title' in this.state.edition) { return ( + + onSelected: function(e) { + // doesn't need to have functionality (necessarily) ... just wired up + } + Internally, a call to DropdownButton.setDropDownState(false) is made which will hide the dropdown menu. + So, you should be able to call that directly on the DropdownButton instance as well if needed. + + NOW, THAT DIDN'T WORK - the onSelect routine isnt triggered in all cases + Hence, we do this manually + */ + this.refs.dropdownbutton.setDropdownState(false); + }, + render() { let account; let signup; @@ -103,9 +128,15 @@ let Header = React.createClass({ if (this.state.currentUser.username){ account = ( - {getLangText('Account Settings')} + + {getLangText('Account Settings')} + {getLangText('Log out')} diff --git a/js/components/header_notification.js b/js/components/header_notification.js index 9222c0c4..73d68a5d 100644 --- a/js/components/header_notification.js +++ b/js/components/header_notification.js @@ -8,7 +8,8 @@ import MenuItem from 'react-bootstrap/lib/MenuItem'; import Nav from 'react-bootstrap/lib/Nav'; -import PieceListStore from '../stores/piece_list_store'; +import NotificationActions from '../actions/notification_actions'; +import NotificationStore from '../stores/notification_store'; import { mergeOptions } from '../utils/general_utils'; import { getLangText } from '../utils/lang_utils'; @@ -20,23 +21,25 @@ let HeaderNotifications = React.createClass({ getInitialState() { return mergeOptions( - PieceListStore.getState() + NotificationStore.getState() ); }, componentDidMount() { - PieceListStore.listen(this.onChange); + NotificationStore.listen(this.onChange); + NotificationActions.fetchPieceListNotifications(); + NotificationActions.fetchEditionListNotifications(); }, componentWillUnmount() { - PieceListStore.unlisten(this.onChange); + NotificationStore.unlisten(this.onChange); }, onChange(state) { this.setState(state); }, - onSelected(event) { + onMenuItemClick(event) { /* This is a hack to make the dropdown close after clicking on an item The function just need to be defined @@ -54,32 +57,87 @@ let HeaderNotifications = React.createClass({ } Internally, a call to DropdownButton.setDropDownState(false) is made which will hide the dropdown menu. So, you should be able to call that directly on the DropdownButton instance as well if needed. + + NOW, THAT DIDN'T WORK - the onSelect routine isnt triggered in all cases + Hence, we do this manually */ + this.refs.dropdownbutton.setDropdownState(false); + }, + + getPieceNotifications(){ + if (this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) { + return ( +
    +
    + Artworks ({this.state.pieceListNotifications.length}) +
    + {this.state.pieceListNotifications.map((pieceNotification, i) => { + return ( + + + + ); + } + )} +
    + ); + } + return null; + }, + + getEditionNotifications(){ + if (this.state.editionListNotifications && this.state.editionListNotifications.length > 0) { + return ( +
    +
    + Editions ({this.state.editionListNotifications.length}) +
    + {this.state.editionListNotifications.map((editionNotification, i) => { + return ( + + + + ); + } + )} +
    + ); + } + return null; }, render() { - if (this.state.requestActions && this.state.requestActions.length > 0) { + if ((this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) || + (this.state.editionListNotifications && this.state.editionListNotifications.length > 0)){ + let numNotifications = 0; + if (this.state.pieceListNotifications && this.state.pieceListNotifications.length > 0) { + numNotifications += this.state.pieceListNotifications.length; + } + if (this.state.editionListNotifications && this.state.editionListNotifications.length > 0) { + numNotifications += this.state.editionListNotifications.length; + } return ( ); @@ -90,33 +148,42 @@ let HeaderNotifications = React.createClass({ let NotificationListItem = React.createClass({ propTypes: { - pieceOrEdition: React.PropTypes.object + notification: React.PropTypes.array, + pieceOrEdition: React.PropTypes.object, + onClick: React.PropTypes.func + }, + + isPiece() { + return !(this.props.pieceOrEdition && this.props.pieceOrEdition.parent); }, getLinkData() { - if(this.props.pieceOrEdition && this.props.pieceOrEdition.parent) { - return { - to: 'edition', - params: { - editionId: this.props.pieceOrEdition.bitcoin_id - } - }; - } else { + if (this.isPiece()) { return { to: 'piece', params: { pieceId: this.props.pieceOrEdition.id } }; + } else { + return { + to: 'edition', + params: { + editionId: this.props.pieceOrEdition.bitcoin_id + } + }; } }, + onClick(event){ + this.props.onClick(event); + }, render() { if (this.props.pieceOrEdition) { return ( - +
    @@ -127,11 +194,7 @@ let NotificationListItem = React.createClass({

    {this.props.pieceOrEdition.title}

    by {this.props.pieceOrEdition.artist_name}
    - { - this.props.pieceOrEdition.request_action.map((requestAction) => { - return 'Pending ' + requestAction.action + ' request'; - }) - } + {'Pending ' + this.props.notification[0].action + ' request'}
    diff --git a/js/components/piece_list.js b/js/components/piece_list.js index d841f7af..71304a63 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -65,8 +65,7 @@ let PieceList = React.createClass({ let orderBy = this.props.orderBy ? this.props.orderBy : this.state.orderBy; if (this.state.pieceList.length === 0 || this.state.page !== page){ PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, - orderBy, this.state.orderAsc, this.state.filterBy) - .then(() => PieceListActions.fetchPieceRequestActions()); + orderBy, this.state.orderAsc, this.state.filterBy); } }, diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index 6e43b8ef..f72eabdd 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -27,6 +27,8 @@ let ApiUrls = { 'note_private_piece': AppConstants.apiEndpoint + 'note/private/pieces/', 'note_public_edition': AppConstants.apiEndpoint + 'note/public/editions/', 'note_public_piece': AppConstants.apiEndpoint + 'note/public/pieces/', + 'notification_piecelist': AppConstants.apiEndpoint + 'notifications/pieces/', + 'notification_editionlist': AppConstants.apiEndpoint + 'notifications/editions/', 'ownership_contract_agreements': AppConstants.apiEndpoint + 'ownership/contract_agreements/', 'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/', @@ -52,7 +54,6 @@ let ApiUrls = { 'piece_extradata': AppConstants.apiEndpoint + 'pieces/${piece_id}/extradata/', 'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/', 'pieces_list': AppConstants.apiEndpoint + 'pieces/', - 'pieces_list_request_actions': AppConstants.apiEndpoint + 'pieces/request_actions/', 'piece_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/pieces/${piece_id}/', 'user': AppConstants.apiEndpoint + 'users/', 'users_login': AppConstants.apiEndpoint + 'users/login/', diff --git a/js/fetchers/notification_fetcher.js b/js/fetchers/notification_fetcher.js new file mode 100644 index 00000000..c6f9be54 --- /dev/null +++ b/js/fetchers/notification_fetcher.js @@ -0,0 +1,17 @@ +'use strict'; + +import requests from '../utils/requests'; + + +let NotificationFetcher = { + + fetchPieceListNotifications() { + return requests.get('notification_piecelist'); + }, + + fetchEditionListNotifications() { + return requests.get('notification_editionlist'); + } +}; + +export default NotificationFetcher; diff --git a/js/stores/notification_store.js b/js/stores/notification_store.js new file mode 100644 index 00000000..c5401190 --- /dev/null +++ b/js/stores/notification_store.js @@ -0,0 +1,26 @@ +'use strict'; + +import React from 'react'; +import alt from '../alt'; + +import NotificationActions from '../actions/notification_actions'; + + +class NotificationStore { + constructor() { + this.pieceListNotifications = {}; + this.editionListNotifications = {}; + this.bindActions(NotificationActions); + } + + onUpdatePieceListNotifications(res) { + this.pieceListNotifications = res.notifications; + } + + onUpdateEditionListNotifications(res) { + this.editionListNotifications = res.notifications; + } + +} + +export default alt.createStore(NotificationStore, 'NotificationStore'); diff --git a/sass/ascribe_notification_list.scss b/sass/ascribe_notification_list.scss index bd3c0b20..c1d2ef65 100644 --- a/sass/ascribe_notification_list.scss +++ b/sass/ascribe_notification_list.scss @@ -2,13 +2,27 @@ $break-small: 764px; $break-medium: 991px; $break-medium: 1200px; -.notification-wrapper { +.notification-header,.notification-wrapper { width: 350px; - height:8em; - padding: 0.3em; - border-bottom: 1px solid #cccccc; - margin: -3px -20px; +} +.notification-header { + border-bottom: 1px solid #cccccc; + border-top: 1px solid #cccccc; + padding: 0.3em 1em; + background-color: #eeeeee; +} + +.notification-wrapper { + height:8.4em; + border-bottom: 1px solid #eeeeee; + margin: -3px 0; + padding: 0.5em; + color: black; + + &:hover{ + background-color: rgba(2, 182, 163, .05); + } // ToDo: Include media queries for thumbnail .thumbnail-wrapper { width: 7.4em; @@ -46,6 +60,10 @@ $break-medium: 1200px; li a { padding-top: 0; } + border-top: 0; + overflow-y:auto; + overflow-x:hidden; + max-height: 70vh; } } From 9334251fd388ca17c30ffde05d6e26388e764fc3 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 3 Sep 2015 15:17:12 +0200 Subject: [PATCH 198/397] notifications on piece details (www, ikono, cyland) and edition details --- js/actions/notification_actions.js | 22 ++++++++++++++- js/components/ascribe_detail/edition.js | 26 +++++++++++++++-- .../ascribe_detail/piece_container.js | 15 ++++++---- .../ascribe_forms/form_request_action.js | 11 ++++++-- .../ascribe_detail/prize_piece_container.js | 28 +++++++++++++++---- .../ascribe_detail/ikonotv_piece_container.js | 16 +++++++---- js/constants/api_urls.js | 2 ++ js/fetchers/notification_fetcher.js | 8 ++++++ js/stores/notification_store.js | 10 +++++++ sass/ascribe_notification_list.scss | 4 +-- 10 files changed, 119 insertions(+), 23 deletions(-) diff --git a/js/actions/notification_actions.js b/js/actions/notification_actions.js index 06fce61f..429ae666 100644 --- a/js/actions/notification_actions.js +++ b/js/actions/notification_actions.js @@ -8,7 +8,9 @@ class NotificationActions { constructor() { this.generateActions( 'updatePieceListNotifications', - 'updateEditionListNotifications' + 'updateEditionListNotifications', + 'updateEditionNotifications', + 'updatePieceNotifications' ); } @@ -21,6 +23,15 @@ class NotificationActions { .catch((err) => console.logGlobal(err)); } + fetchPieceNotifications(pieceId) { + NotificationFetcher + .fetchPieceNotifications(pieceId) + .then((res) => { + this.actions.updatePieceNotifications(res); + }) + .catch((err) => console.logGlobal(err)); + } + fetchEditionListNotifications() { NotificationFetcher .fetchEditionListNotifications() @@ -29,6 +40,15 @@ class NotificationActions { }) .catch((err) => console.logGlobal(err)); } + + fetchEditionNotifications(editionId) { + NotificationFetcher + .fetchEditionNotifications(editionId) + .then((res) => { + this.actions.updateEditionNotifications(res); + }) + .catch((err) => console.logGlobal(err)); + } } export default alt.createActions(NotificationActions); diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index 49175851..db8f0b7e 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -16,6 +16,9 @@ import PieceListActions from '../../actions/piece_list_actions'; import PieceListStore from '../../stores/piece_list_store'; import EditionListActions from '../../actions/edition_list_actions'; +import NotificationActions from '../../actions/notification_actions'; +import NotificationStore from '../../stores/notification_store'; + import HistoryIterator from './history_iterator'; import MediaContainer from './media_container'; @@ -208,6 +211,25 @@ let EditionSummary = React.createClass({ handleDeleteSuccess: React.PropTypes.func }, + getInitialState() { + return mergeOptions( + NotificationStore.getState() + ); + }, + + componentDidMount() { + NotificationStore.listen(this.onChange); + NotificationActions.fetchEditionNotifications(this.props.edition.bitcoin_id); + }, + + componentWillUnmount() { + NotificationStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + getTransferWithdrawData(){ return {'bitcoin_id': this.props.edition.bitcoin_id}; }, @@ -234,13 +256,13 @@ let EditionSummary = React.createClass({ getActions(){ let actions = null; - if (this.props.edition.request_action && this.props.edition.request_action.length > 0){ + if (this.state.editionNotifications && this.state.editionNotifications.notification){ actions = ( ); + requestActions={this.state.editionNotifications.notification}/>); } else { diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 7297825d..0de25beb 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -9,6 +9,9 @@ import PieceStore from '../../stores/piece_store'; import PieceListActions from '../../actions/piece_list_actions'; import PieceListStore from '../../stores/piece_list_store'; +import NotificationActions from '../../actions/notification_actions'; +import NotificationStore from '../../stores/notification_store'; + import UserActions from '../../actions/user_actions'; import UserStore from '../../stores/user_store'; @@ -62,6 +65,8 @@ let PieceContainer = React.createClass({ UserActions.fetchCurrentUser(); PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); + NotificationStore.listen(this.onChange); + NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, componentWillUnmount() { @@ -73,6 +78,7 @@ let PieceContainer = React.createClass({ PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); + NotificationStore.unlisten(this.onChange); }, onChange(state) { @@ -172,17 +178,16 @@ let PieceContainer = React.createClass({ return {'id': this.state.piece.id}; }, - getActions(){ + getActions() { if (this.state.piece && - this.state.piece.request_action && - this.state.piece.request_action.length > 0) { + this.state.pieceNotifications && + this.state.pieceNotifications.notification) { return ( - ); + requestActions={this.state.pieceNotifications.notification}/>); } else { return ( diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index 2448720a..c65a7394 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -6,7 +6,7 @@ import AclButton from './../ascribe_buttons/acl_button'; import ActionPanel from '../ascribe_panel/action_panel'; import Form from './form'; -import PieceListActions from '../../actions/piece_list_actions'; +import NotificationActions from '../../actions/notification_actions'; import GlobalNotificationModel from '../../models/global_notification_model'; import GlobalNotificationActions from '../../actions/global_notification_actions'; @@ -79,7 +79,14 @@ let RequestActionForm = React.createClass({ }, handleSuccess() { - PieceListActions.fetchPieceRequestActions(); + if (this.isPiece()){ + NotificationActions.fetchPieceListNotifications(); + //NotificationActions.fetchPieceNotifications(this.props.pieceOrEditions.id); + } + else { + NotificationActions.fetchEditionListNotifications(); + NotificationActions.fetchEditionNotifications(this.props.pieceOrEditions[0].bitcoin_id); + } if(this.props.handleSuccess) { this.props.handleSuccess(); } diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index 9e927ac4..cb9e1593 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -15,6 +15,9 @@ import PieceListActions from '../../../../../actions/piece_list_actions'; import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; +import NotificationStore from '../../../../../stores/notification_store'; +import NotificationActions from '../../../../../actions/notification_actions.js'; + import UserStore from '../../../../../stores/user_store'; import Piece from '../../../../../components/ascribe_detail/piece'; @@ -50,7 +53,8 @@ let PieceContainer = React.createClass({ getInitialState() { return mergeOptions( PieceStore.getState(), - UserStore.getState() + UserStore.getState(), + NotificationStore.getState() ); }, @@ -58,6 +62,8 @@ let PieceContainer = React.createClass({ PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); + NotificationStore.listen(this.onChange); + NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, // This is done to update the container when the user clicks on the prev or next @@ -77,6 +83,7 @@ let PieceContainer = React.createClass({ PieceActions.updatePiece({}); PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); + NotificationStore.unlisten(this.onChange); }, @@ -88,6 +95,19 @@ let PieceContainer = React.createClass({ PieceActions.fetchOne(this.props.params.pieceId); }, + getActions() { + if (this.state.piece && + this.state.pieceNotifications && + this.state.pieceNotifications.notification) { + return ( + ); + } + }, + render() { if('title' in this.state.piece) { // Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted @@ -111,11 +131,7 @@ let PieceContainer = React.createClass({ {artistEmail} - + {this.getActions()}
    } diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js index 7f094a26..781b148b 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js @@ -10,6 +10,9 @@ import PieceListStore from '../../../../../../stores/piece_list_store'; import UserStore from '../../../../../../stores/user_store'; +import NotificationStore from '../../../../../../stores/notification_store'; +import NotificationActions from '../../../../../../actions/notification_actions.js'; + import Piece from '../../../../../../components/ascribe_detail/piece'; import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions'; @@ -41,7 +44,8 @@ let IkonotvPieceContainer = React.createClass({ return mergeOptions( PieceStore.getState(), UserStore.getState(), - PieceListStore.getState() + PieceListStore.getState(), + NotificationStore.getState() ); }, @@ -50,6 +54,8 @@ let IkonotvPieceContainer = React.createClass({ PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); PieceListStore.listen(this.onChange); + NotificationStore.listen(this.onChange); + NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, componentWillReceiveProps(nextProps) { @@ -68,6 +74,7 @@ let IkonotvPieceContainer = React.createClass({ PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); + NotificationStore.unlisten(this.onChange); }, onChange(state) { @@ -89,15 +96,14 @@ let IkonotvPieceContainer = React.createClass({ getActions(){ if (this.state.piece && - this.state.piece.request_action && - this.state.piece.request_action.length > 0) { + this.state.pieceNotifications && + this.state.pieceNotifications.notification) { return ( - ); + requestActions={this.state.pieceNotifications.notification}/>); } else { diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index f72eabdd..6b1d7dee 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -28,7 +28,9 @@ let ApiUrls = { 'note_public_edition': AppConstants.apiEndpoint + 'note/public/editions/', 'note_public_piece': AppConstants.apiEndpoint + 'note/public/pieces/', 'notification_piecelist': AppConstants.apiEndpoint + 'notifications/pieces/', + 'notification_piece': AppConstants.apiEndpoint + 'notifications/pieces/${piece_id}/', 'notification_editionlist': AppConstants.apiEndpoint + 'notifications/editions/', + 'notification_edition': AppConstants.apiEndpoint + 'notifications/editions/${edition_id}/', 'ownership_contract_agreements': AppConstants.apiEndpoint + 'ownership/contract_agreements/', 'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/', diff --git a/js/fetchers/notification_fetcher.js b/js/fetchers/notification_fetcher.js index c6f9be54..6d2f7424 100644 --- a/js/fetchers/notification_fetcher.js +++ b/js/fetchers/notification_fetcher.js @@ -9,8 +9,16 @@ let NotificationFetcher = { return requests.get('notification_piecelist'); }, + fetchPieceNotifications(pieceId) { + return requests.get('notification_piece', {'piece_id': pieceId}); + }, + fetchEditionListNotifications() { return requests.get('notification_editionlist'); + }, + + fetchEditionNotifications(editionId) { + return requests.get('notification_edition', {'edition_id': editionId}); } }; diff --git a/js/stores/notification_store.js b/js/stores/notification_store.js index c5401190..6e706699 100644 --- a/js/stores/notification_store.js +++ b/js/stores/notification_store.js @@ -10,6 +10,8 @@ class NotificationStore { constructor() { this.pieceListNotifications = {}; this.editionListNotifications = {}; + this.editionNotifications = null; + this.pieceNotifications = null; this.bindActions(NotificationActions); } @@ -17,10 +19,18 @@ class NotificationStore { this.pieceListNotifications = res.notifications; } + onUpdatePieceNotifications(res) { + this.pieceNotifications = res.notification; + } + onUpdateEditionListNotifications(res) { this.editionListNotifications = res.notifications; } + onUpdateEditionNotifications(res) { + this.editionNotifications = res.notification; + } + } export default alt.createStore(NotificationStore, 'NotificationStore'); diff --git a/sass/ascribe_notification_list.scss b/sass/ascribe_notification_list.scss index c1d2ef65..696d9169 100644 --- a/sass/ascribe_notification_list.scss +++ b/sass/ascribe_notification_list.scss @@ -61,8 +61,8 @@ $break-medium: 1200px; padding-top: 0; } border-top: 0; - overflow-y:auto; - overflow-x:hidden; + overflow-y: auto; + overflow-x: hidden; max-height: 70vh; } } From d2f8b658afc14c9366a634bc8947e045cba9dbf0 Mon Sep 17 00:00:00 2001 From: Cevo Date: Thu, 3 Sep 2015 15:53:02 +0200 Subject: [PATCH 199/397] contract listing being done --- .gitignore~ | 24 ++++++++ js/actions/contract_actions.js | 1 + js/actions/contract_list_actions.js | 13 +++- .../ascribe_forms/form_create_contract.js | 2 +- js/components/ascribe_panel/action_panel.js | 1 - .../ascribe_settings/contract_settings.js | 60 +++++++++++++++++-- js/constants/api_urls.js | 3 +- js/fetchers/ownership_fetcher.js | 7 ++- js/utils/general_utils.js | 13 ++++ js/utils/requests.js | 21 +++++-- 10 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 .gitignore~ diff --git a/.gitignore~ b/.gitignore~ new file mode 100644 index 00000000..41b217c2 --- /dev/null +++ b/.gitignore~ @@ -0,0 +1,24 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +*.sublime-project +.idea +spool-project.sublime-project +*.sublime-workspace +*.sublime-workspace +webapp-dependencies.txt + +pids +logs +results +README.md~ +node_modules/* + +build + +.DS_Store diff --git a/js/actions/contract_actions.js b/js/actions/contract_actions.js index e14dbf83..c6055ffc 100644 --- a/js/actions/contract_actions.js +++ b/js/actions/contract_actions.js @@ -43,6 +43,7 @@ class ContractActions { /* No email was entered - Ignore and keep going*/ } } + } export default alt.createActions(ContractActions); diff --git a/js/actions/contract_list_actions.js b/js/actions/contract_list_actions.js index f4257d37..b019ecc0 100644 --- a/js/actions/contract_list_actions.js +++ b/js/actions/contract_list_actions.js @@ -3,7 +3,6 @@ import alt from '../alt'; import OwnershipFetcher from '../fetchers/ownership_fetcher'; - class ContractListActions { constructor() { this.generateActions( @@ -15,13 +14,23 @@ class ContractListActions { fetchContractList() { OwnershipFetcher.fetchContractList() .then((contracts) => { - this.actions.updateContractList(contracts); + this.actions.updateContractList(contracts.results); }) .catch((err) => { console.logGlobal(err); this.actions.updateContractList([]); }); } + + makeContractPublic(contract){ + OwnershipFetcher.makeContractPublic(contract) + .then((res) =>{ + return res; + }) + .catch((err)=>{ + console.logGlobal(err); + }); + } } export default alt.createActions(ContractListActions); diff --git a/js/components/ascribe_forms/form_create_contract.js b/js/components/ascribe_forms/form_create_contract.js index 416ae0e5..e3b4321a 100644 --- a/js/components/ascribe_forms/form_create_contract.js +++ b/js/components/ascribe_forms/form_create_contract.js @@ -44,7 +44,7 @@ let CreateContractForm = React.createClass({ render() { return ( ContractListActions.fetchContractList()) + .catch((error)=>{console.log("Error ", error)}) + }, + getPublicContracts(){ + return this.state.contractList.filter((contract) => contract.public); + }, + getPrivateContracts(){ + return this.state.contractList.filter((contract) => !contract.public); + }, + getblobEndName(contract){ + return contract.blob.match(/.*\/(.*)/)[1]; + }, render() { + let publicContracts = this.getPublicContracts(); + let privateContracts = this.getPrivateContracts(); + console.log(this.state.contractList); return ( + defaultExpanded={false}> {/* this should be this.props.defaultExpanded */} - {this.state.contractList} + defaultExpanded={false}> + {
    +

    Public Contracts

    + {(publicContracts.length > 0) ? + publicContracts.map( + (contract) => { + return( + + + + } + />) + } + ) : null } +
    } + + {
    +

    Private Contracts

    + {(privateContracts.length>0) ? + privateContracts.map( + (contract) => { + return( + + + } + />) + } + ) : null} +
    }
    + defaultExpanded={false}>
    diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index b056ee03..1e159ed7 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -46,7 +46,8 @@ let ApiUrls = { 'ownership_unconsigns': AppConstants.apiEndpoint + 'ownership/unconsigns/', 'ownership_unconsigns_deny': AppConstants.apiEndpoint + 'ownership/unconsigns/deny/', 'ownership_unconsigns_request': AppConstants.apiEndpoint + 'ownership/unconsigns/request/', - 'ownership_contract': AppConstants.apiEndpoint + 'ownership/contracts/', + 'ownership_contract':AppConstants.apiEndpoint + 'ownership/contracts/${contract_id}', + "ownership_contract_list": AppConstants.apiEndpoint + 'ownership/contracts/', 'piece': AppConstants.apiEndpoint + 'pieces/${piece_id}/', 'piece_extradata': AppConstants.apiEndpoint + 'pieces/${piece_id}/extradata/', 'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/', diff --git a/js/fetchers/ownership_fetcher.js b/js/fetchers/ownership_fetcher.js index 051f2d08..8f97add5 100644 --- a/js/fetchers/ownership_fetcher.js +++ b/js/fetchers/ownership_fetcher.js @@ -16,11 +16,16 @@ let OwnershipFetcher = { * Fetch the contracts of the logged-in user from the API. */ fetchContractList(){ - return requests.get(ApiUrls.ownership_contract); + return requests.get(ApiUrls.ownership_contract_list); }, fetchLoanPieceRequestList(){ return requests.get(ApiUrls.ownership_loans_pieces_request); + }, + + makeContractPublic(contractObj){ + console.log(contractObj); + return requests.put('ownership_contract_list',{ body: contractObj, contract_id:contractObj.id }); } }; diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 15b0e85f..673a5509 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -52,6 +52,19 @@ export function sumNumList(l) { return sum; } +export function excludePropFromObject(obj, propList){ + let clonedObj = mergeOptions({},obj); + for (let item in propList){ + console.log(item); + if (clonedObj[propList[item]]){ + console.log('deleting... '); + delete clonedObj[propList[item]]; + } + } + console.log(clonedObj); + return clonedObj; +} + /* Taken from http://stackoverflow.com/a/4795914/1263876 Behaves like C's format string function diff --git a/js/utils/requests.js b/js/utils/requests.js index 793e1f21..3cf84690 100644 --- a/js/utils/requests.js +++ b/js/utils/requests.js @@ -6,6 +6,7 @@ import { argsToQueryParams, getCookie } from '../utils/fetch_api_utils'; import AppConstants from '../constants/application_constants'; +import {excludePropFromObject} from '../utils/general_utils'; class Requests { _merge(defaults, options) { @@ -137,15 +138,25 @@ class Requests { return this.request('delete', newUrl); } - post(url, params) { - let paramsCopy = this._merge(params); - let newUrl = this.prepareUrl(url, paramsCopy); + _putOrPost(url,paramsAndBody,method){ + let paramsCopy = this._merge(paramsAndBody); + let params = excludePropFromObject(paramsAndBody,['body']); + let newUrl = this.prepareUrl(url, params); let body = null; - if (paramsCopy && paramsCopy.body) { + console.log(paramsCopy.body); body = JSON.stringify(paramsCopy.body); } - return this.request('post', newUrl, { body }); + return this.request(method, newUrl, { body }); + } + + post(url, params) { + return this._putOrPost(url,params,'post') + } + + put(url, params){ + console.log(params); + return this._putOrPost(url,params,'put') } defaults(options) { From 4a4d4ac737d560f2fc1eb6b390426fdc6f920618 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 3 Sep 2015 16:11:41 +0200 Subject: [PATCH 200/397] Add support for long file names --- js/components/ascribe_media/media_player.js | 12 ++++++++++-- sass/ascribe_media_player.scss | 7 ++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_media/media_player.js b/js/components/ascribe_media/media_player.js index ad53b61f..e4b69c69 100644 --- a/js/components/ascribe_media/media_player.js +++ b/js/components/ascribe_media/media_player.js @@ -28,12 +28,20 @@ let Other = React.createClass({ }, render() { - let ext = this.props.url.split('.').pop(); + let filename = this.props.url.split('/').pop(); + let tokens = filename.split('.'); + let preview; + + if (tokens.length > 1) { + preview = '.' + tokens.pop(); + } else { + preview = 'file'; + } return (

    - .{ext} + {preview}

    ); diff --git a/sass/ascribe_media_player.scss b/sass/ascribe_media_player.scss index f3b87618..213fbafa 100644 --- a/sass/ascribe_media_player.scss +++ b/sass/ascribe_media_player.scss @@ -12,8 +12,13 @@ } .media-other { - font-size: 500%; color: #cccccc; + font-size: 500%; + p { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .audiojs { From a4a0e9d149dd5608bef66eae5655a171bb1fd204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 15:54:49 +0200 Subject: [PATCH 201/397] catch error in onComplete for fineuploader --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 8ecaf40b..ff72813b 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -20,7 +20,6 @@ import AppConstants from '../../constants/application_constants'; import { computeHashOfFile } from '../../utils/file_utils'; var ReactS3FineUploader = React.createClass({ - propTypes: { keyRoutine: React.PropTypes.shape({ url: React.PropTypes.string, @@ -125,6 +124,7 @@ var ReactS3FineUploader = React.createClass({ bucket: 'ascribe0' }, request: { + //endpoint: 'https://www.ascribe.io.global.prod.fastly.net', endpoint: 'https://ascribe0.s3.amazonaws.com', accessKey: 'AKIAIVCZJ33WSCBQ3QDA' }, @@ -352,10 +352,11 @@ var ReactS3FineUploader = React.createClass({ }, onComplete(id, name, res, xhr) { + console.log(xhr); // there has been an issue with the server's connection - if(xhr.status === 0) { - - console.logGlobal(new Error('Complete was called but there wasn\t a success'), false, { + if((xhr && xhr.status === 0) || res.error) { + console.log('asdasdas'); + console.logGlobal(new Error(res.error || 'Complete was called but there wasn\t a success'), false, { files: this.state.filesToUpload, chunks: this.state.chunks }); From 8a75e944133f2ad181f7a033485db240cfa8fb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 16:24:29 +0200 Subject: [PATCH 202/397] fix bug --- js/fetchers/ownership_fetcher.js | 3 +-- js/utils/requests.js | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/js/fetchers/ownership_fetcher.js b/js/fetchers/ownership_fetcher.js index 8f97add5..9b5e81f7 100644 --- a/js/fetchers/ownership_fetcher.js +++ b/js/fetchers/ownership_fetcher.js @@ -24,8 +24,7 @@ let OwnershipFetcher = { }, makeContractPublic(contractObj){ - console.log(contractObj); - return requests.put('ownership_contract_list',{ body: contractObj, contract_id:contractObj.id }); + return requests.put('ownership_contract', { body: contractObj, contract_id: contractObj.id }); } }; diff --git a/js/utils/requests.js b/js/utils/requests.js index 3cf84690..f9e1af04 100644 --- a/js/utils/requests.js +++ b/js/utils/requests.js @@ -78,7 +78,6 @@ class Requests { throw new Error(`Cannot find a mapping for "${name}"`); } } - return url; } @@ -138,9 +137,10 @@ class Requests { return this.request('delete', newUrl); } - _putOrPost(url,paramsAndBody,method){ + _putOrPost(url, paramsAndBody, method){ let paramsCopy = this._merge(paramsAndBody); let params = excludePropFromObject(paramsAndBody,['body']); + let newUrl = this.prepareUrl(url, params); let body = null; if (paramsCopy && paramsCopy.body) { @@ -155,7 +155,6 @@ class Requests { } put(url, params){ - console.log(params); return this._putOrPost(url,params,'put') } From 57c4076c1ef8349cae21fe17afdebfaf140d238d Mon Sep 17 00:00:00 2001 From: Cevo Date: Thu, 3 Sep 2015 17:19:29 +0200 Subject: [PATCH 203/397] pushing the contract u[pdate on client side --- js/actions/contract_list_actions.js | 19 ++++++++++++------- .../ascribe_settings/contract_settings.js | 7 ++++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/js/actions/contract_list_actions.js b/js/actions/contract_list_actions.js index b019ecc0..c57bceb9 100644 --- a/js/actions/contract_list_actions.js +++ b/js/actions/contract_list_actions.js @@ -2,6 +2,7 @@ import alt from '../alt'; import OwnershipFetcher from '../fetchers/ownership_fetcher'; +import Q from 'q'; class ContractListActions { constructor() { @@ -23,13 +24,17 @@ class ContractListActions { } makeContractPublic(contract){ - OwnershipFetcher.makeContractPublic(contract) - .then((res) =>{ - return res; - }) - .catch((err)=>{ - console.logGlobal(err); - }); + contract.public=true; + return Q.Promise((resolve, reject) => { + OwnershipFetcher.makeContractPublic(contract) + .then((res) => { + resolve(res); + }) + .catch((err)=> { + console.logGlobal(err); + reject(err); + }); + }); } } diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js index 6b4c624e..222bd42e 100644 --- a/js/components/ascribe_settings/contract_settings.js +++ b/js/components/ascribe_settings/contract_settings.js @@ -11,6 +11,8 @@ import ContractListActions from '../../actions/contract_list_actions'; import ActionPanel from '../ascribe_panel/action_panel'; import { getLangText } from '../../utils/lang_utils'; +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; let ContractSettings = React.createClass({ propTypes: { @@ -33,7 +35,10 @@ let ContractSettings = React.createClass({ console.log(contract); ContractListActions.makeContractPublic(contract) .then(( ) => ContractListActions.fetchContractList()) - .catch((error)=>{console.log("Error ", error)}) + .catch((error)=>{console.log("Error ", error); + let notification = new GlobalNotificationModel("Service is unavailable", 'danger', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); +}) }, getPublicContracts(){ return this.state.contractList.filter((contract) => contract.public); From 73ee0753c1431c4b9cb92155528e69253c8dcd59 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 3 Sep 2015 17:25:22 +0200 Subject: [PATCH 204/397] refactored notifications per detail --- .../accordion_list_item_table_editions.js | 2 +- .../accordion_list_item_wallet.js | 3 +- js/components/ascribe_detail/edition.js | 30 ++----- .../ascribe_detail/piece_container.js | 12 +-- .../ascribe_forms/form_request_action.js | 34 +++----- .../list_form_request_actions.js | 11 ++- .../prizes_dashboard.js | 82 ------------------- .../ascribe_table/table_item_acl_filtered.js | 6 +- js/components/header_notification.js | 17 +++- .../ascribe_detail/prize_piece_container.js | 15 +--- .../ascribe_detail/ikonotv_piece_container.js | 15 +--- js/routes.js | 2 - sass/ascribe_notification_list.scss | 8 +- 13 files changed, 60 insertions(+), 177 deletions(-) delete mode 100644 js/components/ascribe_prizes_dashboard/prizes_dashboard.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js index d1ab2112..350d61a8 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js @@ -160,7 +160,7 @@ let AccordionListItemTableEditions = React.createClass({ let content = item.acl; return { 'content': content, - 'requestAction': item.request_action + 'notifications': item.notifications }; }, 'acl', getLangText('Actions'), diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js index 178a7db4..dde5c43d 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js @@ -61,8 +61,7 @@ let AccordionListItemWallet = React.createClass({ }, getGlyphicon(){ - if ((this.props.content.request_action && this.props.content.request_action.length > 0) || - (this.props.content.request_action_editions)){ + if ((this.props.content.notifications && this.props.content.notifications.length > 0)){ return ( 0){ actions = ( ); + notifications={this.props.edition.notifications}/>); } else { diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js index 0de25beb..a4460073 100644 --- a/js/components/ascribe_detail/piece_container.js +++ b/js/components/ascribe_detail/piece_container.js @@ -9,9 +9,6 @@ import PieceStore from '../../stores/piece_store'; import PieceListActions from '../../actions/piece_list_actions'; import PieceListStore from '../../stores/piece_list_store'; -import NotificationActions from '../../actions/notification_actions'; -import NotificationStore from '../../stores/notification_store'; - import UserActions from '../../actions/user_actions'; import UserStore from '../../stores/user_store'; @@ -65,8 +62,6 @@ let PieceContainer = React.createClass({ UserActions.fetchCurrentUser(); PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); - NotificationStore.listen(this.onChange); - NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, componentWillUnmount() { @@ -78,7 +73,6 @@ let PieceContainer = React.createClass({ PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); - NotificationStore.unlisten(this.onChange); }, onChange(state) { @@ -180,14 +174,14 @@ let PieceContainer = React.createClass({ getActions() { if (this.state.piece && - this.state.pieceNotifications && - this.state.pieceNotifications.notification) { + this.state.piece.notifications && + this.state.piece.notifications.length > 0) { return ( ); + notifications={this.state.piece.notifications}/>); } else { return ( diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js index c65a7394..b0f3b6c6 100644 --- a/js/components/ascribe_forms/form_request_action.js +++ b/js/components/ascribe_forms/form_request_action.js @@ -22,8 +22,7 @@ let RequestActionForm = React.createClass({ React.PropTypes.object, React.PropTypes.array ]).isRequired, - requestAction: React.PropTypes.string, - requestUser: React.PropTypes.string, + notifications: React.PropTypes.object, currentUser: React.PropTypes.object, handleSuccess: React.PropTypes.func }, @@ -35,19 +34,19 @@ let RequestActionForm = React.createClass({ getUrls() { let urls = {}; - if (this.props.requestAction === 'consign'){ + if (this.props.notifications.action === 'consign'){ urls.accept = ApiUrls.ownership_consigns_confirm; urls.deny = ApiUrls.ownership_consigns_deny; - } else if (this.props.requestAction === 'unconsign'){ + } else if (this.props.notifications.action === 'unconsign'){ urls.accept = ApiUrls.ownership_unconsigns; urls.deny = ApiUrls.ownership_unconsigns_deny; - } else if (this.props.requestAction === 'loan' && !this.isPiece()){ + } else if (this.props.notifications.action === 'loan' && !this.isPiece()){ urls.accept = ApiUrls.ownership_loans_confirm; urls.deny = ApiUrls.ownership_loans_deny; - } else if (this.props.requestAction === 'loan' && this.isPiece()){ + } else if (this.props.notifications.action === 'loan' && this.isPiece()){ urls.accept = ApiUrls.ownership_loans_pieces_confirm; urls.deny = ApiUrls.ownership_loans_pieces_deny; - } else if (this.props.requestAction === 'loan_request' && this.isPiece()){ + } else if (this.props.notifications.action === 'loan_request' && this.isPiece()){ urls.accept = ApiUrls.ownership_loans_pieces_request_confirm; urls.deny = ApiUrls.ownership_loans_pieces_request_deny; } @@ -70,8 +69,8 @@ let RequestActionForm = React.createClass({ return () => { let message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner; - let notification = new GlobalNotificationModel(message, 'success'); - GlobalNotificationActions.appendGlobalNotification(notification); + let notifications = new GlobalNotificationModel(message, 'success'); + GlobalNotificationActions.appendGlobalNotification(notifications); this.handleSuccess(); @@ -81,11 +80,9 @@ let RequestActionForm = React.createClass({ handleSuccess() { if (this.isPiece()){ NotificationActions.fetchPieceListNotifications(); - //NotificationActions.fetchPieceNotifications(this.props.pieceOrEditions.id); } else { NotificationActions.fetchEditionListNotifications(); - NotificationActions.fetchEditionNotifications(this.props.pieceOrEditions[0].bitcoin_id); } if(this.props.handleSuccess) { this.props.handleSuccess(); @@ -93,20 +90,15 @@ let RequestActionForm = React.createClass({ }, getContent() { - let pieceOrEditionStr = this.isPiece() ? getLangText('this work%s', '.') : getLangText('this edition%s', '.'); - let message = this.props.requestUser + ' ' + getLangText('requests you') + ' ' + this.props.requestAction + ' ' + pieceOrEditionStr; - if (this.props.requestAction === 'loan_request'){ - message = this.props.requestUser + ' ' + getLangText('requests you to loan') + ' ' + pieceOrEditionStr; - } return ( - {message} + {this.props.notifications.action_str + ' by ' + this.props.notifications.by} ); }, getAcceptButtonForm(urls) { - if(this.props.requestAction === 'unconsign') { + if(this.props.notifications.action === 'unconsign') { return ( ); - } else if(this.props.requestAction === 'loan_request') { + } else if(this.props.notifications.action === 'loan_request') { return ( @@ -158,7 +150,7 @@ let RequestActionForm = React.createClass({ isInline={true} getFormData={this.getFormData} handleSuccess={ - this.showNotification(getLangText('denied'), this.props.requestAction, this.props.requestUser) + this.showNotification(getLangText('denied'), this.props.notifications.action, this.props.notifications.by) } className='inline pull-right'>
    ); diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js index cb9e1593..2dd56dca 100644 --- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js +++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js @@ -15,9 +15,6 @@ import PieceListActions from '../../../../../actions/piece_list_actions'; import PrizeRatingActions from '../../actions/prize_rating_actions'; import PrizeRatingStore from '../../stores/prize_rating_store'; -import NotificationStore from '../../../../../stores/notification_store'; -import NotificationActions from '../../../../../actions/notification_actions.js'; - import UserStore from '../../../../../stores/user_store'; import Piece from '../../../../../components/ascribe_detail/piece'; @@ -53,8 +50,7 @@ let PieceContainer = React.createClass({ getInitialState() { return mergeOptions( PieceStore.getState(), - UserStore.getState(), - NotificationStore.getState() + UserStore.getState() ); }, @@ -62,8 +58,6 @@ let PieceContainer = React.createClass({ PieceStore.listen(this.onChange); PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); - NotificationStore.listen(this.onChange); - NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, // This is done to update the container when the user clicks on the prev or next @@ -83,7 +77,6 @@ let PieceContainer = React.createClass({ PieceActions.updatePiece({}); PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); - NotificationStore.unlisten(this.onChange); }, @@ -97,14 +90,14 @@ let PieceContainer = React.createClass({ getActions() { if (this.state.piece && - this.state.pieceNotifications && - this.state.pieceNotifications.notification) { + this.state.piece.notifications && + this.state.piece.notifications.length > 0) { return ( ); + notifications={this.state.piece.notifications}/>); } }, diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js index 781b148b..fac26f7d 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js @@ -10,9 +10,6 @@ import PieceListStore from '../../../../../../stores/piece_list_store'; import UserStore from '../../../../../../stores/user_store'; -import NotificationStore from '../../../../../../stores/notification_store'; -import NotificationActions from '../../../../../../actions/notification_actions.js'; - import Piece from '../../../../../../components/ascribe_detail/piece'; import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions'; @@ -44,8 +41,7 @@ let IkonotvPieceContainer = React.createClass({ return mergeOptions( PieceStore.getState(), UserStore.getState(), - PieceListStore.getState(), - NotificationStore.getState() + PieceListStore.getState() ); }, @@ -54,8 +50,6 @@ let IkonotvPieceContainer = React.createClass({ PieceActions.fetchOne(this.props.params.pieceId); UserStore.listen(this.onChange); PieceListStore.listen(this.onChange); - NotificationStore.listen(this.onChange); - NotificationActions.fetchPieceNotifications(this.props.params.pieceId); }, componentWillReceiveProps(nextProps) { @@ -74,7 +68,6 @@ let IkonotvPieceContainer = React.createClass({ PieceStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange); - NotificationStore.unlisten(this.onChange); }, onChange(state) { @@ -96,14 +89,14 @@ let IkonotvPieceContainer = React.createClass({ getActions(){ if (this.state.piece && - this.state.pieceNotifications && - this.state.pieceNotifications.notification) { + this.state.piece.notifications && + this.state.piece.notifications.length > 0) { return ( ); + notifications={this.state.piece.notifications}/>); } else { diff --git a/js/routes.js b/js/routes.js index 2762052b..314dc89a 100644 --- a/js/routes.js +++ b/js/routes.js @@ -22,7 +22,6 @@ import CoaVerifyContainer from './components/coa_verify_container'; import RegisterPiece from './components/register_piece'; -import PrizesDashboard from './components/ascribe_prizes_dashboard/prizes_dashboard'; import AppConstants from './constants/application_constants'; @@ -45,7 +44,6 @@ const COMMON_ROUTES = ( - ); diff --git a/sass/ascribe_notification_list.scss b/sass/ascribe_notification_list.scss index 696d9169..1b4b6a0c 100644 --- a/sass/ascribe_notification_list.scss +++ b/sass/ascribe_notification_list.scss @@ -45,9 +45,15 @@ $break-medium: 1200px; margin-top: 0.3em; margin-bottom: 0.15em; font-size: 1.8em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .sub-header{ - margin-bottom: 1em; + margin-bottom: 0.6em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .notification-action{ color: $ascribe-color-green; From 7dae23a265b3e4c8a722678f0e0658718f8ea9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 17:05:17 +0200 Subject: [PATCH 205/397] remove fastly --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index a1f76086..2bb39ca2 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -125,8 +125,8 @@ var ReactS3FineUploader = React.createClass({ bucket: 'ascribe0' }, request: { - endpoint: 'https://www.ascribe.io.global.prod.fastly.net', - //endpoint: 'https://ascribe0.s3.amazonaws.com', + //endpoint: 'https://www.ascribe.io.global.prod.fastly.net', + endpoint: 'https://ascribe0.s3.amazonaws.com', accessKey: 'AKIAIVCZJ33WSCBQ3QDA' }, uploadSuccess: { From 3b61ac5c6a39b2b9f99ebad49f2be8a385b99420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 17:31:58 +0200 Subject: [PATCH 206/397] remove mangle and fix bug in react-fineuploader --- gulpfile.js | 12 +-- .../react_s3_fine_uploader.js | 94 +++++++++---------- 2 files changed, 45 insertions(+), 61 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index c7816a3a..212c39c9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -189,17 +189,7 @@ function bundle(watch) { .pipe(gulpif(!argv.production, sourcemaps.write())) // writes .map file .on('error', notify.onError('Error: <%= error.message %>')) .pipe(gulpif(argv.production, uglify({ - mangle: true, - compress: { - sequences: true, - dead_code: true, - conditionals: true, - booleans: true, - unused: true, - if_return: true, - join_vars: true, - drop_console: true - } + mangle: false }))) .on('error', notify.onError('Error: <%= error.message %>')) .pipe(gulp.dest('./build/js')) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index ff72813b..5f616dcf 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -352,66 +352,60 @@ var ReactS3FineUploader = React.createClass({ }, onComplete(id, name, res, xhr) { - console.log(xhr); // there has been an issue with the server's connection if((xhr && xhr.status === 0) || res.error) { - console.log('asdasdas'); console.logGlobal(new Error(res.error || 'Complete was called but there wasn\t a success'), false, { files: this.state.filesToUpload, chunks: this.state.chunks }); + } else { + let files = this.state.filesToUpload; - return; - } + // Set the state of the completed file to 'upload successful' in order to + // remove it from the GUI + files[id].status = 'upload successful'; + files[id].key = this.state.uploader.getKey(id); - let files = this.state.filesToUpload; - - // Set the state of the completed file to 'upload successful' in order to - // remove it from the GUI - files[id].status = 'upload successful'; - files[id].key = this.state.uploader.getKey(id); - - let newState = React.addons.update(this.state, { - filesToUpload: { $set: files } - }); - - this.setState(newState); - - // Only after the blob has been created server-side, we can make the form submittable. - this.createBlob(files[id]) - .then(() => { - // since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey - // are optional, we'll only trigger them when they're actually defined - if(this.props.submitKey) { - this.props.submitKey(files[id].key); - } else { - console.warn('You didn\'t define submitKey in as a prop in react-s3-fine-uploader'); - } - - // for explanation, check comment of if statement above - if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) { - // also, lets check if after the completion of this upload, - // the form is ready for submission or not - if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) { - // if so, set uploadstatus to true - this.props.setIsUploadReady(true); - } else { - this.props.setIsUploadReady(false); - } - } else { - console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader'); - } - }) - .catch((err) => { - console.logGlobal(err, false, { - files: this.state.filesToUpload, - chunks: this.state.chunks - }); - let notification = new GlobalNotificationModel(err.message, 'danger', 5000); - GlobalNotificationActions.appendGlobalNotification(notification); + let newState = React.addons.update(this.state, { + filesToUpload: { $set: files } }); - + this.setState(newState); + + // Only after the blob has been created server-side, we can make the form submittable. + this.createBlob(files[id]) + .then(() => { + // since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey + // are optional, we'll only trigger them when they're actually defined + if(this.props.submitKey) { + this.props.submitKey(files[id].key); + } else { + console.warn('You didn\'t define submitKey in as a prop in react-s3-fine-uploader'); + } + + // for explanation, check comment of if statement above + if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) { + // also, lets check if after the completion of this upload, + // the form is ready for submission or not + if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) { + // if so, set uploadstatus to true + this.props.setIsUploadReady(true); + } else { + this.props.setIsUploadReady(false); + } + } else { + console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader'); + } + }) + .catch((err) => { + console.logGlobal(err, false, { + files: this.state.filesToUpload, + chunks: this.state.chunks + }); + let notification = new GlobalNotificationModel(err.message, 'danger', 5000); + GlobalNotificationActions.appendGlobalNotification(notification); + }); + } }, onError(id, name, errorReason) { From 4374235c1b87da89175139108171f6fa03759d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Thu, 3 Sep 2015 17:55:15 +0200 Subject: [PATCH 207/397] use log global again --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 5f616dcf..8605379c 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -3,6 +3,7 @@ import React from 'react/addons'; import Router from 'react-router'; import Q from 'q'; +import Raven from 'raven-js'; import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; From c1a5790bfe35d5b403035b0ab36a115f8c0e1f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 18:04:03 +0200 Subject: [PATCH 208/397] activate mangling --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index 212c39c9..3c92945d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -189,7 +189,7 @@ function bundle(watch) { .pipe(gulpif(!argv.production, sourcemaps.write())) // writes .map file .on('error', notify.onError('Error: <%= error.message %>')) .pipe(gulpif(argv.production, uglify({ - mangle: false + mangle: true }))) .on('error', notify.onError('Error: <%= error.message %>')) .pipe(gulp.dest('./build/js')) From ac28ef4ee023d7a9893e6b93df0d2156e7b7cbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 18:15:42 +0200 Subject: [PATCH 209/397] remove raven --- js/components/ascribe_uploader/react_s3_fine_uploader.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 8605379c..5f616dcf 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -3,7 +3,6 @@ import React from 'react/addons'; import Router from 'react-router'; import Q from 'q'; -import Raven from 'raven-js'; import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; From eb4994b05eb94ef4687e2f8d895135ddd6a38dc4 Mon Sep 17 00:00:00 2001 From: Cevo Date: Thu, 3 Sep 2015 18:25:12 +0200 Subject: [PATCH 210/397] add more --- js/actions/contract_actions.js | 2 -- .../ascribe_settings/contract_settings.js | 16 ++++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/js/actions/contract_actions.js b/js/actions/contract_actions.js index c6055ffc..d1bf1432 100644 --- a/js/actions/contract_actions.js +++ b/js/actions/contract_actions.js @@ -39,8 +39,6 @@ class ContractActions { contractEmail: null }); }); - } else { - /* No email was entered - Ignore and keep going*/ } } diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js index 222bd42e..f38464f3 100644 --- a/js/components/ascribe_settings/contract_settings.js +++ b/js/components/ascribe_settings/contract_settings.js @@ -35,10 +35,10 @@ let ContractSettings = React.createClass({ console.log(contract); ContractListActions.makeContractPublic(contract) .then(( ) => ContractListActions.fetchContractList()) - .catch((error)=>{console.log("Error ", error); - let notification = new GlobalNotificationModel("Service is unavailable", 'danger', 10000); + .catch((error)=>{console.log('Error ', error); + let notification = new GlobalNotificationModel('Service is unavailable', 'danger', 10000); GlobalNotificationActions.appendGlobalNotification(notification); -}) +}); }, getPublicContracts(){ return this.state.contractList.filter((contract) => contract.public); @@ -68,31 +68,31 @@ let ContractSettings = React.createClass({ {(publicContracts.length > 0) ? publicContracts.map( (contract) => { - return( + return ( } - />) + />); } ) : null }
    } {

    Private Contracts

    - {(privateContracts.length>0) ? + {(privateContracts.length > 0) ? privateContracts.map( (contract) => { - return( + return ( } - />) + />); } ) : null}
    } From f312c94eeb9ce57371d866486bcf5d33325135e2 Mon Sep 17 00:00:00 2001 From: Cevo Date: Fri, 4 Sep 2015 11:31:53 +0200 Subject: [PATCH 211/397] if there is anything else --- js/actions/contract_list_actions.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/actions/contract_list_actions.js b/js/actions/contract_list_actions.js index c57bceb9..608b5df1 100644 --- a/js/actions/contract_list_actions.js +++ b/js/actions/contract_list_actions.js @@ -24,13 +24,15 @@ class ContractListActions { } makeContractPublic(contract){ - contract.public=true; + contract.public = true; return Q.Promise((resolve, reject) => { OwnershipFetcher.makeContractPublic(contract) .then((res) => { + console.log('Here is the result... '); resolve(res); }) .catch((err)=> { + console.log('Here we have an error'); console.logGlobal(err); reject(err); }); From 9b7a69bc20deb3b0a37c29395006710b3e886f26 Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 4 Sep 2015 11:49:55 +0200 Subject: [PATCH 212/397] contract agreement notifications --- js/actions/notification_actions.js | 16 ++++++- js/app.js | 3 +- .../ascribe_forms/form_contract_agreement.js | 6 +-- js/components/contract_notification.js | 36 +++++++++++++++ .../ikonotv/ikonotv_contract_notifications.js | 45 +++++++++++++++++++ .../whitelabel/wallet/wallet_routes.js | 2 + js/constants/api_urls.js | 5 ++- js/fetchers/notification_fetcher.js | 4 ++ js/routes.js | 3 +- js/stores/notification_store.js | 5 +++ js/third_party/notifications.js | 36 +++++++++++++++ 11 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 js/components/contract_notification.js create mode 100644 js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js create mode 100644 js/third_party/notifications.js diff --git a/js/actions/notification_actions.js b/js/actions/notification_actions.js index 429ae666..9318c922 100644 --- a/js/actions/notification_actions.js +++ b/js/actions/notification_actions.js @@ -1,6 +1,7 @@ 'use strict'; import alt from '../alt'; +import Q from 'q'; import NotificationFetcher from '../fetchers/notification_fetcher'; @@ -10,7 +11,8 @@ class NotificationActions { 'updatePieceListNotifications', 'updateEditionListNotifications', 'updateEditionNotifications', - 'updatePieceNotifications' + 'updatePieceNotifications', + 'updateContractAgreementListNotifications' ); } @@ -49,6 +51,18 @@ class NotificationActions { }) .catch((err) => console.logGlobal(err)); } + + fetchContractAgreementListNotifications() { + return Q.Promise((resolve, reject) => { + NotificationFetcher + .fetchContractAgreementListNotifications() + .then((res) => { + this.actions.updateContractAgreementListNotifications(res); + resolve(res); + }) + .catch((err) => console.logGlobal(err)); + }); + } } export default alt.createActions(NotificationActions); diff --git a/js/app.js b/js/app.js index 6dcf58bf..785068a4 100644 --- a/js/app.js +++ b/js/app.js @@ -26,6 +26,7 @@ import EventActions from './actions/event_actions'; import GoogleAnalyticsHandler from './third_party/ga'; import RavenHandler from './third_party/raven'; import IntercomHandler from './third_party/intercom'; +import NotificationsHandler from './third_party/notifications'; /* eslint-enable */ initLogging(); @@ -73,7 +74,7 @@ class AppGateway { } EventActions.applicationWillBoot(settings); - Router.run(getRoutes(type, subdomain), Router.HistoryLocation, (App) => { + window.appRouter = Router.run(getRoutes(type, subdomain), Router.HistoryLocation, (App) => { React.render( , document.getElementById('main') diff --git a/js/components/ascribe_forms/form_contract_agreement.js b/js/components/ascribe_forms/form_contract_agreement.js index 1d9f7c72..d3b352c4 100644 --- a/js/components/ascribe_forms/form_contract_agreement.js +++ b/js/components/ascribe_forms/form_contract_agreement.js @@ -60,8 +60,8 @@ let ContractAgreementForm = React.createClass({ }, getContracts() { - if (this.state.contractList && this.state.contractList.count > 0) { - let contractList = this.state.contractList.results; + if (this.state.contractList && this.state.contractList.length > 0) { + let contractList = this.state.contractList; return ( + value={ contract.id }> { contract.name } ); diff --git a/js/components/contract_notification.js b/js/components/contract_notification.js new file mode 100644 index 00000000..cd6ceb53 --- /dev/null +++ b/js/components/contract_notification.js @@ -0,0 +1,36 @@ +'use strict'; + +import React from 'react'; + +import NotificationStore from '../stores/notification_store'; + +import { mergeOptions } from '../utils/general_utils'; + +let ContractNotification = React.createClass({ + getInitialState() { + return mergeOptions( + NotificationStore.getState() + ); + }, + + componentDidMount() { + NotificationStore.listen(this.onChange); + }, + + componentWillUnmount() { + NotificationStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + + return ( + null + ); + } +}); + +export default ContractNotification; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js new file mode 100644 index 00000000..80b39bee --- /dev/null +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js @@ -0,0 +1,45 @@ +'use strict'; + +import React from 'react'; + +import NotificationStore from '../../../../../stores/notification_store'; +import WhitelabelStore from '../../../../../stores/whitelabel_store'; + +import { mergeOptions } from '../../../../../utils/general_utils'; + +let IkonotvContractNotifications = React.createClass({ + + getInitialState() { + return mergeOptions( + NotificationStore.getState(), + WhitelabelStore.getState() + ); + }, + + componentDidMount() { + NotificationStore.listen(this.onChange); + WhitelabelStore.listen(this.onChange); + }, + + componentWillUnmount() { + NotificationStore.unlisten(this.onChange); + WhitelabelStore.unlisten(this.onChange); + }, + + onChange(state) { + this.setState(state); + }, + + render() { + console.log(this.state) + return ( +
    +
    + +
    +
    + ); + } +}); + +export default IkonotvContractNotifications; \ No newline at end of file diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js index 1c4ef4a7..4a0f022c 100644 --- a/js/components/whitelabel/wallet/wallet_routes.js +++ b/js/components/whitelabel/wallet/wallet_routes.js @@ -22,6 +22,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 IkonotvPieceContainer from './components/ikonotv/ascribe_detail/ikonotv_piece_container'; +import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications'; import CCRegisterPiece from './components/cc/cc_register_piece'; @@ -77,6 +78,7 @@ let ROUTES = { + ) }; diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index aa484142..54a398d2 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -31,6 +31,7 @@ let ApiUrls = { 'notification_piece': AppConstants.apiEndpoint + 'notifications/pieces/${piece_id}/', 'notification_editionlist': AppConstants.apiEndpoint + 'notifications/editions/', 'notification_edition': AppConstants.apiEndpoint + 'notifications/editions/${edition_id}/', + 'notification_contractagreementlist': AppConstants.apiEndpoint + 'notifications/contract_agreements/', 'ownership_contract_agreements': AppConstants.apiEndpoint + 'ownership/contract_agreements/', 'ownership_consigns': AppConstants.apiEndpoint + 'ownership/consigns/', 'ownership_consigns_confirm': AppConstants.apiEndpoint + 'ownership/consigns/confirm/', @@ -51,8 +52,8 @@ let ApiUrls = { 'ownership_unconsigns': AppConstants.apiEndpoint + 'ownership/unconsigns/', 'ownership_unconsigns_deny': AppConstants.apiEndpoint + 'ownership/unconsigns/deny/', 'ownership_unconsigns_request': AppConstants.apiEndpoint + 'ownership/unconsigns/request/', - 'ownership_contract':AppConstants.apiEndpoint + 'ownership/contracts/${contract_id}', - "ownership_contract_list": AppConstants.apiEndpoint + 'ownership/contracts/', + 'ownership_contract': AppConstants.apiEndpoint + 'ownership/contracts/${contract_id}', + 'ownership_contract_list': AppConstants.apiEndpoint + 'ownership/contracts/', 'piece': AppConstants.apiEndpoint + 'pieces/${piece_id}/', 'piece_extradata': AppConstants.apiEndpoint + 'pieces/${piece_id}/extradata/', 'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/', diff --git a/js/fetchers/notification_fetcher.js b/js/fetchers/notification_fetcher.js index 6d2f7424..48606b70 100644 --- a/js/fetchers/notification_fetcher.js +++ b/js/fetchers/notification_fetcher.js @@ -19,6 +19,10 @@ let NotificationFetcher = { fetchEditionNotifications(editionId) { return requests.get('notification_edition', {'edition_id': editionId}); + }, + + fetchContractAgreementListNotifications() { + return requests.get('notification_contractagreementlist'); } }; diff --git a/js/routes.js b/js/routes.js index 314dc89a..1d521cab 100644 --- a/js/routes.js +++ b/js/routes.js @@ -21,7 +21,7 @@ import SettingsContainer from './components/ascribe_settings/settings_container' import CoaVerifyContainer from './components/coa_verify_container'; import RegisterPiece from './components/register_piece'; - +import ContractNotification from './components/contract_notification'; import AppConstants from './constants/application_constants'; @@ -44,6 +44,7 @@ const COMMON_ROUTES = ( + ); diff --git a/js/stores/notification_store.js b/js/stores/notification_store.js index 6e706699..84c5f5d7 100644 --- a/js/stores/notification_store.js +++ b/js/stores/notification_store.js @@ -10,6 +10,7 @@ class NotificationStore { constructor() { this.pieceListNotifications = {}; this.editionListNotifications = {}; + this.contractAgreementListNotifications = {}; this.editionNotifications = null; this.pieceNotifications = null; this.bindActions(NotificationActions); @@ -31,6 +32,10 @@ class NotificationStore { this.editionNotifications = res.notification; } + onUpdateContractAgreementListNotifications(res) { + this.contractAgreementListNotifications = res.notifications; + } + } export default alt.createStore(NotificationStore, 'NotificationStore'); diff --git a/js/third_party/notifications.js b/js/third_party/notifications.js new file mode 100644 index 00000000..8887bbe2 --- /dev/null +++ b/js/third_party/notifications.js @@ -0,0 +1,36 @@ +'use strict'; + +import alt from '../alt'; +import EventActions from '../actions/event_actions'; + +import NotificationActions from '../actions/notification_actions'; + + +class NotificationsHandler { + + constructor() { + this.bindActions(EventActions); + this.loaded = false; + } + + onProfileDidLoad(profile) { + if (this.loaded) { + return; + } + let subdomain = window.location.host.split('.')[0]; + if (subdomain === 'ikonotv') { + NotificationActions.fetchContractAgreementListNotifications().then( + (res) => { + if (res.notifications && res.notifications.length > 0) { + this.loaded = true; + console.log('Contractagreement notifications loaded'); + setTimeout(() => window.appRouter.transitionTo('contract_notifications'), 0); + } + } + ); + } + this.loaded = true; + } +} + +export default alt.createStore(NotificationsHandler, 'NotificationsHandler'); From 4bdab3410e46c1951e1a13ffb3f40006aba1b87e Mon Sep 17 00:00:00 2001 From: diminator Date: Fri, 4 Sep 2015 14:48:10 +0200 Subject: [PATCH 213/397] contractagreementserializer with contract fully expanded --- js/app.js | 1 - .../components/ikonotv/ikonotv_contract_notifications.js | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/js/app.js b/js/app.js index 785068a4..5ad36d28 100644 --- a/js/app.js +++ b/js/app.js @@ -72,7 +72,6 @@ class AppGateway { type = settings.type; subdomain = settings.subdomain; } - EventActions.applicationWillBoot(settings); window.appRouter = Router.run(getRoutes(type, subdomain), Router.HistoryLocation, (App) => { React.render( diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js index 80b39bee..636948d6 100644 --- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js +++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_contract_notifications.js @@ -35,7 +35,14 @@ let IkonotvContractNotifications = React.createClass({ return (
    - +
    + +
    +
    + +
    ); From 8e98a7bff7f049cadd3df02af67ac5e38a278bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Fri, 4 Sep 2015 14:54:39 +0200 Subject: [PATCH 214/397] show overall progress --- js/app.js | 1 - .../file_drag_and_drop_preview.js | 2 +- .../file_drag_and_drop_preview_iterator.js | 43 +++++++++++-------- .../file_drag_and_drop_preview_progress.js | 38 ++++++++++++++++ .../react_s3_fine_uploader.js | 1 - .../ikonotv_accordion_list_item.js | 3 -- .../whitelabel/wallet/wallet_routes.js | 2 +- js/third_party/ga.js | 1 - sass/ascribe_uploader.scss | 8 ++++ 9 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 js/components/ascribe_uploader/file_drag_and_drop_preview_progress.js diff --git a/js/app.js b/js/app.js index 6dcf58bf..addd0494 100644 --- a/js/app.js +++ b/js/app.js @@ -45,7 +45,6 @@ requests.defaults({ class AppGateway { - start() { let settings; let subdomain = window.location.host.split('.')[0]; diff --git a/js/components/ascribe_uploader/file_drag_and_drop_preview.js b/js/components/ascribe_uploader/file_drag_and_drop_preview.js index 9c6cdbdd..05c4a688 100644 --- a/js/components/ascribe_uploader/file_drag_and_drop_preview.js +++ b/js/components/ascribe_uploader/file_drag_and_drop_preview.js @@ -72,7 +72,7 @@ let FileDragAndDropPreview = React.createClass({ if(this.props.areAssetsEditable) { removeBtn = (
    -