From 7a18c150c791f782f9fd662d6248c470d287312b Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 10:58:07 +0200 Subject: [PATCH 01/33] merged all branches fixed clear errors --- .../ascribe_forms/button_submit_close.js | 10 +++++----- js/components/ascribe_forms/form_share_email.js | 16 ++++++++++------ js/mixins/alert_mixin.js | 4 ++++ js/mixins/form_mixin.js | 3 +++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/js/components/ascribe_forms/button_submit_close.js b/js/components/ascribe_forms/button_submit_close.js index 60091f2f..e811cab5 100644 --- a/js/components/ascribe_forms/button_submit_close.js +++ b/js/components/ascribe_forms/button_submit_close.js @@ -3,11 +3,11 @@ import React from 'react'; let ButtonSubmitOrClose = React.createClass({ render() { if (this.props.submitted){ - return ( -
- Loading -
- ) + //return ( + //
+ // Loading + //
+ //) } return (
diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index dd61bc7b..ea87b4cf 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -22,12 +22,16 @@ let ShareForm = React.createClass({ } }, renderForm() { - let message = "Hi,\n" + - "\n" + - "I am sharing \"" + this.props.edition.title + "\" with you.\n" + - "\n" + - "Truly yours,\n" + - this.props.currentUser.username; + let title = this.props.edition.title; + let username = this.props.currentUser.username; + let message = +`Hi, + +I am sharing \" ${title} \" with you. + +Truly yours, +${username}`; + return (
Date: Fri, 29 May 2015 15:16:42 +0200 Subject: [PATCH 02/33] errors for non-fields, 500 removed retry consign_form --- js/components/ascribe_forms/form_consign.js | 66 +++++++++++++++++++ js/components/ascribe_forms/input_text.js | 3 +- js/components/ascribe_forms/input_textarea.js | 3 +- js/components/ascribe_modal/modal_consign.js | 43 ++++++++++++ js/components/ascribe_modal/modal_share.js | 8 +-- js/components/ascribe_modal/modal_transfer.js | 8 +-- js/components/edition.js | 2 + js/constants/api_urls.js | 3 +- js/mixins/alert_mixin.js | 5 +- js/mixins/form_mixin.js | 22 +++++-- js/mixins/modal_mixin.js | 11 ++++ 11 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 js/components/ascribe_forms/form_consign.js create mode 100644 js/components/ascribe_modal/modal_consign.js create mode 100644 js/mixins/modal_mixin.js diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js new file mode 100644 index 00000000..cf68d429 --- /dev/null +++ b/js/components/ascribe_forms/form_consign.js @@ -0,0 +1,66 @@ +import fetch from 'isomorphic-fetch'; + +import React from 'react'; + +import ApiUrls from '../../constants/api_urls'; +import FormMixin from '../../mixins/form_mixin'; +import InputText from './input_text'; +import InputTextArea from './input_textarea'; +import ButtonSubmitOrClose from './button_submit_close'; + +let ConsignForm = React.createClass({ + mixins: [FormMixin], + + url() { + return ApiUrls.ownership_consigns + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + consignee: this.refs.consignee.state.value, + consign_message: this.refs.consign_message.state.value, + password: this.refs.password.state.value + } + }, + renderForm() { + let title = this.props.edition.title; + let username = this.props.currentUser.username; + let message = +`Hi, + +I consign \" ${title} \" to you. + +Truly yours, +${username}`; + + return ( + + + + + + + + + ); + } +}); + +export default ConsignForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_text.js b/js/components/ascribe_forms/input_text.js index a65bcc8f..9d4d4b61 100644 --- a/js/components/ascribe_forms/input_text.js +++ b/js/components/ascribe_forms/input_text.js @@ -8,8 +8,7 @@ let InputText = React.createClass({ getInitialState() { return {value: null, - alerts: null, // needed in AlertMixin - retry: 0 // needed in AlertMixin for generating unique alerts + alerts: null }; }, handleChange(event) { diff --git a/js/components/ascribe_forms/input_textarea.js b/js/components/ascribe_forms/input_textarea.js index b5f64b66..c4e0d7b1 100644 --- a/js/components/ascribe_forms/input_textarea.js +++ b/js/components/ascribe_forms/input_textarea.js @@ -8,8 +8,7 @@ let InputTextArea = React.createClass({ getInitialState() { return {value: this.props.defaultValue, - alerts: null, // needed in AlertMixin - retry: 0 // needed in AlertMixin for generating unique alerts + alerts: null // needed in AlertMixin }; }, handleChange(event) { diff --git a/js/components/ascribe_modal/modal_consign.js b/js/components/ascribe_modal/modal_consign.js new file mode 100644 index 00000000..bcd47973 --- /dev/null +++ b/js/components/ascribe_modal/modal_consign.js @@ -0,0 +1,43 @@ +import React from 'react'; +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 ConsignForm from '../ascribe_forms/form_consign' +import ModalMixin from '../../mixins/modal_mixin' + +let ConsignModalButton = React.createClass({ + render() { + return ( + Have someone else sell the artwork}> + }> +
+ CONSIGN +
+
+
+ ) + } +}); + +let ConsignModal = React.createClass({ + mixins : [ModalMixin], + + render() { + return ( + +
+ +
+
+ ) + } +}); + + +export default ConsignModalButton; diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 176541ee..4ada244c 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -4,6 +4,7 @@ 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' import ShareForm from '../ascribe_forms/form_share_email' @@ -24,11 +25,8 @@ let ShareModalButton = React.createClass({ }); let ShareModal = React.createClass({ - onRequestHide(e){ - if (e) - e.preventDefault(); - this.props.onRequestHide(); - }, + mixins : [ModalMixin], + render() { return ( diff --git a/js/components/ascribe_modal/modal_transfer.js b/js/components/ascribe_modal/modal_transfer.js index b57064ff..12b40524 100644 --- a/js/components/ascribe_modal/modal_transfer.js +++ b/js/components/ascribe_modal/modal_transfer.js @@ -5,7 +5,7 @@ import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import TransferForm from '../ascribe_forms/form_transfer' - +import ModalMixin from '../../mixins/modal_mixin' let TransferModalButton = React.createClass({ render() { @@ -24,10 +24,8 @@ let TransferModalButton = React.createClass({ }); let TransferModal = React.createClass({ - onRequestHide(e){ - e.preventDefault(); - this.props.onRequestHide(); - }, + mixins : [ModalMixin], + render() { return ( diff --git a/js/components/edition.js b/js/components/edition.js index ffeb9b25..65fa2a51 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,6 +1,7 @@ import React from 'react'; import ImageViewer from './ascribe_media/image_viewer'; +import ConsignModalButton from './ascribe_modal/modal_consign'; import TransferModalButton from './ascribe_modal/modal_transfer'; import ShareModalButton from './ascribe_modal/modal_share'; @@ -47,6 +48,7 @@ let EditionDetails = React.createClass({
+
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index f0c7f9b6..d26352bc 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -2,7 +2,8 @@ import AppConstants from './application_constants'; let apiUrls = { 'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/', - 'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/' + 'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/', + 'ownership_consigns' : AppConstants.baseUrl + 'ownership/consigns/' }; export default apiUrls; \ No newline at end of file diff --git a/js/mixins/alert_mixin.js b/js/mixins/alert_mixin.js index 90289d22..f52890c7 100644 --- a/js/mixins/alert_mixin.js +++ b/js/mixins/alert_mixin.js @@ -5,11 +5,10 @@ let AlertMixin = { setAlerts(errors){ let alerts = errors.map( function(error) { - let key = error + this.state.retry; - return ; + return ; }.bind(this) ); - this.setState({alerts: alerts, retry: this.state.retry + 1}); + this.setState({alerts: alerts}); }, clearAlerts(){ this.setState({alerts: null}); diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js index 060a297e..65983653 100644 --- a/js/mixins/form_mixin.js +++ b/js/mixins/form_mixin.js @@ -1,5 +1,6 @@ import React from 'react'; +import EditionActions from '../actions/edition_actions' import AppConstants from '../constants/application_constants' import AlertDismissable from '../components/ascribe_forms/alert' @@ -8,6 +9,7 @@ export const FormMixin = { return { submitted: false , status: null + , errors: [] } }, submit(e) { @@ -15,7 +17,7 @@ export const FormMixin = { for (var ref in this.refs){ this.refs[ref].clearAlerts(); } - this.setState({submitted: true}); + this.setState({submitted: true, errors: []}); fetch(this.url(), { method: 'post', headers: { @@ -30,15 +32,16 @@ export const FormMixin = { ); }, handleResponse(response){ + let submitted = false; if (response.status >= 200 && response.status < 300){ + EditionActions.fetchOne(this.props.edition.id); this.props.onRequestHide(); + submitted = true; } else if (response.status >= 400 && response.status < 500) { this.handleError(response); } - else { - this.setState({submitted: false, status: response.status}); - } + this.setState({submitted: submitted, status: response.status}); }, handleError(response){ response.json().then((response) => this.dispatchErrors(response.errors)); @@ -49,14 +52,23 @@ export const FormMixin = { if (this.refs && this.refs[input] && this.refs[input].state){ this.refs[input].setAlerts(errors[input]); } + else{ + this.setState({errors: this.state.errors.concat(errors[input])}); + } } - this.setState({submitted: false}); }, render(){ let alert = null; if (this.state.status >= 500){ alert = ; } + if (this.state.errors.length > 0){ + alert = this.state.errors.map( + function(error) { + return ; + }.bind(this) + ); + } return (
{alert} diff --git a/js/mixins/modal_mixin.js b/js/mixins/modal_mixin.js new file mode 100644 index 00000000..7dee243b --- /dev/null +++ b/js/mixins/modal_mixin.js @@ -0,0 +1,11 @@ +import React from 'react'; + +let ModalMixin = { + onRequestHide(e){ + if (e) + e.preventDefault(); + this.props.onRequestHide(); + } +}; + +export default ModalMixin; \ No newline at end of file From c6e97d916dcab20a0b1290e73bc2c1780aaeceee Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 15:27:40 +0200 Subject: [PATCH 03/33] Merge remote-tracking branch 'remotes/origin/master' into AD-51-easy-to-view-manage-1-editions-coi Conflicts: piece/models.py web/urls/frontend.py --- js/components/ascribe_forms/input_text.js | 2 +- js/components/ascribe_forms/input_textarea.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/js/components/ascribe_forms/input_text.js b/js/components/ascribe_forms/input_text.js index 9d4d4b61..d242de86 100644 --- a/js/components/ascribe_forms/input_text.js +++ b/js/components/ascribe_forms/input_text.js @@ -8,7 +8,7 @@ let InputText = React.createClass({ getInitialState() { return {value: null, - alerts: null + alerts: null // needed in AlertMixin }; }, handleChange(event) { diff --git a/js/components/ascribe_forms/input_textarea.js b/js/components/ascribe_forms/input_textarea.js index c4e0d7b1..cf5cfc4a 100644 --- a/js/components/ascribe_forms/input_textarea.js +++ b/js/components/ascribe_forms/input_textarea.js @@ -27,7 +27,6 @@ let InputTextArea = React.createClass({ onChange={this.handleChange}>
); - } }); From 2c7535a73ae04d661edfeb3387bbfcd86d344120 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 16:53:30 +0200 Subject: [PATCH 04/33] unconsign --- js/components/ascribe_forms/form_consign.js | 2 +- js/components/ascribe_forms/form_loan.js | 66 +++++++++++++++++++ js/components/ascribe_forms/form_unconsign.js | 58 ++++++++++++++++ .../ascribe_forms/form_unconsign_request.js | 49 ++++++++++++++ js/components/ascribe_modal/modal_loan.js | 43 ++++++++++++ .../ascribe_modal/modal_unconsign.js | 43 ++++++++++++ .../ascribe_modal/modal_unconsign_request.js | 43 ++++++++++++ js/components/edition.js | 4 ++ js/constants/api_urls.js | 4 +- js/constants/application_constants.js | 4 +- 10 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 js/components/ascribe_forms/form_loan.js create mode 100644 js/components/ascribe_forms/form_unconsign.js create mode 100644 js/components/ascribe_forms/form_unconsign_request.js create mode 100644 js/components/ascribe_modal/modal_loan.js create mode 100644 js/components/ascribe_modal/modal_unconsign.js create mode 100644 js/components/ascribe_modal/modal_unconsign_request.js diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index cf68d429..708ab70e 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -34,7 +34,7 @@ Truly yours, ${username}`; return ( -
+ + + + + + + + + ); + } +}); + +export default ConsignForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_unconsign.js b/js/components/ascribe_forms/form_unconsign.js new file mode 100644 index 00000000..60112334 --- /dev/null +++ b/js/components/ascribe_forms/form_unconsign.js @@ -0,0 +1,58 @@ +import fetch from 'isomorphic-fetch'; + +import React from 'react'; + +import ApiUrls from '../../constants/api_urls'; +import FormMixin from '../../mixins/form_mixin'; +import InputText from './input_text'; +import InputTextArea from './input_textarea'; +import ButtonSubmitOrClose from './button_submit_close'; + +let UnConsignForm = React.createClass({ + mixins: [FormMixin], + + url() { + return ApiUrls.ownership_unconsigns + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + unconsign_message: this.refs.unconsign_message.state.value, + password: this.refs.password.state.value + } + }, + renderForm() { + let title = this.props.edition.title; + let username = this.props.currentUser.username; + let message = +`Hi, + +I un-consign \" ${title} \" from you. + +Truly yours, +${username}`; + + return ( +
+ + + + + + + ); + } +}); + +export default UnConsignForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_unconsign_request.js b/js/components/ascribe_forms/form_unconsign_request.js new file mode 100644 index 00000000..f572a287 --- /dev/null +++ b/js/components/ascribe_forms/form_unconsign_request.js @@ -0,0 +1,49 @@ +import fetch from 'isomorphic-fetch'; + +import React from 'react'; + +import ApiUrls from '../../constants/api_urls'; +import FormMixin from '../../mixins/form_mixin'; +import InputText from './input_text'; +import InputTextArea from './input_textarea'; +import ButtonSubmitOrClose from './button_submit_close'; + +let UnConsignRequestForm = React.createClass({ + mixins: [FormMixin], + + url() { + return ApiUrls.ownership_unconsigns_request + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + unconsign_request_message: this.refs.unconsign_request_message.state.value + } + }, + renderForm() { + let title = this.props.edition.title; + let username = this.props.currentUser.username; + let message = +`Hi, + +I request you to un-consign \" ${title} \". + +Truly yours, +${username}`; + + return ( +
+ + + + ); + } +}); + +export default UnConsignRequestForm; \ No newline at end of file diff --git a/js/components/ascribe_modal/modal_loan.js b/js/components/ascribe_modal/modal_loan.js new file mode 100644 index 00000000..bcd47973 --- /dev/null +++ b/js/components/ascribe_modal/modal_loan.js @@ -0,0 +1,43 @@ +import React from 'react'; +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 ConsignForm from '../ascribe_forms/form_consign' +import ModalMixin from '../../mixins/modal_mixin' + +let ConsignModalButton = React.createClass({ + render() { + return ( + Have someone else sell the artwork}> + }> +
+ CONSIGN +
+
+
+ ) + } +}); + +let ConsignModal = React.createClass({ + mixins : [ModalMixin], + + render() { + return ( + +
+ +
+
+ ) + } +}); + + +export default ConsignModalButton; diff --git a/js/components/ascribe_modal/modal_unconsign.js b/js/components/ascribe_modal/modal_unconsign.js new file mode 100644 index 00000000..1245fc01 --- /dev/null +++ b/js/components/ascribe_modal/modal_unconsign.js @@ -0,0 +1,43 @@ +import React from 'react'; +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 UnConsignForm from '../ascribe_forms/form_unconsign' +import ModalMixin from '../../mixins/modal_mixin' + +let UnConsignModalButton = React.createClass({ + render() { + return ( + Unconsign this artwork}> + }> +
+ UNCONSIGN +
+
+
+ ) + } +}); + +let UnConsignModal = React.createClass({ + mixins : [ModalMixin], + + render() { + return ( + +
+ +
+
+ ) + } +}); + + +export default UnConsignModalButton; diff --git a/js/components/ascribe_modal/modal_unconsign_request.js b/js/components/ascribe_modal/modal_unconsign_request.js new file mode 100644 index 00000000..c74e637b --- /dev/null +++ b/js/components/ascribe_modal/modal_unconsign_request.js @@ -0,0 +1,43 @@ +import React from 'react'; +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 UnConsignRequestForm from '../ascribe_forms/form_unconsign_request' +import ModalMixin from '../../mixins/modal_mixin' + +let UnConsignRequestModalButton = React.createClass({ + render() { + return ( + Request to unconsign the artwork}> + }> +
+ UNCONSIGN REQUEST +
+
+
+ ) + } +}); + +let UnConsignRequestModal = React.createClass({ + mixins : [ModalMixin], + + render() { + return ( + +
+ +
+
+ ) + } +}); + + +export default UnConsignRequestModalButton; diff --git a/js/components/edition.js b/js/components/edition.js index 65fa2a51..2c5279c1 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -2,6 +2,8 @@ import React from 'react'; import ImageViewer from './ascribe_media/image_viewer'; import ConsignModalButton from './ascribe_modal/modal_consign'; +import UnConsignModalButton from './ascribe_modal/modal_unconsign'; +import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request'; import TransferModalButton from './ascribe_modal/modal_transfer'; import ShareModalButton from './ascribe_modal/modal_share'; @@ -49,6 +51,8 @@ let EditionDetails = React.createClass({
+ +
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index d26352bc..6099710b 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -3,7 +3,9 @@ import AppConstants from './application_constants'; let apiUrls = { 'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/', 'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/', - 'ownership_consigns' : AppConstants.baseUrl + 'ownership/consigns/' + 'ownership_consigns' : AppConstants.baseUrl + 'ownership/consigns/', + 'ownership_unconsigns' : AppConstants.baseUrl + 'ownership/unconsigns/', + 'ownership_unconsigns_request' : AppConstants.baseUrl + 'ownership/unconsigns/request/' }; export default apiUrls; \ No newline at end of file diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 17a6d7df..9c20a7ba 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -1,6 +1,6 @@ let constants = { - //'baseUrl': 'http://localhost:8000/api/', - 'baseUrl': 'http://staging.ascribe.io/api/', + 'baseUrl': 'http://localhost:8000/api/', + //'baseUrl': 'http://staging.ascribe.io/api/', 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000 'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'] }; From d90a4f97dbc55eb11b841faa41998a2cfcd7b538 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Mon, 1 Jun 2015 13:02:53 +0200 Subject: [PATCH 05/33] loan --- index.html | 1 + js/components/ascribe_forms/form_loan.js | 107 +++++++++++++++--- js/components/ascribe_forms/input_checkbox.js | 40 +++++++ js/components/ascribe_forms/input_date.js | 53 +++++++++ js/components/ascribe_forms/input_hidden.js | 33 ++++++ js/components/ascribe_forms/input_text.js | 3 +- js/components/ascribe_modal/modal_loan.js | 24 ++-- js/components/edition.js | 2 + js/constants/api_urls.js | 1 + js/fetchers/ownership_fetcher.js | 24 ++++ package.json | 3 +- sass/main.scss | 8 ++ 12 files changed, 270 insertions(+), 29 deletions(-) create mode 100644 js/components/ascribe_forms/input_checkbox.js create mode 100644 js/components/ascribe_forms/input_date.js create mode 100644 js/components/ascribe_forms/input_hidden.js create mode 100644 js/fetchers/ownership_fetcher.js diff --git a/index.html b/index.html index 4c875443..dec0a732 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,7 @@ +
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 708ab70e..1822b8ce 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -5,46 +5,122 @@ import React from 'react'; import ApiUrls from '../../constants/api_urls'; import FormMixin from '../../mixins/form_mixin'; import InputText from './input_text'; +import InputHidden from './input_hidden'; +import InputCheckbox from './input_checkbox'; +//import InputDate from './input_date'; import InputTextArea from './input_textarea'; +import OwnershipFetcher from '../../fetchers/ownership_fetcher' import ButtonSubmitOrClose from './button_submit_close'; -let ConsignForm = React.createClass({ +let LoanForm = React.createClass({ mixins: [FormMixin], url() { - return ApiUrls.ownership_consigns + return ApiUrls.ownership_loans + }, + componentDidMount(){ + this.setState({contract_key: null, + contract_url: null, + loaneeHasContract: false}); }, getFormData() { return { bitcoin_id: this.props.edition.bitcoin_id, - consignee: this.refs.consignee.state.value, - consign_message: this.refs.consign_message.state.value, - password: this.refs.password.state.value + loanee: this.refs.loanee.state.value, + gallery_name: this.refs.gallery_name.state.value, + startdate: this.refs.startdate.state.value, + enddate: this.refs.enddate.state.value, + loan_message: this.refs.loan_message.state.value, + password: this.refs.password.state.value, + terms: this.refs.terms.state.value } }, + handleLoanEmailBlur(e){ + OwnershipFetcher.fetchLoanContract(this.refs.loanee.state.value) + .then((res) => { + if (res && res.length > 0) { + this.setState({contract_key: res[0].s3Key, + contract_url: res[0].s3Url, + loaneeHasContract: true}); + } + else{ + this.resetLoanContract(); + } + }) + .catch((err) => { + console.log(err); + this.resetLoanContract(); + }); + }, + resetLoanContract(){ + this.setState({contract_key: null, + contract_url: null, + loaneeHasContract: false + }); + }, renderForm() { let title = this.props.edition.title; let username = this.props.currentUser.username; let message = `Hi, -I consign \" ${title} \" to you. +I loan \" ${title} \" to you. Truly yours, ${username}`; - + let contract = ; + if (this.state.loaneeHasContract){ + let label = ; + contract = + } return ( -
- + + + +
+
+ +
+
+ +
+
@@ -54,8 +130,9 @@ ${username}`; required="required" type="password" submitted={this.state.submitted}/> - @@ -63,4 +140,4 @@ ${username}`; } }); -export default ConsignForm; \ No newline at end of file +export default LoanForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_checkbox.js b/js/components/ascribe_forms/input_checkbox.js new file mode 100644 index 00000000..c1ecda1a --- /dev/null +++ b/js/components/ascribe_forms/input_checkbox.js @@ -0,0 +1,40 @@ +import React from 'react'; + +import AlertMixin from '../../mixins/alert_mixin' + +let InputCheckbox = React.createClass({ + + mixins : [AlertMixin], + + getInitialState() { + return {value: null, + alerts: null // needed in AlertMixin + }; + }, + handleChange(event) { + this.setState({value: event.target.value}); + }, + render() { + let alerts = (this.props.submitted) ? null : this.state.alerts; + return ( +
+ {alerts} +
+
+ +
+
+
+ ); + + } +}); + +export default InputCheckbox; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_date.js b/js/components/ascribe_forms/input_date.js new file mode 100644 index 00000000..aa3e9e94 --- /dev/null +++ b/js/components/ascribe_forms/input_date.js @@ -0,0 +1,53 @@ +import React from 'react'; + +import AlertMixin from '../../mixins/alert_mixin' +import DatePicker from 'react-datepicker/dist/react-datepicker' + +let InputDate = React.createClass({ + + mixins : [AlertMixin], + + getInitialState() { + return {value: '2015-01-01', + alerts: null // needed in AlertMixin + }; + }, + handleChange(moment_date) { + this.setState({value: moment_date.format("YYYY-MM-DD")}); + }, + isValidDate: function (str) { + return ( + /^[0-9]{4}$/.test(str) && + moment(str, 'YYYY-MM-DD').isValid() + ); + }, + render: function () { + let className = "form-control input-text-ascribe"; + let alerts = (this.props.submitted) ? null : this.state.alerts; + return ( + + ); + //return ( + //
+ // + // + // + // + //
+ //) + + + } +}); + +export default InputDate; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_hidden.js b/js/components/ascribe_forms/input_hidden.js new file mode 100644 index 00000000..96ff95ce --- /dev/null +++ b/js/components/ascribe_forms/input_hidden.js @@ -0,0 +1,33 @@ +import React from 'react'; + +import AlertMixin from '../../mixins/alert_mixin' + +let InputHidden = React.createClass({ + + mixins : [AlertMixin], + + getInitialState() { + return {value: this.props.value, + alerts: null // needed in AlertMixin + }; + }, + handleChange(event) { + this.setState({value: event.target.value}); + }, + render() { + let alerts = (this.props.submitted) ? null : this.state.alerts; + return ( +
+ {alerts} + +
+ ); + + } +}); + +export default InputHidden; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_text.js b/js/components/ascribe_forms/input_text.js index d242de86..b9e7287a 100644 --- a/js/components/ascribe_forms/input_text.js +++ b/js/components/ascribe_forms/input_text.js @@ -24,7 +24,8 @@ let InputText = React.createClass({ placeholder={this.props.placeHolder} required={this.props.required} type={this.props.type} - onChange={this.handleChange}/> + onChange={this.handleChange} + onBlur={this.props.onBlur}/>
); diff --git a/js/components/ascribe_modal/modal_loan.js b/js/components/ascribe_modal/modal_loan.js index bcd47973..aed475b1 100644 --- a/js/components/ascribe_modal/modal_loan.js +++ b/js/components/ascribe_modal/modal_loan.js @@ -4,18 +4,18 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; -import ConsignForm from '../ascribe_forms/form_consign' +import LoanForm from '../ascribe_forms/form_loan' import ModalMixin from '../../mixins/modal_mixin' -let ConsignModalButton = React.createClass({ +let LoanModalButton = React.createClass({ render() { return ( Have someone else sell the artwork}> - }> + overlay={Loan your artwork for a limited period of time}> + }>
- CONSIGN + LOAN
@@ -23,16 +23,16 @@ let ConsignModalButton = React.createClass({ } }); -let ConsignModal = React.createClass({ +let LoanModal = React.createClass({ mixins : [ModalMixin], render() { return ( - +
- +
) @@ -40,4 +40,4 @@ let ConsignModal = React.createClass({ }); -export default ConsignModalButton; +export default LoanModalButton; diff --git a/js/components/edition.js b/js/components/edition.js index 2c5279c1..18c09675 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,6 +1,7 @@ import React from 'react'; import ImageViewer from './ascribe_media/image_viewer'; +import LoanModalButton from './ascribe_modal/modal_loan'; import ConsignModalButton from './ascribe_modal/modal_consign'; import UnConsignModalButton from './ascribe_modal/modal_unconsign'; import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request'; @@ -50,6 +51,7 @@ let EditionDetails = React.createClass({
+ diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js index 6099710b..c1288fcd 100644 --- a/js/constants/api_urls.js +++ b/js/constants/api_urls.js @@ -3,6 +3,7 @@ import AppConstants from './application_constants'; let apiUrls = { 'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/', 'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/', + 'ownership_loans' : AppConstants.baseUrl + 'ownership/loans/', 'ownership_consigns' : AppConstants.baseUrl + 'ownership/consigns/', 'ownership_unconsigns' : AppConstants.baseUrl + 'ownership/unconsigns/', 'ownership_unconsigns_request' : AppConstants.baseUrl + 'ownership/unconsigns/request/' diff --git a/js/fetchers/ownership_fetcher.js b/js/fetchers/ownership_fetcher.js new file mode 100644 index 00000000..94050860 --- /dev/null +++ b/js/fetchers/ownership_fetcher.js @@ -0,0 +1,24 @@ +import fetch from 'isomorphic-fetch'; + +import AppConstants from '../constants/application_constants'; +import FetchApiUtils from '../utils/fetch_api_utils'; + + +let OwnershipFetcher = { + /** + * Fetch one user from the API. + * If no arg is supplied, load the current user + * + */ + fetchLoanContract(email) { + return fetch(AppConstants.baseUrl + 'ownership/loans/contract/?loanee=' + email, { + headers: { + 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64 + } + }).then( + (res) => res.json() + ); + } +}; + +export default OwnershipFetcher; diff --git a/package.json b/package.json index 38710b47..adc61664 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "react": "^0.13.2", "react-router": "^0.13.3", "uglifyjs": "^2.4.10", - "react-bootstrap": "~0.22.6" + "react-bootstrap": "~0.22.6", + "react-datepicker": "~0.8.0" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", diff --git a/sass/main.scss b/sass/main.scss index cd0edf3a..d1a54ee8 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -163,6 +163,14 @@ height: 13em !important; } +.input-checkbox-ascribe { + text-align: left; + line-height: 1.6; + width: 90%; + margin-left: auto; + margin-right: auto; +} + /* columns of same height styles */ /* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */ .row-full-height { From f9a3be61d2cd29fbbb128b0fa49aab3db3a76db4 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Mon, 1 Jun 2015 14:16:06 +0200 Subject: [PATCH 06/33] loan date --- js/components/ascribe_forms/form_loan.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 1822b8ce..be44bb54 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -7,7 +7,7 @@ import FormMixin from '../../mixins/form_mixin'; import InputText from './input_text'; import InputHidden from './input_hidden'; import InputCheckbox from './input_checkbox'; -//import InputDate from './input_date'; +import InputDate from './input_date'; import InputTextArea from './input_textarea'; import OwnershipFetcher from '../../fetchers/ownership_fetcher' import ButtonSubmitOrClose from './button_submit_close'; @@ -82,6 +82,13 @@ ${username}`; label={label} /> } + // return (
@@ -101,13 +108,7 @@ ${username}`; submitted={this.state.submitted}/>
- +
Date: Mon, 1 Jun 2015 14:49:13 +0200 Subject: [PATCH 07/33] Fix datetime selector --- js/components/ascribe_forms/form_loan.js | 8 +++++--- js/components/ascribe_forms/input_date.js | 18 ++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index be44bb54..9a1cce27 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -108,13 +108,15 @@ ${username}`; submitted={this.state.submitted}/>
- +
@@ -141,4 +143,4 @@ ${username}`; } }); -export default LoanForm; \ No newline at end of file +export default LoanForm; diff --git a/js/components/ascribe_forms/input_date.js b/js/components/ascribe_forms/input_date.js index aa3e9e94..98422c72 100644 --- a/js/components/ascribe_forms/input_date.js +++ b/js/components/ascribe_forms/input_date.js @@ -8,19 +8,15 @@ let InputDate = React.createClass({ mixins : [AlertMixin], getInitialState() { - return {value: '2015-01-01', + return {value: null, alerts: null // needed in AlertMixin }; }, - handleChange(moment_date) { - this.setState({value: moment_date.format("YYYY-MM-DD")}); - }, - isValidDate: function (str) { - return ( - /^[0-9]{4}$/.test(str) && - moment(str, 'YYYY-MM-DD').isValid() - ); + + handleChange(date) { + this.setState({value: date}); }, + render: function () { let className = "form-control input-text-ascribe"; let alerts = (this.props.submitted) ? null : this.state.alerts; @@ -28,7 +24,9 @@ let InputDate = React.createClass({ ); //return ( @@ -50,4 +48,4 @@ let InputDate = React.createClass({ } }); -export default InputDate; \ No newline at end of file +export default InputDate; From 420516a2fe99ad321d7e1c6d25b7f16f0ea73abe Mon Sep 17 00:00:00 2001 From: ddejongh Date: Mon, 1 Jun 2015 16:03:41 +0200 Subject: [PATCH 08/33] merge fix --- js/components/edition.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index f8a433f1..f5792c37 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,7 +1,5 @@ import React from 'react'; -<<<<<<< HEAD import ResourceViewer from './ascribe_media/resource_viewer'; -======= import ImageViewer from './ascribe_media/image_viewer'; import LoanModalButton from './ascribe_modal/modal_loan'; @@ -10,7 +8,6 @@ import UnConsignModalButton from './ascribe_modal/modal_unconsign'; import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request'; import TransferModalButton from './ascribe_modal/modal_transfer'; import ShareModalButton from './ascribe_modal/modal_share'; ->>>>>>> master /** * This is the component that implements display-specific functionality From 1c76c5ef487ea6f14d303127dfdf0bbf1604a1d8 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Mon, 1 Jun 2015 16:04:34 +0200 Subject: [PATCH 09/33] merge fix --- js/components/edition.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/components/edition.js b/js/components/edition.js index f5792c37..c3c14c57 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,7 +1,6 @@ import React from 'react'; import ResourceViewer from './ascribe_media/resource_viewer'; -import ImageViewer from './ascribe_media/image_viewer'; import LoanModalButton from './ascribe_modal/modal_loan'; import ConsignModalButton from './ascribe_modal/modal_consign'; import UnConsignModalButton from './ascribe_modal/modal_unconsign'; From f2d9f3b1157919fcbabecb918023939e35e751a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 1 Jun 2015 18:20:15 +0200 Subject: [PATCH 10/33] start implementing localization functionality --- .../accordion_list_item_table_editions.js | 6 +- js/components/header.js | 58 ++++++++----------- js/constants/languages.js | 8 +++ js/stores/edition_store.js | 4 +- js/utils/lang_utils.js | 13 +++++ 5 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 js/constants/languages.js create mode 100644 js/utils/lang_utils.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 2b3bd5c0..e18b7a3f 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 @@ -12,6 +12,8 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; +import getText from '../../utils/lang_utils'; + let AccordionListItemTableEditions = React.createClass({ propTypes: { @@ -47,8 +49,8 @@ let AccordionListItemTableEditions = React.createClass({ render() { let columnList = [ new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', 'Nr', TableItemText, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', 'Bitcoin Address', TableItemText, 5, false), + new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', '#', TableItemText, 1, false), + new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getText('Bitcoin Address'), TableItemText, 5, false), new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', 'Actions', TableItemAclFiltered, 4, false) ]; diff --git a/js/components/header.js b/js/components/header.js index 20855b1b..588f73bf 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -5,6 +5,12 @@ import AltContainer from 'alt/AltContainer'; import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; +import Nav from 'react-bootstrap/lib/Nav'; +import Navbar from 'react-bootstrap/lib/Navbar'; +import NavItem from 'react-bootstrap/lib/NavItem'; +import DropdownButton from 'react-bootstrap/lib/DropdownButton'; +import MenuItem from 'react-bootstrap/lib/MenuItem'; + let Link = Router.Link; let Header = React.createClass({ @@ -24,40 +30,24 @@ let Header = React.createClass({ render() { return ( - + + + + ); } }); diff --git a/js/constants/languages.js b/js/constants/languages.js new file mode 100644 index 00000000..db14a490 --- /dev/null +++ b/js/constants/languages.js @@ -0,0 +1,8 @@ +const languages = { + 'en-US': { + 'Bitcoin Address': 'Bitcoin Address', + 'Actions': 'Actions' + } +}; + +export default languages; \ No newline at end of file diff --git a/js/stores/edition_store.js b/js/stores/edition_store.js index 9859ec7c..b33e248f 100644 --- a/js/stores/edition_store.js +++ b/js/stores/edition_store.js @@ -1,11 +1,11 @@ import alt from '../alt'; -import EditionAction from '../actions/edition_actions'; +import EditionActions from '../actions/edition_actions'; class EditionStore { constructor() { this.edition = {}; - this.bindActions(EditionAction); + this.bindActions(EditionActions); } onUpdateEdition(edition) { diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js new file mode 100644 index 00000000..b7a7681e --- /dev/null +++ b/js/utils/lang_utils.js @@ -0,0 +1,13 @@ +import languages from '../constants/languages'; + +let getText = function(s) { + let lang = navigator.language || navigator.userLanguage; + if(lang in languages && s in languages[lang]) { + return languages[lang][s]; + } else { + throw new Error('Your language is not supported.'); + // How ironic that this error is thrown in the english language... + } +}; + +export default getText; \ No newline at end of file From cbecbf44ad58d8df361e272d2a4050eaaeca3aaf Mon Sep 17 00:00:00 2001 From: ddejongh Date: Mon, 1 Jun 2015 18:59:47 +0200 Subject: [PATCH 11/33] bind modals to actionbuttons --- js/components/acl_button.js | 55 +++++++++++++++--- js/components/ascribe_modal/modal_consign.js | 43 -------------- js/components/ascribe_modal/modal_wrapper.js | 57 +++++++++++++++++++ .../piece_list_toolbar.js | 35 ++++++++++-- js/components/edition.js | 13 ++++- js/components/edition_container.js | 1 - js/mixins/inject_in_head_mixin.js | 2 +- js/stores/user_store.js | 4 +- 8 files changed, 148 insertions(+), 62 deletions(-) delete mode 100644 js/components/ascribe_modal/modal_consign.js create mode 100644 js/components/ascribe_modal/modal_wrapper.js diff --git a/js/components/acl_button.js b/js/components/acl_button.js index 6d4f1756..65af1e18 100644 --- a/js/components/acl_button.js +++ b/js/components/acl_button.js @@ -1,27 +1,68 @@ import React from 'react'; +import ConsignForm from './ascribe_forms/form_consign'; +import TransferForm from './ascribe_forms/form_transfer'; +import LoanForm from './ascribe_forms/form_loan'; +import ShareForm from './ascribe_forms/form_share_email'; +import ModalWrapper from './ascribe_modal/modal_wrapper'; import AppConstants from '../constants/application_constants'; let AclButton = React.createClass({ propTypes: { action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, availableAcls: React.PropTypes.array.isRequired, - actionFunction: React.PropTypes.func.isRequired + editions: React.PropTypes.array.isRequired, + currentUser: React.PropTypes.object }, actionFunction() { this.props.actionFunction(this.props.action); }, + actionProperties(){ + if (this.props.action == 'consign'){ + return { + title: "Consign artwork", + tooltip: "Have someone else sell the artwork", + form: + } + } + else if (this.props.action == 'transfer') { + return { + title: "Transfer artwork", + tooltip: "Transfer the ownership of the artwork", + form: + } + } + else if (this.props.action == 'loan'){ + return { + title: "Loan artwork", + tooltip: "Loan your artwork for a limited period of time", + form: } + } + else if (this.props.action == 'share'){ + return { + title: "Share artwork", + tooltip: "Share the artwork", + form: } + } + }, render() { let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; + let aclProps = this.actionProperties(); return ( - + + {this.props.action.toUpperCase()} +
+ } + currentUser={ this.props.currentUser } + edition={ this.props.editions[0] } + title={ aclProps.title } + tooltip={ aclProps.tooltip }> + { aclProps.form } + ); } }); diff --git a/js/components/ascribe_modal/modal_consign.js b/js/components/ascribe_modal/modal_consign.js deleted file mode 100644 index bcd47973..00000000 --- a/js/components/ascribe_modal/modal_consign.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -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 ConsignForm from '../ascribe_forms/form_consign' -import ModalMixin from '../../mixins/modal_mixin' - -let ConsignModalButton = React.createClass({ - render() { - return ( - Have someone else sell the artwork}> - }> -
- CONSIGN -
-
-
- ) - } -}); - -let ConsignModal = React.createClass({ - mixins : [ModalMixin], - - render() { - return ( - -
- -
-
- ) - } -}); - - -export default ConsignModalButton; diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js new file mode 100644 index 00000000..83a60c64 --- /dev/null +++ b/js/components/ascribe_modal/modal_wrapper.js @@ -0,0 +1,57 @@ +import React from 'react'; +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' + +let ModalWrapper = React.createClass({ + + render() { + return ( + {this.props.tooltip}}> + + {this.props.children} + + }> + {this.props.button} + + + ) + } +}); + +// +let ModalBody = React.createClass({ + mixins : [ModalMixin], + + renderChildren() { + return ReactAddons.Children.map(this.props.children, (child, i) => { + return ReactAddons.addons.cloneWithProps(child, { + edition: this.props.edition, + currentUser: this.props.currentUser, + onRequestHide: this.onRequestHide + }); + }); + }, + render() { + return ( + +
+ {this.renderChildren()} +
+
+ ) + } +}); + + +export default ModalWrapper; diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index f7b04cc6..30a30ecb 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -3,6 +3,9 @@ import React from 'react'; import EditionListStore from '../../stores/edition_list_store'; import EditionListActions from '../../actions/edition_list_actions'; +import UserActions from '../../actions/user_actions'; +import UserStore from '../../stores/user_store'; + import AclButton from '../acl_button'; import PieceListToolbarSelectedEditionsWidget from './piece_list_toolbar_selected_editions_widget'; @@ -20,11 +23,14 @@ let PieceListToolbar = React.createClass({ }, componentDidMount() { - EditionListStore.listen(this.onChange) + EditionListStore.listen(this.onChange); + UserStore.listen(this.onChange); + UserActions.fetchCurrentUser(); }, componentDidUnmount() { - EditionListStore.unlisten(this.onChange) + EditionListStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); }, filterForSelected(edition) { @@ -77,6 +83,7 @@ let PieceListToolbar = React.createClass({ render() { let availableAcls = this.getAvailableAcls(); + let editions = this.fetchSelectedEditionList(); if(availableAcls.length > 0) { return ( @@ -97,10 +104,26 @@ let PieceListToolbar = React.createClass({

- - - - + + + +
diff --git a/js/components/edition.js b/js/components/edition.js index c3c14c57..92bf5c77 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -2,7 +2,8 @@ import React from 'react'; import ResourceViewer from './ascribe_media/resource_viewer'; import LoanModalButton from './ascribe_modal/modal_loan'; -import ConsignModalButton from './ascribe_modal/modal_consign'; +import ModalWrapper from './ascribe_modal/modal_wrapper'; +import ConsignForm from './ascribe_forms/form_consign.js'; import UnConsignModalButton from './ascribe_modal/modal_unconsign'; import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request'; import TransferModalButton from './ascribe_modal/modal_transfer'; @@ -48,6 +49,7 @@ let EditionHeader = React.createClass({ }); let EditionDetails = React.createClass({ + render() { return (
@@ -57,7 +59,14 @@ let EditionDetails = React.createClass({
- + CONSIGN
} + currentUser={ this.props.currentUser } + edition={ this.props.edition } + title="Consign artwork" + tooltip="Have someone else sell the artwork"> + + diff --git a/js/components/edition_container.js b/js/components/edition_container.js index 77d28962..6887fd20 100644 --- a/js/components/edition_container.js +++ b/js/components/edition_container.js @@ -27,7 +27,6 @@ let EditionContainer = React.createClass({ UserActions.fetchCurrentUser(); UserStore.listen(this.onChange); }, - componentDidUnmount() { EditionStore.unlisten(this.onChange); UserStore.unlisten(this.onChange); diff --git a/js/mixins/inject_in_head_mixin.js b/js/mixins/inject_in_head_mixin.js index 0c83be16..72ecdfe1 100644 --- a/js/mixins/inject_in_head_mixin.js +++ b/js/mixins/inject_in_head_mixin.js @@ -42,7 +42,7 @@ let InjectInHeadMixin = { }, inject(src) { - debugger; + //debugger; let ext = src.split('.').pop(); try { let tag = mapAttr(src); diff --git a/js/stores/user_store.js b/js/stores/user_store.js index 45fbec57..6ae631c9 100644 --- a/js/stores/user_store.js +++ b/js/stores/user_store.js @@ -4,13 +4,13 @@ import UserAction from '../actions/user_actions'; class UserStore{ constructor() { - this.currentUser = {} + this.currentUser = {}; this.bindActions(UserAction); } onUpdateCurrentUser(user) { this.currentUser = user; } -}; +} export default alt.createStore(UserStore); From c2c204922923914340d23f406f6b6a7e11b732e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 09:10:26 +0200 Subject: [PATCH 12/33] rename piece_list_toolbar to a more fitting name: piece_list_bulk_modal --- .../piece_list_bulk_modal.js} | 12 ++++++------ ...iece_list_bulk_modal_selected_editions_widget.js} | 4 ++-- js/components/piece_list.js | 4 ++-- ...cordion_list.scss => ascribe_accordion_list.scss} | 0 ...olbar.scss => ascribe_piece_list_bulk_modal.scss} | 4 ++-- ...ascribe-variables.scss => ascribe_variables.scss} | 0 sass/main.scss | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) rename js/components/{ascribe_piece_list_toolbar/piece_list_toolbar.js => ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js} (90%) rename js/components/{ascribe_piece_list_toolbar/piece_list_toolbar_selected_editions_widget.js => ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js} (74%) rename sass/{ascribe-accordion_list.scss => ascribe_accordion_list.scss} (100%) rename sass/{ascribe-piece-list-toolbar.scss => ascribe_piece_list_bulk_modal.scss} (85%) rename sass/{ascribe-variables.scss => ascribe_variables.scss} (100%) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js similarity index 90% rename from js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js rename to js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js index f7b04cc6..43330538 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js @@ -4,9 +4,9 @@ import EditionListStore from '../../stores/edition_list_store'; import EditionListActions from '../../actions/edition_list_actions'; import AclButton from '../acl_button'; -import PieceListToolbarSelectedEditionsWidget from './piece_list_toolbar_selected_editions_widget'; +import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_selected_editions_widget'; -let PieceListToolbar = React.createClass({ +let PieceListBulkModal = React.createClass({ propTypes: { className: React.PropTypes.string }, @@ -82,15 +82,15 @@ let PieceListToolbar = React.createClass({ return (
-
+

-           clear all
@@ -114,4 +114,4 @@ let PieceListToolbar = React.createClass({ } }); -export default PieceListToolbar; \ No newline at end of file +export default PieceListBulkModal; \ No newline at end of file diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_selected_editions_widget.js b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js similarity index 74% rename from js/components/ascribe_piece_list_toolbar/piece_list_toolbar_selected_editions_widget.js rename to js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js index 5c020d45..22b35a4a 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_selected_editions_widget.js +++ b/js/components/ascribe_piece_list_bulk_modal/piece_list_bulk_modal_selected_editions_widget.js @@ -1,6 +1,6 @@ import React from 'react'; -let PieceListToolbarSelectedEditionsWidget = React.createClass({ +let PieceListBulkModalSelectedEditionsWidget = React.createClass({ propTypes: { numberOfSelectedEditions: React.PropTypes.number.isRequired }, @@ -14,4 +14,4 @@ let PieceListToolbarSelectedEditionsWidget = React.createClass({ } }); -export default PieceListToolbarSelectedEditionsWidget; \ No newline at end of file +export default PieceListBulkModalSelectedEditionsWidget; \ No newline at end of file diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 9580ffb1..2a75b7da 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -10,7 +10,7 @@ import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_l import Pagination from './ascribe_pagination/pagination'; -import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar'; +import PieceListBulkModal from './ascribe_piece_list_bulk_modal/piece_list_bulk_modal'; let PieceList = React.createClass({ @@ -50,7 +50,7 @@ let PieceList = React.createClass({ return (
- + Date: Tue, 2 Jun 2015 10:10:09 +0200 Subject: [PATCH 13/33] implement search functionality --- .../piece_list_toolbar.js | 56 ++++++ js/components/piece_list.js | 2 + sass/ascribe_piece_list_toolbar.scss | 7 + sass/main.scss | 4 +- sass/offset_right.scss | 164 ++++++++++++++++++ 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js create mode 100644 sass/ascribe_piece_list_toolbar.scss create mode 100644 sass/offset_right.scss diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js new file mode 100644 index 00000000..d2597ed1 --- /dev/null +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -0,0 +1,56 @@ +import React from 'react'; + +import PieceListStore from '../../stores/piece_list_store'; +import PieceListActions from '../../actions/piece_list_actions'; + +import Input from 'react-bootstrap/lib/Input'; +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import Button from 'react-bootstrap/lib/Button'; + +let PieceListToolbar = React.createClass({ + + getInitialState() { + return PieceListStore.getState(); + }, + + onChange(state) { + this.setState(state); + }, + + componentDidMount() { + PieceListStore.listen(this.onChange); + }, + + componentDidUnmount() { + PieceListStore.unlisten(this.onChange); + }, + + searchFor() { + let searchTerm = this.refs.search.getInputDOMNode().value; + PieceListActions.fetchPieceList(this.state.page, this.pageSize, searchTerm, this.state.orderBy, this.state.orderAsc); + }, + + render() { + let searchIcon = ; + + return ( +
+
+
+
+
+ +    + +
+
+
+
+
+ ); + } +}); + +export default PieceListToolbar; \ No newline at end of file diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 2a75b7da..ea1ef790 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -11,6 +11,7 @@ import AccordionListItemTableEditions from './ascribe_accordion_list/accordion_l import Pagination from './ascribe_pagination/pagination'; import PieceListBulkModal from './ascribe_piece_list_bulk_modal/piece_list_bulk_modal'; +import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar'; let PieceList = React.createClass({ @@ -50,6 +51,7 @@ let PieceList = React.createClass({ return (
+ Date: Tue, 2 Jun 2015 11:38:18 +0200 Subject: [PATCH 14/33] bulk transfer part 1 --- js/components/acl_button.js | 10 ++--- js/components/ascribe_forms/form_consign.js | 8 ++-- js/components/ascribe_forms/form_transfer.js | 19 +++++---- js/components/ascribe_modal/modal_wrapper.js | 15 +++++-- .../piece_list_toolbar.js | 14 +++++-- js/components/edition.js | 40 +++++++++---------- js/mixins/form_mixin.js | 14 +++++-- 7 files changed, 72 insertions(+), 48 deletions(-) diff --git a/js/components/acl_button.js b/js/components/acl_button.js index 65af1e18..5f2a0708 100644 --- a/js/components/acl_button.js +++ b/js/components/acl_button.js @@ -12,11 +12,8 @@ let AclButton = React.createClass({ action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, availableAcls: React.PropTypes.array.isRequired, editions: React.PropTypes.array.isRequired, - currentUser: React.PropTypes.object - }, - - actionFunction() { - this.props.actionFunction(this.props.action); + currentUser: React.PropTypes.object, + handleSuccess: React.PropTypes.func.isRequired }, actionProperties(){ @@ -58,7 +55,8 @@ let AclButton = React.createClass({
} currentUser={ this.props.currentUser } - edition={ this.props.editions[0] } + editions={ this.props.editions } + handleSuccess={ this.props.handleSuccess } title={ aclProps.title } tooltip={ aclProps.tooltip }> { aclProps.form } diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js index 708ab70e..dbb1eee0 100644 --- a/js/components/ascribe_forms/form_consign.js +++ b/js/components/ascribe_forms/form_consign.js @@ -16,19 +16,21 @@ let ConsignForm = React.createClass({ }, getFormData() { return { - bitcoin_id: this.props.edition.bitcoin_id, + bitcoin_id: this.getBitcoinIds().join(), consignee: this.refs.consignee.state.value, consign_message: this.refs.consign_message.state.value, password: this.refs.password.state.value } }, + renderForm() { - let title = this.props.edition.title; + let title = this.getTitlesString().join(""); let username = this.props.currentUser.username; let message = `Hi, -I consign \" ${title} \" to you. +I consign : +${title}to you. Truly yours, ${username}`; diff --git a/js/components/ascribe_forms/form_transfer.js b/js/components/ascribe_forms/form_transfer.js index 28e86db3..c724edd0 100644 --- a/js/components/ascribe_forms/form_transfer.js +++ b/js/components/ascribe_forms/form_transfer.js @@ -18,19 +18,24 @@ let TransferForm = React.createClass({ }, getFormData() { return { - bitcoin_id: this.props.edition.bitcoin_id, + bitcoin_id: this.getBitcoinIds().join(), transferee: this.refs.transferee.state.value, transfer_message: this.refs.transfer_message.state.value, password: this.refs.password.state.value } }, renderForm() { - let message = "Hi,\n" + - "\n" + - "I transfer ownership of \"" + this.props.edition.title + "\" to you.\n" + - "\n" + - "Truly yours,\n" + - this.props.currentUser.username; + let title = this.getTitlesString().join(""); + let username = this.props.currentUser.username; + let message = +`Hi, + +I transfer ownership of : +${title}to you. + +Truly yours, +${username}`; + return ( diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js index 83a60c64..a5d20389 100644 --- a/js/components/ascribe_modal/modal_wrapper.js +++ b/js/components/ascribe_modal/modal_wrapper.js @@ -17,8 +17,10 @@ let ModalWrapper = React.createClass({ + editions={this.props.editions} + currentUser={this.props.currentUser} + handleSuccess={this.props.handleSuccess} + > {this.props.children} }> @@ -33,12 +35,17 @@ let ModalWrapper = React.createClass({ let ModalBody = React.createClass({ mixins : [ModalMixin], + handleSuccess(){ + this.props.handleSuccess(); + this.props.onRequestHide(); + }, renderChildren() { return ReactAddons.Children.map(this.props.children, (child, i) => { return ReactAddons.addons.cloneWithProps(child, { - edition: this.props.edition, + editions: this.props.editions, currentUser: this.props.currentUser, - onRequestHide: this.onRequestHide + onRequestHide: this.onRequestHide, + handleSuccess: this.handleSuccess }); }); }, diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index 30a30ecb..dc6fad19 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -80,7 +80,9 @@ let PieceListToolbar = React.createClass({ clearAllSelections() { EditionListActions.clearAllEditionSelections(); }, + handleSuccess(){ + }, render() { let availableAcls = this.getAvailableAcls(); let editions = this.fetchSelectedEditionList(); @@ -107,23 +109,27 @@ let PieceListToolbar = React.createClass({ + handleSuccess={this.handleSuccess}/> + handleSuccess={this.handleSuccess}/> + handleSuccess={this.handleSuccess}/> + handleSuccess={this.handleSuccess}/>
diff --git a/js/components/edition.js b/js/components/edition.js index 92bf5c77..9d0352de 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,13 +1,8 @@ import React from 'react'; import ResourceViewer from './ascribe_media/resource_viewer'; -import LoanModalButton from './ascribe_modal/modal_loan'; -import ModalWrapper from './ascribe_modal/modal_wrapper'; -import ConsignForm from './ascribe_forms/form_consign.js'; -import UnConsignModalButton from './ascribe_modal/modal_unconsign'; -import UnConsignRequestModalButton from './ascribe_modal/modal_unconsign_request'; -import TransferModalButton from './ascribe_modal/modal_transfer'; -import ShareModalButton from './ascribe_modal/modal_share'; +import EditionActions from '../actions/edition_actions' +import AclButton from './acl_button' /** * This is the component that implements display-specific functionality @@ -49,7 +44,9 @@ let EditionHeader = React.createClass({ }); let EditionDetails = React.createClass({ - + handleSuccess(){ + EditionActions.fetchOne(this.props.edition.id); + }, render() { return (
@@ -58,19 +55,20 @@ let EditionDetails = React.createClass({
- - CONSIGN
} - currentUser={ this.props.currentUser } - edition={ this.props.edition } - title="Consign artwork" - tooltip="Have someone else sell the artwork"> - - - - - - + +
); diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js index 65983653..aa58c8a8 100644 --- a/js/mixins/form_mixin.js +++ b/js/mixins/form_mixin.js @@ -1,6 +1,5 @@ import React from 'react'; -import EditionActions from '../actions/edition_actions' import AppConstants from '../constants/application_constants' import AlertDismissable from '../components/ascribe_forms/alert' @@ -34,8 +33,7 @@ export const FormMixin = { handleResponse(response){ let submitted = false; if (response.status >= 200 && response.status < 300){ - EditionActions.fetchOne(this.props.edition.id); - this.props.onRequestHide(); + this.props.handleSuccess(); submitted = true; } else if (response.status >= 400 && response.status < 500) { @@ -57,6 +55,16 @@ export const FormMixin = { } } }, + getBitcoinIds(){ + return this.props.editions.map(function(edition){ + return edition.bitcoin_id + }) + }, + getTitlesString(){ + return this.props.editions.map(function(edition){ + return '- \"' + edition.title + ', edition ' + edition.edition_number + '\"\n' + }) + }, render(){ let alert = null; if (this.state.status >= 500){ From 713dd72b2bebb05a3f06025697f3f100c4bb76de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 11:40:55 +0200 Subject: [PATCH 15/33] add unfinished filtering widget --- index.html | 2 +- .../piece_list_toolbar.js | 15 ++++----- .../piece_list_toolbar_filter_widget.js | 31 +++++++++++++++++++ sass/ascribe_piece_list_toolbar.scss | 4 --- sass/main.scss | 2 +- 5 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js diff --git a/index.html b/index.html index 8b61e4b0..b61794b4 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ -
+
diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index d2597ed1..ff2bd68f 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -5,7 +5,8 @@ import PieceListActions from '../../actions/piece_list_actions'; import Input from 'react-bootstrap/lib/Input'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; -import Button from 'react-bootstrap/lib/Button'; + +import PieceListToolbarFilterWidgetFilter from './piece_list_toolbar_filter_widget'; let PieceListToolbar = React.createClass({ @@ -38,12 +39,12 @@ let PieceListToolbar = React.createClass({
-
- -    - +
+
+ +    + +
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 new file mode 100644 index 00000000..7aaf9dd8 --- /dev/null +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js @@ -0,0 +1,31 @@ +import React from 'react'; + +import Glyphicon from 'react-bootstrap/lib/Glyphicon'; +import DropdownButton from 'react-bootstrap/lib/DropdownButton'; +import MenuItem from 'react-bootstrap/lib/MenuItem'; + +let PieceListToolbarFilterWidgetFilter = React.createClass({ + render() { + let filterIcon = ; + + return ( + +
  • + Show Pieces that: +
  • + +
    + I can transfer +
    +
    + +
    + I can consign +
    +
    +
    + ); + } +}); + +export default PieceListToolbarFilterWidgetFilter; \ No newline at end of file diff --git a/sass/ascribe_piece_list_toolbar.scss b/sass/ascribe_piece_list_toolbar.scss index 834ed14b..73c0bc94 100644 --- a/sass/ascribe_piece_list_toolbar.scss +++ b/sass/ascribe_piece_list_toolbar.scss @@ -1,7 +1,3 @@ .ascribe-piece-list-toolbar { margin-bottom: 1.5em; -} - -.ascribe-piece-list-toolbar-search { - padding-right:0; } \ No newline at end of file diff --git a/sass/main.scss b/sass/main.scss index be07e18a..5327032e 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -20,7 +20,7 @@ margin-bottom: 1.5em; } -.clear-margins-and-paddings { +.clear-paddings { padding-left:0; padding-right:0; } From 777857b50cee1a32f12efad06b71913ad601de65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 12:00:59 +0200 Subject: [PATCH 16/33] include lodash.templates --- js/utils/lang_utils.js | 17 +++++++++++------ package.json | 5 +++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index b7a7681e..a936294e 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,12 +1,17 @@ import languages from '../constants/languages'; +import template from 'lodash.template'; -let getText = function(s) { +let getText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; - if(lang in languages && s in languages[lang]) { - return languages[lang][s]; - } else { - throw new Error('Your language is not supported.'); - // How ironic that this error is thrown in the english language... + try { + if(lang in languages) { + return languages[lang][s]; + } else { + // just use the english language + return languages['en-US'][s]; + } + } catch(err) { + console.error(err); } }; diff --git a/package.json b/package.json index 38710b47..3007fdf4 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,12 @@ "alt": "^0.16.5", "classnames": "^1.2.2", "isomorphic-fetch": "^2.0.2", + "lodash.template": "^3.6.1", "object-assign": "^2.0.0", "react": "^0.13.2", + "react-bootstrap": "~0.22.6", "react-router": "^0.13.3", - "uglifyjs": "^2.4.10", - "react-bootstrap": "~0.22.6" + "uglifyjs": "^2.4.10" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", From 6f33b291f9c33277cc5b00ab5d62bde293cc8ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:10:10 +0200 Subject: [PATCH 17/33] remove lodash templates --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 3007fdf4..c3025fc6 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "alt": "^0.16.5", "classnames": "^1.2.2", "isomorphic-fetch": "^2.0.2", - "lodash.template": "^3.6.1", "object-assign": "^2.0.0", "react": "^0.13.2", "react-bootstrap": "~0.22.6", From 68be98c3f0957d8662f9b5f7dea86610c7e6fa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:31:12 +0200 Subject: [PATCH 18/33] integrate string formating functionality --- js/actions/piece_actions.js | 2 +- js/actions/piece_list_actions.js | 1 - .../accordion_list_item_table.js | 4 ++- .../accordion_list_item_table_editions.js | 6 ++-- js/constants/languages.js | 4 ++- js/utils/general_utils.js | 35 ++++++++++++++++++- js/utils/lang_utils.js | 14 ++++---- 7 files changed, 52 insertions(+), 14 deletions(-) diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js index d657539b..274ef458 100644 --- a/js/actions/piece_actions.js +++ b/js/actions/piece_actions.js @@ -15,7 +15,7 @@ class PieceActions { this.actions.updatePiece(res.piece); }) .catch((err) => { - console.log(err); + console.log(err); }); } } diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 4ec237ca..29c8413f 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -14,7 +14,6 @@ class PieceListActions { PieceListFetcher .fetch(page, pageSize, search, orderBy, orderAsc) .then((res) => { - console.log(res); this.actions.updatePieceList({ page, pageSize, diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 9ddb3308..953fffa1 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -5,6 +5,8 @@ import TableItem from '../ascribe_table/table_item'; import TableColumnContentModel from '../../models/table_column_content_model'; +import getLangText from '../../utils/lang_utils'; + let AccordionListItemTable = React.createClass({ getInitialState() { return { @@ -78,7 +80,7 @@ let AccordionListItemTableToggle = React.createClass({ - {this.props.show ? 'Hide all ' + this.props.numOfTableItems + ' Editions' : 'Show all ' + this.props.numOfTableItems + ' Editions'} + {this.props.show ? getLangText('Hide all %d Editions', this.props.numOfTableItems) : getLangText('Show all %d Editions', this.props.numOfTableItems)} ); } 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 e18b7a3f..356e5fe0 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 @@ -12,7 +12,7 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; -import getText from '../../utils/lang_utils'; +import getLangText from '../../utils/lang_utils'; let AccordionListItemTableEditions = React.createClass({ @@ -50,8 +50,8 @@ let AccordionListItemTableEditions = React.createClass({ let columnList = [ new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', '#', TableItemText, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getText('Bitcoin Address'), TableItemText, 5, false), - new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', 'Actions', TableItemAclFiltered, 4, false) + new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getLangText('Bitcoin Address'), TableItemText, 5, false), + new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', getLangText('Actions'), TableItemAclFiltered, 4, false) ]; return ( diff --git a/js/constants/languages.js b/js/constants/languages.js index db14a490..c49caf53 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -1,7 +1,9 @@ const languages = { 'en-US': { 'Bitcoin Address': 'Bitcoin Address', - 'Actions': 'Actions' + 'Actions': 'Actions', + 'Hide all %d Editions': 'Hide all %d Editions', + 'Show all %d Editions': 'Show all %d Editions' } }; diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 7ab180fa..14118d94 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -34,8 +34,41 @@ let GeneralUtils = { let sum = 0; l.forEach((num) => sum += parseFloat(num) || 0); return sum; - } + }, + /* + Taken from http://stackoverflow.com/a/4795914/1263876 + Behaves like C's format string function + + Does not throw errors though if a argument's type is not + matching its template's representative!!! + This essentially means you can use %d or %s for anything... + */ + formatText() { + var args = arguments, + string = args[0], + i = 1; + return string.replace(/%((%)|s|d)/g, function (m) { + // m is the matched format, e.g. %s, %d + var val = null; + if (m[2]) { + val = m[2]; + } else { + val = args[i]; + // A switch statement so that the formatter can be extended. Default is %s + switch (m) { + case '%d': + val = parseFloat(val); + if (isNaN(val)) { + val = 0; + } + break; + } + i++; + } + return val; + }); + } }; export default GeneralUtils; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index a936294e..0eddcd30 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,18 +1,20 @@ import languages from '../constants/languages'; -import template from 'lodash.template'; -let getText = function(s, ...args) { +import GeneralUtils from './general_utils'; + +let getLangText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; + try { if(lang in languages) { - return languages[lang][s]; + return GeneralUtils.formatText(languages[lang][s], args); } else { // just use the english language - return languages['en-US'][s]; + return GeneralUtils.formatText(languages['en-US'][s], args); } } catch(err) { - console.error(err); + console.error(new Error('Language-string is not in constants file.')); } }; -export default getText; \ No newline at end of file +export default getLangText; \ No newline at end of file From 366fcbf4f3a4ac978f817a56690df1aab5ad9230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:42:17 +0200 Subject: [PATCH 19/33] refactor general utils --- js/components/ascribe_table/table_header.js | 1 - js/mixins/table_column_mixin.js | 4 +- js/utils/fetch_api_utils.js | 4 +- js/utils/general_utils.js | 125 +++++++++----------- js/utils/lang_utils.js | 13 +- 5 files changed, 70 insertions(+), 77 deletions(-) diff --git a/js/components/ascribe_table/table_header.js b/js/components/ascribe_table/table_header.js index 8176ad31..44594394 100644 --- a/js/components/ascribe_table/table_header.js +++ b/js/components/ascribe_table/table_header.js @@ -1,7 +1,6 @@ import React from 'react'; import TableColumnMixin from '../../mixins/table_column_mixin'; -import GeneralUtils from '../../utils/general_utils'; import TableHeaderItem from './table_header_item'; import TableColumnContentModel from '../../models/table_column_content_model'; diff --git a/js/mixins/table_column_mixin.js b/js/mixins/table_column_mixin.js index d74214e1..eac266b6 100644 --- a/js/mixins/table_column_mixin.js +++ b/js/mixins/table_column_mixin.js @@ -1,6 +1,6 @@ import React from 'react'; -import GeneralUtils from '../utils/general_utils'; +import { sumNumList } from '../utils/general_utils'; let TableColumnMixin = { /** @@ -11,7 +11,7 @@ let TableColumnMixin = { let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-']; let listOfRowValues = list.map((column) => column.rowWidth ); - let numOfUsedColumns = GeneralUtils.sumNumList(listOfRowValues); + let numOfUsedColumns = sumNumList(listOfRowValues); if(numOfUsedColumns > numOfColumns) { throw new Error('This table has only ' + numOfColumns + ' columns to assign. You defined ' + numOfUsedColumns + '. Change this in the columnMap you\'re passing to the table.') diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index 47b52e66..ccee8ae5 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -1,4 +1,4 @@ -import GeneralUtils from './general_utils'; +import { sanitize } from './general_utils'; // TODO: Create Unittests that test all functions @@ -22,7 +22,7 @@ let FetchApiUtils = { */ argsToQueryParams(obj) { - obj = GeneralUtils.sanitize(obj); + obj = sanitize(obj); return Object .keys(obj) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 14118d94..96f56c1e 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -1,74 +1,63 @@ // TODO: Create Unittests that test all functions -let GeneralUtils = { - /** - * Removes undefined and null values from an key-value object. - */ - sanitize(obj) { - Object - .keys(obj) - .map((key) => { - // By matching null with a double equal, we can match undefined and null - // http://stackoverflow.com/a/15992131 - if(obj[key] == null || obj[key] === '') { - delete obj[key]; - } - }); - - return obj; - }, - - /** - * Returns the values of an object. - */ - valuesOfObject(obj) { - return Object - .keys(obj) - .map(key => obj[key]); - }, - - /** - * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... - */ - sumNumList(l) { - let sum = 0; - l.forEach((num) => sum += parseFloat(num) || 0); - return sum; - }, - - /* - Taken from http://stackoverflow.com/a/4795914/1263876 - Behaves like C's format string function - - Does not throw errors though if a argument's type is not - matching its template's representative!!! - This essentially means you can use %d or %s for anything... - */ - formatText() { - var args = arguments, - string = args[0], - i = 1; - return string.replace(/%((%)|s|d)/g, function (m) { - // m is the matched format, e.g. %s, %d - var val = null; - if (m[2]) { - val = m[2]; - } else { - val = args[i]; - // A switch statement so that the formatter can be extended. Default is %s - switch (m) { - case '%d': - val = parseFloat(val); - if (isNaN(val)) { - val = 0; - } - break; - } - i++; +export function sanitize(obj) { + Object + .keys(obj) + .map((key) => { + // By matching null with a double equal, we can match undefined and null + // http://stackoverflow.com/a/15992131 + if(obj[key] == null || obj[key] === '') { + delete obj[key]; } - return val; }); - } + + return obj; }; -export default GeneralUtils; +/** + * Returns the values of an object. + */ +export function valuesOfObject(obj) { + return Object + .keys(obj) + .map(key => obj[key]); +}; + +/** + * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... + */ +export function sumNumList(l) { + let sum = 0; + l.forEach((num) => sum += parseFloat(num) || 0); + return sum; +}; + +/* + Taken from http://stackoverflow.com/a/4795914/1263876 + Behaves like C's format string function +*/ +export function formatText() { + var args = arguments, + string = args[0], + i = 1; + return string.replace(/%((%)|s|d)/g, function (m) { + // m is the matched format, e.g. %s, %d + var val = null; + if (m[2]) { + val = m[2]; + } else { + val = args[i]; + // A switch statement so that the formatter can be extended. Default is %s + switch (m) { + case '%d': + val = parseFloat(val); + if (isNaN(val)) { + val = 0; + } + break; + } + i++; + } + return val; + }); +}; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0eddcd30..8157caf9 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,19 +1,24 @@ import languages from '../constants/languages'; -import GeneralUtils from './general_utils'; +import { formatText } from './general_utils'; let getLangText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; try { if(lang in languages) { - return GeneralUtils.formatText(languages[lang][s], args); + return formatText(languages[lang][s], args); } else { // just use the english language - return GeneralUtils.formatText(languages['en-US'][s], args); + return formatText(languages['en-US'][s], args); } } catch(err) { - console.error(new Error('Language-string is not in constants file.')); + if(!(s in languages[lang])) { + console.error(new Error('Language-string is not in constants file for string: ' + s)); + } else { + console.error(err); + } + } }; From 141d21155ba5ecdd20638030adf61767cf7eb178 Mon Sep 17 00:00:00 2001 From: vrde Date: Tue, 2 Jun 2015 13:44:50 +0200 Subject: [PATCH 20/33] WIP to style widgets, will continue later --- index.html | 4 ++-- sass/main.scss | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 7b54e6a2..f11830bf 100644 --- a/index.html +++ b/index.html @@ -5,9 +5,9 @@ ascribe - - + +
    diff --git a/sass/main.scss b/sass/main.scss index 2734ffdf..abd0a757 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -162,7 +162,8 @@ text-transform: uppercase; } -.input-text-ascribe { +.input-text-ascribe, +.datepicker__input { border-bottom: 1px solid black; border-top: 0; border-left: 0; @@ -240,4 +241,4 @@ .col-bottom { vertical-align: bottom; -} \ No newline at end of file +} From 347517a0b36a6fb16999ca8e3d24b119f68467fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:48:01 +0200 Subject: [PATCH 21/33] refactor all util functions for nicer usability --- .../accordion_list_item_table.js | 2 +- .../accordion_list_item_table_editions.js | 2 +- js/fetchers/edition_fetcher.js | 1 - js/fetchers/piece_list_fetcher.js | 4 +- js/fetchers/user_fetcher.js | 1 - js/utils/fetch.js | 4 +- js/utils/fetch_api_utils.js | 75 +++++++++---------- js/utils/lang_utils.js | 6 +- 8 files changed, 43 insertions(+), 52 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 953fffa1..66eb3baf 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -5,7 +5,7 @@ import TableItem from '../ascribe_table/table_item'; import TableColumnContentModel from '../../models/table_column_content_model'; -import getLangText from '../../utils/lang_utils'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItemTable = React.createClass({ getInitialState() { 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 356e5fe0..f14f6016 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 @@ -12,7 +12,7 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; -import getLangText from '../../utils/lang_utils'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItemTableEditions = React.createClass({ diff --git a/js/fetchers/edition_fetcher.js b/js/fetchers/edition_fetcher.js index 7ce5bdab..46cdf1b7 100644 --- a/js/fetchers/edition_fetcher.js +++ b/js/fetchers/edition_fetcher.js @@ -1,7 +1,6 @@ import fetch from '../utils/fetch'; import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; let EditionFetcher = { diff --git a/js/fetchers/piece_list_fetcher.js b/js/fetchers/piece_list_fetcher.js index 9490c6fb..ed867253 100644 --- a/js/fetchers/piece_list_fetcher.js +++ b/js/fetchers/piece_list_fetcher.js @@ -1,5 +1,5 @@ import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; +import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import fetch from '../utils/fetch'; @@ -9,7 +9,7 @@ let PieceListFetcher = { * Can be called with all supplied queryparams the API. */ fetch(page, pageSize, search, orderBy, orderAsc) { - let ordering = FetchApiUtils.generateOrderingQueryParams(orderBy, orderAsc); + let ordering = generateOrderingQueryParams(orderBy, orderAsc); return fetch.get('pieces_list', { page, pageSize, search, ordering }); } }; diff --git a/js/fetchers/user_fetcher.js b/js/fetchers/user_fetcher.js index b5313cd6..df3e887e 100644 --- a/js/fetchers/user_fetcher.js +++ b/js/fetchers/user_fetcher.js @@ -1,7 +1,6 @@ import fetch from '../utils/fetch'; import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; let UserFetcher = { diff --git a/js/utils/fetch.js b/js/utils/fetch.js index 37626a71..d533d62d 100644 --- a/js/utils/fetch.js +++ b/js/utils/fetch.js @@ -1,5 +1,5 @@ import { default as _fetch } from 'isomorphic-fetch'; -import FetchApiUtils from '../utils/fetch_api_utils'; +import { argsToQueryParams } from '../utils/fetch_api_utils'; class UrlMapError extends Error {}; @@ -66,7 +66,7 @@ class Fetch { }); if (attachParamsToQuery && params && Object.keys(params).length > 0) { - newUrl += FetchApiUtils.argsToQueryParams(params); + newUrl += argsToQueryParams(params); } return newUrl; diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index ccee8ae5..bf66a45c 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -1,8 +1,6 @@ import { sanitize } from './general_utils'; - // TODO: Create Unittests that test all functions -let FetchApiUtils = { /** * Takes a key-value object of this form: @@ -20,48 +18,45 @@ let FetchApiUtils = { * CamelCase gets converted to snake_case! * */ - argsToQueryParams(obj) { +export function argsToQueryParams(obj) { - obj = sanitize(obj); + obj = sanitize(obj); - return Object - .keys(obj) - .map((key, i) => { - let s = ''; + return Object + .keys(obj) + .map((key, i) => { + let s = ''; - if(i === 0) { - s += '?'; - } else { - s += '&'; - } + if(i === 0) { + s += '?'; + } else { + s += '&'; + } - let snakeCaseKey = key.replace(/[A-Z]/, (match) => '_' + match.toLowerCase()); + let snakeCaseKey = key.replace(/[A-Z]/, (match) => '_' + match.toLowerCase()); - return s + snakeCaseKey + '=' + encodeURIComponent(obj[key]); - }) - .join(''); - }, - - /** - * Takes a string and a boolean and generates a string query parameter for - * an API call. - */ - generateOrderingQueryParams(orderBy, orderAsc) { - let interpolation = ''; - - if(!orderAsc) { - interpolation += '-'; - } - - return interpolation + orderBy; - }, - - status(response) { - if (response.status >= 200 && response.status < 300) { - return response - } - throw new Error(response.json()) - } + return s + snakeCaseKey + '=' + encodeURIComponent(obj[key]); + }) + .join(''); }; -export default FetchApiUtils; +/** + * Takes a string and a boolean and generates a string query parameter for + * an API call. + */ +export function generateOrderingQueryParams(orderBy, orderAsc) { + let interpolation = ''; + + if(!orderAsc) { + interpolation += '-'; + } + + return interpolation + orderBy; +}; + +export function status(response) { + if (response.status >= 200 && response.status < 300) { + return response + } + throw new Error(response.json()) +}; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 8157caf9..826cf184 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -2,7 +2,7 @@ import languages from '../constants/languages'; import { formatText } from './general_utils'; -let getLangText = function(s, ...args) { +export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; try { @@ -20,6 +20,4 @@ let getLangText = function(s, ...args) { } } -}; - -export default getLangText; \ No newline at end of file +}; \ No newline at end of file From 74faa286f1a8a1734b8724d0bb94805326d8db68 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 2 Jun 2015 14:00:05 +0200 Subject: [PATCH 22/33] loan/share forms multiedition --- js/components/ascribe_forms/form_loan.js | 15 +++---- .../ascribe_forms/form_share_email.js | 7 +-- js/components/ascribe_modal/modal_transfer.js | 43 ------------------- js/constants/application_constants.js | 4 +- 4 files changed, 11 insertions(+), 58 deletions(-) delete mode 100644 js/components/ascribe_modal/modal_transfer.js diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 9a1cce27..90232bd8 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -25,7 +25,7 @@ let LoanForm = React.createClass({ }, getFormData() { return { - bitcoin_id: this.props.edition.bitcoin_id, + bitcoin_id: this.getBitcoinIds().join(), loanee: this.refs.loanee.state.value, gallery_name: this.refs.gallery_name.state.value, startdate: this.refs.startdate.state.value, @@ -59,15 +59,17 @@ let LoanForm = React.createClass({ }); }, renderForm() { - let title = this.props.edition.title; + let title = this.getTitlesString().join(""); let username = this.props.currentUser.username; let message = `Hi, -I loan \" ${title} \" to you. +I loan : +${title}to you. Truly yours, ${username}`; + let contract = ; if (this.state.loaneeHasContract){ let label =
    @@ -82,13 +84,6 @@ ${username}`; label={label} /> } - // return ( diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index ea87b4cf..cbcfc7a1 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -16,18 +16,19 @@ let ShareForm = React.createClass({ }, getFormData() { return { - bitcoin_id: this.props.edition.bitcoin_id, + bitcoin_id: this.getBitcoinIds().join(), share_emails: this.refs.share_emails.state.value, share_message: this.refs.share_message.state.value } }, renderForm() { - let title = this.props.edition.title; + let title = this.getTitlesString().join(""); let username = this.props.currentUser.username; let message = `Hi, -I am sharing \" ${title} \" with you. +I am sharing : +${title}with you. Truly yours, ${username}`; diff --git a/js/components/ascribe_modal/modal_transfer.js b/js/components/ascribe_modal/modal_transfer.js deleted file mode 100644 index 12b40524..00000000 --- a/js/components/ascribe_modal/modal_transfer.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -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 TransferForm from '../ascribe_forms/form_transfer' -import ModalMixin from '../../mixins/modal_mixin' - -let TransferModalButton = React.createClass({ - render() { - return ( - Transfer the ownership of the artwork}> - }> -
    - TRANSFER -
    -
    -
    - ) - } -}); - -let TransferModal = React.createClass({ - mixins : [ModalMixin], - - render() { - return ( - -
    - -
    -
    - ) - } -}); - - -export default TransferModalButton; diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 9c20a7ba..17a6d7df 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -1,6 +1,6 @@ let constants = { - 'baseUrl': 'http://localhost:8000/api/', - //'baseUrl': 'http://staging.ascribe.io/api/', + //'baseUrl': 'http://localhost:8000/api/', + 'baseUrl': 'http://staging.ascribe.io/api/', 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000 'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'] }; From 3183dae054ab3c0169314a49de79e68711451f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:25:26 +0200 Subject: [PATCH 23/33] add german language file and integrated translation method --- .../accordion_list_item.js | 3 ++- .../ascribe_pagination/pagination_button.js | 6 +++-- js/components/header.js | 10 +++++---- js/constants/languages.js | 22 ++++++++++++++++++- js/utils/fetch.js | 2 +- js/utils/lang_utils.js | 1 - 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index f932b12b..e9bb8742 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -2,6 +2,7 @@ import React from 'react'; import AccordionListItemTable from './accordion_list_item_table'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItem = React.createClass({ propTypes: { @@ -19,7 +20,7 @@ let AccordionListItem = React.createClass({

    {this.props.content.title}

    -

    by {this.props.content.artist_name}

    +

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

    diff --git a/js/components/ascribe_pagination/pagination_button.js b/js/components/ascribe_pagination/pagination_button.js index ee9c1374..bbb2a789 100644 --- a/js/components/ascribe_pagination/pagination_button.js +++ b/js/components/ascribe_pagination/pagination_button.js @@ -1,6 +1,8 @@ import React from 'react'; import Router from 'react-router'; +import { getLangText } from '../../utils/lang_utils'; + let Link = Router.Link; let PaginationButton = React.createClass({ @@ -25,14 +27,14 @@ let PaginationButton = React.createClass({ page -= 1; directionDisplay = ( - Previous + {getLangText('Previous')} ); } else { page += 1; directionDisplay = ( - Next + {getLangText('Next')} ); } diff --git a/js/components/header.js b/js/components/header.js index 588f73bf..b7a412e0 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -11,6 +11,8 @@ import NavItem from 'react-bootstrap/lib/NavItem'; import DropdownButton from 'react-bootstrap/lib/DropdownButton'; import MenuItem from 'react-bootstrap/lib/MenuItem'; +import { getLangText } from '../utils/lang_utils'; + let Link = Router.Link; let Header = React.createClass({ @@ -39,12 +41,12 @@ let Header = React.createClass({ diff --git a/js/constants/languages.js b/js/constants/languages.js index c49caf53..5fd15048 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -3,7 +3,27 @@ const languages = { 'Bitcoin Address': 'Bitcoin Address', 'Actions': 'Actions', 'Hide all %d Editions': 'Hide all %d Editions', - 'Show all %d Editions': 'Show all %d Editions' + 'Show all %d Editions': 'Show all %d Editions', + 'by %s': 'by %s', + 'Account Settings': 'Account Settings', + 'FAQ': 'FAQ', + 'Terms of Service': 'Terms of Service', + 'Log out': 'Log out', + 'Previous': 'Previous', + 'Next': 'Next' + }, + 'de': { + 'Bitcoin Address': 'Bitcoin Adresse', + 'Actions': 'Aktionen', + 'Hide all %d Editions': 'Zeige all %d Editionen an', + 'Show all %d Editions': 'Verstecke alle %d Editionen', + 'by %s': 'von %s', + 'Account Settings': 'Kontoeinstellungen', + 'FAQ': 'Fragen & Antworten', + 'Terms of Service': 'AGB', + 'Log out': 'Log out', + 'Previous': 'Zurück', + 'Next': 'Weiter' } }; diff --git a/js/utils/fetch.js b/js/utils/fetch.js index d533d62d..038f152f 100644 --- a/js/utils/fetch.js +++ b/js/utils/fetch.js @@ -55,7 +55,7 @@ class Fetch { prepareUrl(url, params, attachParamsToQuery) { let newUrl = this.getUrl(url); let re = /\${(\w+)}/g; - + newUrl = newUrl.replace(re, (match, key) => { let val = params[key] if (!val) { diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 826cf184..0df598e3 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -4,7 +4,6 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; - try { if(lang in languages) { return formatText(languages[lang][s], args); From fd0b3c0eadf71add7144e287305d57e5edc14cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:29:06 +0200 Subject: [PATCH 24/33] minor stuff --- js/utils/lang_utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0df598e3..0e94cc72 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -4,6 +4,8 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; + // this is just for testing, as changing the navigator.language wasn't possible + //lang = 'de'; try { if(lang in languages) { return formatText(languages[lang][s], args); From b5c434aa18b941227d9802f67d6adfdb9b81d4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:33:30 +0200 Subject: [PATCH 25/33] documentation --- js/utils/lang_utils.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0e94cc72..fb9ab196 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -2,6 +2,12 @@ import languages from '../constants/languages'; import { formatText } from './general_utils'; +/** + * Is used to translate strings to another language. Basically can be used with C's string format method. + * @param {string} s The string you want to translate + * @param {array} args An array of arguments (essentially JavaScript's this.arguments) that can be used to substitute digits and other strings + * @return {string} The formated string + */ export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; // this is just for testing, as changing the navigator.language wasn't possible From ff5355f0ee57c4d9fb10998a84644ad6adf949c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:43:42 +0200 Subject: [PATCH 26/33] better error messages --- .../ascribe_accordion_list/accordion_list_item_table.js | 5 ++++- js/constants/languages.js | 8 +++++--- js/utils/lang_utils.js | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 66eb3baf..45879a07 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -76,11 +76,14 @@ let AccordionListItemTableToggle = React.createClass({ }, render() { + let messageShow = this.props.numOfTableItems == 1 ? + getLangText('Show the edition') : + getLangText('Show all %d Editions', this.props.numOfTableItems) return ( - {this.props.show ? getLangText('Hide all %d Editions', this.props.numOfTableItems) : getLangText('Show all %d Editions', this.props.numOfTableItems)} + {this.props.show ? getLangText('Hide') : messageShow} ); } diff --git a/js/constants/languages.js b/js/constants/languages.js index 5fd15048..47e29ee0 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -2,7 +2,8 @@ const languages = { 'en-US': { 'Bitcoin Address': 'Bitcoin Address', 'Actions': 'Actions', - 'Hide all %d Editions': 'Hide all %d Editions', + 'Hide': 'Hide', + 'Show the edition': 'Show the edition', 'Show all %d Editions': 'Show all %d Editions', 'by %s': 'by %s', 'Account Settings': 'Account Settings', @@ -15,8 +16,9 @@ const languages = { 'de': { 'Bitcoin Address': 'Bitcoin Adresse', 'Actions': 'Aktionen', - 'Hide all %d Editions': 'Zeige all %d Editionen an', - 'Show all %d Editions': 'Verstecke alle %d Editionen', + 'Hide': 'Verstecke', + 'Show the edition': 'Zeige die Edition', + 'Show all %d Editions': 'Zeige alle %d Editionen an', 'by %s': 'von %s', 'Account Settings': 'Kontoeinstellungen', 'FAQ': 'Fragen & Antworten', diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index fb9ab196..de9f41e5 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -11,7 +11,7 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; // this is just for testing, as changing the navigator.language wasn't possible - //lang = 'de'; + lang = 'de'; try { if(lang in languages) { return formatText(languages[lang][s], args); @@ -21,7 +21,7 @@ export function getLangText(s, ...args) { } } catch(err) { if(!(s in languages[lang])) { - console.error(new Error('Language-string is not in constants file for string: ' + s)); + console.error(new Error('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file.')); } else { console.error(err); } From cdf8a358df36f0b646bee724bf8eb4d6a0c06bac Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 2 Jun 2015 15:10:40 +0200 Subject: [PATCH 27/33] loan/share forms multiedition --- 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 17a6d7df..9c20a7ba 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -1,6 +1,6 @@ let constants = { - //'baseUrl': 'http://localhost:8000/api/', - 'baseUrl': 'http://staging.ascribe.io/api/', + 'baseUrl': 'http://localhost:8000/api/', + //'baseUrl': 'http://staging.ascribe.io/api/', 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000 'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'] }; From 53a01115f2957fcfc85d65cd0dd4da00e5c9a564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 15:33:48 +0200 Subject: [PATCH 28/33] put show state of item list in store to fix bug --- js/actions/piece_list_actions.js | 3 +- .../accordion_list_item_table.js | 50 ++----------------- .../accordion_list_item_table_editions.js | 38 +++++++++----- .../accordion_list_item_table_toggle.js | 22 ++++++++ js/components/piece_list.js | 3 +- js/stores/piece_list_store.js | 13 +++++ 6 files changed, 70 insertions(+), 59 deletions(-) create mode 100644 js/components/ascribe_accordion_list/accordion_list_item_table_toggle.js diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 8830b2b6..4ba91870 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -6,7 +6,8 @@ import PieceListFetcher from '../fetchers/piece_list_fetcher'; class PieceListActions { constructor() { this.generateActions( - 'updatePieceList' + 'updatePieceList', + 'showEditionList' ); } diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 9ddb3308..2cbb54d7 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -6,30 +6,17 @@ import TableItem from '../ascribe_table/table_item'; import TableColumnContentModel from '../../models/table_column_content_model'; let AccordionListItemTable = React.createClass({ - getInitialState() { - return { - 'show': false - }; - }, - propTypes: { className: React.PropTypes.string, parentId: React.PropTypes.number, - fetchData: React.PropTypes.func, itemList: React.PropTypes.array, columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), - numOfTableItems: React.PropTypes.number - }, - - toggleTable() { - this.props.fetchData(); - this.setState({ - 'show': !this.state.show - }); + numOfTableItems: React.PropTypes.number, + show: React.PropTypes.bool }, render() { - if(this.props.itemList && this.state.show) { + if(this.props.show && this.props.itemList) { return (
    - + {this.props.children} ); } else { return (
    - + {this.props.children}
    ); } } }); -let AccordionListItemTableToggle = React.createClass({ - propTypes: { - className: React.PropTypes.string, - onClick: React.PropTypes.func, - show: React.PropTypes.bool, - numOfTableItems: React.PropTypes.number - }, - - render() { - return ( - - {this.props.show ? 'Hide all ' + this.props.numOfTableItems + ' Editions' : 'Show all ' + this.props.numOfTableItems + ' Editions'} - - ); - } -}); - export default AccordionListItemTable; \ No newline at end of file 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 2b3bd5c0..e5789528 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 @@ -2,8 +2,11 @@ import React from 'react'; import EditionListStore from '../../stores/edition_list_store'; import EditionListActions from '../../actions/edition_list_actions'; +import PieceListStore from '../../stores/piece_list_store'; +import PieceListActions from '../../actions/piece_list_actions'; import AccordionListItemTable from './accordion_list_item_table'; +import AccordionListItemTableToggle from './accordion_list_item_table_toggle'; import TableColumnContentModel from '../../models/table_column_content_model'; @@ -17,7 +20,8 @@ let AccordionListItemTableEditions = React.createClass({ propTypes: { className: React.PropTypes.string, parentId: React.PropTypes.number, - numOfEditions: React.PropTypes.number + numOfEditions: React.PropTypes.number, + show: React.PropTypes.bool }, getInitialState() { @@ -36,14 +40,15 @@ let AccordionListItemTableEditions = React.createClass({ EditionListStore.unlisten(this.onChange); }, - getEditionList() { - EditionListActions.fetchEditionList(this.props.parentId); - }, - selectItem(pieceId, editionId) { EditionListActions.selectEdition({pieceId, editionId}); }, + toggleTable() { + PieceListActions.showEditionList(this.props.parentId); + EditionListActions.fetchEditionList(this.props.parentId); + }, + render() { let columnList = [ new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), @@ -53,13 +58,22 @@ let AccordionListItemTableEditions = React.createClass({ ]; return ( - +
    + + + + +
    ); } }); diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table_toggle.js b/js/components/ascribe_accordion_list/accordion_list_item_table_toggle.js new file mode 100644 index 00000000..a3431b04 --- /dev/null +++ b/js/components/ascribe_accordion_list/accordion_list_item_table_toggle.js @@ -0,0 +1,22 @@ +import React from 'react'; + +let AccordionListItemTableToggle = React.createClass({ + propTypes: { + className: React.PropTypes.string, + onClick: React.PropTypes.func, + show: React.PropTypes.bool, + numOfTableItems: React.PropTypes.number + }, + + render() { + return ( + + {this.props.show ? 'Hide all ' + this.props.numOfTableItems + ' Editions' : 'Show all ' + this.props.numOfTableItems + ' Editions'} + + ); + } +}); + +export default AccordionListItemTableToggle; \ No newline at end of file diff --git a/js/components/piece_list.js b/js/components/piece_list.js index ea1ef790..e6735a27 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -70,7 +70,8 @@ let PieceList = React.createClass({ key={i}> ); diff --git a/js/stores/piece_list_store.js b/js/stores/piece_list_store.js index 97e3f4a4..7ca96c87 100644 --- a/js/stores/piece_list_store.js +++ b/js/stores/piece_list_store.js @@ -24,6 +24,19 @@ class PieceListStore { this.bindActions(PieceListActions); } + onShowEditionList(pieceId) { + this.pieceList + .forEach((piece) => { + if(piece.id === pieceId) { + if(piece.show) { + piece.show = false; + } else { + piece.show = true; + } + } + }); + } + onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount }) { this.page = page; this.pageSize = pageSize; From 4b64f52d716cb721d3e3039dfe972048945e08bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 15:36:06 +0200 Subject: [PATCH 29/33] comment out filter widget --- js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index ff2bd68f..ce9150b1 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -43,7 +43,7 @@ let PieceListToolbar = React.createClass({
       - + {/**/}
    From d1577190430c7d961f0b91ab6c937e781d6b3b7a Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 2 Jun 2015 15:38:47 +0200 Subject: [PATCH 30/33] multiloan --- js/components/ascribe_forms/form_loan.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js index 90232bd8..483d0f0a 100644 --- a/js/components/ascribe_forms/form_loan.js +++ b/js/components/ascribe_forms/form_loan.js @@ -28,8 +28,8 @@ let LoanForm = React.createClass({ bitcoin_id: this.getBitcoinIds().join(), loanee: this.refs.loanee.state.value, gallery_name: this.refs.gallery_name.state.value, - startdate: this.refs.startdate.state.value, - enddate: this.refs.enddate.state.value, + startdate: this.refs.startdate.state.value.format("YYYY-MM-DD"), + enddate: this.refs.enddate.state.value.format("YYYY-MM-DD"), loan_message: this.refs.loan_message.state.value, password: this.refs.password.state.value, terms: this.refs.terms.state.value @@ -108,13 +108,9 @@ ${username}`; placeholderText="Loan start date" />
    - + placeholderText="Loan end date" />
    Date: Tue, 2 Jun 2015 16:47:25 +0200 Subject: [PATCH 31/33] multiloan --- js/components/fatal_error.js | 0 js/utils/fetch.js | 113 +++++++++++++++++++++++++++++++++++ js/utils/lang_utils.js | 18 ++++++ 3 files changed, 131 insertions(+) create mode 100644 js/components/fatal_error.js create mode 100644 js/utils/fetch.js create mode 100644 js/utils/lang_utils.js diff --git a/js/components/fatal_error.js b/js/components/fatal_error.js new file mode 100644 index 00000000..e69de29b diff --git a/js/utils/fetch.js b/js/utils/fetch.js new file mode 100644 index 00000000..37626a71 --- /dev/null +++ b/js/utils/fetch.js @@ -0,0 +1,113 @@ +import { default as _fetch } from 'isomorphic-fetch'; +import FetchApiUtils from '../utils/fetch_api_utils'; + + +class UrlMapError extends Error {}; +class ServerError extends Error {}; +class APIError extends Error {}; + + +class Fetch { + _merge(defaults, options) { + let merged = {}; + for (let key in defaults) { + merged[key] = defaults[key]; + } + for (let key in options) { + merged[key] = options[key]; + } + return merged; + } + + unpackResponse(response) { + if (response.status >= 500) { + throw new ServerError(); + } + return response.text(); + } + + handleFatalError(err) { + this.fatalErrorHandler(err); + throw new ServerError(err); + } + + handleAPIError(json) { + if (!json['success']) { + let error = new APIError(); + error.json = json; + throw error; + } + return json; + } + + getUrl(url) { + let name = url; + if (!url.match(/^http/)) { + url = this.urlMap[url]; + if (!url) { + throw new UrlMapError(`Cannot find a mapping for "${name}"`); + } + } + + return url; + } + + prepareUrl(url, params, attachParamsToQuery) { + let newUrl = this.getUrl(url); + let re = /\${(\w+)}/g; + + newUrl = newUrl.replace(re, (match, key) => { + let val = params[key] + if (!val) { + throw new Error(`Cannot find param ${key}`); + } + delete params[key]; + return val; + }); + + if (attachParamsToQuery && params && Object.keys(params).length > 0) { + newUrl += FetchApiUtils.argsToQueryParams(params); + } + + return newUrl; + } + + request(verb, url, options) { + options = options || {}; + let merged = this._merge(this.httpOptions, options); + merged['method'] = verb; + return _fetch(url, merged) + .then(this.unpackResponse) + .then(JSON.parse) + .catch(this.handleFatalError.bind(this)) + .then(this.handleAPIError); + } + + get(url, params) { + let paramsCopy = this._merge(params); + let newUrl = this.prepareUrl(url, params); + return this.request('get', newUrl, true); + } + + post(url, params) { + let paramsCopy = this._merge(params); + let newUrl = this.prepareUrl(url, params); + let body = null; + + if (params['body']) { + body = JSON.stringify(params['body']) + } + return this.request('post', url, { body }); + } + + defaults(options) { + this.httpOptions = options.http || {}; + this.urlMap = options.urlMap || {}; + this.fatalErrorHandler = options.fatalErrorHandler || (() => {}); + } +} + + +let fetch = new Fetch(); + +export default fetch; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js new file mode 100644 index 00000000..a936294e --- /dev/null +++ b/js/utils/lang_utils.js @@ -0,0 +1,18 @@ +import languages from '../constants/languages'; +import template from 'lodash.template'; + +let getText = function(s, ...args) { + let lang = navigator.language || navigator.userLanguage; + try { + if(lang in languages) { + return languages[lang][s]; + } else { + // just use the english language + return languages['en-US'][s]; + } + } catch(err) { + console.error(err); + } +}; + +export default getText; \ No newline at end of file From 82d14b30fc0441f7faddae6e65a01c43be0609f3 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 2 Jun 2015 18:16:18 +0200 Subject: [PATCH 32/33] fixed form mixin --- js/mixins/form_mixin.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js index 6954ba4c..4e2c7045 100644 --- a/js/mixins/form_mixin.js +++ b/js/mixins/form_mixin.js @@ -18,20 +18,24 @@ export const FormMixin = { this.setState({submitted: true}); fetch .post(this.url(), { body: this.getFormData() }) - .then(response => { this.props.onRequestHide(); }) + .then(response => { this.props.handleSuccess(); }) .catch(this.handleError); }, handleError(err){ if (err.json) { - for (var input in errors){ + for (var input in err.json.errors){ if (this.refs && this.refs[input] && this.refs[input].state) { - this.refs[input].setAlerts(errors[input]); + this.refs[input].setAlerts( err.json.errors[input]); } else { - this.setState({errors: this.state.errors.concat(errors[input])}); + this.setState({errors: this.state.errors.concat(err.json.errors[input])}); } } } + else{ + this.setState({errors: ['Something went wrong, please try again later"']}); + } + this.setState({submitted: false}); }, getBitcoinIds(){ @@ -48,15 +52,12 @@ export const FormMixin = { render(){ let alert = null; - if (this.state.status >= 500){ - alert = ; - } if (this.state.errors.length > 0){ alert = this.state.errors.map( - function(error) { - return ; - }.bind(this) - ); + function(error) { + return ; + }.bind(this) + ); } return (
    From b4076aeef75f1b7e2b42f6fb5e5d999305bff06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 3 Jun 2015 10:45:23 +0200 Subject: [PATCH 33/33] code styling --- index.html | 1 - .../accordion_list_item_table_editions.js | 51 +++++++++++++++++-- .../piece_list_bulk_modal.js | 10 +--- .../ascribe_table/table_item_acl_filtered.js | 4 +- sass/main.scss | 1 + 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/index.html b/index.html index 066b36cc..8d16b099 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,6 @@ ascribe - 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 1d8daa45..13225c59 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 @@ -53,10 +53,53 @@ let AccordionListItemTableEditions = React.createClass({ render() { let columnList = [ - new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', '#', TableItemText, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getLangText('Bitcoin Address'), TableItemText, 5, false), - new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', getLangText('Actions'), TableItemAclFiltered, 4, false) + new TableColumnContentModel( + (item) => { + return { + 'editionId': item.id, + 'pieceId': this.props.parentId, + 'selectItem': this.selectItem, + 'selected': item.selected + }}, + '', + '', + TableItemCheckbox, + 1, + false + ), + new TableColumnContentModel( + (item) => { + return { + 'content': item.edition_number + }}, + 'num_editions', + '#', + TableItemText, + 1, + false + ), + new TableColumnContentModel( + (item) => { + return { + 'content': item.bitcoin_id + }}, + 'bitcoin_id', + getLangText('Bitcoin Address'), + TableItemText, + 5, + false + ), + new TableColumnContentModel( + (item) => { + return { + 'content': item.acl + }}, + 'acl', + getLangText('Actions'), + TableItemAclFiltered, + 4, + false + ) ]; return ( 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 f229ef07..896882df 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 @@ -33,17 +33,13 @@ let PieceListBulkModal = React.createClass({ UserStore.unlisten(this.onChange); }, - filterForSelected(edition) { - return edition.selected; - }, - fetchSelectedEditionList() { let selectedEditionList = []; Object .keys(this.state.editionList) .forEach((key) => { - let filteredEditionsForPiece = this.state.editionList[key].filter(this.filterForSelected); + let filteredEditionsForPiece = this.state.editionList[key].filter((edition) => edition.selected); selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece); }); @@ -54,10 +50,6 @@ let PieceListBulkModal = React.createClass({ return a.filter((val) => b.indexOf(val) > -1); }, - bulk(action) { - console.log(action); - }, - getAvailableAcls() { let availableAcls = []; let selectedEditionList = this.fetchSelectedEditionList(); diff --git a/js/components/ascribe_table/table_item_acl_filtered.js b/js/components/ascribe_table/table_item_acl_filtered.js index dada05ab..6fd8e9fe 100644 --- a/js/components/ascribe_table/table_item_acl_filtered.js +++ b/js/components/ascribe_table/table_item_acl_filtered.js @@ -7,8 +7,10 @@ let TableItemAclFiltered = React.createClass({ }, render() { + var availableAcls = ['consign', 'loan', 'transfer', 'view']; + let filteredAcls = this.props.content.filter((v) => { - return v === 'consign' || v === 'loan' || v === 'transfer' || v === 'view'; + return availableAcls.indexOf(v) > -1; }); return ( diff --git a/sass/main.scss b/sass/main.scss index 1a00481b..2fe60cac 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -3,6 +3,7 @@ @import 'variables'; @import 'ascribe_variables'; @import '../node_modules/bootstrap-sass/assets/stylesheets/bootstrap'; +@import '../node_modules/react-datepicker/dist/react-datepicker'; @import './ascribe-fonts/style'; @import './ascribe-fonts/ascribe-fonts'; @import 'ascribe_accordion_list';