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 01/29] 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 02/29] 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 03/29] 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 04/29] 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 05/29] 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 06/29] 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 07/29] 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 08/29] 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 09/29] 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 10/29] 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 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 11/29] 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 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 12/29] 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 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 13/29] 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 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 14/29] 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 15/29] 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 16/29] 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 18/29] 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 19/29] 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 20/29] 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 21/29] 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 22/29] 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 23/29] 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 27/29] 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 28/29] 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 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 29/29] 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