From 23b7ebd7761bbe0400ff4893d204b4b0f2231619 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 19 Oct 2015 15:29:57 +0200
Subject: [PATCH 001/115] add 404 routine to EditionContainer
---
js/actions/edition_actions.js | 4 +-
.../ascribe_detail/edition_container.js | 50 ++++++++++++-------
js/stores/edition_store.js | 6 +++
js/utils/requests.js | 9 ++++
4 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/js/actions/edition_actions.js b/js/actions/edition_actions.js
index 4bdf093a..3f659524 100644
--- a/js/actions/edition_actions.js
+++ b/js/actions/edition_actions.js
@@ -7,7 +7,8 @@ import EditionFetcher from '../fetchers/edition_fetcher';
class EditionActions {
constructor() {
this.generateActions(
- 'updateEdition'
+ 'updateEdition',
+ 'editionFailed'
);
}
@@ -18,6 +19,7 @@ class EditionActions {
})
.catch((err) => {
console.logGlobal(err);
+ this.actions.editionFailed(err.json);
});
}
}
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index fa24bcbf..030a7150 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -1,6 +1,7 @@
'use strict';
import React from 'react';
+import { History } from 'react-router';
import EditionActions from '../../actions/edition_actions';
import EditionStore from '../../stores/edition_store';
@@ -15,26 +16,23 @@ import AppConstants from '../../constants/application_constants';
*/
let EditionContainer = React.createClass({
propTypes: {
- location: React.PropTypes.object
+ location: React.PropTypes.object,
+ params: React.PropTypes.object
},
+ mixins: [History],
+
getInitialState() {
return EditionStore.getState();
},
- onChange(state) {
- this.setState(state);
- if (!state.edition.digital_work) {
- return;
- }
- let isEncoding = state.edition.digital_work.isEncoding;
- if (state.edition.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
- let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000);
- this.setState({timerId: timerId});
- }
- },
-
componentDidMount() {
+ // Every time we're entering the edition detail page,
+ // just reset the edition that is saved in the edition store
+ // as it will otherwise display wrong/old data once the user loads
+ // the edition detail a second time
+ EditionActions.updateEdition({});
+
EditionStore.listen(this.onChange);
EditionActions.fetchOne(this.props.params.editionId);
},
@@ -48,16 +46,32 @@ let EditionContainer = React.createClass({
}
},
+ componentDidUpdate() {
+ const { editionError } = this.state;
+
+ if(editionError && editionError.status === 404) {
+ // Even though the /404 path doesn't really exist,
+ // we can still redirect there and the page will show up
+ this.history.pushState(null, '/404');
+ }
+ },
+
componentWillUnmount() {
- // Every time we're leaving the edition detail page,
- // just reset the edition that is saved in the edition store
- // as it will otherwise display wrong/old data once the user loads
- // the edition detail a second time
- EditionActions.updateEdition({});
window.clearInterval(this.state.timerId);
EditionStore.unlisten(this.onChange);
},
+ onChange(state) {
+ this.setState(state);
+ if (!state.edition.digital_work) {
+ return;
+ }
+ let isEncoding = state.edition.digital_work.isEncoding;
+ if (state.edition.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
+ let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000);
+ this.setState({timerId: timerId});
+ }
+ },
loadEdition() {
EditionActions.fetchOne(this.props.params.editionId);
diff --git a/js/stores/edition_store.js b/js/stores/edition_store.js
index 14ee4fee..22e78d23 100644
--- a/js/stores/edition_store.js
+++ b/js/stores/edition_store.js
@@ -7,11 +7,17 @@ import EditionActions from '../actions/edition_actions';
class EditionStore {
constructor() {
this.edition = {};
+ this.editionError = null;
this.bindActions(EditionActions);
}
onUpdateEdition(edition) {
this.edition = edition;
+ this.editionError = null;
+ }
+
+ onEditionFailed(error) {
+ this.editionError = error;
}
}
diff --git a/js/utils/requests.js b/js/utils/requests.js
index 7e9c9a58..eeaa3513 100644
--- a/js/utils/requests.js
+++ b/js/utils/requests.js
@@ -40,6 +40,15 @@ class Requests {
reject(error);
} else if(body && body.detail) {
reject(new Error(body.detail));
+ } else if(!body.success) {
+ let error = new Error('Client Request Error');
+ error.json = {
+ status: response.status,
+ statusText: response.status,
+ type: response.status,
+ url: response.url
+ };
+ reject(error);
} else {
resolve(body);
}
From 757ee40e4eb874a300f9e442cb50b47f1bf6b515 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 19 Oct 2015 15:58:05 +0200
Subject: [PATCH 002/115] add 404 routine to PieceContainer
---
js/actions/piece_actions.js | 4 ++-
.../ascribe_detail/piece_container.js | 33 +++++++++++++------
js/stores/piece_store.js | 6 ++++
3 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js
index 7aed13fc..64dcb2e2 100644
--- a/js/actions/piece_actions.js
+++ b/js/actions/piece_actions.js
@@ -8,7 +8,8 @@ class PieceActions {
constructor() {
this.generateActions(
'updatePiece',
- 'updateProperty'
+ 'updateProperty',
+ 'pieceFailed'
);
}
@@ -18,6 +19,7 @@ class PieceActions {
this.actions.updatePiece(res.piece);
})
.catch((err) => {
+ this.actions.pieceFailed(err.json);
console.logGlobal(err);
});
}
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index e2ebaa43..175008b4 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -44,7 +44,8 @@ import { getLangText } from '../../utils/lang_utils';
*/
let PieceContainer = React.createClass({
propTypes: {
- location: React.PropTypes.object
+ location: React.PropTypes.object,
+ params: React.PropTypes.object
},
mixins: [History],
@@ -61,19 +62,31 @@ let PieceContainer = React.createClass({
},
componentDidMount() {
- UserStore.listen(this.onChange);
- PieceListStore.listen(this.onChange);
- UserActions.fetchCurrentUser();
- PieceStore.listen(this.onChange);
- PieceActions.fetchOne(this.props.params.pieceId);
- },
-
- componentWillUnmount() {
- // Every time we're leaving the piece detail page,
+ // Every time we're entering the piece detail page,
// just reset the piece that is saved in the piece store
// as it will otherwise display wrong/old data once the user loads
// the piece detail a second time
PieceActions.updatePiece({});
+
+ UserStore.listen(this.onChange);
+ PieceListStore.listen(this.onChange);
+ PieceStore.listen(this.onChange);
+
+ UserActions.fetchCurrentUser();
+ PieceActions.fetchOne(this.props.params.pieceId);
+ },
+
+ componentDidUpdate() {
+ const { pieceError } = this.state;
+
+ if(pieceError && pieceError.status === 404) {
+ // Even though this path doesn't exist we can redirect
+ // to it as it catches all unknown paths
+ this.history.pushState(null, '/404');
+ }
+ },
+
+ componentWillUnmount() {
PieceStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
diff --git a/js/stores/piece_store.js b/js/stores/piece_store.js
index ccef50b1..3b04736b 100644
--- a/js/stores/piece_store.js
+++ b/js/stores/piece_store.js
@@ -7,11 +7,13 @@ import PieceActions from '../actions/piece_actions';
class PieceStore {
constructor() {
this.piece = {};
+ this.pieceError = null;
this.bindActions(PieceActions);
}
onUpdatePiece(piece) {
this.piece = piece;
+ this.pieceError = null;
}
onUpdateProperty({key, value}) {
@@ -21,6 +23,10 @@ class PieceStore {
throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.');
}
}
+
+ onPieceFailed(err) {
+ this.pieceError = err;
+ }
}
export default alt.createStore(PieceStore, 'PieceStore');
From f82278070b2d19c9f154d0a701116cd35282941f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 19 Oct 2015 16:01:05 +0200
Subject: [PATCH 003/115] Log before dispatch in PieceActions
---
js/actions/piece_actions.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js
index 64dcb2e2..9002e8c5 100644
--- a/js/actions/piece_actions.js
+++ b/js/actions/piece_actions.js
@@ -19,8 +19,8 @@ class PieceActions {
this.actions.updatePiece(res.piece);
})
.catch((err) => {
- this.actions.pieceFailed(err.json);
console.logGlobal(err);
+ this.actions.pieceFailed(err.json);
});
}
}
From 74e07d5ce597567dfd341eb73db6cb4b383af062 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Tue, 20 Oct 2015 11:33:04 +0200
Subject: [PATCH 004/115] Fix stupid mistake
---
js/utils/requests.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/utils/requests.js b/js/utils/requests.js
index eeaa3513..04bde25c 100644
--- a/js/utils/requests.js
+++ b/js/utils/requests.js
@@ -44,8 +44,8 @@ class Requests {
let error = new Error('Client Request Error');
error.json = {
status: response.status,
- statusText: response.status,
- type: response.status,
+ statusText: response.statusText,
+ type: response.type,
url: response.url
};
reject(error);
From 7116133337a987ccb2faf696052b97a4aac11514 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 21 Oct 2015 14:10:21 +0200
Subject: [PATCH 005/115] AD-1194 Create front-end host configs
Default route components to be replaced with Lumenus specific ones.
---
.../wallet/constants/wallet_api_urls.js | 9 ++++-
.../whitelabel/wallet/wallet_routes.js | 35 +++++++++++++++++++
js/constants/application_constants.js | 7 ++++
3 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 2cdc0054..8f4543c7 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -19,7 +19,14 @@ function getWalletApiUrls(subdomain) {
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
}
+ else if (subdomain === 'lumenus'){
+ return {
+ 'editions': walletConstants.walletApiEndpoint + subdomain + 'editions/',
+ 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
+ 'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
+ };
+ }
return {};
}
-export default getWalletApiUrls;
\ No newline at end of file
+export default getWalletApiUrls;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 8e4d5197..bcd0a60b 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -15,6 +15,7 @@ import EditionContainer from '../../../components/ascribe_detail/edition_contain
import SettingsContainer from '../../../components/ascribe_settings/settings_container';
import ContractSettings from '../../../components/ascribe_settings/contract_settings';
import ErrorNotFoundPage from '../../../components/error_not_found_page';
+import RegisterPiece from '../../../components/register_piece'; //TODO: Remove once finished with LumenusRegisterPiece
import CylandLanding from './components/cyland/cyland_landing';
import CylandPieceContainer from './components/cyland/cyland_detail/cyland_piece_container';
@@ -148,6 +149,40 @@ let ROUTES = {
+ ),
+ 'lumenus': (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
)
};
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js
index 0fe5e210..a961f453 100644
--- a/js/constants/application_constants.js
+++ b/js/constants/application_constants.js
@@ -46,6 +46,13 @@ let constants = {
'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/ikonotv/ikono-logo-black.png',
'permissions': ['register', 'edit', 'share', 'del_from_collection'],
'type': 'wallet'
+ },
+ {
+ 'subdomain': 'lumenus',
+ 'name': 'Lumenus',
+ 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/lumenus/lumenus-logo.png',
+ 'permissions': ['register', 'edit', 'share', 'del_from_collection'],
+ 'type': 'wallet'
}
],
'defaultDomain': {
From 0c51eb374e76f27bc46a89c4e7417bf8fe385695 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 21 Oct 2015 17:37:29 +0200
Subject: [PATCH 006/115] Add Lumenus specific piece list
---
.../piece_list_bulk_modal.js | 13 ++--
js/components/piece_list.js | 7 ++-
.../components/lumenus/lumenus_piece_list.js | 61 +++++++++++++++++++
.../whitelabel/wallet/wallet_routes.js | 4 +-
sass/ascribe_piece_list_toolbar.scss | 4 ++
5 files changed, 82 insertions(+), 7 deletions(-)
create mode 100644 js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
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 3e5b6495..f5d97842 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
@@ -22,9 +22,16 @@ import { getLangText } from '../../utils/lang_utils.js';
let PieceListBulkModal = React.createClass({
propTypes: {
+ aclFilterBy: React.PropTypes.func,
className: React.PropTypes.string
},
+ getDefaultProps() {
+ return {
+ aclFilterBy: (aclName) => aclName !== 'acl_view'
+ };
+ },
+
getInitialState() {
return mergeOptions(
EditionListStore.getState(),
@@ -33,8 +40,6 @@ let PieceListBulkModal = React.createClass({
);
},
-
-
componentDidMount() {
EditionListStore.listen(this.onChange);
UserStore.listen(this.onChange);
@@ -95,7 +100,7 @@ let PieceListBulkModal = React.createClass({
render() {
let selectedEditions = this.fetchSelectedEditionList();
- let availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view');
+ let availableAcls = getAvailableAcls(selectedEditions, this.props.aclFilterBy);
if(Object.keys(availableAcls).length > 0) {
return (
@@ -136,4 +141,4 @@ let PieceListBulkModal = React.createClass({
}
});
-export default PieceListBulkModal;
\ No newline at end of file
+export default PieceListBulkModal;
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index de40be22..a5b9ff55 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -30,6 +30,7 @@ import { setDocumentTitle } from '../utils/dom_utils';
let PieceList = React.createClass({
propTypes: {
accordionListItemType: React.PropTypes.func,
+ aclFilterBy: React.PropTypes.func,
redirectTo: React.PropTypes.string,
customSubmitButton: React.PropTypes.element,
filterParams: React.PropTypes.array,
@@ -63,7 +64,7 @@ let PieceList = React.createClass({
componentDidMount() {
let page = this.props.location.query.page || 1;
-
+
PieceListStore.listen(this.onChange);
EditionListStore.listen(this.onChange);
@@ -170,7 +171,9 @@ let PieceList = React.createClass({
applyOrderBy={this.applyOrderBy}>
{this.props.customSubmitButton}
-
+
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
new file mode 100644
index 00000000..0a6b3b27
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
@@ -0,0 +1,61 @@
+'use strict';
+
+import React from 'react';
+import PieceList from '../../../../piece_list';
+
+import UserActions from '../../../../../actions/user_actions';
+import UserStore from '../../../../../stores/user_store';
+
+import { getLangText } from '../../../../../utils/lang_utils';
+import { setDocumentTitle } from '../../../../../utils/dom_utils';
+
+
+let LumenusPieceList = React.createClass({
+ propTypes: {
+ location: React.PropTypes.object
+ },
+
+ getInitialState() {
+ return UserStore.getState();
+ },
+
+ componentDidMount() {
+ UserStore.listen(this.onChange);
+ UserActions.fetchCurrentUser();
+ },
+
+ componentWillUnmount() {
+ UserStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
+ showOnlyConsignAcl(aclName) {
+ return aclName === 'acl_consign' ||
+ aclName === 'acl_unconsign';
+ },
+
+ render() {
+ setDocumentTitle(getLangText('Collection'));
+
+ return (
+
+ );
+ }
+});
+
+export default LumenusPieceList;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index bcd0a60b..e258dfa7 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -29,6 +29,8 @@ import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
+import LumenusPieceList from './components/lumenus/lumenus_piece_list';
+
import CCRegisterPiece from './components/cc/cc_register_piece';
import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
@@ -176,7 +178,7 @@ let ROUTES = {
headerTitle='+ NEW WORK'/>
diff --git a/sass/ascribe_piece_list_toolbar.scss b/sass/ascribe_piece_list_toolbar.scss
index dde7f2f0..166ba382 100644
--- a/sass/ascribe_piece_list_toolbar.scss
+++ b/sass/ascribe_piece_list_toolbar.scss
@@ -86,4 +86,8 @@
top: 2px;
}
}
+
+ .dropdown-menu {
+ min-width: 170px;
+ }
}
From de3c5bca14863b79c9cb5d66ad24f28b56629412 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 22 Oct 2015 11:12:41 +0200
Subject: [PATCH 007/115] Correct misleading comments in utils
---
js/utils/general_utils.js | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js
index 2cba98b9..cc1d22dd 100644
--- a/js/utils/general_utils.js
+++ b/js/utils/general_utils.js
@@ -131,7 +131,8 @@ export function mergeOptions(...l) {
}
/**
- * Merges a number of objects even if there're having duplicates.
+ * Merges a number of objects even if there're having duplicates,
+ * taking the last given value for the key.
*
* DOES NOT RETURN AN ERROR!
*
@@ -141,8 +142,6 @@ export function mergeOptions(...l) {
* @return {[type]} [description]
*/
export function mergeOptionsWithDuplicates(...l) {
- // If the objects submitted in the list have duplicates,in their key names,
- // abort the merge and tell the function's user to check his objects.
let newObj = {};
for(let i = 1; i < l.length; i++) {
@@ -174,7 +173,7 @@ export function update(a, ...l) {
*/
function _mergeOptions(obj1, obj2) {
let obj3 = {};
-
+
for (let attrname in obj1) {
obj3[attrname] = obj1[attrname];
}
@@ -232,4 +231,4 @@ export function getSubdomain() {
let { host } = window.location;
let tokens = host.split('.');
return tokens.length > 2 ? tokens[0] : 'www';
-}
\ No newline at end of file
+}
From ba777781b7a81a5f7a67132118a476ab6485b507 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 22 Oct 2015 11:13:44 +0200
Subject: [PATCH 008/115] Add sliding piece registration with dummy additional
form
---
.../lumenus_additional_data_form.js | 129 ++++++++++++
.../lumenus/lumenus_register_piece.js | 195 ++++++++++++++++++
.../whitelabel/wallet/wallet_routes.js | 3 +-
3 files changed, 326 insertions(+), 1 deletion(-)
create mode 100644 js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
create mode 100644 js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
new file mode 100644
index 00000000..c0493ddd
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
@@ -0,0 +1,129 @@
+'use strict';
+
+import React from 'react';
+
+import Form from '../../../../../ascribe_forms/form';
+import Property from '../../../../../ascribe_forms/property';
+
+import GlobalNotificationModel from '../../../../../../models/global_notification_model';
+import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
+
+import ApiUrls from '../../../../../../constants/api_urls';
+import AppConstants from '../../../../../../constants/application_constants';
+
+import requests from '../../../../../../utils/requests';
+
+import { getLangText } from '../../../../../../utils/lang_utils';
+
+
+let LumenusAdditionalDataForm = React.createClass({
+ propTypes: {
+ handleSuccess: React.PropTypes.func,
+ piece: React.PropTypes.object.isRequired,
+ isInline: React.PropTypes.bool,
+ location: React.PropTypes.object
+ },
+
+ getDefaultProps() {
+ return {
+ isInline: false
+ };
+ },
+
+ getInitialState() {
+ return {
+ isUploadReady: true
+ };
+ },
+
+ handleSuccess() {
+ let notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ },
+
+ getFormData() {
+ let extradata = {};
+ let formRefs = this.refs.form.refs;
+
+ // Put additional fields in extra data object
+ Object
+ .keys(formRefs)
+ .forEach((fieldName) => {
+ extradata[fieldName] = formRefs[fieldName].state.value;
+ });
+
+ return {
+ extradata: extradata,
+ piece_id: this.props.piece.id
+ };
+
+ },
+
+ render() {
+ let { piece, isInline, handleSuccess } = this.props;
+ let buttons, spinner, heading;
+
+ if(!isInline) {
+ buttons = (
+
+ {getLangText('Register work')}
+
+ );
+
+ spinner = (
+
+
+
+ );
+
+ heading = (
+
+
+ {getLangText('Provide additional details')}
+
+
+ );
+ }
+
+ if(piece && piece.id) {
+ return (
+
+ );
+ } else {
+ return (
+
+
+
+ );
+ }
+ }
+});
+
+export default LumenusAdditionalDataForm;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
new file mode 100644
index 00000000..9d671ee0
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
@@ -0,0 +1,195 @@
+'use strict';
+
+import React from 'react';
+import { History } from 'react-router';
+
+import Col from 'react-bootstrap/lib/Col';
+import Row from 'react-bootstrap/lib/Row';
+
+import Property from '../../../../ascribe_forms/property';
+import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
+
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
+
+import PieceListStore from '../../../../../stores/piece_list_store';
+import PieceListActions from '../../../../../actions/piece_list_actions';
+
+import UserStore from '../../../../../stores/user_store';
+import UserActions from '../../../../../actions/user_actions';
+
+import PieceStore from '../../../../../stores/piece_store';
+import PieceActions from '../../../../../actions/piece_actions';
+
+import LumenusAdditionalDataForm from './lumenus_forms/lumenus_additional_data_form';
+
+import SlidesContainer from '../../../../ascribe_slides_container/slides_container';
+
+import { getLangText } from '../../../../../utils/lang_utils';
+import { setDocumentTitle } from '../../../../../utils/dom_utils';
+import { mergeOptions } from '../../../../../utils/general_utils';
+
+
+let LumenusRegisterPiece = React.createClass({
+ propTypes: {
+ location: React.PropTypes.object
+ },
+
+ mixins: [History],
+
+ getInitialState(){
+ return mergeOptions(
+ UserStore.getState(),
+ PieceListStore.getState(),
+ PieceStore.getState(),
+ WhitelabelStore.getState(),
+ {
+ selectedLicense: 0,
+ isFineUploaderActive: false,
+ step: 0
+ });
+ },
+
+ componentDidMount() {
+ PieceListStore.listen(this.onChange);
+ UserStore.listen(this.onChange);
+ PieceStore.listen(this.onChange);
+ WhitelabelStore.listen(this.onChange);
+ UserActions.fetchCurrentUser();
+ WhitelabelActions.fetchWhitelabel();
+
+ let queryParams = this.props.location.query;
+
+ // Since every step of this register process is atomic,
+ // we may need to enter the process at step 1 or 2.
+ // If this is the case, we'll need the piece number to complete submission.
+ // It is encoded in the URL as a queryParam and we're checking for it here.
+ //
+ // We're using 'in' here as we want to know if 'piece_id' is present in the url,
+ // we don't care about the value.
+ if(queryParams && 'piece_id' in queryParams) {
+ PieceActions.fetchOne(queryParams.piece_id);
+ }
+ },
+
+ componentWillUnmount() {
+ PieceListStore.unlisten(this.onChange);
+ UserStore.unlisten(this.onChange);
+ PieceStore.unlisten(this.onChange);
+ WhitelabelStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+
+ if(this.state.currentUser && this.state.currentUser.email) {
+ // we should also make the fineuploader component editable again
+ this.setState({
+ isFineUploaderActive: true
+ });
+ }
+ },
+
+ handleRegisterSuccess(response){
+ this.refreshPieceList();
+
+ // also start loading the piece for the next step
+ if(response && response.piece) {
+ PieceActions.updatePiece({});
+ PieceActions.updatePiece(response.piece);
+ }
+
+ this.incrementStep();
+
+ this.refs.slidesContainer.nextSlide({ piece_id: response.piece.id });
+ },
+
+ handleAdditionalDataSuccess() {
+ // We need to refetch the piece again after submitting the additional data
+ // since we want it's otherData to be displayed when the user choses to click
+ // on the browsers back button.
+ PieceActions.fetchOne(this.state.piece.id);
+
+ this.refreshPieceList();
+
+ this.history.pushState(null, `/collection`);
+ },
+
+ // We need to increase the step to lock the forms that are already filled out
+ incrementStep() {
+ // also increase step
+ let newStep = this.state.step + 1;
+ this.setState({
+ step: newStep
+ });
+ },
+
+ refreshPieceList() {
+ PieceListActions.fetchPieceList(
+ this.state.page,
+ this.state.pageSize,
+ this.state.searchTerm,
+ this.state.orderBy,
+ this.state.orderAsc,
+ this.state.filterBy
+ );
+ },
+
+ // basically redirects to the second slide (index: 1), when the user is not logged in
+ onLoggedOut() {
+ this.history.pushState(null, '/login');
+ },
+
+ render() {
+ setDocumentTitle(getLangText('Register a new piece'));
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+});
+
+export default LumenusRegisterPiece;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index e258dfa7..e170d671 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -30,6 +30,7 @@ import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_p
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
import LumenusPieceList from './components/lumenus/lumenus_piece_list';
+import LumenusRegisterPiece from './components/lumenus/lumenus_register_piece';
import CCRegisterPiece from './components/cc/cc_register_piece';
@@ -174,7 +175,7 @@ let ROUTES = {
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
Date: Thu, 22 Oct 2015 14:14:06 +0200
Subject: [PATCH 009/115] Fix typo in edition api url
---
.../ascribe_piece_list_bulk_modal/piece_list_bulk_modal.js | 1 -
js/components/whitelabel/wallet/constants/wallet_api_urls.js | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
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 f5d97842..2a4d4301 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
@@ -137,7 +137,6 @@ let PieceListBulkModal = React.createClass({
} else {
return null;
}
-
}
});
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 8f4543c7..87ee6b14 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -21,7 +21,7 @@ function getWalletApiUrls(subdomain) {
}
else if (subdomain === 'lumenus'){
return {
- 'editions': walletConstants.walletApiEndpoint + subdomain + 'editions/',
+ 'editions': walletConstants.walletApiEndpoint + subdomain + '/editions/',
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
From 3dedc93d2e979fc33c3d821343256691a03122b8 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 23 Oct 2015 14:19:44 +0200
Subject: [PATCH 010/115] Force consignee to be submissions@lumenus.co
Special white label form settings only defined for consign form for
now, but could be added to others as needed.
---
js/components/ascribe_buttons/acl_button.js | 70 ++++++++-----------
js/components/ascribe_forms/form_consign.js | 10 ++-
.../cyland/cyland_register_piece.js | 7 +-
js/constants/application_constants.js | 8 ++-
js/utils/form_utils.js | 57 ++++++++++++---
5 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js
index e3c7fa1c..ee337149 100644
--- a/js/components/ascribe_buttons/acl_button.js
+++ b/js/components/ascribe_buttons/acl_button.js
@@ -34,15 +34,19 @@ let AclButton = React.createClass({
className: React.PropTypes.string
},
- isPiece(){
+ isPiece() {
return this.props.pieceOrEditions.constructor !== Array;
},
- actionProperties(){
+ actionProperties() {
+ let message = getAclFormMessage({
+ aclName: this.props.action,
+ entities: this.props.pieceOrEditions,
+ isPiece: this.isPiece(),
+ senderName: this.props.currentUser.username
+ });
- let message = getAclFormMessage(this.props.action, this.getTitlesString(), this.props.currentUser.username);
-
- if (this.props.action === 'acl_consign'){
+ if (this.props.action === 'acl_consign') {
return {
title: getLangText('Consign artwork'),
tooltip: getLangText('Have someone else sell the artwork'),
@@ -51,11 +55,10 @@ let AclButton = React.createClass({
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_consigns}/>
- ),
+ ),
handleSuccess: this.showNotification
};
- }
- if (this.props.action === 'acl_unconsign'){
+ } else if (this.props.action === 'acl_unconsign') {
return {
title: getLangText('Unconsign artwork'),
tooltip: getLangText('Have the owner manage his sales again'),
@@ -64,10 +67,10 @@ let AclButton = React.createClass({
message={message}
id={this.getFormDataId()}
url={ApiUrls.ownership_unconsigns}/>
- ),
+ ),
handleSuccess: this.showNotification
};
- }else if (this.props.action === 'acl_transfer') {
+ } else if (this.props.action === 'acl_transfer') {
return {
title: getLangText('Transfer artwork'),
tooltip: getLangText('Transfer the ownership of the artwork'),
@@ -79,32 +82,32 @@ let AclButton = React.createClass({
),
handleSuccess: this.showNotification
};
- }
- else if (this.props.action === 'acl_loan'){
+ } else if (this.props.action === 'acl_loan') {
return {
title: getLangText('Loan artwork'),
tooltip: getLangText('Loan your artwork for a limited period of time'),
- form: (
+ url={this.isPiece() ? ApiUrls.ownership_loans_pieces
+ : ApiUrls.ownership_loans_editions}/>
),
handleSuccess: this.showNotification
};
- }
- else if (this.props.action === 'acl_loan_request'){
+ } else if (this.props.action === 'acl_loan_request') {
return {
title: getLangText('Loan artwork'),
tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time'),
- form: (
),
handleSuccess: this.showNotification
};
- }
- else if (this.props.action === 'acl_share'){
+ } else if (this.props.action === 'acl_share') {
return {
title: getLangText('Share artwork'),
tooltip: getLangText('Share the artwork'),
@@ -112,8 +115,9 @@ let AclButton = React.createClass({
- ),
+ url={this.isPiece() ? ApiUrls.ownership_shares_pieces
+ : ApiUrls.ownership_shares_editions}/>
+ ),
handleSuccess: this.showNotification
};
} else {
@@ -121,32 +125,18 @@ let AclButton = React.createClass({
}
},
- showNotification(response){
+ showNotification(response) {
this.props.handleSuccess();
- if(response.notification) {
+ if (response.notification) {
let notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
},
- // plz move to share form
- getTitlesString(){
- if (this.isPiece()){
- return '\"' + this.props.pieceOrEditions.title + '\"';
- }
- else {
- return this.props.pieceOrEditions.map(function(edition) {
- return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n';
- }).join('');
- }
-
- },
-
getFormDataId(){
if (this.isPiece()) {
return {piece_id: this.props.pieceOrEditions.id};
- }
- else {
+ } else {
return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){
return edition.bitcoin_id;
}).join()};
@@ -162,7 +152,7 @@ let AclButton = React.createClass({
},
render() {
- if (this.props.availableAcls){
+ if (this.props.availableAcls) {
let shouldDisplay = this.props.availableAcls[this.props.action];
let aclProps = this.actionProperties();
let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : '';
@@ -183,4 +173,4 @@ let AclButton = React.createClass({
}
});
-export default AclButton;
\ No newline at end of file
+export default AclButton;
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index f57e0045..7e3233e8 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -11,6 +11,7 @@ import InputTextAreaToggable from './input_textarea_toggable';
import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils.js';
+import { getSubdomainFormSettings } from '../../utils/form_utils';
let ConsignForm = React.createClass({
propTypes: {
@@ -25,6 +26,8 @@ let ConsignForm = React.createClass({
},
render() {
+ let envSettings = getSubdomainFormSettings('consign');
+
return (
-
);
}
});
-
export default Form;
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index 9617acd4..db18ba4f 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -9,6 +9,9 @@ import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable';
import AscribeSpinner from '../ascribe_spinner';
+
+import AclInformation from '../ascribe_buttons/acl_information';
+
import { getLangText } from '../../utils/lang_utils.js';
let ConsignForm = React.createClass({
@@ -47,6 +50,7 @@ let ConsignForm = React.createClass({
}>
+
}>
+
{getLangText('Are you sure you would like to permanently delete this edition')}?
{getLangText('This is an irrevocable action%s', '.')}
diff --git a/js/components/ascribe_forms/form_delete_piece.js b/js/components/ascribe_forms/form_delete_piece.js
index 4b0c9e39..ee066d3f 100644
--- a/js/components/ascribe_forms/form_delete_piece.js
+++ b/js/components/ascribe_forms/form_delete_piece.js
@@ -4,6 +4,8 @@ import React from 'react';
import Form from '../ascribe_forms/form';
+import AclInformation from '../ascribe_buttons/acl_information';
+
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
@@ -51,6 +53,7 @@ let PieceDeleteForm = React.createClass({
}>
+
{getLangText('Are you sure you would like to permanently delete this piece')}?
{getLangText('This is an irrevocable action%s', '.')}
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index 919b6118..d6102f14 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -19,7 +19,7 @@ import AscribeSpinner from '../ascribe_spinner';
import { mergeOptions } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
-
+import AclInformation from '../ascribe_buttons/acl_information';
let LoanForm = React.createClass({
propTypes: {
@@ -232,6 +232,7 @@ let LoanForm = React.createClass({
{this.props.loanHeading}
+
}>
+
diff --git a/js/components/ascribe_forms/form_transfer.js b/js/components/ascribe_forms/form_transfer.js
index 010c4829..3fb95ff6 100644
--- a/js/components/ascribe_forms/form_transfer.js
+++ b/js/components/ascribe_forms/form_transfer.js
@@ -9,6 +9,8 @@ import Form from './form';
import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable';
+import AclInformation from '../ascribe_buttons/acl_information';
+
import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils.js';
@@ -52,6 +54,7 @@ let TransferForm = React.createClass({
}>
+
diff --git a/js/components/ascribe_modal/modal_wrapper.js b/js/components/ascribe_modal/modal_wrapper.js
index f00eee9e..5c3ce742 100644
--- a/js/components/ascribe_modal/modal_wrapper.js
+++ b/js/components/ascribe_modal/modal_wrapper.js
@@ -65,7 +65,7 @@ let ModalWrapper = React.createClass({
{this.props.title}
-
+
{this.renderChildren()}
diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
index 16886def..38de2af6 100644
--- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
+++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
@@ -7,7 +7,7 @@ import DropdownButton from 'react-bootstrap/lib/DropdownButton';
import { getLangText } from '../../utils/lang_utils.js';
-let PieceListToolbarFilterWidgetFilter = React.createClass({
+let PieceListToolbarFilterWidget = React.createClass({
propTypes: {
filterParams: React.PropTypes.arrayOf(
React.PropTypes.shape({
@@ -83,6 +83,7 @@ let PieceListToolbarFilterWidgetFilter = React.createClass({
return (
{/* We iterate over filterParams, to receive the label and then for each
@@ -139,4 +140,4 @@ let PieceListToolbarFilterWidgetFilter = React.createClass({
}
});
-export default PieceListToolbarFilterWidgetFilter;
\ No newline at end of file
+export default PieceListToolbarFilterWidget;
\ No newline at end of file
diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_order_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_order_widget.js
index a3615aec..c38144b0 100644
--- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_order_widget.js
+++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_order_widget.js
@@ -54,6 +54,7 @@ let PieceListToolbarOrderWidget = React.createClass({
return (
@@ -72,7 +73,7 @@ let PieceListToolbarOrderWidget = React.createClass({
-1} />
diff --git a/js/components/ascribe_spinner.js b/js/components/ascribe_spinner.js
index ecdf641b..e1daf5b2 100644
--- a/js/components/ascribe_spinner.js
+++ b/js/components/ascribe_spinner.js
@@ -20,12 +20,13 @@ let AscribeSpinner = React.createClass({
render() {
return (
-
-
-
A
+
);
}
diff --git a/js/components/header.js b/js/components/header.js
index 042d2b1c..51f91318 100644
--- a/js/components/header.js
+++ b/js/components/header.js
@@ -2,6 +2,8 @@
import React from 'react';
+import { Link } from 'react-router';
+
import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav';
@@ -29,7 +31,7 @@ import NavRoutesLinks from './nav_routes_links';
import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils';
-import {constructHead} from '../utils/head_setter';
+import { constructHead } from '../utils/dom_utils';
let Header = React.createClass({
@@ -71,12 +73,16 @@ let Header = React.createClass({
}
if (whitelabel.subdomain && whitelabel.subdomain !== 'www' && whitelabel.logo){
- return (
);
+ return (
+
+
+
+ );
}
return (
-
+
);
},
@@ -201,7 +207,7 @@ let Header = React.createClass({
{this.getPoweredBy()}
-
+
{account}
{signup}
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 528ee409..425247da 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -25,8 +25,6 @@ import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar';
import AscribeSpinner from './ascribe_spinner';
-import AppConstants from '../constants/application_constants';
-
import { getAvailableAcls } from '../utils/acl_utils';
import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils';
diff --git a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js
index abda8a1b..caef504b 100644
--- a/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js
+++ b/js/components/whitelabel/prize/components/ascribe_accordion_list/accordion_list_item_prize.js
@@ -182,7 +182,7 @@ let AccordionListItemPrize = React.createClass({
artistName={artistName}
subsubheading={
- {this.props.content.date_created.split('-')[0]}
+ {new Date(this.props.content.date_created).getFullYear()}
}
buttons={this.getPrizeButtons()}
badge={this.getPrizeBadge()}>
diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
index a5f9838f..07e84b0e 100644
--- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
+++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
@@ -141,7 +141,7 @@ let PieceContainer = React.createClass({
{this.state.piece.title}
-
+
{artistEmail}
{this.getActions()}
diff --git a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js
index 8a38f02e..5644b5b0 100644
--- a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js
+++ b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_piece_container.js
@@ -39,7 +39,7 @@ let WalletPieceContainer = React.createClass({
{this.props.piece.title}
-
+
}
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js
index ae96db98..755e550b 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_accordion_list/cyland_accordion_list_item.js
@@ -100,7 +100,7 @@ let CylandAccordionListItem = React.createClass({
piece={this.props.content}
subsubheading={
- {this.props.content.date_created.split('-')[0]}
+ {new Date(this.props.content.date_created).getFullYear()}
}
buttons={this.getSubmitButtons()}>
{this.props.children}
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
index 8a6c38b5..63085fc9 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
@@ -3,7 +3,6 @@
import React from 'react';
import { History } from 'react-router';
-
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../stores/whitelabel_store';
@@ -14,10 +13,13 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import UserStore from '../../../../../stores/user_store';
import UserActions from '../../../../../actions/user_actions';
+import AscribeSpinner from '../../../../ascribe_spinner';
+
import { mergeOptions } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
+
let CylandLanding = React.createClass({
mixins: [History],
@@ -61,10 +63,9 @@ let CylandLanding = React.createClass({
- {getLangText('Submissions to Cyland Archive are powered by')}
+ {getLangText('Submissions to Cyland Archive are powered by') + ' '}
- ascribe
-
+
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js
index 00e7f318..7445eb36 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_accordion_list/ikonotv_accordion_list_item.js
@@ -106,7 +106,7 @@ let IkonotvAccordionListItem = React.createClass({
piece={this.props.content}
subsubheading={
- {this.props.content.date_created.split('-')[0]}
+ {new Date(this.props.content.date_created).getFullYear()}
}
buttons={this.getSubmitButtons()}>
{this.props.children}
diff --git a/js/constants/information_text.js b/js/constants/information_text.js
new file mode 100644
index 00000000..442e481e
--- /dev/null
+++ b/js/constants/information_text.js
@@ -0,0 +1,33 @@
+'use strict';
+
+export const InformationTexts = {
+ 'titles': {
+ 'acl_consign': 'CONSIGN',
+ 'acl_loan': 'LOAN',
+ 'acl_share': 'SHARE',
+ 'acl_delete': 'DELETE',
+ 'acl_create_editions': 'CREATE EDITIONS',
+ 'acl_unconsign': 'UNCONSIGN',
+ 'acl_request_unconsign': 'REQUEST UNCONSIGN'
+ },
+ 'informationSentences': {
+ 'acl_consign': ' - Lets someone represent you in dealing with the work, under the terms you agree to.',
+ 'acl_loan': ' - Lets someone use or put the Work on display for a limited amount of time.',
+ 'acl_share': ' - Lets someone view the Work or Edition, but does not give rights to publish or display it.',
+ 'acl_delete': ' - Removes the Work from your Wallet. Note that the previous registration and transfer ' +
+ 'history will still exist on the blockchain and cannot be deleted.',
+ 'acl_create_editions': ' Lets the artist set a fixed number of editions of a work which can then be transferred, guaranteeing each edition is authentic and from the artist.',
+ 'acl_unconsign': 'Ends the consignment agreement between the owner and a consignee.',
+ 'acl_request_unconsign': 'Lets the owner ask the consignee to confirm that they will no longer manage the work.'
+ },
+ 'exampleSentences': {
+ 'acl_consign': '(e.g. an artist Consigns 10 Editions of her new Work to a gallery ' +
+ 'so the gallery can sell them on her behalf, under the terms the artist and the gallery have agreed to)',
+ 'acl_loan': '(e.g. a collector Loans a Work to a gallery for one month for display in the gallery\'s show)',
+ 'acl_share': '(e.g. a photographer Shares proofs of a graduation photo with the graduate\'s grandparents)',
+ 'acl_delete': '(e.g. an artist uploaded the wrong file and doesn\'t want it cluttering his Wallet, so he Deletes it)',
+ 'acl_create_editions': '(e.g. A company commissions a visual artists to create three limited edition prints for a giveaway)',
+ 'acl_unconsign': '(e.g. An artist regains full control over their work and releases the consignee of any rights or responsibilities)',
+ 'acl_request_unconsign': '(e.g. An artist submits an unconsign request to a gallery after his exhibition ends, as per their agreement)'
+ }
+};
\ No newline at end of file
diff --git a/js/utils/acl_utils.js b/js/utils/acl_utils.js
index 170d7aec..dd39a380 100644
--- a/js/utils/acl_utils.js
+++ b/js/utils/acl_utils.js
@@ -1,10 +1,6 @@
'use strict';
-import { sanitize } from './general_utils';
-
-function intersectAcls(a, b) {
- return a.filter((val) => b.indexOf(val) > -1);
-}
+import { sanitize, intersectLists } from './general_utils';
export function getAvailableAcls(editions, filterFn) {
let availableAcls = [];
@@ -37,13 +33,15 @@ export function getAvailableAcls(editions, filterFn) {
});
// If no edition has been selected, availableActions is empty
- // If only one edition has been selected, their actions are available
- // If more than one editions have been selected, their acl properties are intersected
+ // If only one edition has been selected, its actions are available
+ // If more than one editions have been selected, intersect all their acl properties
if (editionsCopy.length >= 1) {
availableAcls = editionsCopy[0].acl;
- } else if (editionsCopy.length >= 2) {
- for (let i = 1; i < editionsCopy.length; i++) {
- availableAcls = intersectAcls(availableAcls, editionsCopy[i].acl);
+
+ if (editionsCopy.length >= 2) {
+ for (let i = 1; i < editionsCopy.length; i++) {
+ availableAcls = intersectLists(availableAcls, editionsCopy[i].acl);
+ }
}
}
@@ -53,6 +51,5 @@ export function getAvailableAcls(editions, filterFn) {
availableAclsObj[availableAcls[i]] = true;
}
-
return availableAclsObj;
}
diff --git a/js/utils/dom_utils.js b/js/utils/dom_utils.js
index c20e1009..d009f90f 100644
--- a/js/utils/dom_utils.js
+++ b/js/utils/dom_utils.js
@@ -1,9 +1,45 @@
'use strict';
-
/**
* Set the title in the browser window.
*/
export function setDocumentTitle(title) {
document.title = title;
}
+
+/**
+ * @param {string} elementType: string, is the type of the element, such as link, meta, etc.
+ * @param {string} elementId id of the element
+ * @param {object} elementAttributes: hash table containing the attributes of the relevant element
+ */
+function constructHeadElement(elementType, elementId, elementAttributes) {
+ let head = (document.head || document.getElementsByTagName('head')[0]);
+ let element = document.createElement(elementType);
+ let oldElement = document.getElementById(elementId);
+ element.setAttribute('id', elementId);
+ for (let k in elementAttributes){
+ try {
+ element.setAttribute(k, elementAttributes[k]);
+ }
+ catch(e){
+ console.warn(e.message);
+ }
+ }
+ if (oldElement) {
+ head.removeChild(oldElement);
+ }
+ head.appendChild(element);
+}
+
+/**
+ * Accepts a dictionary of dictionaries which comprises a part or all of html head part
+ * @param {object} headObject {link : {id1: {rel: ... }}}
+ */
+export function constructHead(headObject){
+ for (let k in headObject){
+ let favicons = headObject[k];
+ for (let f in favicons){
+ constructHeadElement(k, f, favicons[f]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js
index cc1d22dd..1aea3cd9 100644
--- a/js/utils/general_utils.js
+++ b/js/utils/general_utils.js
@@ -222,6 +222,16 @@ export function truncateTextAtCharIndex(text, charIndex, replacement = '...') {
return truncatedText;
}
+/**
+ * @param index, int, the starting index of the substring to be replaced
+ * @param character, substring to be replaced
+ * @returns {string}
+ */
+export function replaceSubstringAtIndex(baseString, substrToReplace, stringToBePut) {
+ let index = baseString.indexOf(substrToReplace);
+ return baseString.substr(0, index) + stringToBePut + baseString.substr(index + substrToReplace.length);
+}
+
/**
* Extracts the user's subdomain from the browser's window.
* If no subdomain is found (for example on a naked domain), the default "www" is just assumed.
@@ -232,3 +242,13 @@ export function getSubdomain() {
let tokens = host.split('.');
return tokens.length > 2 ? tokens[0] : 'www';
}
+
+/**
+ * Takes two lists and returns their intersection as a list
+ * @param {Array} a
+ * @param {Array} b
+ * @return {[Array]} Intersected list of a and b
+ */
+export function intersectLists(a, b) {
+ return a.filter((val) => b.indexOf(val) > -1);
+}
diff --git a/js/utils/head_setter.js b/js/utils/head_setter.js
deleted file mode 100644
index 6ca2c9b0..00000000
--- a/js/utils/head_setter.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-// elementType: string, is the type of the element, such as link, meta, etc.
-// elementId id of the element
-// elementAttributes: hash table containing the attributes of the relevant element
-
-function constructHeadElement(elementType, elementId, elementAttributes) {
- let head = (document.head || document.getElementsByTagName('head')[0]);
- let element = document.createElement(elementType);
- let oldElement = document.getElementById(elementId);
- element.setAttribute('id', elementId);
- for (let k in elementAttributes){
- try {
- element.setAttribute(k, elementAttributes[k]);
- }
- catch(e){
- console.warn(e.message);
- continue;
- }
- }
- if (oldElement) {
- head.removeChild(oldElement);
- }
- head.appendChild(element);
-}
-
-// Accepts a dictionary of dictionaries which comprises a part or all of html head part
-// {link : {id1: {rel: ... }}}
-// traverses a tree of depth 3 (no backtracking)
-export function constructHead(headObject){
- for (let k in headObject){
- let favicons = headObject[k];
- for (let f in favicons){
- constructHeadElement(k, f, favicons[f]);
- }
- }
-}
diff --git a/sass/ascribe_acl_information.scss b/sass/ascribe_acl_information.scss
new file mode 100644
index 00000000..063c8ae6
--- /dev/null
+++ b/sass/ascribe_acl_information.scss
@@ -0,0 +1,25 @@
+.acl-information-dropdown-list {
+ text-align: justify;
+ padding: .5em .5em .5em 0;
+
+ p {
+ margin: 0 .5em 1em 0;
+ line-height: 1.2;
+ }
+
+ span {
+ font-size: 13px;
+ }
+
+ .title {
+ color: $ascribe-dark-blue;
+ }
+
+ .info {
+ color: #212121;
+ }
+
+ .example {
+ color: #616161;
+ }
+}
\ No newline at end of file
diff --git a/sass/ascribe_custom_style.scss b/sass/ascribe_custom_style.scss
index 51281d91..05d39027 100644
--- a/sass/ascribe_custom_style.scss
+++ b/sass/ascribe_custom_style.scss
@@ -91,12 +91,27 @@ hr {
}
}
- .navbar-brand,
- .navbar-brand:hover {
+ .navbar-brand {
font-size: 23px;
padding: 12px 15px;
- color: $ascribe--nav-fg-prim-color;
+
+ .icon-ascribe-logo {
+ color: $ascribe--nav-fg-prim-color;
+
+ &:hover {
+ color: $ascribe--nav-fg-sec-color;
+ text-decoration: none;
+ }
+ &:focus {
+ text-decoration: none;
+ }
+ }
+
+ .img-brand {
+ height: 100%;
+ }
}
+
.img-brand .navbar-brand {
width: 0;
height: 0;
@@ -327,6 +342,29 @@ fieldset[disabled] .btn-secondary.active {
}
}
+.btn-tertiary {
+ background-color: transparent;
+ border-color: transparent;
+ color: $ascribe-dark-blue;
+
+ &:focus,
+ &:active:focus,
+ &:active.focus {
+ background-color: transparent;
+ border-color: transparent;
+ color: $ascribe-dark-blue;
+ }
+
+ &:hover,
+ &:active,
+ &:active:hover,
+ &.active:hover{
+ background-color: $ascribe-pink;
+ border-color: $ascribe-pink;
+ color: $ascribe-white;
+ }
+}
+
.ascribe-piece-list-toolbar-filter-widget button {
background-color: transparent;
border: 1px solid transparent;
diff --git a/sass/ascribe_edition.scss b/sass/ascribe_edition.scss
index 9fa30387..195e79e0 100644
--- a/sass/ascribe_edition.scss
+++ b/sass/ascribe_edition.scss
@@ -17,8 +17,4 @@
border: 1px solid #CCC;
display: table-cell;
vertical-align: middle;
-}
-
-.ascribe-button-list {
- margin-top: 1em;
-}
+}
\ No newline at end of file
diff --git a/sass/lib/buttons.scss b/sass/lib/buttons.scss
index e69de29b..68a124f9 100644
--- a/sass/lib/buttons.scss
+++ b/sass/lib/buttons.scss
@@ -0,0 +1,9 @@
+.btn-transparent {
+ color: black;
+ background-color: transparent;
+
+ &:hover, &:active, &:focus {
+ color:#424242;
+ outline: none;
+ }
+}
\ No newline at end of file
diff --git a/sass/lib/modals.scss b/sass/lib/modals.scss
new file mode 100644
index 00000000..20a720c1
--- /dev/null
+++ b/sass/lib/modals.scss
@@ -0,0 +1,8 @@
+.modal-body {
+ padding-top:0;
+}
+
+.modal-header {
+ padding: 15px 15px 0 15px;
+ border-bottom: none;
+}
\ No newline at end of file
diff --git a/sass/main.scss b/sass/main.scss
index 4b9e0f71..337dd32e 100644
--- a/sass/main.scss
+++ b/sass/main.scss
@@ -35,6 +35,9 @@ $BASE_URL: '<%= BASE_URL %>';
@import 'ascribe_form';
@import 'ascribe_panel';
@import 'ascribe_collapsible';
+@import 'ascribe_acl_information';
+@import 'lib/buttons';
+@import 'lib/modals';
@import 'ascribe_custom_style';
@import 'ascribe_spinner';
@@ -155,6 +158,7 @@ hr {
}
.ascribe-detail-property-label {
+ vertical-align: top;
font-size: .8em;
}
diff --git a/sass/variables.scss b/sass/variables.scss
index ccd48864..ac93a2fb 100644
--- a/sass/variables.scss
+++ b/sass/variables.scss
@@ -613,7 +613,7 @@ $modal-header-border-color: #e5e5e5 !default;
$modal-footer-border-color: $modal-header-border-color !default;
$modal-lg: 900px !default;
-$modal-md: 600px !default;
+$modal-md: 500px !default;
$modal-sm: 300px !default;
diff --git a/sass/whitelabel/prize/sluice/sluice_custom_style.scss b/sass/whitelabel/prize/sluice/sluice_custom_style.scss
index e2ceeeb3..4cfb7c82 100644
--- a/sass/whitelabel/prize/sluice/sluice_custom_style.scss
+++ b/sass/whitelabel/prize/sluice/sluice_custom_style.scss
@@ -251,3 +251,7 @@ $sluice--button-color: $sluice--nav-fg-prim-color;
.client--sluice .ascribe-progress-bar > .progress-bar {
background-color: $sluice--button-color;
}
+
+.client--sluice .acl-information-dropdown-list .title {
+ color: $sluice--button-color;
+}
\ No newline at end of file
diff --git a/sass/whitelabel/wallet/cc/cc_custom_style.scss b/sass/whitelabel/wallet/cc/cc_custom_style.scss
index 238937e7..44cb0dd1 100644
--- a/sass/whitelabel/wallet/cc/cc_custom_style.scss
+++ b/sass/whitelabel/wallet/cc/cc_custom_style.scss
@@ -204,3 +204,7 @@ $cc--button-color: $cc--nav-fg-prim-color;
.client--cc .ascribe-progress-bar > .progress-bar {
background-color: $cc--button-color;
}
+
+.client--cc .acl-information-dropdown-list .title {
+ color: $cc--button-color;
+}
\ No newline at end of file
diff --git a/sass/whitelabel/wallet/cyland/cyland_custom_style.scss b/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
index c33e247b..eaf45621 100644
--- a/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
+++ b/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
@@ -179,3 +179,7 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
.client--cyland .ascribe-progress-bar > .progress-bar {
background-color: $cyland--button-color;
}
+
+.client--cyland .acl-information-dropdown-list .title {
+ color: $cyland--button-color;
+}
\ No newline at end of file
diff --git a/sass/whitelabel/wallet/ikonotv/ikonotv_custom_style.scss b/sass/whitelabel/wallet/ikonotv/ikonotv_custom_style.scss
index 5fc9220b..52affdaf 100644
--- a/sass/whitelabel/wallet/ikonotv/ikonotv_custom_style.scss
+++ b/sass/whitelabel/wallet/ikonotv/ikonotv_custom_style.scss
@@ -521,3 +521,7 @@ $ikono--font: 'Helvetica Neue', 'Helvetica', sans-serif !important;
.client--ikonotv .ascribe-progress-bar > .progress-bar {
background-color: $ikono--button-color;
}
+
+.client--ikonotv .acl-information-dropdown-list .title {
+ color: $ikono--button-color;
+}
\ No newline at end of file
From 3a8f91e29ef16e390b6f326357ef05a345a7b74a Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 3 Nov 2015 10:49:06 +0100
Subject: [PATCH 018/115] Change required prop for AD1251 changes
---
.../lumenus/lumenus_forms/lumenus_additional_data_form.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
index 3df03fd8..e08a8bc7 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
@@ -134,7 +134,7 @@ let LumenusAdditionalDataForm = React.createClass({
rows={1}
defaultValue={piece.extra_data.artist_bio}
placeholder={getLangText('Enter a biography of the artist...')}
- required="required"/>
+ required />
+ required />
+ required />
+ required />
);
From f7259a8ab3784cb74ac2d71e710cd6ef90ee917c Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 3 Nov 2015 11:13:32 +0100
Subject: [PATCH 019/115] Merge with AD-1255
---
js/components/ascribe_buttons/acl_button.js | 174 ------------------
.../ascribe_buttons/acl_button_list.js | 45 +++--
.../ascribe_buttons/acls/acl_button.js | 83 +++++++++
.../ascribe_buttons/acls/consign_button.js | 27 +++
.../ascribe_buttons/acls/loan_button.js | 27 +++
.../acls/loan_request_button.js | 24 +++
.../ascribe_buttons/acls/share_button.js | 24 +++
.../ascribe_buttons/acls/transfer_button.js | 24 +++
.../ascribe_buttons/acls/unconsign_button.js | 24 +++
.../ascribe_detail/edition_action_panel.js | 2 +-
.../ascribe_detail/piece_container.js | 2 +-
.../ascribe_forms/acl_form_factory.js | 128 +++++++++++++
.../ascribe_forms/form_request_action.js | 70 ++++---
.../ascribe_detail/wallet_action_panel.js | 4 +-
js/utils/form_utils.js | 16 ++
js/utils/general_utils.js | 39 +++-
js/utils/lang_utils.js | 6 +-
js/utils/requests.js | 8 +-
18 files changed, 474 insertions(+), 253 deletions(-)
delete mode 100644 js/components/ascribe_buttons/acl_button.js
create mode 100644 js/components/ascribe_buttons/acls/acl_button.js
create mode 100644 js/components/ascribe_buttons/acls/consign_button.js
create mode 100644 js/components/ascribe_buttons/acls/loan_button.js
create mode 100644 js/components/ascribe_buttons/acls/loan_request_button.js
create mode 100644 js/components/ascribe_buttons/acls/share_button.js
create mode 100644 js/components/ascribe_buttons/acls/transfer_button.js
create mode 100644 js/components/ascribe_buttons/acls/unconsign_button.js
create mode 100644 js/components/ascribe_forms/acl_form_factory.js
diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js
deleted file mode 100644
index 5197a744..00000000
--- a/js/components/ascribe_buttons/acl_button.js
+++ /dev/null
@@ -1,174 +0,0 @@
-'use strict';
-
-import React from 'react';
-
-import ConsignForm from '../ascribe_forms/form_consign';
-import UnConsignForm from '../ascribe_forms/form_unconsign';
-import TransferForm from '../ascribe_forms/form_transfer';
-import LoanForm from '../ascribe_forms/form_loan';
-import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer';
-import ShareForm from '../ascribe_forms/form_share_email';
-import ModalWrapper from '../ascribe_modal/modal_wrapper';
-import AppConstants from '../../constants/application_constants';
-
-import GlobalNotificationModel from '../../models/global_notification_model';
-import GlobalNotificationActions from '../../actions/global_notification_actions';
-
-import ApiUrls from '../../constants/api_urls';
-
-import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils';
-import { getLangText } from '../../utils/lang_utils';
-
-let AclButton = React.createClass({
- propTypes: {
- action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
- availableAcls: React.PropTypes.object.isRequired,
- pieceOrEditions: React.PropTypes.oneOfType([
- React.PropTypes.object,
- React.PropTypes.array
- ]).isRequired,
- currentUser: React.PropTypes.object,
- buttonAcceptName: React.PropTypes.string,
- buttonAcceptClassName: React.PropTypes.string,
- email: React.PropTypes.string,
- handleSuccess: React.PropTypes.func.isRequired,
- className: React.PropTypes.string
- },
-
- isPiece() {
- return this.props.pieceOrEditions.constructor !== Array;
- },
-
- actionProperties() {
- let message = getAclFormMessage({
- aclName: this.props.action,
- entities: this.props.pieceOrEditions,
- isPiece: this.isPiece(),
- senderName: this.props.currentUser.username
- });
-
- if (this.props.action === 'acl_consign') {
- return {
- title: getLangText('Consign artwork'),
- tooltip: getLangText('Have someone else sell the artwork'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else if (this.props.action === 'acl_unconsign') {
- return {
- title: getLangText('Unconsign artwork'),
- tooltip: getLangText('Have the owner manage his sales again'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else if (this.props.action === 'acl_transfer') {
- return {
- title: getLangText('Transfer artwork'),
- tooltip: getLangText('Transfer the ownership of the artwork'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else if (this.props.action === 'acl_loan') {
- return {
- title: getLangText('Loan artwork'),
- tooltip: getLangText('Loan your artwork for a limited period of time'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else if (this.props.action === 'acl_loan_request') {
- return {
- title: getLangText('Loan artwork'),
- tooltip: getLangText('Someone requested you to loan your artwork for a limited period of time'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else if (this.props.action === 'acl_share') {
- return {
- title: getLangText('Share artwork'),
- tooltip: getLangText('Share the artwork'),
- form: (
-
- ),
- handleSuccess: this.showNotification
- };
- } else {
- throw new Error('Your specified action did not match a form.');
- }
- },
-
- showNotification(response) {
- this.props.handleSuccess();
- if (response.notification) {
- let notification = new GlobalNotificationModel(response.notification, 'success');
- GlobalNotificationActions.appendGlobalNotification(notification);
- }
- },
-
- getFormDataId(){
- return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions);
- },
-
- // Removes the acl_ prefix and converts to upper case
- sanitizeAction() {
- if (this.props.buttonAcceptName) {
- return this.props.buttonAcceptName;
- }
- return this.props.action.split('acl_')[1].toUpperCase();
- },
-
- render() {
- if (this.props.availableAcls) {
- let shouldDisplay = this.props.availableAcls[this.props.action];
- let aclProps = this.actionProperties();
- let buttonClassName = this.props.buttonAcceptClassName ? this.props.buttonAcceptClassName : '';
- return (
-
- {this.sanitizeAction()}
-
- }
- handleSuccess={aclProps.handleSuccess}
- title={aclProps.title}>
- {aclProps.form}
-
- );
- }
- return null;
- }
-});
-
-export default AclButton;
diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js
index e87a6407..83495363 100644
--- a/js/components/ascribe_buttons/acl_button_list.js
+++ b/js/components/ascribe_buttons/acl_button_list.js
@@ -5,21 +5,25 @@ import React from 'react/addons';
import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store';
-import AclButton from '../ascribe_buttons/acl_button';
+import ConsignButton from './acls/consign_button';
+import LoanButton from './acls/loan_button';
+import LoanRequestButton from './acls/loan_request_button';
+import ShareButton from './acls/share_button';
+import TransferButton from './acls/transfer_button';
+import UnconsignButton from './acls/unconsign_button';
import { mergeOptions } from '../../utils/general_utils';
-
let AclButtonList = React.createClass({
propTypes: {
className: React.PropTypes.string,
- editions: React.PropTypes.oneOfType([
+ pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
- ]),
- availableAcls: React.PropTypes.object,
+ ]).isRequired,
+ availableAcls: React.PropTypes.object.isRequired,
buttonsStyle: React.PropTypes.object,
- handleSuccess: React.PropTypes.func,
+ handleSuccess: React.PropTypes.func.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
@@ -78,7 +82,7 @@ let AclButtonList = React.createClass({
const { className,
buttonsStyle,
availableAcls,
- editions,
+ pieceOrEditions,
handleSuccess } = this.props;
const { currentUser } = this.state;
@@ -86,34 +90,29 @@ let AclButtonList = React.createClass({
return (
-
-
-
-
-
{this.renderChildren()}
@@ -123,4 +122,4 @@ let AclButtonList = React.createClass({
}
});
-export default AclButtonList;
\ No newline at end of file
+export default AclButtonList;
diff --git a/js/components/ascribe_buttons/acls/acl_button.js b/js/components/ascribe_buttons/acls/acl_button.js
new file mode 100644
index 00000000..d81a19f4
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/acl_button.js
@@ -0,0 +1,83 @@
+'use strict';
+
+import React from 'react';
+import classNames from 'classnames';
+
+import AclProxy from '../../acl_proxy';
+
+import AclFormFactory from '../../ascribe_forms/acl_form_factory';
+
+import ModalWrapper from '../../ascribe_modal/modal_wrapper';
+
+import AppConstants from '../../../constants/application_constants';
+
+import GlobalNotificationModel from '../../../models/global_notification_model';
+import GlobalNotificationActions from '../../../actions/global_notification_actions';
+
+import ApiUrls from '../../../constants/api_urls';
+
+import { getAclFormMessage, getAclFormDataId } from '../../../utils/form_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let AclButton = React.createClass({
+ propTypes: {
+ action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
+ availableAcls: React.PropTypes.object.isRequired,
+ buttonAcceptName: React.PropTypes.string,
+ buttonAcceptClassName: React.PropTypes.string,
+ currentUser: React.PropTypes.object.isRequired,
+ email: React.PropTypes.string,
+ pieceOrEditions: React.PropTypes.oneOfType([
+ React.PropTypes.object,
+ React.PropTypes.array
+ ]).isRequired,
+ title: React.PropTypes.string,
+ handleSuccess: React.PropTypes.func.isRequired,
+ className: React.PropTypes.string
+ },
+
+ // Removes the acl_ prefix and converts to upper case
+ sanitizeAction() {
+ if (this.props.buttonAcceptName) {
+ return this.props.buttonAcceptName;
+ }
+ return this.props.action.split('acl_')[1].toUpperCase();
+ },
+
+ render() {
+ const {
+ action,
+ availableAcls,
+ buttonAcceptClassName,
+ currentUser,
+ email,
+ pieceOrEditions,
+ handleSuccess,
+ title } = this.props;
+
+ return (
+
+
+ {this.sanitizeAction()}
+
+ }
+ handleSuccess={handleSuccess}
+ title={title}>
+
+
+
+ );
+ }
+});
+
+export default AclButton;
diff --git a/js/components/ascribe_buttons/acls/consign_button.js b/js/components/ascribe_buttons/acls/consign_button.js
new file mode 100644
index 00000000..6a3759db
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/consign_button.js
@@ -0,0 +1,27 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let ConsignButton = React.createClass({
+ propTypes: {
+ ...omitFromObject(AclButton.propTypes, ['action']),
+ email: React.PropTypes.string
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default ConsignButton;
diff --git a/js/components/ascribe_buttons/acls/loan_button.js b/js/components/ascribe_buttons/acls/loan_button.js
new file mode 100644
index 00000000..283b43eb
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/loan_button.js
@@ -0,0 +1,27 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let LoanButton = React.createClass({
+ propTypes: {
+ ...omitFromObject(AclButton.propTypes, ['action']),
+ email: React.PropTypes.string
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default LoanButton;
diff --git a/js/components/ascribe_buttons/acls/loan_request_button.js b/js/components/ascribe_buttons/acls/loan_request_button.js
new file mode 100644
index 00000000..f4ffe9a4
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/loan_request_button.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let LoanButton = React.createClass({
+ propTypes: omitFromObject(AclButton.propTypes, ['action']),
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default LoanButton;
diff --git a/js/components/ascribe_buttons/acls/share_button.js b/js/components/ascribe_buttons/acls/share_button.js
new file mode 100644
index 00000000..4fb914a0
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/share_button.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let ShareButton = React.createClass({
+ propTypes: omitFromObject(AclButton.propTypes, ['action']),
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default ShareButton;
diff --git a/js/components/ascribe_buttons/acls/transfer_button.js b/js/components/ascribe_buttons/acls/transfer_button.js
new file mode 100644
index 00000000..e85a81d1
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/transfer_button.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let TransferButton = React.createClass({
+ propTypes: omitFromObject(AclButton.propTypes, ['action']),
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default TransferButton;
diff --git a/js/components/ascribe_buttons/acls/unconsign_button.js b/js/components/ascribe_buttons/acls/unconsign_button.js
new file mode 100644
index 00000000..39029c18
--- /dev/null
+++ b/js/components/ascribe_buttons/acls/unconsign_button.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import AclButton from './acl_button';
+
+import { omitFromObject } from '../../../utils/general_utils';
+import { getLangText } from '../../../utils/lang_utils';
+
+let UnconsignButton = React.createClass({
+ propTypes: omitFromObject(AclButton.propTypes, ['action']),
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default UnconsignButton;
diff --git a/js/components/ascribe_detail/edition_action_panel.js b/js/components/ascribe_detail/edition_action_panel.js
index d0f16103..6bd8108d 100644
--- a/js/components/ascribe_detail/edition_action_panel.js
+++ b/js/components/ascribe_detail/edition_action_panel.js
@@ -115,7 +115,7 @@ let EditionActionPanel = React.createClass({
+ );
+ } else if (action === 'acl_unconsign') {
+ return (
+
+ );
+ } else if (action === 'acl_transfer') {
+ return (
+
+ );
+ } else if (action === 'acl_loan') {
+ return (
+
+ );
+ } else if (action === 'acl_loan_request') {
+ return (
+
+ );
+ } else if (action === 'acl_share') {
+ return (
+
+ );
+ } else {
+ throw new Error('Your specified action did not match a form.');
+ }
+ }
+});
+
+export default AclFormFactory;
diff --git a/js/components/ascribe_forms/form_request_action.js b/js/components/ascribe_forms/form_request_action.js
index b0f3b6c6..d3d1bc71 100644
--- a/js/components/ascribe_forms/form_request_action.js
+++ b/js/components/ascribe_forms/form_request_action.js
@@ -2,10 +2,13 @@
import React from 'react';
-import AclButton from './../ascribe_buttons/acl_button';
-import ActionPanel from '../ascribe_panel/action_panel';
import Form from './form';
+import LoanRequestButton from '../ascribe_buttons/acls/loan_request_button';
+import UnconsignButton from '../ascribe_buttons/acls/unconsign_button';
+
+import ActionPanel from '../ascribe_panel/action_panel';
+
import NotificationActions from '../../actions/notification_actions';
import GlobalNotificationModel from '../../models/global_notification_model';
@@ -13,9 +16,9 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import ApiUrls from '../../constants/api_urls';
+import { getAclFormDataId } from '../../utils/form_utils';
import { getLangText } from '../../utils/lang_utils.js';
-
let RequestActionForm = React.createClass({
propTypes: {
pieceOrEditions: React.PropTypes.oneOfType([
@@ -27,26 +30,26 @@ let RequestActionForm = React.createClass({
handleSuccess: React.PropTypes.func
},
- isPiece(){
+ isPiece() {
return this.props.pieceOrEditions.constructor !== Array;
},
getUrls() {
let urls = {};
- if (this.props.notifications.action === 'consign'){
+ if (this.props.notifications.action === 'consign') {
urls.accept = ApiUrls.ownership_consigns_confirm;
urls.deny = ApiUrls.ownership_consigns_deny;
- } else if (this.props.notifications.action === 'unconsign'){
+ } else if (this.props.notifications.action === 'unconsign') {
urls.accept = ApiUrls.ownership_unconsigns;
urls.deny = ApiUrls.ownership_unconsigns_deny;
- } else if (this.props.notifications.action === 'loan' && !this.isPiece()){
+ } else if (this.props.notifications.action === 'loan' && !this.isPiece()) {
urls.accept = ApiUrls.ownership_loans_confirm;
urls.deny = ApiUrls.ownership_loans_deny;
- } else if (this.props.notifications.action === 'loan' && this.isPiece()){
+ } else if (this.props.notifications.action === 'loan' && this.isPiece()) {
urls.accept = ApiUrls.ownership_loans_pieces_confirm;
urls.deny = ApiUrls.ownership_loans_pieces_deny;
- } else if (this.props.notifications.action === 'loan_request' && this.isPiece()){
+ } else if (this.props.notifications.action === 'loan_request' && this.isPiece()) {
urls.accept = ApiUrls.ownership_loans_pieces_request_confirm;
urls.deny = ApiUrls.ownership_loans_pieces_request_deny;
}
@@ -54,37 +57,28 @@ let RequestActionForm = React.createClass({
return urls;
},
- getFormData(){
- if (this.isPiece()) {
- return {piece_id: this.props.pieceOrEditions.id};
- }
- else {
- return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){
- return edition.bitcoin_id;
- }).join()};
- }
+ getFormData() {
+ return getAclFormDataId(this.isPiece(), this.props.pieceOrEditions);
},
showNotification(option, action, owner) {
return () => {
- let message = getLangText('You have successfully') + ' ' + option + ' the ' + action + ' request ' + getLangText('from') + ' ' + owner;
-
- let notifications = new GlobalNotificationModel(message, 'success');
+ const message = getLangText('You have successfully %s the %s request from %s', getLangText(option), getLangText(action), owner);
+ const notifications = new GlobalNotificationModel(message, 'success');
GlobalNotificationActions.appendGlobalNotification(notifications);
this.handleSuccess();
-
};
},
handleSuccess() {
- if (this.isPiece()){
+ if (this.isPiece()) {
NotificationActions.fetchPieceListNotifications();
- }
- else {
+ } else {
NotificationActions.fetchEditionListNotifications();
}
- if(this.props.handleSuccess) {
+
+ if (typeof this.props.handleSuccess === 'function') {
this.props.handleSuccess();
}
},
@@ -98,21 +92,19 @@ let RequestActionForm = React.createClass({
},
getAcceptButtonForm(urls) {
- if(this.props.notifications.action === 'unconsign') {
+ if (this.props.notifications.action === 'unconsign') {
return (
-
);
- } else if(this.props.notifications.action === 'loan_request') {
+ } else if (this.props.notifications.action === 'loan_request') {
return (
-
@@ -140,8 +132,8 @@ let RequestActionForm = React.createClass({
},
getButtonForm() {
- let urls = this.getUrls();
- let acceptButtonForm = this.getAcceptButtonForm(urls);
+ const urls = this.getUrls();
+ const acceptButtonForm = this.getAcceptButtonForm(urls);
return (
@@ -150,13 +142,13 @@ let RequestActionForm = React.createClass({
isInline={true}
getFormData={this.getFormData}
handleSuccess={
- this.showNotification(getLangText('denied'), this.props.notifications.action, this.props.notifications.by)
+ this.showNotification('denied', this.props.notifications.action, this.props.notifications.by)
}
className='inline pull-right'>
- {getLangText('REJECT')}
+ {getLangText('REJECT')}
{acceptButtonForm}
@@ -168,10 +160,10 @@ let RequestActionForm = React.createClass({
return (
+ buttons={this.getButtonForm()} />
);
}
});
-export default RequestActionForm;
\ No newline at end of file
+export default RequestActionForm;
diff --git a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_action_panel.js b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_action_panel.js
index 178be7da..bd240126 100644
--- a/js/components/whitelabel/wallet/components/ascribe_detail/wallet_action_panel.js
+++ b/js/components/whitelabel/wallet/components/ascribe_detail/wallet_action_panel.js
@@ -47,7 +47,7 @@ let WalletActionPanel = React.createClass({
{
+ return filter.indexOf(key) >= 0;
+ });
+ } else if (filter && typeof filter === 'function') {
+ return filterObjOnFn(obj, filter);
+ } else {
+ throw new Error('The given filter is not an array or function. Exclude aborted');
+ }
}
/**
diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js
index f2e2fa14..ee2d292c 100644
--- a/js/utils/lang_utils.js
+++ b/js/utils/lang_utils.js
@@ -22,15 +22,15 @@ export function getLangText(s, ...args) {
let lang = getLang();
try {
if(lang in languages) {
- return formatText(languages[lang][s], args);
+ return formatText(languages[lang][s], ...args);
} else {
// just use the english language
- return formatText(languages['en-US'][s], args);
+ return formatText(languages['en-US'][s], ...args);
}
} catch(err) {
//if(!(s in languages[lang])) {
//console.warn('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file. Defaulting to keyname');
- return formatText(s, args);
+ return formatText(s, ...args);
//} else {
// console.error(err);
//}
diff --git a/js/utils/requests.js b/js/utils/requests.js
index 7e9c9a58..43c09458 100644
--- a/js/utils/requests.js
+++ b/js/utils/requests.js
@@ -6,7 +6,7 @@ import { argsToQueryParams, getCookie } from '../utils/fetch_api_utils';
import AppConstants from '../constants/application_constants';
-import {excludePropFromObject} from '../utils/general_utils';
+import { omitFromObject } from '../utils/general_utils';
class Requests {
_merge(defaults, options) {
@@ -138,9 +138,9 @@ class Requests {
return this.request('delete', newUrl);
}
- _putOrPost(url, paramsAndBody, method){
- let paramsCopy = this._merge(paramsAndBody);
- let params = excludePropFromObject(paramsAndBody, ['body']);
+ _putOrPost(url, paramsAndBody, method) {
+ let paramsCopy = Object.assign({}, paramsAndBody);
+ let params = omitFromObject(paramsAndBody, ['body']);
let newUrl = this.prepareUrl(url, params);
let body = null;
if (paramsCopy && paramsCopy.body) {
From 54212627bbab35b1b7ab3b2bda841f8b77c095d3 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 3 Nov 2015 12:10:21 +0100
Subject: [PATCH 020/115] Change lumens buttons for AD-1264 changes
---
js/components/piece_list.js | 2 +-
.../lumenus_buttons/lumenus_acl_button_list.js | 13 ++++++-------
.../lumenus_buttons/lumenus_submit_button.js | 11 +++++------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 425247da..3099d31a 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -224,7 +224,7 @@ let PieceList = React.createClass({
className="ascribe-piece-list-bulk-modal">
-
{this.props.children}
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
index 365a5a34..941b3ec0 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
@@ -3,7 +3,7 @@
import React from 'react';
import classNames from 'classnames';
-import AclButton from '../../../../../ascribe_buttons/acl_button';
+import ConsignButton from '../../../../../ascribe_buttons/acls/consign_button';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
@@ -14,7 +14,7 @@ let LumenusSubmitButton = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object,
- editions: React.PropTypes.array,
+ pieceOrEditions: React.PropTypes.array,
handleSuccess: React.PropTypes.func,
className: React.PropTypes.string,
},
@@ -37,17 +37,16 @@ let LumenusSubmitButton = React.createClass({
},
render() {
- const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
+ const { availableAcls, currentUser, className, pieceOrEditions, handleSuccess } = this.props;
return (
-
);
}
From 3929712e9ddbe9fc2efa019739bddd3a6096df2a Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 3 Nov 2015 12:10:43 +0100
Subject: [PATCH 021/115] Prune unnecessary divs from some components
---
.../lumenus_edition_container.js | 12 ++++------
.../lumenus_detail/lumenus_piece_container.js | 10 ++++----
.../components/lumenus/lumenus_piece_list.js | 24 +++++++++----------
3 files changed, 20 insertions(+), 26 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
index 756735eb..77cca99c 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
@@ -16,13 +16,11 @@ let LumenusEditionContainer = React.createClass({
render() {
return (
-
-
-
+
);
}
});
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
index 03fd9d9b..5b7cf8ee 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
@@ -14,12 +14,10 @@ let LumenusPieceContainer = React.createClass({
render() {
return (
-
+
);
}
});
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
index 4bc2485f..14dac214 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
@@ -18,19 +18,17 @@ let LumenusPieceList = React.createClass({
setDocumentTitle(getLangText('Collection'));
return (
-
+
);
}
});
From 85eb45b5cd8cb443441e1da40bde06dc1caf604c Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 4 Nov 2015 00:41:12 +0100
Subject: [PATCH 022/115] Add small changes for previous merges that were
missed
---
js/components/piece_list.js | 2 +-
.../lumenus/lumenus_buttons/lumenus_acl_button_list.js | 8 +++++++-
.../lumenus_forms/lumenus_additional_data_form.js | 6 ++----
.../wallet/components/lumenus/lumenus_piece_list.js | 6 +++---
js/stores/edition_list_store.js | 2 +-
js/utils/requests.js | 10 +++-------
6 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 3099d31a..69f5b23f 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -184,7 +184,7 @@ let PieceList = React.createClass({
this.fetchSelectedPieceEditionList()
.forEach((pieceId) => {
- EditionListActions.refreshEditionList({pieceId, filterBy: {}});
+ EditionListActions.refreshEditionList({pieceId});
});
EditionListActions.clearAllEditionSelections();
},
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
index b902b93b..76608032 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
@@ -6,6 +6,7 @@ import LumenusSubmitButton from './lumenus_submit_button';
import DeleteButton from '../../../../../ascribe_buttons/delete_button';
import ShareButton from '../../../../../ascribe_buttons/acls/share_button';
+import TransferButton from '../../../../../ascribe_buttons/acls/transfer_button';
import UserActions from '../../../../../../actions/user_actions';
import UserStore from '../../../../../../stores/user_store';
@@ -46,13 +47,18 @@ let LumenusAclButtonList = React.createClass({
+
{this.props.children}
);
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
index e08a8bc7..3e67c21a 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
@@ -28,8 +28,7 @@ let LumenusAdditionalDataForm = React.createClass({
extra_data: React.PropTypes.object,
other_data: React.PropTypes.arrayOf(React.PropTypes.object)
}).isRequired,
- isInline: React.PropTypes.bool,
- location: React.PropTypes.object
+ isInline: React.PropTypes.bool
},
getDefaultProps() {
@@ -125,8 +124,7 @@ let LumenusAdditionalDataForm = React.createClass({
setIsUploadReady={this.setIsUploadReady}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
pieceId={piece.id}
- otherData={piece.other_data}
- location={this.props.location}/>
+ otherData={piece.other_data} />
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
index 14dac214..ccfb7e1c 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
@@ -22,10 +22,10 @@ let LumenusPieceList = React.createClass({
redirectTo="/register_piece?slide_num=0"
bulkModalButtonListType={LumenusAclButtonList}
filterParams={[{
- label: getLangText('Show works I have'),
+ label: getLangText('Show works I can'),
items: [{
- key: 'acl_consigned',
- label: getLangText('consigned to Lumenus')
+ key: 'acl_consign',
+ label: getLangText('consign to Lumenus')
}]
}]}
location={this.props.location}/>
diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js
index 4ccada4e..107f9af4 100644
--- a/js/stores/edition_list_store.js
+++ b/js/stores/edition_list_store.js
@@ -60,7 +60,7 @@ class EditionListStore {
* We often just have to refresh the edition list for a certain pieceId,
* this method provides exactly that functionality without any side effects
*/
- onRefreshEditionList({pieceId, filterBy}) {
+ onRefreshEditionList({pieceId, filterBy = {}}) {
// It may happen that the user enters the site logged in already
// through /editions
// If he then tries to delete a piece/edition and this method is called,
diff --git a/js/utils/requests.js b/js/utils/requests.js
index 8f015a11..112588e0 100644
--- a/js/utils/requests.js
+++ b/js/utils/requests.js
@@ -99,8 +99,7 @@ class Requests {
return newUrl;
}
- request(verb, url, options) {
- options = options || {};
+ request(verb, url, options = {}) {
let merged = Object.assign({}, this.httpOptions, options);
let csrftoken = getCookie(AppConstants.csrftoken);
if (csrftoken) {
@@ -128,13 +127,10 @@ class Requests {
}
_putOrPost(url, paramsAndBody, method) {
- let paramsCopy = Object.assign({}, paramsAndBody);
let params = omitFromObject(paramsAndBody, ['body']);
let newUrl = this.prepareUrl(url, params);
- let body = null;
- if (paramsCopy && paramsCopy.body) {
- body = JSON.stringify(paramsCopy.body);
- }
+ let body = paramsAndBody && paramsAndBody.body ? JSON.stringify(paramsAndBody.body)
+ : null;
return this.request(method, newUrl, { body });
}
From adf0d411d67a06331f1b002f663fb50cf4f9426e Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 5 Nov 2015 11:56:17 +0100
Subject: [PATCH 023/115] Fetch piece data in AdditionalDetailForm
Although this moves state further down the hierarchy, it allows the
AdditionalDataForm to be used more easily. Parent components would
otherwise have to have the piece prop carried down through multiple
levels or create a makeshift object.
---
js/components/ascribe_forms/property.js | 5 +-
.../lumenus_edition_container.js | 10 +-
.../lumenus_detail/lumenus_further_details.js | 31 +-----
.../lumenus_detail/lumenus_piece_container.js | 10 +-
.../lumenus_additional_data_form.js | 99 ++++++++++++++-----
.../lumenus/lumenus_register_piece.js | 58 +++++------
6 files changed, 111 insertions(+), 102 deletions(-)
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index 793be538..b4baf9df 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -31,7 +31,10 @@ let Property = React.createClass({
footer: React.PropTypes.element,
handleChange: React.PropTypes.func,
ignoreFocus: React.PropTypes.bool,
- name: React.PropTypes.string.isRequired,
+ name: React.PropTypes.oneOfType([
+ React.PropTypes.string,
+ React.PropTypes.number
+ ]).isRequired,
className: React.PropTypes.string,
onClick: React.PropTypes.func,
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
index 77cca99c..c81fb0bb 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
@@ -9,18 +9,14 @@ import LumenusAclButtonList from '../lumenus_buttons/lumenus_acl_button_list';
import EditionContainer from '../../../../../ascribe_detail/edition_container';
let LumenusEditionContainer = React.createClass({
- propTypes: {
- params: React.PropTypes.object,
- location: React.PropTypes.object
- },
+ propTypes: EditionContainer.propTypes,
render() {
return (
+ furtherDetailsType={LumenusFurtherDetails} />
);
}
});
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js
index 17dbad20..79199b68 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js
@@ -4,43 +4,20 @@ import React from 'react';
import LumenusAdditionalDataForm from '../lumenus_forms/lumenus_additional_data_form'
-import GlobalNotificationModel from '../../../../../../models/global_notification_model';
-import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
-
-let FurtherDetails = React.createClass({
+let LumenusFurtherDetails = React.createClass({
propTypes: {
pieceId: React.PropTypes.number,
- extraData: React.PropTypes.object,
- otherData: React.PropTypes.arrayOf(React.PropTypes.object),
handleSuccess: React.PropTypes.func,
- location: React.PropTypes.object
- },
-
- showNotification() {
- this.props.handleSuccess();
- let notification = new GlobalNotificationModel('Further details updated', 'success');
- GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
- const { pieceId, extraData, otherData, handleSuccess, location } = this.props;
-
- // Instead of grabbing the entire piece from the PieceStore and making this component
- // stateful, we can put together a piece for the additional form solely based on the props
- const piece = {
- id: pieceId,
- extra_data: extraData,
- other_data: otherData
- };
-
return (
+ showNotification />
);
}
});
-export default FurtherDetails;
+export default LumenusFurtherDetails;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
index 5b7cf8ee..391a7cb5 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
@@ -7,17 +7,13 @@ import LumenusFurtherDetails from './lumenus_further_details';
import PieceContainer from '../../../../../ascribe_detail/piece_container';
let LumenusPieceContainer = React.createClass({
- propTypes: {
- params: React.PropTypes.object,
- location: React.PropTypes.object
- },
+ propTypes: PieceContainer.propTypes,
render() {
return (
+ {...this.props}
+ furtherDetailsType={LumenusFurtherDetails} />
);
}
});
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
index 3e67c21a..3b69ce81 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
@@ -14,38 +14,70 @@ import GlobalNotificationActions from '../../../../../../actions/global_notifica
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
+import PieceActions from '../../../../../../actions/piece_actions';
+import PieceStore from '../../../../../../stores/piece_store';
+
import ApiUrls from '../../../../../../constants/api_urls';
import AppConstants from '../../../../../../constants/application_constants';
import requests from '../../../../../../utils/requests';
+import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
let LumenusAdditionalDataForm = React.createClass({
propTypes: {
- handleSuccess: React.PropTypes.func,
- piece: React.PropTypes.shape({
- id: React.PropTypes.number,
- extra_data: React.PropTypes.object,
- other_data: React.PropTypes.arrayOf(React.PropTypes.object)
- }).isRequired,
- isInline: React.PropTypes.bool
- },
-
- getDefaultProps() {
- return {
- isInline: false
- };
+ pieceId: React.PropTypes.oneOfType([
+ React.PropTypes.number,
+ React.PropTypes.string
+ ]),
+ isInline: React.PropTypes.bool,
+ showHeading: React.PropTypes.bool,
+ showNotification: React.PropTypes.bool,
+ handleSuccess: React.PropTypes.func
},
getInitialState() {
- return {
- isUploadReady: false
- };
+ const pieceStore = PieceStore.getState();
+
+ return mergeOptions(
+ pieceStore,
+ {
+ // Allow the form to be submitted if there's already an additional image uploaded
+ isUploadReady: this.isUploadReadyOnChange(pieceStore.piece),
+ forceUpdateKey: 0,
+ });
},
- handleSuccess() {
- let notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
- GlobalNotificationActions.appendGlobalNotification(notification);
+ componentDidMount() {
+ PieceStore.listen(this.onChange);
+
+ // If the Piece store doesn't already have the piece we want loaded, load it
+ const { pieceId } = this.props;
+ if (pieceId && this.state.piece.id !== pieceId) {
+ PieceActions.fetchOne(pieceId);
+ }
+ },
+
+ componentWillUnmount() {
+ PieceStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+
+ this.setState({
+ // Allow the form to be submitted if the updated piece already has an additional image uploaded
+ isUploadReady: this.isUploadReadyOnChange(state.piece),
+
+ /**
+ * Increment the forceUpdateKey to force the form to rerender on each change
+ *
+ * THIS IS A HACK TO MAKE SURE THE FORM ALWAYS DISPLAYS THE MOST RECENT STATE
+ * BECAUSE SOME OF OUR FORM ELEMENTS DON'T UPDATE FROM PROP CHANGES (ie.
+ * InputTextAreaToggable).
+ */
+ forceUpdateKey: this.state.forceUpdateKey + 1
+ });
},
getFormData() {
@@ -61,10 +93,23 @@ let LumenusAdditionalDataForm = React.createClass({
return {
extradata: extradata,
- piece_id: this.props.piece.id
+ piece_id: this.state.piece.id
};
},
+ isUploadReadyOnChange(piece) {
+ return piece && piece.other_data && piece.other_data.length > 0 ? true : false;
+ },
+
+ handleSuccessWithNotification() {
+ if (typeof this.props.handleSuccess === 'function') {
+ this.props.handleSuccess();
+ }
+
+ let notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ },
+
uploadStarted() {
this.setState({
isUploadReady: false
@@ -78,7 +123,8 @@ let LumenusAdditionalDataForm = React.createClass({
},
render() {
- let { piece, isInline, handleSuccess } = this.props;
+ const { isInline, handleSuccess, showHeading, showNotification } = this.props;
+ const { piece } = this.state;
let buttons, spinner, heading;
if (!isInline) {
@@ -97,13 +143,13 @@ let LumenusAdditionalDataForm = React.createClass({
);
- heading = (
+ heading = showHeading ? (
{getLangText('Provide additional details')}
- );
+ ) : null;
}
if (piece && piece.id) {
@@ -111,8 +157,9 @@ let LumenusAdditionalDataForm = React.createClass({
@@ -144,11 +191,11 @@ let LumenusAdditionalDataForm = React.createClass({
required />
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
index 342c4a32..3d43418d 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_register_piece.js
@@ -13,7 +13,6 @@ import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import UserStore from '../../../../../stores/user_store';
import UserActions from '../../../../../actions/user_actions';
-import PieceStore from '../../../../../stores/piece_store';
import PieceActions from '../../../../../actions/piece_actions';
import PieceListStore from '../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../actions/piece_list_actions';
@@ -35,7 +34,6 @@ let LumenusRegisterPiece = React.createClass({
return mergeOptions(
UserStore.getState(),
PieceListStore.getState(),
- PieceStore.getState(),
{
selectedLicense: 0,
isFineUploaderActive: false,
@@ -46,33 +44,22 @@ let LumenusRegisterPiece = React.createClass({
componentDidMount() {
PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
- PieceStore.listen(this.onChange);
UserActions.fetchCurrentUser();
- let queryParams = this.props.location.query;
-
- // Since every step of this register process is atomic,
- // we may need to enter the process at step 1 or 2.
- // If this is the case, we'll need the piece number to complete submission.
- // It is encoded in the URL as a queryParam and we're checking for it here.
- //
- // We're using 'in' here as we want to know if 'piece_id' is present in the url,
- // we don't care about the value.
- if(queryParams && 'piece_id' in queryParams) {
- PieceActions.fetchOne(queryParams.piece_id);
- }
+ // Reset the piece store to make sure that we don't display old data
+ // if the user repeatedly registers works
+ PieceActions.updatePiece({});
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
- PieceStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
- if(this.state.currentUser && this.state.currentUser.email) {
+ if (this.state.currentUser && this.state.currentUser.email) {
// we should also make the fineuploader component editable again
this.setState({
isFineUploaderActive: true
@@ -80,26 +67,21 @@ let LumenusRegisterPiece = React.createClass({
}
},
- handleRegisterSuccess(response){
+ handleRegisterSuccess(response) {
this.refreshPieceList();
- // also start loading the piece for the next step
- if(response && response.piece) {
- PieceActions.updatePiece({});
+ // Use the response's piece for the next step if available
+ let pieceId = null;
+ if (response && response.piece) {
+ pieceId = response.piece.id;
PieceActions.updatePiece(response.piece);
}
this.incrementStep();
-
- this.refs.slidesContainer.nextSlide({ piece_id: response.piece.id });
+ this.refs.slidesContainer.nextSlide({ piece_id: pieceId });
},
handleAdditionalDataSuccess() {
- // We need to refetch the piece again after submitting the additional data
- // since we want it's otherData to be displayed when the user choses to click
- // on the browsers back button.
- PieceActions.fetchOne(this.state.piece.id);
-
this.refreshPieceList();
this.history.pushState(null, `/collection`);
@@ -107,13 +89,21 @@ let LumenusRegisterPiece = React.createClass({
// We need to increase the step to lock the forms that are already filled out
incrementStep() {
- // also increase step
- let newStep = this.state.step + 1;
this.setState({
- step: newStep
+ step: this.state.step + 1
});
},
+ getPieceFromQueryParam() {
+ const queryParams = this.props.location.query;
+
+ // Since every step of this register process is atomic,
+ // we may need to enter the process at step 1 or 2.
+ // If this is the case, we'll need the piece number to complete submission.
+ // It is encoded in the URL as a queryParam and we're checking for it here.
+ return queryParams && queryParams.piece_id;
+ },
+
refreshPieceList() {
PieceListActions.fetchPieceList(
this.state.page,
@@ -161,7 +151,7 @@ let LumenusRegisterPiece = React.createClass({
type="number"
placeholder="(e.g. 32)"
min={0}
- required/>
+ required />
@@ -172,8 +162,8 @@ let LumenusRegisterPiece = React.createClass({
+ pieceId={this.getPieceFromQueryParam()}
+ showHeading />
From 4ca8ca8feb8a992e89fba0c93380536181497d1c Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 5 Nov 2015 11:58:32 +0100
Subject: [PATCH 024/115] Show AdditionalDetailsModal from SubmitButton when
details need to be filled in
---
.../lumenus_buttons/lumenus_submit_button.js | 102 +++++++++++++++---
1 file changed, 87 insertions(+), 15 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
index 941b3ec0..6722beb7 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
@@ -3,19 +3,30 @@
import React from 'react';
import classNames from 'classnames';
+import LumenusAdditionalDataForm from '../lumenus_forms/lumenus_additional_data_form';
+
import ConsignButton from '../../../../../ascribe_buttons/acls/consign_button';
+import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
+import ConsignForm from '../../../../../ascribe_forms/form_consign';
+
+import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
+
+import PieceActions from '../../../../../../actions/piece_actions';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
+import ApiUrls from '../../../../../../constants/api_urls';
+
+import { getAclFormDataId } from '../../../../../../utils/form_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
let LumenusSubmitButton = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
- currentUser: React.PropTypes.object,
- pieceOrEditions: React.PropTypes.array,
- handleSuccess: React.PropTypes.func,
+ currentUser: React.PropTypes.object.isRequired,
+ editions: React.PropTypes.array.isRequired,
+ handleSuccess: React.PropTypes.func.isRequired,
className: React.PropTypes.string,
},
@@ -25,6 +36,7 @@ let LumenusSubmitButton = React.createClass({
componentDidMount() {
WhitelabelStore.listen(this.onChange);
+
WhitelabelActions.fetchWhitelabel();
},
@@ -36,19 +48,79 @@ let LumenusSubmitButton = React.createClass({
this.setState(state);
},
- render() {
- const { availableAcls, currentUser, className, pieceOrEditions, handleSuccess } = this.props;
+ getFormDataId() {
+ return getAclFormDataId(false, this.props.editions);
+ },
- return (
-
- );
+ getAggregateEditionDetails() {
+ const { editions } = this.props;
+
+ // Currently, we only care if all the given editions are from the same parent piece
+ // and if they can be submitted
+ return editions.reduce((details, curEdition) => {
+ return {
+ solePieceId: details.solePieceId === curEdition.parent ? details.solePieceId : null,
+ canSubmit: details.canSubmit && curEdition.acl.acl_wallet_submit
+ };
+ }, {
+ solePieceId: editions.length > 0 ? editions[0].parent : null,
+ canSubmit: editions.length > 0 ? editions[0].acl.acl_wallet_submit : false
+ });
+ },
+
+ handleAdditionalDataSuccess(pieceId) {
+ // Fetch newly updated piece to update the views
+ PieceActions.fetchOne(pieceId);
+
+ this.refs.consignModal.show();
+ },
+
+ render() {
+ const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
+ const buttonTitle = getLangText('CONSIGN TO LUMENUS');
+
+ const { solePieceId, canSubmit } = this.getAggregateEditionDetails();
+
+ if (solePieceId && !canSubmit) {
+ return (
+
+
+ {buttonTitle}
+
+ }
+ handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
+ title={getLangText('Add additional information')}>
+
+
+
+
+
+
+
+ );
+ } else {
+ return (
+
+ );
+ }
}
});
From 6223248ea03e58c2af3a460455c112a44ee3ab3d Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 5 Nov 2015 13:51:40 +0100
Subject: [PATCH 025/115] Fix lumenus whitelabel api endpoints
---
.../whitelabel/wallet/constants/wallet_api_urls.js | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 87ee6b14..11e29a39 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -4,25 +4,26 @@ import walletConstants from './wallet_application_constants';
// gets subdomain as a parameter
function getWalletApiUrls(subdomain) {
- if (subdomain === 'cyland'){
+ if (subdomain === 'cyland') {
return {
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
'piece_extradata': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/extradata/',
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
- }
- else if (subdomain === 'ikonotv'){
+ } else if (subdomain === 'ikonotv') {
return {
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
- }
- else if (subdomain === 'lumenus'){
+ } else if (subdomain === 'lumenus') {
return {
- 'editions': walletConstants.walletApiEndpoint + subdomain + '/editions/',
+ 'editions_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/editions/',
+ 'edition': walletConstants.walletApiEndpoint + subdomain + '/editions/${edition_id}/',
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
+ 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
+ 'piece_extradata': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/extradata/',
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
}
From 04e453b28cf6041b4c4e92c2f662259ed00f77d8 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 5 Nov 2015 16:05:20 +0100
Subject: [PATCH 026/115] Fix lumenus edition endpoint
---
js/components/whitelabel/wallet/constants/wallet_api_urls.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 11e29a39..27be363d 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -20,7 +20,7 @@ function getWalletApiUrls(subdomain) {
} else if (subdomain === 'lumenus') {
return {
'editions_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/editions/',
- 'edition': walletConstants.walletApiEndpoint + subdomain + '/editions/${edition_id}/',
+ 'edition': walletConstants.walletApiEndpoint + subdomain + '/editions/${bitcoin_id}/',
'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
'piece_extradata': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/extradata/',
From fb62d2d2e0461b2511eb38d55f333e11d9332916 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 6 Nov 2015 14:00:58 +0100
Subject: [PATCH 027/115] Check for completion of additional data on front end
In the end, it made more sense to check if all the additional details
have been filled in on the front end than receiving an acl or flag from
the backend.
---
.../lumenus_buttons/lumenus_submit_button.js | 28 +++++++++++++++----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
index 6722beb7..7046c069 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_submit_button.js
@@ -12,6 +12,8 @@ import ConsignForm from '../../../../../ascribe_forms/form_consign';
import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
+import AclProxy from '../../../../../acl_proxy';
+
import PieceActions from '../../../../../../actions/piece_actions';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
@@ -48,6 +50,20 @@ let LumenusSubmitButton = React.createClass({
this.setState(state);
},
+ canEditionBeSubmitted(edition) {
+ if (edition && edition.extra_data && edition.other_data) {
+ const { extra_data, other_data } = edition;
+
+ if (extra_data.artist_bio && extra_data.work_description &&
+ extra_data.technology_details && extra_data.display_instructions &&
+ other_data.length > 0) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
getFormDataId() {
return getAclFormDataId(false, this.props.editions);
},
@@ -60,11 +76,11 @@ let LumenusSubmitButton = React.createClass({
return editions.reduce((details, curEdition) => {
return {
solePieceId: details.solePieceId === curEdition.parent ? details.solePieceId : null,
- canSubmit: details.canSubmit && curEdition.acl.acl_wallet_submit
+ canSubmit: details.canSubmit && this.canEditionBeSubmitted(curEdition)
};
}, {
solePieceId: editions.length > 0 ? editions[0].parent : null,
- canSubmit: editions.length > 0 ? editions[0].acl.acl_wallet_submit : false
+ canSubmit: this.canEditionBeSubmitted(editions[0])
});
},
@@ -83,7 +99,9 @@ let LumenusSubmitButton = React.createClass({
if (solePieceId && !canSubmit) {
return (
-
+
@@ -107,12 +125,12 @@ let LumenusSubmitButton = React.createClass({
pieceOrEditions={editions}
showNotification />
-
+
);
} else {
return (
Date: Fri, 6 Nov 2015 14:01:26 +0100
Subject: [PATCH 028/115] Show unconsign button
---
.../lumenus/lumenus_buttons/lumenus_acl_button_list.js | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
index 76608032..77657aca 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
@@ -7,6 +7,7 @@ import LumenusSubmitButton from './lumenus_submit_button';
import DeleteButton from '../../../../../ascribe_buttons/delete_button';
import ShareButton from '../../../../../ascribe_buttons/acls/share_button';
import TransferButton from '../../../../../ascribe_buttons/acls/transfer_button';
+import UnconsignButton from '../../../../../ascribe_buttons/acls/transfer_button';
import UserActions from '../../../../../../actions/user_actions';
import UserStore from '../../../../../../stores/user_store';
@@ -59,6 +60,11 @@ let LumenusAclButtonList = React.createClass({
currentUser={this.state.currentUser}
pieceOrEditions={pieceOrEditions}
handleSuccess={handleSuccess} />
+
{this.props.children}
);
From 318a0bf4b2c0f2e8b383342de5a54d4ad117b158 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 6 Nov 2015 14:10:54 +0100
Subject: [PATCH 029/115] Filter the collection to only show the consignable
items by default
---
.../piece_list_bulk_modal.js | 31 -------------------
.../piece_list_toolbar_filter_widget.js | 10 +++---
js/components/piece_list.js | 23 +++++++++++++-
.../components/lumenus/lumenus_piece_list.js | 3 +-
4 files changed, 29 insertions(+), 38 deletions(-)
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 1380f21d..bb8d4ccc 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
@@ -6,12 +6,6 @@ import { mergeOptions } from '../../utils/general_utils';
import EditionListActions from '../../actions/edition_list_actions';
-import UserStore from '../../stores/user_store';
-import UserActions from '../../actions/user_actions';
-
-import PieceListStore from '../../stores/piece_list_store';
-import PieceListActions from '../../actions/piece_list_actions';
-
import PieceListBulkModalSelectedEditionsWidget from './piece_list_bulk_modal_selected_editions_widget';
import { getLangText } from '../../utils/lang_utils.js';
@@ -30,31 +24,6 @@ let PieceListBulkModal = React.createClass({
])
},
- getInitialState() {
- return mergeOptions(
- UserStore.getState(),
- PieceListStore.getState()
- );
- },
-
- componentDidMount() {
- UserStore.listen(this.onChange);
- PieceListStore.listen(this.onChange);
-
- UserActions.fetchCurrentUser();
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
- },
-
- componentWillUnmount() {
- PieceListStore.unlisten(this.onChange);
- UserStore.unlisten(this.onChange);
- },
-
- onChange(state) {
- this.setState(state);
- },
-
clearAllSelections() {
EditionListActions.clearAllEditionSelections();
EditionListActions.closeAllEditionLists();
diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
index 38de2af6..cea41e3b 100644
--- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
+++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
@@ -28,7 +28,7 @@ let PieceListToolbarFilterWidget = React.createClass({
},
generateFilterByStatement(param) {
- let filterBy = this.props.filterBy;
+ const { filterBy } = this.props;
if(filterBy) {
// we need hasOwnProperty since the values are all booleans
@@ -56,13 +56,13 @@ let PieceListToolbarFilterWidget = React.createClass({
*/
filterBy(param) {
return () => {
- let filterBy = this.generateFilterByStatement(param);
+ const filterBy = this.generateFilterByStatement(param);
this.props.applyFilterBy(filterBy);
};
},
isFilterActive() {
- let trueValuesOnly = Object.keys(this.props.filterBy).filter((acl) => acl);
+ const trueValuesOnly = Object.keys(this.props.filterBy).filter((acl) => acl);
// We're hiding the star in that complicated matter so that,
// the surrounding button is not resized up on appearance
@@ -74,7 +74,7 @@ let PieceListToolbarFilterWidget = React.createClass({
},
render() {
- let filterIcon = (
+ const filterIcon = (
*
@@ -140,4 +140,4 @@ let PieceListToolbarFilterWidget = React.createClass({
}
});
-export default PieceListToolbarFilterWidget;
\ No newline at end of file
+export default PieceListToolbarFilterWidget;
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 69f5b23f..1ea64ff6 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -60,11 +60,17 @@ let PieceList = React.createClass({
}]
};
},
+
getInitialState() {
- return mergeOptions(
+ const stores = mergeOptions(
PieceListStore.getState(),
EditionListStore.getState()
);
+
+ // Use the default filters but use the stores' settings if they're available
+ stores.filterBy = Object.assign(this.getDefaultFilterBy(), stores.filterBy);
+
+ return stores;
},
componentDidMount() {
@@ -96,6 +102,21 @@ let PieceList = React.createClass({
this.setState(state);
},
+ getDefaultFilterBy() {
+ const { filterParams } = this.props;
+ const defaultFilterBy = {};
+
+ filterParams.forEach(({ label, items }) => {
+ items.forEach((item) => {
+ if (typeof item === 'object' && item.defaultValue) {
+ defaultFilterBy[item.key] = true;
+ }
+ });
+ });
+
+ return defaultFilterBy;
+ },
+
paginationGoToPage(page) {
return () => {
// if the users clicks a pager of the pagination,
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
index ccfb7e1c..58ad7813 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
@@ -25,7 +25,8 @@ let LumenusPieceList = React.createClass({
label: getLangText('Show works I can'),
items: [{
key: 'acl_consign',
- label: getLangText('consign to Lumenus')
+ label: getLangText('consign to Lumenus'),
+ defaultValue: true
}]
}]}
location={this.props.location}/>
From b100fdd80a35ae138afd2a33c9c9391e50d6f0bc Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 6 Nov 2015 16:13:47 +0100
Subject: [PATCH 030/115] Change default collection filter for lumens admin
---
.../lumenus_acl_button_list.js | 2 +-
.../components/lumenus/lumenus_piece_list.js | 39 +++++++++++++++++--
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
index 77657aca..8398dbda 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
@@ -7,7 +7,7 @@ import LumenusSubmitButton from './lumenus_submit_button';
import DeleteButton from '../../../../../ascribe_buttons/delete_button';
import ShareButton from '../../../../../ascribe_buttons/acls/share_button';
import TransferButton from '../../../../../ascribe_buttons/acls/transfer_button';
-import UnconsignButton from '../../../../../ascribe_buttons/acls/transfer_button';
+import UnconsignButton from '../../../../../ascribe_buttons/acls/unconsign_button';
import UserActions from '../../../../../../actions/user_actions';
import UserStore from '../../../../../../stores/user_store';
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
index 58ad7813..ebf90b3c 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_piece_list.js
@@ -6,15 +6,48 @@ import LumenusAclButtonList from './lumenus_buttons/lumenus_acl_button_list';
import PieceList from '../../../../piece_list';
-import { getLangText } from '../../../../../utils/lang_utils';
+import UserActions from '../../../../../actions/user_actions';
+import UserStore from '../../../../../stores/user_store';
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
+
import { setDocumentTitle } from '../../../../../utils/dom_utils';
+import { mergeOptions } from '../../../../../utils/general_utils';
+import { getLangText } from '../../../../../utils/lang_utils';
let LumenusPieceList = React.createClass({
propTypes: {
location: React.PropTypes.object
},
+ getInitialState() {
+ return mergeOptions(
+ UserStore.getState(),
+ WhitelabelStore.getState()
+ );
+ },
+
+ componentDidMount() {
+ UserStore.listen(this.onChange);
+ WhitelabelStore.listen(this.onChange);
+
+ UserActions.fetchCurrentUser();
+ WhitelabelActions.fetchWhitelabel();
+ },
+
+ componentWillUnmount() {
+ UserStore.unlisten(this.onChange);
+ WhitelabelStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
render() {
+ const { currentUser, whitelabel } = this.state;
+ const isUserAdmin = currentUser.email === whitelabel.user;
+
setDocumentTitle(getLangText('Collection'));
return (
@@ -24,8 +57,8 @@ let LumenusPieceList = React.createClass({
filterParams={[{
label: getLangText('Show works I can'),
items: [{
- key: 'acl_consign',
- label: getLangText('consign to Lumenus'),
+ key: isUserAdmin ? 'acl_transfer' : 'acl_consign',
+ label: getLangText(isUserAdmin ? 'transfer' : 'consign to Lumenus'),
defaultValue: true
}]
}]}
From 84e8e4612f23809c4ff19c719a1bc0df9450f731 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 10 Nov 2015 18:24:46 +0100
Subject: [PATCH 031/115] Autofocus message field in consignment form and use
custom labels
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
For now, we’ll let the artist specify their suggested price in the
consignment form’s message field.
---
.../ascribe_buttons/acls/acl_button.js | 2 +-
.../ascribe_forms/acl_form_factory.js | 10 ++-
js/components/ascribe_forms/form_consign.js | 24 ++++---
.../ascribe_forms/input_textarea_toggable.js | 6 ++
.../list_form_request_actions.js | 4 +-
js/components/ascribe_forms/property.js | 7 ++
.../lumenus_buttons/lumenus_submit_button.js | 64 +++++++++++--------
.../lumenus_additional_data_form.js | 6 +-
js/utils/form_utils.js | 4 ++
9 files changed, 84 insertions(+), 43 deletions(-)
diff --git a/js/components/ascribe_buttons/acls/acl_button.js b/js/components/ascribe_buttons/acls/acl_button.js
index 82650bb6..8b21f92a 100644
--- a/js/components/ascribe_buttons/acls/acl_button.js
+++ b/js/components/ascribe_buttons/acls/acl_button.js
@@ -31,7 +31,7 @@ export default function ({ action, displayName, title, tooltip }) {
availableAcls: React.PropTypes.object.isRequired,
buttonAcceptName: React.PropTypes.string,
buttonAcceptClassName: React.PropTypes.string,
- currentUser: React.PropTypes.object.isRequired,
+ currentUser: React.PropTypes.object,
email: React.PropTypes.string,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
diff --git a/js/components/ascribe_forms/acl_form_factory.js b/js/components/ascribe_forms/acl_form_factory.js
index d5494c2d..9422a351 100644
--- a/js/components/ascribe_forms/acl_form_factory.js
+++ b/js/components/ascribe_forms/acl_form_factory.js
@@ -20,9 +20,11 @@ import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils';
let AclFormFactory = React.createClass({
propTypes: {
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
- currentUser: React.PropTypes.object.isRequired,
+ autoFocusProperty: React.PropTypes.string,
+ currentUser: React.PropTypes.object,
email: React.PropTypes.string,
message: React.PropTypes.string,
+ labels: React.PropTypes.object,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
@@ -53,10 +55,12 @@ let AclFormFactory = React.createClass({
render() {
const {
action,
+ autoFocusProperty,
pieceOrEditions,
currentUser,
email,
message,
+ labels,
handleSuccess,
showNotification } = this.props;
@@ -64,14 +68,16 @@ let AclFormFactory = React.createClass({
aclName: action,
entities: pieceOrEditions,
isPiece: this.isPiece(),
- senderName: currentUser.username
+ senderName: currentUser && currentUser.username
});
if (action === 'acl_consign') {
return (
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index b8417961..c659610d 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -17,8 +17,10 @@ let ConsignForm = React.createClass({
propTypes: {
url: React.PropTypes.string,
id: React.PropTypes.object,
+ autoFocusProperty: React.PropTypes.string,
email: React.PropTypes.string,
message: React.PropTypes.string,
+ labels: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
@@ -27,10 +29,12 @@ let ConsignForm = React.createClass({
},
render() {
+ const { autoFocusProperty, email, id, handleSuccess, message, labels, url } = this.props;
+
return (
}>
+ label={labels.email || getLangText('Email')}
+ editable={!email}
+ overrideForm={!!email}>
+ label={labels.message || getLangText('Personal Message')}
+ editable
+ overrideForm>
diff --git a/js/components/ascribe_forms/input_textarea_toggable.js b/js/components/ascribe_forms/input_textarea_toggable.js
index c17a0e5a..0be8b87a 100644
--- a/js/components/ascribe_forms/input_textarea_toggable.js
+++ b/js/components/ascribe_forms/input_textarea_toggable.js
@@ -7,6 +7,7 @@ import TextareaAutosize from 'react-textarea-autosize';
let InputTextAreaToggable = React.createClass({
propTypes: {
+ autoFocus: React.PropTypes.bool,
disabled: React.PropTypes.bool,
rows: React.PropTypes.number.isRequired,
required: React.PropTypes.bool,
@@ -23,6 +24,10 @@ let InputTextAreaToggable = React.createClass({
},
componentDidMount() {
+ if (this.props.autoFocus) {
+ this.refs.textarea.focus();
+ }
+
this.setState({
value: this.props.defaultValue
});
@@ -51,6 +56,7 @@ let InputTextAreaToggable = React.createClass({
className = className + ' ascribe-textarea-editable';
textarea = (
+ {getLangText('CONSIGN TO LUMENUS')}
+
+ );
+ const consignForm = (
+
+ );
if (solePieceId && !canSubmit) {
return (
@@ -103,11 +124,7 @@ let LumenusSubmitButton = React.createClass({
aclObject={availableAcls}
aclName='acl_consign'>
- {buttonTitle}
-
- }
+ trigger={triggerButton}
handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
title={getLangText('Add additional information')}>
-
+ {consignForm}
);
} else {
return (
-
+
+
+ {consignForm}
+
+
);
}
}
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
index 3b69ce81..2fbf5679 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
@@ -51,10 +51,8 @@ let LumenusAdditionalDataForm = React.createClass({
componentDidMount() {
PieceStore.listen(this.onChange);
- // If the Piece store doesn't already have the piece we want loaded, load it
- const { pieceId } = this.props;
- if (pieceId && this.state.piece.id !== pieceId) {
- PieceActions.fetchOne(pieceId);
+ if (this.props.pieceId) {
+ PieceActions.fetchOne(this.props.pieceId);
}
},
diff --git a/js/utils/form_utils.js b/js/utils/form_utils.js
index d2d2cd29..8d12a8c1 100644
--- a/js/utils/form_utils.js
+++ b/js/utils/form_utils.js
@@ -72,6 +72,10 @@ export function getAclFormMessage(options) {
throw new Error('Your specified aclName did not match a an acl class.');
}
+ if (options.additionalMessage) {
+ message += '\n\n' + options.additionalMessage;
+ }
+
if (options.senderName) {
message += '\n\n';
message += getLangText('Truly yours,');
From e85747144aacb402df4f1795c5240b23472522aa Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 10 Nov 2015 18:49:08 +0100
Subject: [PATCH 032/115] Add Lumenus landing page
---
.../components/lumenus/lumenus_landing.js | 82 +++++++++++++++++++
.../whitelabel/wallet/wallet_routes.js | 2 +
2 files changed, 84 insertions(+)
create mode 100644 js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
new file mode 100644
index 00000000..279327d5
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
@@ -0,0 +1,82 @@
+'use strict';
+
+import React from 'react';
+
+import Button from 'react-bootstrap/lib/Button';
+import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
+
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
+
+import { mergeOptions } from '../../../../../utils/general_utils';
+import { getLangText } from '../../../../../utils/lang_utils';
+import { setDocumentTitle } from '../../../../../utils/dom_utils';
+
+
+let LumenusLanding = React.createClass({
+
+ getInitialState() {
+ return mergeOptions(
+ WhitelabelStore.getState()
+ );
+ },
+
+ componentDidMount() {
+ WhitelabelStore.listen(this.onChange);
+ WhitelabelActions.fetchWhitelabel();
+ },
+
+ componentWillUnmount() {
+ WhitelabelStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
+ render() {
+ setDocumentTitle('Lumenus Marketplace');
+
+ return (
+
+
+
+
+
+
+ {getLangText('Artwork from the Lumenus Marketplace is powered by') + ' '}
+
+
+
+
+
+
+
+
+ {getLangText('Existing ascribe user?')}
+
+
+
+ {getLangText('Log in')}
+
+
+
+
+
+ {getLangText('Do you need an account?')}
+
+
+
+ {getLangText('Sign up')}
+
+
+
+
+
+
+
+ );
+ }
+});
+
+export default LumenusLanding;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 9b0e9465..86b3474a 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -29,6 +29,7 @@ import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
+import LumenusLanding from './components/lumenus/lumenus_landing';
import LumenusPieceList from './components/lumenus/lumenus_piece_list';
import LumenusRegisterPiece from './components/lumenus/lumenus_register_piece';
import LumenusPieceContainer from './components/lumenus/lumenus_detail/lumenus_piece_container';
@@ -157,6 +158,7 @@ let ROUTES = {
),
'lumenus': (
+
From c0e0354ce832f106747f68f6a0d135a08d088a8f Mon Sep 17 00:00:00 2001
From: Cevo
Date: Fri, 20 Nov 2015 11:11:03 +0100
Subject: [PATCH 033/115] fixing the public note bug
---
js/components/ascribe_detail/piece_container.js | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 8cd7df1c..1914e3af 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -57,6 +57,7 @@ let PieceContainer = React.createClass({
mixins: [History],
getInitialState() {
+ console.log('Piece initially ... ', PieceStore.getState());
return mergeOptions(
UserStore.getState(),
PieceListStore.getState(),
@@ -103,7 +104,6 @@ let PieceContainer = React.createClass({
let pieceState = mergeOptions({}, state.piece);
pieceState.acl.acl_loan = false;
-
this.setState({
piece: pieceState
});
@@ -273,14 +273,17 @@ let PieceContainer = React.createClass({
currentUser={this.state.currentUser}/>
+ {console.log('hey')}
+ {console.log(this.state.piece)}
+ {console.log(this.state.piece.acl.acl_edit)}
Date: Fri, 20 Nov 2015 11:47:41 +0100
Subject: [PATCH 034/115] piece note hidden from non-owner
---
js/components/ascribe_detail/piece_container.js | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 1914e3af..d0ca2e1e 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -57,7 +57,6 @@ let PieceContainer = React.createClass({
mixins: [History],
getInitialState() {
- console.log('Piece initially ... ', PieceStore.getState());
return mergeOptions(
UserStore.getState(),
PieceListStore.getState(),
@@ -252,7 +251,6 @@ let PieceContainer = React.createClass({
}
buttons={this.getActions()}>
{this.getCreateEditionsDialog()}
-
0}>
@@ -261,7 +259,8 @@ let PieceContainer = React.createClass({
+ show={(!!(this.state.currentUser.username || this.state.piece.public_note)) &&
+ (!!this.state.piece.acl.acl_edit)}>
- {console.log('hey')}
- {console.log(this.state.piece)}
- {console.log(this.state.piece.acl.acl_edit)}
Date: Mon, 23 Nov 2015 10:46:20 +0100
Subject: [PATCH 035/115] Check for piece and edition validity by using their
ids instead of titles
Also removed a few unnecessary location props.
---
js/components/ascribe_detail/edition.js | 6 ++----
js/components/ascribe_detail/edition_container.js | 8 +++-----
js/components/ascribe_detail/further_details.js | 6 ++----
js/components/ascribe_detail/piece_container.js | 8 +++-----
4 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index 6b38ddf8..254746a6 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -42,8 +42,7 @@ import { getLangText } from '../../utils/lang_utils';
let Edition = React.createClass({
propTypes: {
edition: React.PropTypes.object,
- loadEdition: React.PropTypes.func,
- location: React.PropTypes.object
+ loadEdition: React.PropTypes.func
},
mixins: [History],
@@ -156,8 +155,7 @@ let Edition = React.createClass({
pieceId={this.props.edition.parent}
extraData={this.props.edition.extra_data}
otherData={this.props.edition.other_data}
- handleSuccess={this.props.loadEdition}
- location={this.props.location}/>
+ handleSuccess={this.props.loadEdition} />
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index 2c479d24..febe652d 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -17,8 +17,7 @@ import { setDocumentTitle } from '../../utils/dom_utils';
*/
let EditionContainer = React.createClass({
propTypes: {
- params: React.PropTypes.object,
- location: React.PropTypes.object
+ params: React.PropTypes.object
},
getInitialState() {
@@ -67,14 +66,13 @@ let EditionContainer = React.createClass({
},
render() {
- if(this.state.edition && this.state.edition.title) {
+ if(this.state.edition && this.state.edition.id) {
setDocumentTitle([this.state.edition.artist_name, this.state.edition.title].join(', '));
return (
+ loadEdition={this.loadEdition} />
);
} else {
return (
diff --git a/js/components/ascribe_detail/further_details.js b/js/components/ascribe_detail/further_details.js
index 91ce87c5..c178fb93 100644
--- a/js/components/ascribe_detail/further_details.js
+++ b/js/components/ascribe_detail/further_details.js
@@ -23,8 +23,7 @@ let FurtherDetails = React.createClass({
pieceId: React.PropTypes.number,
extraData: React.PropTypes.object,
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
- handleSuccess: React.PropTypes.func,
- location: React.PropTypes.object
+ handleSuccess: React.PropTypes.func
},
getInitialState() {
@@ -86,8 +85,7 @@ let FurtherDetails = React.createClass({
overrideForm={true}
pieceId={this.props.pieceId}
otherData={this.props.otherData}
- multiple={true}
- location={this.props.location}/>
+ multiple={true} />
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 8cd7df1c..cde6eaea 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -50,8 +50,7 @@ import { setDocumentTitle } from '../../utils/dom_utils';
*/
let PieceContainer = React.createClass({
propTypes: {
- params: React.PropTypes.object,
- location: React.PropTypes.object
+ params: React.PropTypes.object
},
mixins: [History],
@@ -226,7 +225,7 @@ let PieceContainer = React.createClass({
},
render() {
- if(this.state.piece && this.state.piece.title) {
+ if(this.state.piece && this.state.piece.id) {
setDocumentTitle([this.state.piece.artist_name, this.state.piece.title].join(', '));
return (
@@ -292,8 +291,7 @@ let PieceContainer = React.createClass({
pieceId={this.state.piece.id}
extraData={this.state.piece.extra_data}
otherData={this.state.piece.other_data}
- handleSuccess={this.loadPiece}
- location={this.props.location}/>
+ handleSuccess={this.loadPiece} />
From e4cafd4bc3df86e8da992db6bd61c39b120dddaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 23 Nov 2015 19:02:28 +0100
Subject: [PATCH 036/115] Fix bug in FB button component & simplify injectHead
util
---
.../ascribe_buttons/acl_button_list.js | 2 +-
.../facebook_share_button.js | 16 ++++++-------
js/utils/inject_utils.js | 23 ++++++++-----------
3 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js
index 42f86320..35e42c20 100644
--- a/js/components/ascribe_buttons/acl_button_list.js
+++ b/js/components/ascribe_buttons/acl_button_list.js
@@ -41,7 +41,7 @@ let AclButtonList = React.createClass({
componentDidMount() {
UserStore.listen(this.onChange);
- UserActions.fetchCurrentUser();
+ UserActions.fetchCurrentUser.defer();
window.addEventListener('resize', this.handleResize);
window.dispatchEvent(new Event('resize'));
diff --git a/js/components/ascribe_social_share/facebook_share_button.js b/js/components/ascribe_social_share/facebook_share_button.js
index 87a2aef6..aa0b6691 100644
--- a/js/components/ascribe_social_share/facebook_share_button.js
+++ b/js/components/ascribe_social_share/facebook_share_button.js
@@ -8,7 +8,6 @@ import { InjectInHeadUtils } from '../../utils/inject_utils';
let FacebookShareButton = React.createClass({
propTypes: {
- url: React.PropTypes.string,
type: React.PropTypes.string
},
@@ -28,12 +27,14 @@ let FacebookShareButton = React.createClass({
* To circumvent this, we always have the sdk parse the entire DOM on the initial load
* (see FacebookHandler) and then use FB.XFBML.parse() on the mounting component later.
*/
- if (!InjectInHeadUtils.isPresent('script', AppConstants.facebook.sdkUrl)) {
- InjectInHeadUtils.inject(AppConstants.facebook.sdkUrl);
- } else {
- // Parse() searches the children of the element we give it, not the element itself.
- FB.XFBML.parse(this.refs.fbShareButton.getDOMNode().parentElement);
- }
+
+ InjectInHeadUtils
+ .inject(AppConstants.facebook.sdkUrl)
+ .then(() => { FB.XFBML.parse(this.refs.fbShareButton.getDOMNode().parentElement) });
+ },
+
+ shouldComponentUpdate(nextProps) {
+ return this.props.type !== nextProps.type;
},
render() {
@@ -41,7 +42,6 @@ let FacebookShareButton = React.createClass({
);
diff --git a/js/utils/inject_utils.js b/js/utils/inject_utils.js
index 174ac8b6..e9430a5e 100644
--- a/js/utils/inject_utils.js
+++ b/js/utils/inject_utils.js
@@ -12,16 +12,16 @@ let mapTag = {
css: 'link'
};
+let tags = {};
+
function injectTag(tag, src) {
- return Q.Promise((resolve, reject) => {
- if (isPresent(tag, src)) {
- resolve();
- } else {
+ if(!tags[src]) {
+ tags[src] = Q.Promise((resolve, reject) => {
let attr = mapAttr[tag];
let element = document.createElement(tag);
if (tag === 'script') {
- element.onload = () => resolve();
- element.onerror = () => reject();
+ element.onload = resolve;
+ element.onerror = reject;
} else {
resolve();
}
@@ -30,14 +30,10 @@ function injectTag(tag, src) {
if (tag === 'link') {
element.rel = 'stylesheet';
}
- }
- });
-}
+ });
+ }
-function isPresent(tag, src) {
- let attr = mapAttr[tag];
- let query = `head > ${tag}[${attr}="${src}"]`;
- return document.querySelector(query);
+ return tags[src];
}
function injectStylesheet(src) {
@@ -65,7 +61,6 @@ export const InjectInHeadUtils = {
* you don't want to embed everything inside the build file.
*/
- isPresent,
injectStylesheet,
injectScript,
inject
From f7b55e56a9f0e53be1cd231d668e436448fff2db Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 12:04:08 +0100
Subject: [PATCH 037/115] Split Lumenus into a generic market wallet for 23vivi
---
.../lumenus_edition_container.js | 24 -------------------
.../market_buttons/market_acl_button_list.js} | 12 +++++-----
.../market_buttons/market_submit_button.js} | 12 +++++-----
.../market_detail/market_edition_container.js | 24 +++++++++++++++++++
.../market_detail/market_further_details.js} | 8 +++----
.../market_detail/market_piece_container.js} | 8 +++----
.../market_additional_data_form.js} | 8 +++----
.../market_piece_list.js} | 10 ++++----
.../market_register_piece.js} | 10 ++++----
.../whitelabel/wallet/wallet_routes.js | 22 ++++++++---------
10 files changed, 69 insertions(+), 69 deletions(-)
delete mode 100644 js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_buttons/lumenus_acl_button_list.js => market/market_buttons/market_acl_button_list.js} (88%)
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_buttons/lumenus_submit_button.js => market/market_buttons/market_submit_button.js} (93%)
create mode 100644 js/components/whitelabel/wallet/components/market/market_detail/market_edition_container.js
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_detail/lumenus_further_details.js => market/market_detail/market_further_details.js} (58%)
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_detail/lumenus_piece_container.js => market/market_detail/market_piece_container.js} (56%)
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_forms/lumenus_additional_data_form.js => market/market_forms/market_additional_data_form.js} (97%)
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_piece_list.js => market/market_piece_list.js} (88%)
rename js/components/whitelabel/wallet/components/{lumenus/lumenus_register_piece.js => market/market_register_piece.js} (96%)
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
deleted file mode 100644
index c81fb0bb..00000000
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_edition_container.js
+++ /dev/null
@@ -1,24 +0,0 @@
-'use strict';
-
-import React from 'react';
-
-import LumenusFurtherDetails from './lumenus_further_details';
-
-import LumenusAclButtonList from '../lumenus_buttons/lumenus_acl_button_list';
-
-import EditionContainer from '../../../../../ascribe_detail/edition_container';
-
-let LumenusEditionContainer = React.createClass({
- propTypes: EditionContainer.propTypes,
-
- render() {
- return (
-
- );
- }
-});
-
-export default LumenusEditionContainer;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
similarity index 88%
rename from js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
rename to js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
index 8398dbda..1dcdd4e5 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_buttons/lumenus_acl_button_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
@@ -2,17 +2,17 @@
import React from 'react';
-import LumenusSubmitButton from './lumenus_submit_button';
+import MarketSubmitButton from './market_submit_button';
import DeleteButton from '../../../../../ascribe_buttons/delete_button';
-import ShareButton from '../../../../../ascribe_buttons/acls/share_button';
+import EmailButton from '../../../../../ascribe_buttons/acls/email_button';
import TransferButton from '../../../../../ascribe_buttons/acls/transfer_button';
import UnconsignButton from '../../../../../ascribe_buttons/acls/unconsign_button';
import UserActions from '../../../../../../actions/user_actions';
import UserStore from '../../../../../../stores/user_store';
-let LumenusAclButtonList = React.createClass({
+let MarketAclButtonList = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
className: React.PropTypes.string,
@@ -45,12 +45,12 @@ let LumenusAclButtonList = React.createClass({
let { availableAcls, className, pieceOrEditions, handleSuccess } = this.props;
return (
-
-
- {getLangText('CONSIGN TO LUMENUS')}
+ {getLangText('CONSIGN TO TODO')}
);
const consignForm = (
@@ -127,7 +127,7 @@ let LumenusSubmitButton = React.createClass({
trigger={triggerButton}
handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
title={getLangText('Add additional information')}>
-
@@ -147,7 +147,7 @@ let LumenusSubmitButton = React.createClass({
+ title={getLangText('Consign artwork to TODO')}>
{consignForm}
@@ -156,4 +156,4 @@ let LumenusSubmitButton = React.createClass({
}
});
-export default LumenusSubmitButton;
+export default MarketSubmitButton;
diff --git a/js/components/whitelabel/wallet/components/market/market_detail/market_edition_container.js b/js/components/whitelabel/wallet/components/market/market_detail/market_edition_container.js
new file mode 100644
index 00000000..97284dbc
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/market/market_detail/market_edition_container.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import MarketFurtherDetails from './market_further_details';
+
+import MarketAclButtonList from '../market_buttons/market_acl_button_list';
+
+import EditionContainer from '../../../../../ascribe_detail/edition_container';
+
+let MarketEditionContainer = React.createClass({
+ propTypes: EditionContainer.propTypes,
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default MarketEditionContainer;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js b/js/components/whitelabel/wallet/components/market/market_detail/market_further_details.js
similarity index 58%
rename from js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js
rename to js/components/whitelabel/wallet/components/market/market_detail/market_further_details.js
index 79199b68..4e1e3ee8 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_further_details.js
+++ b/js/components/whitelabel/wallet/components/market/market_detail/market_further_details.js
@@ -2,9 +2,9 @@
import React from 'react';
-import LumenusAdditionalDataForm from '../lumenus_forms/lumenus_additional_data_form'
+import MarketAdditionalDataForm from '../market_forms/market_additional_data_form'
-let LumenusFurtherDetails = React.createClass({
+let MarketFurtherDetails = React.createClass({
propTypes: {
pieceId: React.PropTypes.number,
handleSuccess: React.PropTypes.func,
@@ -12,7 +12,7 @@ let LumenusFurtherDetails = React.createClass({
render() {
return (
-
@@ -20,4 +20,4 @@ let LumenusFurtherDetails = React.createClass({
}
});
-export default LumenusFurtherDetails;
+export default MarketFurtherDetails;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js b/js/components/whitelabel/wallet/components/market/market_detail/market_piece_container.js
similarity index 56%
rename from js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
rename to js/components/whitelabel/wallet/components/market/market_detail/market_piece_container.js
index 391a7cb5..d41ade56 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_detail/lumenus_piece_container.js
+++ b/js/components/whitelabel/wallet/components/market/market_detail/market_piece_container.js
@@ -2,20 +2,20 @@
import React from 'react';
-import LumenusFurtherDetails from './lumenus_further_details';
+import MarketFurtherDetails from './market_further_details';
import PieceContainer from '../../../../../ascribe_detail/piece_container';
-let LumenusPieceContainer = React.createClass({
+let MarketPieceContainer = React.createClass({
propTypes: PieceContainer.propTypes,
render() {
return (
+ furtherDetailsType={MarketFurtherDetails} />
);
}
});
-export default LumenusPieceContainer;
+export default MarketPieceContainer;
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
similarity index 97%
rename from js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
rename to js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
index 2fbf5679..a2318b99 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_forms/lumenus_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
@@ -24,7 +24,7 @@ import requests from '../../../../../../utils/requests';
import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
-let LumenusAdditionalDataForm = React.createClass({
+let MarketAdditionalDataForm = React.createClass({
propTypes: {
pieceId: React.PropTypes.oneOfType([
React.PropTypes.number,
@@ -163,7 +163,7 @@ let LumenusAdditionalDataForm = React.createClass({
spinner={spinner}>
{heading}
0}
enableLocalHashing={false}
- headerMessage={getLangText('Consign to Lumenus')}
+ headerMessage={getLangText('Consign to Market')}
submitMessage={getLangText('Proceed to additional details')}
isFineUploaderActive={this.state.isFineUploaderActive}
handleSuccess={this.handleRegisterSuccess}
@@ -160,7 +160,7 @@ let LumenusRegisterPiece = React.createClass({
-
@@ -172,4 +172,4 @@ let LumenusRegisterPiece = React.createClass({
}
});
-export default LumenusRegisterPiece;
+export default MarketRegisterPiece;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 86b3474a..85e79924 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -15,7 +15,8 @@ import EditionContainer from '../../../components/ascribe_detail/edition_contain
import SettingsContainer from '../../../components/ascribe_settings/settings_container';
import ContractSettings from '../../../components/ascribe_settings/contract_settings';
import ErrorNotFoundPage from '../../../components/error_not_found_page';
-import RegisterPiece from '../../../components/register_piece'; //TODO: Remove once finished with LumenusRegisterPiece
+
+import CCRegisterPiece from './components/cc/cc_register_piece';
import CylandLanding from './components/cyland/cyland_landing';
import CylandPieceContainer from './components/cyland/cyland_detail/cyland_piece_container';
@@ -29,13 +30,12 @@ import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
-import LumenusLanding from './components/lumenus/lumenus_landing';
-import LumenusPieceList from './components/lumenus/lumenus_piece_list';
-import LumenusRegisterPiece from './components/lumenus/lumenus_register_piece';
-import LumenusPieceContainer from './components/lumenus/lumenus_detail/lumenus_piece_container';
-import LumenusEditionContainer from './components/lumenus/lumenus_detail/lumenus_edition_container';
+import MarketPieceList from './components/market/market_piece_list';
+import MarketRegisterPiece from './components/market/market_register_piece';
+import MarketPieceContainer from './components/market/market_detail/market_piece_container';
+import MarketEditionContainer from './components/market/market_detail/market_edition_container';
-import CCRegisterPiece from './components/cc/cc_register_piece';
+import LumenusLanding from './components/lumenus/lumenus_landing';
import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
@@ -179,14 +179,14 @@ let ROUTES = {
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
-
-
+
+
From ee61369d46aff112c6aaec6d583218f13be4ea58 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 12:04:18 +0100
Subject: [PATCH 038/115] Update market api endpoints
---
.../whitelabel/wallet/constants/wallet_api_urls.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 27be363d..56088b03 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -19,12 +19,12 @@ function getWalletApiUrls(subdomain) {
};
} else if (subdomain === 'lumenus') {
return {
- 'editions_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/editions/',
- 'edition': walletConstants.walletApiEndpoint + subdomain + '/editions/${bitcoin_id}/',
- 'pieces_list': walletConstants.walletApiEndpoint + subdomain + '/pieces/',
- 'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
- 'piece_extradata': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/extradata/',
- 'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
+ 'editions_list': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/editions/',
+ 'edition': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/editions/${bitcoin_id}/',
+ 'pieces_list': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/',
+ 'piece': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/',
+ 'piece_extradata': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/extradata/',
+ 'user': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/users/'
};
}
return {};
From a72fea5db4f919f2672c997781904b6e7eb79e90 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 12:08:37 +0100
Subject: [PATCH 039/115] Add 23vivi routes
---
.../wallet/constants/wallet_api_urls.js | 2 +-
.../whitelabel/wallet/wallet_routes.js | 44 +++++++++++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index 56088b03..cebe4aa6 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -17,7 +17,7 @@ function getWalletApiUrls(subdomain) {
'piece': walletConstants.walletApiEndpoint + subdomain + '/pieces/${piece_id}/',
'user': walletConstants.walletApiEndpoint + subdomain + '/users/'
};
- } else if (subdomain === 'lumenus') {
+ } else if (subdomain === 'lumenus' || subdomain === '23vivi') {
return {
'editions_list': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/editions/',
'edition': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/editions/${bitcoin_id}/',
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 85e79924..08adec44 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -190,10 +190,54 @@ let ROUTES = {
+ ),
+ '23vivi': (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
)
};
+function getRoutes(commonRoutes, subdomain) {
+ if(subdomain in ROUTES) {
+ return ROUTES[subdomain];
+ } else {
+ throw new Error('Subdomain wasn\'t specified in the wallet app.');
+ }
+};
+
+
function getRoutes(commonRoutes, subdomain) {
if(subdomain in ROUTES) {
return ROUTES[subdomain];
From 2e03ab584a874918a51df8428cf25f2a301e9b97 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 18:17:38 +0100
Subject: [PATCH 040/115] Fix api endpoints
---
.../whitelabel/wallet/constants/wallet_api_urls.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/js/components/whitelabel/wallet/constants/wallet_api_urls.js b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
index cebe4aa6..8ad2eb81 100644
--- a/js/components/whitelabel/wallet/constants/wallet_api_urls.js
+++ b/js/components/whitelabel/wallet/constants/wallet_api_urls.js
@@ -19,12 +19,12 @@ function getWalletApiUrls(subdomain) {
};
} else if (subdomain === 'lumenus' || subdomain === '23vivi') {
return {
- 'editions_list': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/editions/',
- 'edition': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/editions/${bitcoin_id}/',
- 'pieces_list': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/',
- 'piece': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/',
- 'piece_extradata': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/pieces/${piece_id}/extradata/',
- 'user': walletConstants.walletApiEndpoint + 'market/' + subdomain + '/users/'
+ 'editions_list': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/pieces/${piece_id}/editions/',
+ 'edition': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/editions/${bitcoin_id}/',
+ 'pieces_list': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/pieces/',
+ 'piece': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/pieces/${piece_id}/',
+ 'piece_extradata': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/pieces/${piece_id}/extradata/',
+ 'user': walletConstants.walletApiEndpoint + 'markets/' + subdomain + '/users/'
};
}
return {};
From 47f56b5505bcd7e9ad06c50c07be61010165c06f Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 18:17:51 +0100
Subject: [PATCH 041/115] Add 23vivi to app costs
---
js/constants/application_constants.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js
index 70a9be89..1f2129da 100644
--- a/js/constants/application_constants.js
+++ b/js/constants/application_constants.js
@@ -58,6 +58,13 @@ const constants = {
'permissions': ['register', 'edit', 'share', 'del_from_collection'],
'type': 'wallet'
},
+ {
+ 'subdomain': '23vivi',
+ 'name': '23vivi',
+ 'logo': 'https://s3-us-west-2.amazonaws.com/ascribe0/whitelabel/23vivi/23vivi-logo.png',
+ 'permissions': ['register', 'edit', 'share', 'del_from_collection'],
+ 'type': 'wallet'
+ },
{
'subdomain': 'portfolioreview',
'name': 'Portfolio Review',
From e228a4bf153cb9dec93612153438005cae184198 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 18:18:49 +0100
Subject: [PATCH 042/115] Dynamically get marketplace name for submit button
---
.../market/market_buttons/market_submit_button.js | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index 5ad9f995..6a617bfb 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -91,6 +91,7 @@ let MarketSubmitButton = React.createClass({
render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
+ const { whitelabel } = this.state;
const { solePieceId, canSubmit } = this.getAggregateEditionDetails();
const message = getAclFormMessage({
aclName: 'acl_consign',
@@ -102,14 +103,14 @@ let MarketSubmitButton = React.createClass({
const triggerButton = (
- {getLangText('CONSIGN TO TODO')}
+ {getLangText('CONSIGN TO %s', whitelabel.name.toUpperCase())}
);
const consignForm = (
+ title={getLangText('Consign artwork to %s', whitelabel.name)}>
{consignForm}
From c270977eb92f3cd87ccb5ca2b20bcbbe38e930cc Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Tue, 24 Nov 2015 19:26:45 +0100
Subject: [PATCH 043/115] Fix default filter on piece list
---
.../piece_list_toolbar_filter_widget.js | 2 +-
js/components/piece_list.js | 121 ++++++++++++------
.../components/lumenus/lumenus_landing.js | 6 +-
.../components/market/market_piece_list.js | 33 +++--
js/utils/general_utils.js | 6 +
package.json | 1 +
6 files changed, 114 insertions(+), 55 deletions(-)
diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
index cea41e3b..c463330c 100644
--- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
+++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar_filter_widget.js
@@ -28,7 +28,7 @@ let PieceListToolbarFilterWidget = React.createClass({
},
generateFilterByStatement(param) {
- const { filterBy } = this.props;
+ const filterBy = Object.assign({}, this.props.filterBy);
if(filterBy) {
// we need hasOwnProperty since the values are all booleans
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 1ea64ff6..758edf7c 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -26,7 +26,7 @@ import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar';
import AscribeSpinner from './ascribe_spinner';
import { getAvailableAcls } from '../utils/acl_utils';
-import { mergeOptions } from '../utils/general_utils';
+import { mergeOptions, isShallowEqual } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils';
import { setDocumentTitle } from '../utils/dom_utils';
@@ -35,6 +35,7 @@ let PieceList = React.createClass({
propTypes: {
accordionListItemType: React.PropTypes.func,
bulkModalButtonListType: React.PropTypes.func,
+ canLoadPieceList: React.PropTypes.bool,
redirectTo: React.PropTypes.string,
customSubmitButton: React.PropTypes.element,
filterParams: React.PropTypes.array,
@@ -49,6 +50,7 @@ let PieceList = React.createClass({
return {
accordionListItemType: AccordionListItemWallet,
bulkModalButtonListType: AclButtonList,
+ canLoadPieceList: true,
orderParams: ['artist_name', 'title'],
filterParams: [{
label: getLangText('Show works I can'),
@@ -62,27 +64,51 @@ let PieceList = React.createClass({
},
getInitialState() {
+ const pieceListStore = PieceListStore.getState();
const stores = mergeOptions(
- PieceListStore.getState(),
- EditionListStore.getState()
+ pieceListStore,
+ EditionListStore.getState(),
+ {
+ isFilterDirty: false
+ }
);
- // Use the default filters but use the stores' settings if they're available
- stores.filterBy = Object.assign(this.getDefaultFilterBy(), stores.filterBy);
+ // Use the default filters but use the pieceListStore's settings if they're available
+ stores.filterBy = Object.assign(this.getDefaultFilterBy(), pieceListStore.filterBy);
return stores;
},
componentDidMount() {
- let page = this.props.location.query.page || 1;
-
PieceListStore.listen(this.onChange);
EditionListStore.listen(this.onChange);
- let orderBy = this.props.orderBy ? this.props.orderBy : this.state.orderBy;
- if (this.state.pieceList.length === 0 || this.state.page !== page){
- PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
- orderBy, this.state.orderAsc, this.state.filterBy);
+ let page = this.props.location.query.page || 1;
+ if (this.props.canLoadPieceList && (this.state.pieceList.length === 0 || this.state.page !== page)) {
+ this.loadPieceList({ page });
+ }
+ },
+
+ componentWillReceiveProps(nextProps) {
+ let filterBy;
+ let page = this.props.location.query.page || 1;
+
+ // If the user hasn't changed the filter and the new default filter is different
+ // than the current filter, apply the new default filter
+ if (!this.state.isFilterDirty) {
+ const newDefaultFilterBy = this.getDefaultFilterBy(nextProps);
+
+ // Only need to check shallowly since the filterBy shouldn't be nested
+ if (!isShallowEqual(this.state.filterBy, newDefaultFilterBy)) {
+ filterBy = newDefaultFilterBy;
+ page = 1;
+ }
+ }
+
+ // Only load if we are applying a new filter or if it's the first time we can
+ // load the piece list
+ if (nextProps.canLoadPieceList && (filterBy || !this.props.canLoadPieceList)) {
+ this.loadPieceList({ page, filterBy });
}
},
@@ -102,17 +128,19 @@ let PieceList = React.createClass({
this.setState(state);
},
- getDefaultFilterBy() {
- const { filterParams } = this.props;
+ getDefaultFilterBy(props = this.props) {
+ const { filterParams } = props;
const defaultFilterBy = {};
- filterParams.forEach(({ label, items }) => {
- items.forEach((item) => {
- if (typeof item === 'object' && item.defaultValue) {
- defaultFilterBy[item.key] = true;
- }
+ if (filterParams && typeof filterParams.forEach === 'function') {
+ filterParams.forEach(({ label, items }) => {
+ items.forEach((item) => {
+ if (typeof item === 'object' && item.defaultValue) {
+ defaultFilterBy[item.key] = true;
+ }
+ });
});
- });
+ }
return defaultFilterBy;
},
@@ -122,9 +150,7 @@ let PieceList = React.createClass({
// if the users clicks a pager of the pagination,
// the site should go to the top
document.body.scrollTop = document.documentElement.scrollTop = 0;
- PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc,
- this.state.filterBy);
+ this.loadPieceList({ page });
};
},
@@ -143,29 +169,35 @@ let PieceList = React.createClass({
},
searchFor(searchTerm) {
- PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy,
- this.state.orderAsc, this.state.filterBy);
- this.history.pushState(null, this.props.location.pathname, {page: 1});
+ this.loadPieceList({
+ page: 1,
+ search: searchTerm
+ });
+ this.history.pushState(null, this.props.location.pathname, {page: 1});
},
applyFilterBy(filterBy){
- // first we need to apply the filter on the piece list
- PieceListActions.fetchPieceList(1, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, filterBy)
- .then(() => {
- // but also, we need to filter all the open edition lists
- this.state.pieceList
- .forEach((piece) => {
- // but only if they're actually open
- if(this.state.isEditionListOpenForPieceId[piece.id].show) {
- EditionListActions.refreshEditionList({
- pieceId: piece.id,
- filterBy
- });
- }
+ this.setState({
+ isFilterDirty: true
+ });
- });
- });
+ // first we need to apply the filter on the piece list
+ this
+ .loadPieceList({ page: 1, filterBy })
+ .then(() => {
+ // but also, we need to filter all the open edition lists
+ this.state.pieceList
+ .forEach((piece) => {
+ // but only if they're actually open
+ if(this.state.isEditionListOpenForPieceId[piece.id].show) {
+ EditionListActions.refreshEditionList({
+ pieceId: piece.id,
+ filterBy
+ });
+ }
+
+ });
+ });
// we have to redirect the user always to page one as it could be that there is no page two
// for filtered pieces
@@ -177,6 +209,13 @@ let PieceList = React.createClass({
orderBy, this.state.orderAsc, this.state.filterBy);
},
+ loadPieceList({ page, filterBy = this.state.filterBy, search = this.state.search }) {
+ let orderBy = this.state.orderBy ? this.state.orderBy : this.props.orderBy;
+
+ return PieceListActions.fetchPieceList(page, this.state.pageSize, search,
+ orderBy, this.state.orderAsc, filterBy);
+ },
+
fetchSelectedPieceEditionList() {
let filteredPieceIdList = Object.keys(this.state.editionList)
.filter((pieceId) => {
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
index 279327d5..e68b1781 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
@@ -21,6 +21,10 @@ let LumenusLanding = React.createClass({
);
},
+ componentWillMount() {
+ setDocumentTitle('Lumenus Marketplace');
+ },
+
componentDidMount() {
WhitelabelStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
@@ -35,8 +39,6 @@ let LumenusLanding = React.createClass({
},
render() {
- setDocumentTitle('Lumenus Marketplace');
-
return (
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index 90564f2b..64198bb3 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -27,6 +27,10 @@ let MarketPieceList = React.createClass({
);
},
+ componentWillMount() {
+ setDocumentTitle(getLangText('Collection'));
+ },
+
componentDidMount() {
UserStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
@@ -46,23 +50,30 @@ let MarketPieceList = React.createClass({
render() {
const { currentUser, whitelabel } = this.state;
- const isUserAdmin = currentUser.email === whitelabel.user;
+ let filterParams = undefined;
+ let canLoadPieceList = false;
- setDocumentTitle(getLangText('Collection'));
+ if (currentUser.email && whitelabel.user) {
+ canLoadPieceList = true;
+ const isUserAdmin = currentUser.email === whitelabel.user;
+
+ filterParams = [{
+ label: getLangText('Show works I can'),
+ items: [{
+ key: isUserAdmin ? 'acl_transfer' : 'acl_consign',
+ label: getLangText(isUserAdmin ? 'transfer' : 'consign to %s', whitelabel.name),
+ defaultValue: true
+ }]
+ }];
+ }
return (
+ filterParams={filterParams}
+ location={this.props.location} />
);
}
});
diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js
index 8283f8cf..e81a806d 100644
--- a/js/utils/general_utils.js
+++ b/js/utils/general_utils.js
@@ -1,5 +1,11 @@
'use strict';
+/**
+ * Checks shallow equality
+ * Re-export of shallow from shallow-equals
+ */
+export { default as isShallowEqual } from 'shallow-equals';
+
/**
* Takes an object and returns a shallow copy without any keys
* that fail the passed in filter function.
diff --git a/package.json b/package.json
index 63c6d1e0..fbae7243 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"react-star-rating": "~1.3.2",
"react-textarea-autosize": "^2.5.2",
"reactify": "^1.1.0",
+ "shallow-equals": "0.0.0",
"shmui": "^0.1.0",
"spark-md5": "~1.0.0",
"uglifyjs": "^2.4.10",
From 5423f5dcd7b17bdabcd25f11f39f2974a74e0d27 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 25 Nov 2015 11:16:09 +0100
Subject: [PATCH 044/115] Bug fix for collapsing nav
---
js/components/contract_notification.js | 36 --------------------------
js/components/header.js | 20 +++++++++++---
2 files changed, 17 insertions(+), 39 deletions(-)
delete mode 100644 js/components/contract_notification.js
diff --git a/js/components/contract_notification.js b/js/components/contract_notification.js
deleted file mode 100644
index cd6ceb53..00000000
--- a/js/components/contract_notification.js
+++ /dev/null
@@ -1,36 +0,0 @@
-'use strict';
-
-import React from 'react';
-
-import NotificationStore from '../stores/notification_store';
-
-import { mergeOptions } from '../utils/general_utils';
-
-let ContractNotification = React.createClass({
- getInitialState() {
- return mergeOptions(
- NotificationStore.getState()
- );
- },
-
- componentDidMount() {
- NotificationStore.listen(this.onChange);
- },
-
- componentWillUnmount() {
- NotificationStore.unlisten(this.onChange);
- },
-
- onChange(state) {
- this.setState(state);
- },
-
- render() {
-
- return (
- null
- );
- }
-});
-
-export default ContractNotification;
\ No newline at end of file
diff --git a/js/components/header.js b/js/components/header.js
index 51f91318..7c2331f9 100644
--- a/js/components/header.js
+++ b/js/components/header.js
@@ -1,9 +1,10 @@
'use strict';
import React from 'react';
-
import { Link } from 'react-router';
+import history from '../history';
+
import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav';
@@ -58,11 +59,17 @@ let Header = React.createClass({
UserStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
WhitelabelStore.listen(this.onChange);
+
+ // react-bootstrap 0.25.1 has a bug in which it doesn't
+ // close the mobile expanded navigation after a click by itself.
+ // To get rid of this, we set the state of the component ourselves.
+ history.listen(this.onRouteChange);
},
componentWillUnmount() {
UserStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
+ history.unlisten(this.onRouteChange);
},
getLogo() {
@@ -135,6 +142,11 @@ let Header = React.createClass({
this.refs.dropdownbutton.setDropdownState(false);
},
+ // On route change, close expanded navbar again
+ onRouteChange() {
+ this.refs.navbar.state.navExpanded = false;
+ },
+
render() {
let account;
let signup;
@@ -201,8 +213,10 @@ let Header = React.createClass({
-
+ fixedTop={true}
+ ref="navbar">
+
{this.getPoweredBy()}
From 121a1dbb8d5ce7b176e841ce93a738af1b9ae95b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 25 Nov 2015 15:00:56 +0100
Subject: [PATCH 045/115] Bump react-router to 1.0.0 because of found bug
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 63c6d1e0..83ce69e3 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"react": "0.13.2",
"react-bootstrap": "0.25.1",
"react-datepicker": "^0.12.0",
- "react-router": "^1.0.0-rc3",
+ "react-router": "1.0.0",
"react-router-bootstrap": "^0.19.0",
"react-star-rating": "~1.3.2",
"react-textarea-autosize": "^2.5.2",
From 88d1edd45c78e1e971de3c2e69d3e2cc73a12f63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 25 Nov 2015 15:01:23 +0100
Subject: [PATCH 046/115] Add pageExitWarning for SlidesContainer
---
.../proxy_routes/auth_proxy_handler.js | 6 ++++--
.../ascribe_slides_container/slides_container.js | 14 ++++++++++----
.../components/ikonotv/ikonotv_register_piece.js | 13 +++++++++----
3 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js b/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js
index b2d552a7..0eb4ad8f 100644
--- a/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js
+++ b/js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js
@@ -1,7 +1,7 @@
'use strict';
import React from 'react';
-import { History } from 'react-router';
+import { History, RouteContext } from 'react-router';
import UserStore from '../../../stores/user_store';
import UserActions from '../../../actions/user_actions';
@@ -37,7 +37,9 @@ export default function AuthProxyHandler({to, when}) {
location: object
},
- mixins: [History],
+ // We need insert `RouteContext` here in order to be able
+ // to use the `Lifecycle` widget in further down nested components
+ mixins: [History, RouteContext],
getInitialState() {
return UserStore.getState();
diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js
index 8ed66c1d..39d515a3 100644
--- a/js/components/ascribe_slides_container/slides_container.js
+++ b/js/components/ascribe_slides_container/slides_container.js
@@ -1,7 +1,7 @@
'use strict';
import React from 'react/addons';
-import { History } from 'react-router';
+import { History, Lifecycle } from 'react-router';
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
@@ -17,14 +17,16 @@ const SlidesContainer = React.createClass({
pending: string,
complete: string
}),
- location: object
+ location: object,
+ pageExitWarning: string
},
- mixins: [History],
+ mixins: [History, Lifecycle],
getInitialState() {
return {
- containerWidth: 0
+ containerWidth: 0,
+ pageExitWarning: null
};
},
@@ -41,6 +43,10 @@ const SlidesContainer = React.createClass({
window.removeEventListener('resize', this.handleContainerResize);
},
+ routerWillLeave() {
+ return this.props.pageExitWarning;
+ },
+
handleContainerResize() {
this.setState({
// +30 to get rid of the padding of the container which is 15px + 15px left and right
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
index 98fe6715..d3f93ddf 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
@@ -32,6 +32,7 @@ import ApiUrls from '../../../../../constants/api_urls';
import { mergeOptions } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
+
let IkonotvRegisterPiece = React.createClass({
propTypes: {
handleSuccess: React.PropTypes.func,
@@ -47,7 +48,8 @@ let IkonotvRegisterPiece = React.createClass({
PieceListStore.getState(),
PieceStore.getState(),
{
- step: 0
+ step: 0,
+ pageExitWarning: getLangText("If you leave this form now, your work will not be loaned to Ikono TV.")
});
},
@@ -94,7 +96,6 @@ let IkonotvRegisterPiece = React.createClass({
handleRegisterSuccess(response){
-
this.refreshPieceList();
// also start loading the piece for the next step
@@ -108,7 +109,6 @@ let IkonotvRegisterPiece = React.createClass({
this.incrementStep();
this.refs.slidesContainer.nextSlide();
}
-
},
handleAdditionalDataSuccess() {
@@ -126,6 +126,8 @@ let IkonotvRegisterPiece = React.createClass({
},
handleLoanSuccess(response) {
+ this.setState({ pageExitWarning: null });
+
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
@@ -238,6 +240,8 @@ let IkonotvRegisterPiece = React.createClass({
},
render() {
+ const { pageExitWarning } = this.state;
+
return (
+ location={this.props.location}
+ pageExitWarning={pageExitWarning}>
From e482caaa994c579fb68602ae7c90f4e3077db4bb Mon Sep 17 00:00:00 2001
From: Cevo
Date: Wed, 25 Nov 2015 21:43:15 +0100
Subject: [PATCH 047/115] public note is visible outside
---
js/components/ascribe_detail/piece_container.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index d0ca2e1e..6fb7b16c 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -259,12 +259,12 @@ let PieceContainer = React.createClass({
+ show={(!!(this.state.currentUser.username || this.state.piece.public_note))}>
Date: Thu, 26 Nov 2015 11:45:40 +0100
Subject: [PATCH 048/115] Bump Rackt/History to 1.13.1
Gracefully handle when sessionStorage is unavailable
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 63c6d1e0..30d70815 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"gulp-uglify": "^1.2.0",
"gulp-util": "^3.0.4",
"harmonize": "^1.4.2",
- "history": "^1.11.1",
+ "history": "^1.13.1",
"invariant": "^2.1.1",
"isomorphic-fetch": "^2.0.2",
"jest-cli": "^0.4.0",
From 1c25f8e7765aaba2eb4f663200e3a9dbdb40f1e7 Mon Sep 17 00:00:00 2001
From: diminator
Date: Fri, 27 Nov 2015 03:24:37 +0100
Subject: [PATCH 049/115] webhooks in settings without acl
---
js/actions/webhook_actions.js | 47 ++++++
.../ascribe_settings/settings_container.js | 2 +
.../ascribe_settings/webhook_settings.js | 151 ++++++++++++++++++
js/constants/api_urls.js | 3 +
js/fetchers/webhook_fetcher.js | 23 +++
js/stores/webhook_store.js | 27 ++++
6 files changed, 253 insertions(+)
create mode 100644 js/actions/webhook_actions.js
create mode 100644 js/components/ascribe_settings/webhook_settings.js
create mode 100644 js/fetchers/webhook_fetcher.js
create mode 100644 js/stores/webhook_store.js
diff --git a/js/actions/webhook_actions.js b/js/actions/webhook_actions.js
new file mode 100644
index 00000000..4e5b2462
--- /dev/null
+++ b/js/actions/webhook_actions.js
@@ -0,0 +1,47 @@
+'use strict';
+
+import { alt } from '../alt';
+import WebhookFetcher from '../fetchers/webhook_fetcher';
+
+
+class WebhookActions {
+ constructor() {
+ this.generateActions(
+ 'updateWebhooks',
+ 'updateEvents',
+ 'removeWebhook'
+ );
+ }
+
+ fetchWebhooks() {
+ WebhookFetcher.fetch()
+ .then((res) => {
+ this.actions.updateWebhooks(res.webhooks);
+ })
+ .catch((err) => {
+ console.logGlobal(err);
+ });
+ }
+
+ fetchWebhookEvents() {
+ WebhookFetcher.fetchEvents()
+ .then((res) => {
+ this.actions.updateEvents(res.events);
+ })
+ .catch((err) => {
+ console.logGlobal(err);
+ });
+ }
+
+ deleteWebhook(id){
+ WebhookFetcher.deleteWebhook(id)
+ .then((res) => {
+ this.actions.removeWebhook(id);
+ })
+ .catch((err) => {
+ console.logGlobal(err);
+ });
+ }
+}
+
+export default alt.createActions(WebhookActions);
diff --git a/js/components/ascribe_settings/settings_container.js b/js/components/ascribe_settings/settings_container.js
index 5b05e708..35a6fbe5 100644
--- a/js/components/ascribe_settings/settings_container.js
+++ b/js/components/ascribe_settings/settings_container.js
@@ -11,6 +11,7 @@ import WhitelabelActions from '../../actions/whitelabel_actions';
import AccountSettings from './account_settings';
import BitcoinWalletSettings from './bitcoin_wallet_settings';
import APISettings from './api_settings';
+import WebhookSettings from './webhook_settings';
import AclProxy from '../acl_proxy';
@@ -70,6 +71,7 @@ let SettingsContainer = React.createClass({
aclName="acl_view_settings_api">
+
diff --git a/js/components/ascribe_settings/webhook_settings.js b/js/components/ascribe_settings/webhook_settings.js
new file mode 100644
index 00000000..1f9eefc5
--- /dev/null
+++ b/js/components/ascribe_settings/webhook_settings.js
@@ -0,0 +1,151 @@
+'use strict';
+
+import React from 'react';
+
+import WebhookStore from '../../stores/webhook_store';
+import WebhookActions from '../../actions/webhook_actions';
+
+import GlobalNotificationModel from '../../models/global_notification_model';
+import GlobalNotificationActions from '../../actions/global_notification_actions';
+
+import Form from '../ascribe_forms/form';
+import Property from '../ascribe_forms/property';
+
+import ActionPanel from '../ascribe_panel/action_panel';
+import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
+
+import ApiUrls from '../../constants/api_urls';
+import AscribeSpinner from '../ascribe_spinner';
+
+import { getLangText } from '../../utils/lang_utils';
+
+
+let WebhookSettings = React.createClass({
+ propTypes: {
+ defaultExpanded: React.PropTypes.bool
+ },
+
+ getInitialState() {
+ return WebhookStore.getState();
+ },
+
+ componentDidMount() {
+ WebhookStore.listen(this.onChange);
+ WebhookActions.fetchWebhooks();
+ WebhookActions.fetchWebhookEvents();
+ },
+
+ componentWillUnmount() {
+ WebhookStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
+ onDeleteWebhook(event) {
+ let webhookId = event.target.getAttribute('data-id');
+ WebhookActions.deleteWebhook(webhookId);
+
+ let notification = new GlobalNotificationModel(getLangText('Webhook deleted'), 'success', 2000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ },
+
+ handleCreateSuccess() {
+ WebhookActions.fetchWebhooks();
+ let notification = new GlobalNotificationModel(getLangText('Webhook successfully created'), 'success', 5000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ },
+
+ getWebhooks(){
+ let content = ;
+
+ if (this.state.webhooks.length > -1) {
+ content = this.state.webhooks.map(function(webhook, i) {
+ const event = webhook.event.split('.')[0];
+ return (
+
+
+ {event.toUpperCase()}
+
+
+ {webhook.target}
+
+
+ }
+ buttons={
+
+
+
+ {getLangText('DELETE')}
+
+
+
+ }/>
+ );
+ }, this);
+ }
+ return content;
+ },
+
+ getEvents() {
+ if (this.state.events && this.state.events.length > 1) {
+ return (
+
+
+ {this.state.events.map((event, i) => {
+ return (
+
+ { event.toUpperCase() }
+
+ );
+ })}
+
+ );
+ }
+ return null;
+ },
+
+
+ render() {
+ return (
+
+
+ { this.getEvents() }
+
+
+
+
+
+
+ Usage: curl <url> -H 'Authorization: Bearer <token>'
+
+ {this.getWebhooks()}
+
+ );
+ }
+});
+
+export default WebhookSettings;
\ No newline at end of file
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js
index a07f29b1..e7f11141 100644
--- a/js/constants/api_urls.js
+++ b/js/constants/api_urls.js
@@ -72,6 +72,9 @@ let ApiUrls = {
'users_username': AppConstants.apiEndpoint + 'users/username/',
'users_profile': AppConstants.apiEndpoint + 'users/profile/',
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/',
+ 'webhook': AppConstants.apiEndpoint + 'webhooks/${webhook_id}/',
+ 'webhooks': AppConstants.apiEndpoint + 'webhooks/',
+ 'webhooks_events': AppConstants.apiEndpoint + 'webhooks/events/',
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
'delete_s3_file': AppConstants.serverUrl + 's3/delete/',
'prize_list': AppConstants.apiEndpoint + 'prize/'
diff --git a/js/fetchers/webhook_fetcher.js b/js/fetchers/webhook_fetcher.js
new file mode 100644
index 00000000..20775c81
--- /dev/null
+++ b/js/fetchers/webhook_fetcher.js
@@ -0,0 +1,23 @@
+'use strict';
+
+import requests from '../utils/requests';
+
+let WebhookFetcher = {
+ /**
+ * Fetch the registered webhooks of a user from the API.
+ */
+ fetch() {
+ return requests.get('webhooks');
+ },
+
+ deleteWebhook(id) {
+ return requests.delete('webhook', {'webhook_id': id });
+ },
+
+ fetchEvents() {
+ return requests.get('webhooks_events');
+ }
+
+};
+
+export default WebhookFetcher;
diff --git a/js/stores/webhook_store.js b/js/stores/webhook_store.js
new file mode 100644
index 00000000..95b081a6
--- /dev/null
+++ b/js/stores/webhook_store.js
@@ -0,0 +1,27 @@
+'use strict';
+
+import { alt } from '../alt';
+import WebhookActions from '../actions/webhook_actions';
+
+
+class WebhookStore {
+ constructor() {
+ this.webhooks = {};
+ this.events = {};
+ this.bindActions(WebhookActions);
+ }
+
+ onUpdateWebhooks(webhooks) {
+ this.webhooks = webhooks;
+ }
+
+ onUpdateEvents(events) {
+ this.events = events;
+ }
+
+ onRemoveWebhook(id) {
+ this.webhooks = this.webhooks.filter((webhook) => webhook.id !== parseInt(id));
+ }
+}
+
+export default alt.createStore(WebhookStore, 'WebhookStore');
From 7146f00c0510566a00f8a91f79a84c1e844dcdb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Fri, 27 Nov 2015 13:36:42 +0100
Subject: [PATCH 050/115] Refactor webhooks: add source, clear state on create
hide create on no items left
---
js/actions/webhook_actions.js | 40 ++--------
.../ascribe_settings/webhook_settings.js | 65 +++++++++--------
.../components/pr_login_container.js | 0
js/fetchers/webhook_fetcher.js | 23 ------
js/sources/webhook_source.js | 46 ++++++++++++
js/stores/webhook_store.js | 73 +++++++++++++++++--
6 files changed, 153 insertions(+), 94 deletions(-)
create mode 100644 js/components/whitelabel/prize/portfolioreview/components/pr_login_container.js
delete mode 100644 js/fetchers/webhook_fetcher.js
create mode 100644 js/sources/webhook_source.js
diff --git a/js/actions/webhook_actions.js b/js/actions/webhook_actions.js
index 4e5b2462..f9555ce7 100644
--- a/js/actions/webhook_actions.js
+++ b/js/actions/webhook_actions.js
@@ -1,47 +1,19 @@
'use strict';
import { alt } from '../alt';
-import WebhookFetcher from '../fetchers/webhook_fetcher';
class WebhookActions {
constructor() {
this.generateActions(
- 'updateWebhooks',
- 'updateEvents',
- 'removeWebhook'
+ 'fetchWebhooks',
+ 'successFetchWebhooks',
+ 'fetchWebhookEvents',
+ 'successFetchWebhookEvents',
+ 'removeWebhook',
+ 'successRemoveWebhook'
);
}
-
- fetchWebhooks() {
- WebhookFetcher.fetch()
- .then((res) => {
- this.actions.updateWebhooks(res.webhooks);
- })
- .catch((err) => {
- console.logGlobal(err);
- });
- }
-
- fetchWebhookEvents() {
- WebhookFetcher.fetchEvents()
- .then((res) => {
- this.actions.updateEvents(res.events);
- })
- .catch((err) => {
- console.logGlobal(err);
- });
- }
-
- deleteWebhook(id){
- WebhookFetcher.deleteWebhook(id)
- .then((res) => {
- this.actions.removeWebhook(id);
- })
- .catch((err) => {
- console.logGlobal(err);
- });
- }
}
export default alt.createActions(WebhookActions);
diff --git a/js/components/ascribe_settings/webhook_settings.js b/js/components/ascribe_settings/webhook_settings.js
index 1f9eefc5..18c21aa6 100644
--- a/js/components/ascribe_settings/webhook_settings.js
+++ b/js/components/ascribe_settings/webhook_settings.js
@@ -11,6 +11,8 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
+import AclProxy from '../acl_proxy';
+
import ActionPanel from '../ascribe_panel/action_panel';
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
@@ -43,16 +45,18 @@ let WebhookSettings = React.createClass({
this.setState(state);
},
- onDeleteWebhook(event) {
- let webhookId = event.target.getAttribute('data-id');
- WebhookActions.deleteWebhook(webhookId);
+ onRemoveWebhook(webhookId) {
+ return (event) => {
+ WebhookActions.removeWebhook(webhookId);
- let notification = new GlobalNotificationModel(getLangText('Webhook deleted'), 'success', 2000);
- GlobalNotificationActions.appendGlobalNotification(notification);
+ let notification = new GlobalNotificationModel(getLangText('Webhook deleted'), 'success', 2000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ };
},
handleCreateSuccess() {
- WebhookActions.fetchWebhooks();
+ this.refs.webhookCreateForm.reset();
+ WebhookActions.fetchWebhooks(true);
let notification = new GlobalNotificationModel(getLangText('Webhook successfully created'), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
@@ -60,7 +64,7 @@ let WebhookSettings = React.createClass({
getWebhooks(){
let content = ;
- if (this.state.webhooks.length > -1) {
+ if (this.state.webhooks) {
content = this.state.webhooks.map(function(webhook, i) {
const event = webhook.event.split('.')[0];
return (
@@ -82,8 +86,7 @@ let WebhookSettings = React.createClass({
+ onClick={this.onRemoveWebhook(webhook.id)}>
{getLangText('DELETE')}
@@ -96,14 +99,13 @@ let WebhookSettings = React.createClass({
},
getEvents() {
- if (this.state.events && this.state.events.length > 1) {
+ if (this.state.webhookEvents && this.state.webhookEvents.length) {
return (
-
- {this.state.events.map((event, i) => {
+ label={getLangText('Select the event to trigger a webhook', '...')}>
+
+ {this.state.webhookEvents.map((event, i) => {
return (
-
- { this.getEvents() }
-
-
-
-
-
-
- Usage: curl <url> -H 'Authorization: Bearer <token>'
-
+
+
+ { this.getEvents() }
+
+
+
+
+
+
{this.getWebhooks()}
);
diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_login_container.js b/js/components/whitelabel/prize/portfolioreview/components/pr_login_container.js
new file mode 100644
index 00000000..e69de29b
diff --git a/js/fetchers/webhook_fetcher.js b/js/fetchers/webhook_fetcher.js
deleted file mode 100644
index 20775c81..00000000
--- a/js/fetchers/webhook_fetcher.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-
-import requests from '../utils/requests';
-
-let WebhookFetcher = {
- /**
- * Fetch the registered webhooks of a user from the API.
- */
- fetch() {
- return requests.get('webhooks');
- },
-
- deleteWebhook(id) {
- return requests.delete('webhook', {'webhook_id': id });
- },
-
- fetchEvents() {
- return requests.get('webhooks_events');
- }
-
-};
-
-export default WebhookFetcher;
diff --git a/js/sources/webhook_source.js b/js/sources/webhook_source.js
new file mode 100644
index 00000000..5351c89c
--- /dev/null
+++ b/js/sources/webhook_source.js
@@ -0,0 +1,46 @@
+'use strict';
+
+import requests from '../utils/requests';
+
+import WebhookActions from '../actions/webhook_actions';
+
+
+const WebhookSource = {
+ lookupWebhooks: {
+ remote() {
+ return requests.get('webhooks');
+ },
+ local(state) {
+ return state.webhooks && !Object.keys(state.webhooks).length ? state : {};
+ },
+ success: WebhookActions.successFetchWebhooks,
+ error: WebhookActions.errorWebhooks,
+ shouldFetch(state) {
+ return state.webhookMeta.invalidateCache || state.webhooks && !Object.keys(state.webhooks).length;
+ }
+ },
+
+ lookupWebhookEvents: {
+ remote() {
+ return requests.get('webhooks_events');
+ },
+ local(state) {
+ return state.webhookEvents && !Object.keys(state.webhookEvents).length ? state : {};
+ },
+ success: WebhookActions.successFetchWebhookEvents,
+ error: WebhookActions.errorWebhookEvents,
+ shouldFetch(state) {
+ return state.webhookEventsMeta.invalidateCache || state.webhookEvents && !Object.keys(state.webhookEvents).length;
+ }
+ },
+
+ performRemoveWebhook: {
+ remote(state) {
+ return requests.delete('webhook', {'webhook_id': state.webhookMeta.idToDelete });
+ },
+ success: WebhookActions.successRemoveWebhook,
+ error: WebhookActions.errorWebhooks
+ }
+};
+
+export default WebhookSource;
\ No newline at end of file
diff --git a/js/stores/webhook_store.js b/js/stores/webhook_store.js
index 95b081a6..7dfcc61d 100644
--- a/js/stores/webhook_store.js
+++ b/js/stores/webhook_store.js
@@ -3,24 +3,85 @@
import { alt } from '../alt';
import WebhookActions from '../actions/webhook_actions';
+import WebhookSource from '../sources/webhook_source';
class WebhookStore {
constructor() {
- this.webhooks = {};
- this.events = {};
+ this.webhooks = [];
+ this.webhookEvents = [];
+ this.webhookMeta = {
+ invalidateCache: false,
+ err: null,
+ idToDelete: null
+ };
+ this.webhookEventsMeta = {
+ invalidateCache: false,
+ err: null
+ };
+
this.bindActions(WebhookActions);
+ this.registerAsync(WebhookSource);
}
- onUpdateWebhooks(webhooks) {
+ onFetchWebhooks(invalidateCache) {
+ this.webhookMeta.invalidateCache = invalidateCache;
+ this.getInstance().lookupWebhooks();
+ }
+
+ onSuccessFetchWebhooks({ webhooks }) {
+ this.webhookMeta.invalidateCache = false;
+ this.webhookMeta.err = null;
this.webhooks = webhooks;
+
+ this.webhookEventsMeta.invalidateCache = true;
+ this.getInstance().lookupWebhookEvents();
}
- onUpdateEvents(events) {
- this.events = events;
+ onFetchWebhookEvents(invalidateCache) {
+ this.webhookEventsMeta.invalidateCache = invalidateCache;
+ this.getInstance().lookupWebhookEvents();
+ }
+
+ onSuccessFetchWebhookEvents({ events }) {
+ this.webhookEventsMeta.invalidateCache = false;
+ this.webhookEventsMeta.err = null;
+
+ // remove all events that have already been used.
+ const usedEvents = this.webhooks
+ .reduce((tempUsedEvents, webhook) => {
+ tempUsedEvents.push(webhook.event.split('.')[0]);
+ return tempUsedEvents;
+ }, []);
+
+ this.webhookEvents = events.filter((event) => {
+ return usedEvents.indexOf(event) === -1;
+ });
}
onRemoveWebhook(id) {
- this.webhooks = this.webhooks.filter((webhook) => webhook.id !== parseInt(id));
+ this.webhookMeta.invalidateCache = true;
+ this.webhookMeta.idToDelete = id;
+
+ if(!this.getInstance().isLoading()) {
+ this.getInstance().performRemoveWebhook();
+ }
+ }
+
+ onSuccessRemoveWebhook() {
+ this.webhookMeta.idToDelete = null;
+ if(!this.getInstance().isLoading()) {
+ this.getInstance().lookupWebhooks();
+ }
+ }
+
+ onErrorWebhooks(err) {
+ console.logGlobal(err);
+ this.webhookMeta.err = err;
+ }
+
+ onErrorWebhookEvents(err) {
+ console.logGlobal(err);
+ this.webhookEventsMeta.err = err;
}
}
From 5137fa01a9ce9927e6f9d5986ad280a3feafcad0 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 27 Nov 2015 14:13:30 +0100
Subject: [PATCH 051/115] Add note for navBar state hack
---
js/components/header.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/js/components/header.js b/js/components/header.js
index 7c2331f9..3e2d244d 100644
--- a/js/components/header.js
+++ b/js/components/header.js
@@ -142,7 +142,9 @@ let Header = React.createClass({
this.refs.dropdownbutton.setDropdownState(false);
},
- // On route change, close expanded navbar again
+ // On route change, close expanded navbar again since react-bootstrap doesn't close
+ // the collapsibleNav by itself on click. setState() isn't available on a ref so
+ // doing this explicitly is the only way for now.
onRouteChange() {
this.refs.navbar.state.navExpanded = false;
},
From d03d1355fffa5bdea519a55a09a76fbd7d103680 Mon Sep 17 00:00:00 2001
From: diminator
Date: Fri, 27 Nov 2015 18:02:25 +0100
Subject: [PATCH 052/115] copy for webhooks
---
js/components/ascribe_settings/webhook_settings.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/js/components/ascribe_settings/webhook_settings.js b/js/components/ascribe_settings/webhook_settings.js
index 18c21aa6..9deecbcd 100644
--- a/js/components/ascribe_settings/webhook_settings.js
+++ b/js/components/ascribe_settings/webhook_settings.js
@@ -127,6 +127,17 @@ let WebhookSettings = React.createClass({
+
+
+ Webhooks allow external services to receive notifications from ascribe.
+ Currently we support webhook notifications when someone transfers, consigns, loans or shares
+ (by email) a work to you.
+
+
+ To get started, simply choose the prefered action that you want to be notified upon and supply
+ a target url.
+
+
Date: Fri, 27 Nov 2015 23:53:54 +0100
Subject: [PATCH 053/115] Fix consign form when labels aren't give as props
---
js/components/ascribe_forms/form_consign.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index c659610d..158fd046 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -24,7 +24,13 @@ let ConsignForm = React.createClass({
handleSuccess: React.PropTypes.func
},
- getFormData(){
+ getInitialProps() {
+ return {
+ labels: {}
+ };
+ },
+
+ getFormData() {
return this.props.id;
},
From 720cf472c8d05590a3327713586a9bdb44d6f519 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Sat, 28 Nov 2015 23:37:46 +0100
Subject: [PATCH 054/115] Make header notification full width on mobile
---
sass/ascribe_notification_list.scss | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/sass/ascribe_notification_list.scss b/sass/ascribe_notification_list.scss
index a09f7049..b5f46a4c 100644
--- a/sass/ascribe_notification_list.scss
+++ b/sass/ascribe_notification_list.scss
@@ -2,8 +2,9 @@ $break-small: 764px;
$break-medium: 991px;
$break-medium: 1200px;
-.notification-header,.notification-wrapper {
- width: 350px;
+.notification-header, .notification-wrapper {
+ min-width: 350px;
+ width: 100%;
}
.notification-header {
@@ -81,4 +82,4 @@ $break-medium: 1200px;
border: 1px solid #cccccc;
background-color: white;
margin-top: 1px;
-}
\ No newline at end of file
+}
From 539c34db48f2d71f64891f61cf6905847866da34 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Mon, 30 Nov 2015 11:19:59 +0100
Subject: [PATCH 055/115] Fix typo for getDefaultProps() in consign form
---
js/components/ascribe_forms/form_consign.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index 158fd046..d88add94 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -24,7 +24,7 @@ let ConsignForm = React.createClass({
handleSuccess: React.PropTypes.func
},
- getInitialProps() {
+ getDefaultProps() {
return {
labels: {}
};
From ea52c54e3a38ef37e0670878c5bf3d31e953e26f Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Mon, 30 Nov 2015 11:27:15 +0100
Subject: [PATCH 056/115] Fix check for determining if a piece's edition list
is open
---
js/components/piece_list.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 3d4309f8..4a269aa8 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -130,7 +130,9 @@ let PieceList = React.createClass({
this.state.pieceList
.forEach((piece) => {
// but only if they're actually open
- if(this.state.isEditionListOpenForPieceId[piece.id].show) {
+ const isEditionListOpenForPiece = this.state.isEditionListOpenForPieceId[piece.id];
+
+ if (isEditionListOpenForPiece && isEditionListOpenForPiece.show) {
EditionListActions.refreshEditionList({
pieceId: piece.id,
filterBy
From 3d017392c10ad28fc3192a4b0a53ec8d9f241aa1 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Mon, 30 Nov 2015 11:32:48 +0100
Subject: [PATCH 057/115] Only use previous filterBy on refreshing edition
lists if no filterBy argument was given
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Also fix the behaviour of refresh using the list’s current length
rather than the previous page size.
---
js/stores/edition_list_store.js | 43 ++++++++++-----------------------
1 file changed, 13 insertions(+), 30 deletions(-)
diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js
index 4ccada4e..6b4d64f9 100644
--- a/js/stores/edition_list_store.js
+++ b/js/stores/edition_list_store.js
@@ -32,7 +32,7 @@ class EditionListStore {
// page
let storeEditionIndex = (page - 1) * pageSize + i;
let editionsForPieces = this.editionList[pieceId];
-
+
// if edition already exists, just merge
if(editionsForPieces[storeEditionIndex]) {
editionsForPieces[storeEditionIndex] = React.addons.update(editionsForPieces[storeEditionIndex], {$merge: editionListOfPiece[i]});
@@ -60,46 +60,29 @@ class EditionListStore {
* We often just have to refresh the edition list for a certain pieceId,
* this method provides exactly that functionality without any side effects
*/
- onRefreshEditionList({pieceId, filterBy}) {
+ onRefreshEditionList({pieceId, filterBy = this.editionList[pieceId].filterBy}) {
+ const pieceEditionList = this.editionList[pieceId];
+
// It may happen that the user enters the site logged in already
// through /editions
// If he then tries to delete a piece/edition and this method is called,
// we'll not be able to refresh his edition list since its not yet there.
// Therefore we can just return, since there is no data to be refreshed
- if(!this.editionList[pieceId]) {
+ if (!pieceEditionList) {
return;
}
- let prevEditionListLength = this.editionList[pieceId].length;
- let prevEditionListPage = this.editionList[pieceId].page;
- let prevEditionListPageSize = this.editionList[pieceId].pageSize;
-
- // we can also refresh the edition list using filterBy,
- // if we decide not to do that then the old filter will just be applied.
- if(filterBy && Object.keys(filterBy).length <= 0) {
- filterBy = this.editionList[pieceId].filterBy;
- prevEditionListLength = 10;
- prevEditionListPage = 1;
- prevEditionListPageSize = 10;
- }
-
// to clear an array, david walsh recommends to just set it's length to zero
// http://davidwalsh.name/empty-array
- this.editionList[pieceId].length = 0;
+ pieceEditionList.length = 0;
- // refetch editions with adjusted page size
- EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength,
- this.editionList[pieceId].orderBy,
- this.editionList[pieceId].orderAsc,
- filterBy)
- .then(() => {
- // reset back to the normal pageSize and page
- this.editionList[pieceId].page = prevEditionListPage;
- this.editionList[pieceId].pageSize = prevEditionListPageSize;
- })
- .catch((err) => {
- console.logGlobal(err);
- });
+ // refetch editions from the beginning with the previous settings
+ EditionsListActions
+ .fetchEditionList(pieceId, 1, pieceEditionList.pageSize,
+ pieceEditionList.orderBy,
+ pieceEditionList.orderAsc,
+ filterBy)
+ .catch(console.logGlobal);
}
onSelectEdition({pieceId, editionId, toValue}) {
From 2b6c9777e91218b86e33d4062fef4a3130d5ac6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 30 Nov 2015 13:20:05 +0100
Subject: [PATCH 058/115] Display actions only if ACLs are available
---
js/components/ascribe_detail/edition.js | 2 +-
js/components/ascribe_detail/piece_container.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index 254746a6..ef5207d9 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -210,7 +210,7 @@ let EditionSummary = React.createClass({
value={ edition.owner } />
{this.getStatus()}
-
+ 1}>
+ show={currentUser && currentUser.email && Object.keys(piece.acl).length > 1}>
Date: Mon, 30 Nov 2015 15:01:07 +0100
Subject: [PATCH 059/115] Implement boilerplate logic for ReactError
---
js/app.js | 22 ++++++++++++++------
js/react_error.js | 42 ++++++++++++++++++++++++++++++++++++++
js/react_error_handlers.js | 5 +++++
3 files changed, 63 insertions(+), 6 deletions(-)
create mode 100644 js/react_error.js
create mode 100644 js/react_error_handlers.js
diff --git a/js/app.js b/js/app.js
index 520bedbd..9e8e3a91 100644
--- a/js/app.js
+++ b/js/app.js
@@ -5,6 +5,8 @@ require('babel/polyfill');
import React from 'react';
import { Router, Redirect } from 'react-router';
import history from './history';
+import { ReactError, ResourceNotFoundError } from './react_error.js';
+import { ResourceNotFoundErrorHandler } from './react_error_handlers';
/* eslint-disable */
import fetch from 'isomorphic-fetch';
@@ -91,12 +93,20 @@ class AppGateway {
// us in that case.
history.listen(EventActions.routeDidChange);
- React.render((
-
- {redirectRoute}
- {getRoutes(type, subdomain)}
-
- ), document.getElementById('main'));
+ ReactError({
+ render: React.render,
+ params: [(
+
+ {redirectRoute}
+ {getRoutes(type, subdomain)}
+
+ ),
+ document.getElementById('main')],
+ errors: [{
+ error: ResourceNotFoundError,
+ handler: ResourceNotFoundErrorHandler
+ }]
+ });
// Send the applicationDidBoot event to the third-party stores
EventActions.applicationDidBoot(settings);
diff --git a/js/react_error.js b/js/react_error.js
new file mode 100644
index 00000000..61fb4a70
--- /dev/null
+++ b/js/react_error.js
@@ -0,0 +1,42 @@
+'use strict';
+
+function _transformErrorsListToHashMap(errors) {
+ return errors.reduce((errObj, { error, handler }) => {
+ const errorName = error.name;
+ if(!errObj[errorName]) {
+ errObj[errorName] = {
+ error: error,
+ handler: handler
+ };
+ return errObj;
+ } else {
+ throw new Error('You\'re trying to override the error handler for ' + errorName + ' by specifying it twice.');
+ }
+ }, {});
+}
+
+export function ReactError({ render, params, errors }) {
+ errors = _transformErrorsListToHashMap(errors);
+ try {
+ // use react's render function + parameters to render
+ // the application
+ render(...params);
+ } catch(err) {
+ const potErrorRoutine = errors[err.name];
+ if(potErrorRoutine) {
+ potErrorRoutine.handler(err);
+ } else {
+ console.error(err.stack);
+ }
+ }
+}
+
+// Followed: http://stackoverflow.com/a/32749533/1263876 for extending errors
+export class ResourceNotFoundError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = this.constructor.name;
+ this.message = message;
+ Error.captureStackTrace(this, this.constructor.name);
+ }
+}
\ No newline at end of file
diff --git a/js/react_error_handlers.js b/js/react_error_handlers.js
new file mode 100644
index 00000000..57366603
--- /dev/null
+++ b/js/react_error_handlers.js
@@ -0,0 +1,5 @@
+'use strict';
+
+export function ResourceNotFoundErrorHandler() {
+ console.log(arguments);
+}
\ No newline at end of file
From 0b2bc1c57b48e5817a4b1a4728112ec61d5ec771 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 30 Nov 2015 18:23:03 +0100
Subject: [PATCH 060/115] Introduce ReactError mixin for handling errors in
React components
---
js/app.js | 22 +++-------
.../ascribe_detail/edition_container.js | 17 +++-----
.../ascribe_detail/piece_container.js | 9 ++--
js/components/error_not_found_page.js | 12 +++++-
js/mixins/react_error.js | 12 ++++++
js/models/errors.js | 24 +++++++++++
js/react_error.js | 42 -------------------
js/react_error_handlers.js | 5 ---
8 files changed, 64 insertions(+), 79 deletions(-)
create mode 100644 js/mixins/react_error.js
create mode 100644 js/models/errors.js
delete mode 100644 js/react_error.js
delete mode 100644 js/react_error_handlers.js
diff --git a/js/app.js b/js/app.js
index 9e8e3a91..520bedbd 100644
--- a/js/app.js
+++ b/js/app.js
@@ -5,8 +5,6 @@ require('babel/polyfill');
import React from 'react';
import { Router, Redirect } from 'react-router';
import history from './history';
-import { ReactError, ResourceNotFoundError } from './react_error.js';
-import { ResourceNotFoundErrorHandler } from './react_error_handlers';
/* eslint-disable */
import fetch from 'isomorphic-fetch';
@@ -93,20 +91,12 @@ class AppGateway {
// us in that case.
history.listen(EventActions.routeDidChange);
- ReactError({
- render: React.render,
- params: [(
-
- {redirectRoute}
- {getRoutes(type, subdomain)}
-
- ),
- document.getElementById('main')],
- errors: [{
- error: ResourceNotFoundError,
- handler: ResourceNotFoundErrorHandler
- }]
- });
+ React.render((
+
+ {redirectRoute}
+ {getRoutes(type, subdomain)}
+
+ ), document.getElementById('main'));
// Send the applicationDidBoot event to the third-party stores
EventActions.applicationDidBoot(settings);
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index af7b7928..189f7e60 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -3,6 +3,9 @@
import React from 'react';
import { History } from 'react-router';
+import ReactError from '../../mixins/react_error';
+import { ResourceNotFoundError } from '../../models/errors';
+
import EditionActions from '../../actions/edition_actions';
import EditionStore from '../../stores/edition_store';
@@ -10,6 +13,7 @@ import Edition from './edition';
import AscribeSpinner from '../ascribe_spinner';
+import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils';
@@ -21,7 +25,7 @@ let EditionContainer = React.createClass({
params: React.PropTypes.object
},
- mixins: [History],
+ mixins: [History, ReactError],
getInitialState() {
return EditionStore.getState();
@@ -33,14 +37,7 @@ let EditionContainer = React.createClass({
// as it will otherwise display wrong/old data once the user loads
// the edition detail a second time
EditionActions.updateEdition({});
-
EditionStore.listen(this.onChange);
-
- // Every time we enter the edition detail page, just reset the edition
- // store as it will otherwise display wrong/old data once the user loads
- // the edition detail a second time
- EditionActions.updateEdition({});
-
this.loadEdition();
},
@@ -57,9 +54,7 @@ let EditionContainer = React.createClass({
const { editionError } = this.state;
if(editionError && editionError.status === 404) {
- // Even though the /404 path doesn't really exist,
- // we can still redirect there and the page will show up
- this.history.pushState(null, '/404');
+ this.throws(new ResourceNotFoundError(getLangText('Ups, the edition you\'re looking for doesn\'t exist.')));
}
},
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 187c53c1..5198e6ac 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -4,6 +4,9 @@ import React from 'react';
import { History } from 'react-router';
import Moment from 'moment';
+import ReactError from '../../mixins/react_error';
+import { ResourceNotFoundError } from '../../models/errors';
+
import PieceActions from '../../actions/piece_actions';
import PieceStore from '../../stores/piece_store';
@@ -53,7 +56,7 @@ let PieceContainer = React.createClass({
params: React.PropTypes.object
},
- mixins: [History],
+ mixins: [History, ReactError],
getInitialState() {
return mergeOptions(
@@ -91,9 +94,7 @@ let PieceContainer = React.createClass({
const { pieceError } = this.state;
if(pieceError && pieceError.status === 404) {
- // Even though this path doesn't exist we can redirect
- // to it as it catches all unknown paths
- this.history.pushState(null, '/404');
+ this.throws(new ResourceNotFoundError(getLangText('Ups, the piece you\'re looking for doesn\'t exist.')));
}
},
diff --git a/js/components/error_not_found_page.js b/js/components/error_not_found_page.js
index 61f83196..670f8629 100644
--- a/js/components/error_not_found_page.js
+++ b/js/components/error_not_found_page.js
@@ -6,6 +6,16 @@ import { getLangText } from '../utils/lang_utils';
let ErrorNotFoundPage = React.createClass({
+ propTypes: {
+ message: React.PropTypes.string
+ },
+
+ getDefaultProps() {
+ return {
+ message: getLangText('Ups, the page you are looking for does not exist.')
+ };
+ },
+
render() {
return (
@@ -13,7 +23,7 @@ let ErrorNotFoundPage = React.createClass({
404
- {getLangText('Ups, the page you are looking for does not exist.')}
+ {this.props.message}
diff --git a/js/mixins/react_error.js b/js/mixins/react_error.js
new file mode 100644
index 00000000..0b7669de
--- /dev/null
+++ b/js/mixins/react_error.js
@@ -0,0 +1,12 @@
+'use strict';
+
+import invariant from 'invariant';
+
+const ReactError = {
+ throws(err) {
+ invariant(err.handler, 'You need to specify a `handler` for this error');
+ err.handler(this, err);
+ }
+};
+
+export default ReactError;
diff --git a/js/models/errors.js b/js/models/errors.js
new file mode 100644
index 00000000..68d97c86
--- /dev/null
+++ b/js/models/errors.js
@@ -0,0 +1,24 @@
+'use strict';
+
+import React from 'react';
+
+import ErrorNotFoundPage from '../components/error_not_found_page';
+
+
+export class ResourceNotFoundError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = this.constructor.name;
+ this.message = message;
+ Error.captureStackTrace(this, this.constructor.name);
+ }
+
+ handler(component, err) {
+ if(!component.state._monkeyPatched) {
+ component.render = () => ;
+ component.setState({
+ _monkeyPatched: true
+ });
+ }
+ }
+}
diff --git a/js/react_error.js b/js/react_error.js
deleted file mode 100644
index 61fb4a70..00000000
--- a/js/react_error.js
+++ /dev/null
@@ -1,42 +0,0 @@
-'use strict';
-
-function _transformErrorsListToHashMap(errors) {
- return errors.reduce((errObj, { error, handler }) => {
- const errorName = error.name;
- if(!errObj[errorName]) {
- errObj[errorName] = {
- error: error,
- handler: handler
- };
- return errObj;
- } else {
- throw new Error('You\'re trying to override the error handler for ' + errorName + ' by specifying it twice.');
- }
- }, {});
-}
-
-export function ReactError({ render, params, errors }) {
- errors = _transformErrorsListToHashMap(errors);
- try {
- // use react's render function + parameters to render
- // the application
- render(...params);
- } catch(err) {
- const potErrorRoutine = errors[err.name];
- if(potErrorRoutine) {
- potErrorRoutine.handler(err);
- } else {
- console.error(err.stack);
- }
- }
-}
-
-// Followed: http://stackoverflow.com/a/32749533/1263876 for extending errors
-export class ResourceNotFoundError extends Error {
- constructor(message) {
- super(message);
- this.name = this.constructor.name;
- this.message = message;
- Error.captureStackTrace(this, this.constructor.name);
- }
-}
\ No newline at end of file
diff --git a/js/react_error_handlers.js b/js/react_error_handlers.js
deleted file mode 100644
index 57366603..00000000
--- a/js/react_error_handlers.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict';
-
-export function ResourceNotFoundErrorHandler() {
- console.log(arguments);
-}
\ No newline at end of file
From 4fe10bb8871c5194408dc84174301fc2466a0be4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 30 Nov 2015 18:26:27 +0100
Subject: [PATCH 061/115] Cosmetic changes for EditionContainer &
PieceContainer
---
js/components/ascribe_detail/edition_container.js | 3 ++-
js/components/ascribe_detail/piece_container.js | 10 +---------
2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index 189f7e60..eac8fcb3 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -32,12 +32,13 @@ let EditionContainer = React.createClass({
},
componentDidMount() {
+ EditionStore.listen(this.onChange);
+
// Every time we're entering the edition detail page,
// just reset the edition that is saved in the edition store
// as it will otherwise display wrong/old data once the user loads
// the edition detail a second time
EditionActions.updateEdition({});
- EditionStore.listen(this.onChange);
this.loadEdition();
},
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 5198e6ac..86c7fc74 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -70,24 +70,16 @@ let PieceContainer = React.createClass({
},
componentDidMount() {
- // Every time we're entering the piece detail page,
- // just reset the piece that is saved in the piece store
- // as it will otherwise display wrong/old data once the user loads
- // the piece detail a second time
- PieceActions.updatePiece({});
-
UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
PieceStore.listen(this.onChange);
+
// Every time we enter the piece detail page, just reset the piece
// store as it will otherwise display wrong/old data once the user loads
// the piece detail a second time
PieceActions.updatePiece({});
-
this.loadPiece();
-
UserActions.fetchCurrentUser();
- PieceActions.fetchOne(this.props.params.pieceId);
},
componentDidUpdate() {
From 85340a91269672813c215c28d366318992a0e0c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 12:23:38 +0100
Subject: [PATCH 062/115] Fix bug that threw an error when passing nullish prop
to PieceListFilterDisplay
---
js/components/piece_list.js | 5 ++---
js/components/piece_list_filter_display.js | 2 +-
.../whitelabel/wallet/components/market/market_piece_list.js | 2 +-
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 383d870f..9208df92 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -133,7 +133,7 @@ let PieceList = React.createClass({
const defaultFilterBy = {};
if (filterParams && typeof filterParams.forEach === 'function') {
- filterParams.forEach(({ label, items }) => {
+ filterParams.forEach(({ items }) => {
items.forEach((item) => {
if (typeof item === 'object' && item.defaultValue) {
defaultFilterBy[item.key] = true;
@@ -211,7 +211,7 @@ let PieceList = React.createClass({
},
loadPieceList({ page, filterBy = this.state.filterBy, search = this.state.search }) {
- let orderBy = this.state.orderBy ? this.state.orderBy : this.props.orderBy;
+ const orderBy = this.state.orderBy || this.props.orderBy;
return PieceListActions.fetchPieceList(page, this.state.pageSize, search,
orderBy, this.state.orderAsc, filterBy);
@@ -259,7 +259,6 @@ let PieceList = React.createClass({
const availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view');
setDocumentTitle(getLangText('Collection'));
-
return (
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index 64198bb3..8ffab5a5 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -50,7 +50,7 @@ let MarketPieceList = React.createClass({
render() {
const { currentUser, whitelabel } = this.state;
- let filterParams = undefined;
+ let filterParams = null;
let canLoadPieceList = false;
if (currentUser.email && whitelabel.user) {
From 8b3060d6133e72765b1c07c3b1c9a0cc3b88e10d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 12:25:11 +0100
Subject: [PATCH 063/115] Fix simple comments in pr
---
.../ascribe_detail/further_details_fileuploader.js | 4 +++-
.../market/market_buttons/market_submit_button.js | 4 ++--
.../market_forms/market_additional_data_form.js | 6 ++++--
.../wallet/components/market/market_register_piece.js | 11 +----------
js/components/whitelabel/wallet/wallet_routes.js | 11 -----------
5 files changed, 10 insertions(+), 26 deletions(-)
diff --git a/js/components/ascribe_detail/further_details_fileuploader.js b/js/components/ascribe_detail/further_details_fileuploader.js
index c8e17036..dc638816 100644
--- a/js/components/ascribe_detail/further_details_fileuploader.js
+++ b/js/components/ascribe_detail/further_details_fileuploader.js
@@ -10,6 +10,8 @@ import ApiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants';
import { getCookie } from '../../utils/fetch_api_utils';
+import { getLangText } from '../../utils/lang_utils';
+
let FurtherDetailsFileuploader = React.createClass({
propTypes: {
@@ -26,7 +28,7 @@ let FurtherDetailsFileuploader = React.createClass({
getDefaultProps() {
return {
- label: 'Additional files',
+ label: getLangText('Additional files'),
multiple: false
};
},
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index 6a617bfb..d75282af 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -53,8 +53,8 @@ let MarketSubmitButton = React.createClass({
const { extra_data, other_data } = edition;
if (extra_data.artist_bio && extra_data.work_description &&
- extra_data.technology_details && extra_data.display_instructions &&
- other_data.length > 0) {
+ extra_data.technology_details && extra_data.display_instructions &&
+ other_data.length > 0) {
return true;
}
}
diff --git a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
index a2318b99..90baebb0 100644
--- a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
@@ -8,6 +8,7 @@ import Property from '../../../../../ascribe_forms/property';
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
+import AscribeSpinner from '../../../../../ascribe_spinner';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
@@ -24,6 +25,7 @@ import requests from '../../../../../../utils/requests';
import { mergeOptions } from '../../../../../../utils/general_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
+
let MarketAdditionalDataForm = React.createClass({
propTypes: {
pieceId: React.PropTypes.oneOfType([
@@ -96,7 +98,7 @@ let MarketAdditionalDataForm = React.createClass({
},
isUploadReadyOnChange(piece) {
- return piece && piece.other_data && piece.other_data.length > 0 ? true : false;
+ return piece && piece.other_data && piece.other_data.length > 0;
},
handleSuccessWithNotification() {
@@ -211,7 +213,7 @@ let MarketAdditionalDataForm = React.createClass({
} else {
return (
-
+
);
}
diff --git a/js/components/whitelabel/wallet/components/market/market_register_piece.js b/js/components/whitelabel/wallet/components/market/market_register_piece.js
index a59ce5fa..9a919561 100644
--- a/js/components/whitelabel/wallet/components/market/market_register_piece.js
+++ b/js/components/whitelabel/wallet/components/market/market_register_piece.js
@@ -35,8 +35,6 @@ let MarketRegisterPiece = React.createClass({
UserStore.getState(),
PieceListStore.getState(),
{
- selectedLicense: 0,
- isFineUploaderActive: false,
step: 0
});
},
@@ -58,13 +56,6 @@ let MarketRegisterPiece = React.createClass({
onChange(state) {
this.setState(state);
-
- if (this.state.currentUser && this.state.currentUser.email) {
- // we should also make the fineuploader component editable again
- this.setState({
- isFineUploaderActive: true
- });
- }
},
handleRegisterSuccess(response) {
@@ -140,7 +131,7 @@ let MarketRegisterPiece = React.createClass({
enableLocalHashing={false}
headerMessage={getLangText('Consign to Market')}
submitMessage={getLangText('Proceed to additional details')}
- isFineUploaderActive={this.state.isFineUploaderActive}
+ isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
onLoggedOut={this.onLoggedOut}
location={this.props.location}>
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 08adec44..92b53dc6 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -228,16 +228,6 @@ let ROUTES = {
)
};
-
-function getRoutes(commonRoutes, subdomain) {
- if(subdomain in ROUTES) {
- return ROUTES[subdomain];
- } else {
- throw new Error('Subdomain wasn\'t specified in the wallet app.');
- }
-};
-
-
function getRoutes(commonRoutes, subdomain) {
if(subdomain in ROUTES) {
return ROUTES[subdomain];
@@ -246,5 +236,4 @@ function getRoutes(commonRoutes, subdomain) {
}
}
-
export default getRoutes;
From fe24a5e15a47c67271d1ef8d6d751ea142482038 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 12:37:21 +0100
Subject: [PATCH 064/115] Remove all occurrences of inactivity mgmt of
ReactS3Fineuploader
---
.../ascribe_forms/form_register_piece.js | 2 --
.../ascribe_forms/input_fineuploader.js | 21 +++++++++--------
.../file_drag_and_drop.js | 9 --------
.../react_s3_fine_uploader.js | 3 ---
js/components/register_piece.js | 14 ++---------
.../cyland/cyland_register_piece.js | 17 +-------------
.../ikonotv/ikonotv_register_piece.js | 23 +------------------
.../market/market_register_piece.js | 6 -----
8 files changed, 15 insertions(+), 80 deletions(-)
diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js
index b09d29ac..5b5f97fe 100644
--- a/js/components/ascribe_forms/form_register_piece.js
+++ b/js/components/ascribe_forms/form_register_piece.js
@@ -26,7 +26,6 @@ let RegisterPieceForm = React.createClass({
isFineUploaderActive: React.PropTypes.bool,
isFineUploaderEditable: React.PropTypes.bool,
enableLocalHashing: React.PropTypes.bool,
- onLoggedOut: React.PropTypes.func,
// For this form to work with SlideContainer, we sometimes have to disable it
disabled: React.PropTypes.bool,
@@ -116,7 +115,6 @@ let RegisterPieceForm = React.createClass({
setIsUploadReady={this.setIsUploadReady}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
isFineUploaderActive={this.props.isFineUploaderActive}
- onLoggedOut={this.props.onLoggedOut}
disabled={!this.props.isFineUploaderEditable}
enableLocalHashing={enableLocalHashing}
uploadMethod={this.props.location.query.method} />
diff --git a/js/components/ascribe_forms/input_fineuploader.js b/js/components/ascribe_forms/input_fineuploader.js
index 948521c0..1a9889db 100644
--- a/js/components/ascribe_forms/input_fineuploader.js
+++ b/js/components/ascribe_forms/input_fineuploader.js
@@ -38,7 +38,6 @@ const InputFineUploader = React.createClass({
// a user is actually not logged in already to prevent him from droping files
// before login in
isFineUploaderActive: bool,
- onLoggedOut: func,
enableLocalHashing: bool,
uploadMethod: string,
@@ -51,7 +50,10 @@ const InputFineUploader = React.createClass({
fileClassToUpload: shape({
singular: string,
plural: string
- })
+ }),
+
+ // Provided by `Property`
+ onChange: React.PropTypes.func
},
getDefaultProps() {
@@ -101,16 +103,16 @@ const InputFineUploader = React.createClass({
setIsUploadReady,
isReadyForFormSubmission,
areAssetsDownloadable,
- onLoggedOut,
enableLocalHashing,
+ uploadMethod,
fileClassToUpload,
- location } = this.props;
+ disabled } = this.props;
let editable = this.props.isFineUploaderActive;
// if disabled is actually set by property, we want to override
// isFineUploaderActive
- if(typeof this.props.disabled !== 'undefined') {
- editable = !this.props.disabled;
+ if(typeof disabled !== 'undefined') {
+ editable = !disabled;
}
return (
@@ -139,10 +141,9 @@ const InputFineUploader = React.createClass({
'X-CSRFToken': getCookie(AppConstants.csrftoken)
}
}}
- onInactive={this.props.onLoggedOut}
- enableLocalHashing={this.props.enableLocalHashing}
- uploadMethod={this.props.uploadMethod}
- fileClassToUpload={this.props.fileClassToUpload} />
+ enableLocalHashing={enableLocalHashing}
+ uploadMethod={uploadMethod}
+ fileClassToUpload={fileClassToUpload} />
);
}
});
diff --git a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
index 0cc7ff5e..2f3d6af5 100644
--- a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
+++ b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
@@ -15,7 +15,6 @@ let FileDragAndDrop = React.createClass({
className: React.PropTypes.string,
onDrop: React.PropTypes.func.isRequired,
onDragOver: React.PropTypes.func,
- onInactive: React.PropTypes.func,
filesToUpload: React.PropTypes.array,
handleDeleteFile: React.PropTypes.func,
handleCancelFile: React.PropTypes.func,
@@ -63,11 +62,6 @@ let FileDragAndDrop = React.createClass({
let files;
if(this.props.dropzoneInactive) {
- // if there is a handle function for doing stuff
- // when the dropzone is inactive, then call it
- if(this.props.onInactive) {
- this.props.onInactive();
- }
return;
}
@@ -119,9 +113,6 @@ let FileDragAndDrop = React.createClass({
if(this.props.dropzoneInactive) {
// if there is a handle function for doing stuff
// when the dropzone is inactive, then call it
- if(this.props.onInactive) {
- this.props.onInactive();
- }
return;
}
diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js
index bf4250c5..911f887e 100644
--- a/js/components/ascribe_uploader/react_s3_fine_uploader.js
+++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js
@@ -99,7 +99,6 @@ let ReactS3FineUploader = React.createClass({
areAssetsDownloadable: React.PropTypes.bool,
areAssetsEditable: React.PropTypes.bool,
defaultErrorMessage: React.PropTypes.string,
- onInactive: React.PropTypes.func,
// We encountered some cases where people had difficulties to upload their
// works to ascribe due to a slow internet connection.
@@ -891,7 +890,6 @@ let ReactS3FineUploader = React.createClass({
multiple,
areAssetsDownloadable,
areAssetsEditable,
- onInactive,
enableLocalHashing,
fileClassToUpload,
fileInputElement: FileInputElement,
@@ -901,7 +899,6 @@ let ReactS3FineUploader = React.createClass({
multiple,
areAssetsDownloadable,
areAssetsEditable,
- onInactive,
enableLocalHashing,
uploadMethod,
fileClassToUpload,
diff --git a/js/components/register_piece.js b/js/components/register_piece.js
index 43ac7bb7..bc0639e3 100644
--- a/js/components/register_piece.js
+++ b/js/components/register_piece.js
@@ -45,10 +45,7 @@ let RegisterPiece = React.createClass( {
UserStore.getState(),
WhitelabelStore.getState(),
PieceListStore.getState(),
- {
- selectedLicense: 0,
- isFineUploaderActive: false
- });
+ );
},
componentDidMount() {
@@ -66,13 +63,6 @@ let RegisterPiece = React.createClass( {
onChange(state) {
this.setState(state);
-
- if(this.state.currentUser && this.state.currentUser.email) {
- // we should also make the fineuploader component editable again
- this.setState({
- isFineUploaderActive: true
- });
- }
},
handleSuccess(response){
@@ -117,7 +107,7 @@ let RegisterPiece = React.createClass( {
{this.props.children}
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
index 470da761..85cd01bd 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
@@ -53,8 +53,6 @@ let CylandRegisterPiece = React.createClass({
PieceStore.getState(),
WhitelabelStore.getState(),
{
- selectedLicense: 0,
- isFineUploaderActive: false,
step: 0
});
},
@@ -90,13 +88,6 @@ let CylandRegisterPiece = React.createClass({
onChange(state) {
this.setState(state);
-
- if(this.state.currentUser && this.state.currentUser.email) {
- // we should also make the fineuploader component editable again
- this.setState({
- isFineUploaderActive: true
- });
- }
},
handleRegisterSuccess(response){
@@ -167,11 +158,6 @@ let CylandRegisterPiece = React.createClass({
}
},
- // basically redirects to the second slide (index: 1), when the user is not logged in
- onLoggedOut() {
- this.history.pushState(null, '/login');
- },
-
render() {
let today = new Moment();
@@ -197,9 +183,8 @@ let CylandRegisterPiece = React.createClass({
enableLocalHashing={false}
headerMessage={getLangText('Submit to Cyland Archive')}
submitMessage={getLangText('Submit')}
- isFineUploaderActive={this.state.isFineUploaderActive}
+ isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
- onLoggedOut={this.onLoggedOut}
location={this.props.location}/>
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
index d3f93ddf..16d893b7 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
@@ -85,13 +85,6 @@ let IkonotvRegisterPiece = React.createClass({
onChange(state) {
this.setState(state);
-
- if(this.state.currentUser && this.state.currentUser.email) {
- // we should also make the fineuploader component editable again
- this.setState({
- isFineUploaderActive: true
- });
- }
},
@@ -157,19 +150,6 @@ let IkonotvRegisterPiece = React.createClass({
);
},
- changeSlide() {
- // only transition to the login store, if user is not logged in
- // ergo the currentUser object is not properly defined
- if(this.state.currentUser && !this.state.currentUser.email) {
- this.onLoggedOut();
- }
- },
-
- // basically redirects to the second slide (index: 1), when the user is not logged in
- onLoggedOut() {
- this.history.pushState(null, '/login');
- },
-
canSubmit() {
let currentUser = this.state.currentUser;
return currentUser && currentUser.acl && currentUser.acl.acl_wallet_submit;
@@ -260,9 +240,8 @@ let IkonotvRegisterPiece = React.createClass({
enableLocalHashing={false}
headerMessage={getLangText('Register work')}
submitMessage={getLangText('Register')}
- isFineUploaderActive={this.state.isFineUploaderActive}
+ isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
- onLoggedOut={this.onLoggedOut}
location={this.props.location}/>
diff --git a/js/components/whitelabel/wallet/components/market/market_register_piece.js b/js/components/whitelabel/wallet/components/market/market_register_piece.js
index 9a919561..3572fd6d 100644
--- a/js/components/whitelabel/wallet/components/market/market_register_piece.js
+++ b/js/components/whitelabel/wallet/components/market/market_register_piece.js
@@ -106,11 +106,6 @@ let MarketRegisterPiece = React.createClass({
);
},
- // basically redirects to the second slide (index: 1), when the user is not logged in
- onLoggedOut() {
- this.history.pushState(null, '/login');
- },
-
render() {
setDocumentTitle(getLangText('Register a new piece'));
@@ -133,7 +128,6 @@ let MarketRegisterPiece = React.createClass({
submitMessage={getLangText('Proceed to additional details')}
isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
- onLoggedOut={this.onLoggedOut}
location={this.props.location}>
Date: Wed, 2 Dec 2015 13:52:17 +0100
Subject: [PATCH 065/115] Rearrange handleDrop() to flow more naturally
---
.../file_drag_and_drop.js | 65 +++++++++----------
1 file changed, 30 insertions(+), 35 deletions(-)
diff --git a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
index 2f3d6af5..1157a540 100644
--- a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
+++ b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
@@ -59,23 +59,21 @@ let FileDragAndDrop = React.createClass({
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
- let files;
- if(this.props.dropzoneInactive) {
- return;
+ if (!this.props.dropzoneInactive) {
+ let files;
+
+ // handle Drag and Drop
+ if(event.dataTransfer && event.dataTransfer.files.length > 0) {
+ files = event.dataTransfer.files;
+ } else if(event.target.files) { // handle input type file
+ files = event.target.files;
+ }
+
+ if(typeof this.props.onDrop === 'function' && files) {
+ this.props.onDrop(files);
+ }
}
-
- // handle Drag and Drop
- if(event.dataTransfer && event.dataTransfer.files.length > 0) {
- files = event.dataTransfer.files;
- } else if(event.target.files) { // handle input type file
- files = event.target.files;
- }
-
- if(typeof this.props.onDrop === 'function' && files) {
- this.props.onDrop(files);
- }
-
},
handleDeleteFile(fileId) {
@@ -107,28 +105,25 @@ let FileDragAndDrop = React.createClass({
},
handleOnClick() {
- let evt;
- // when multiple is set to false and the user already uploaded a piece,
- // do not propagate event
- if(this.props.dropzoneInactive) {
- // if there is a handle function for doing stuff
- // when the dropzone is inactive, then call it
- return;
- }
+ // do not propagate event if the drop zone's inactive,
+ // for example when multiple is set to false and the user already uploaded a piece
+ if (!this.props.dropzoneInactive) {
+ let evt;
- try {
- evt = new MouseEvent('click', {
- view: window,
- bubbles: true,
- cancelable: true
- });
- } catch(e) {
- // For browsers that do not support the new MouseEvent syntax
- evt = document.createEvent('MouseEvents');
- evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
- }
+ try {
+ evt = new MouseEvent('click', {
+ view: window,
+ bubbles: true,
+ cancelable: true
+ });
+ } catch(e) {
+ // For browsers that do not support the new MouseEvent syntax
+ evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
+ }
- this.refs.fileSelector.getDOMNode().dispatchEvent(evt);
+ this.refs.fileSelector.getDOMNode().dispatchEvent(evt);
+ }
},
render: function () {
From 07834414c75ac2ff0b451b0031d241eb0b5c4bc9 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 14:26:15 +0100
Subject: [PATCH 066/115] Set default name for marketplace wallets to be
'Market' until the white label name loads
---
.../market_buttons/market_submit_button.js | 8 +++----
.../components/market/market_piece_list.js | 12 ++++++----
.../market/market_register_piece.js | 23 +++++++++++++++----
3 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index d75282af..a4b1b7c3 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -91,7 +91,7 @@ let MarketSubmitButton = React.createClass({
render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
- const { whitelabel } = this.state;
+ const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state;
const { solePieceId, canSubmit } = this.getAggregateEditionDetails();
const message = getAclFormMessage({
aclName: 'acl_consign',
@@ -103,14 +103,14 @@ let MarketSubmitButton = React.createClass({
const triggerButton = (
- {getLangText('CONSIGN TO %s', whitelabel.name.toUpperCase())}
+ {getLangText('CONSIGN TO %s', whitelabelName.toUpperCase())}
);
const consignForm = (
+ title={getLangText('Consign artwork to %s', whitelabelName)}>
{consignForm}
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index 8ffab5a5..e45da164 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -49,19 +49,23 @@ let MarketPieceList = React.createClass({
},
render() {
- const { currentUser, whitelabel } = this.state;
+ const {
+ currentUser: { email: userEmail },
+ whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail }
+ } = this.state;
+
let filterParams = null;
let canLoadPieceList = false;
- if (currentUser.email && whitelabel.user) {
+ if (userEmail && whitelabelAdminEmail) {
canLoadPieceList = true;
- const isUserAdmin = currentUser.email === whitelabel.user;
+ const isUserAdmin = userEmail === whitelabelAdminEmail;
filterParams = [{
label: getLangText('Show works I can'),
items: [{
key: isUserAdmin ? 'acl_transfer' : 'acl_consign',
- label: getLangText(isUserAdmin ? 'transfer' : 'consign to %s', whitelabel.name),
+ label: getLangText(isUserAdmin ? 'transfer' : 'consign to %s', whitelabelName),
defaultValue: true
}]
}];
diff --git a/js/components/whitelabel/wallet/components/market/market_register_piece.js b/js/components/whitelabel/wallet/components/market/market_register_piece.js
index 3572fd6d..d68be85d 100644
--- a/js/components/whitelabel/wallet/components/market/market_register_piece.js
+++ b/js/components/whitelabel/wallet/components/market/market_register_piece.js
@@ -11,11 +11,13 @@ import MarketAdditionalDataForm from './market_forms/market_additional_data_form
import Property from '../../../../ascribe_forms/property';
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
-import UserStore from '../../../../../stores/user_store';
-import UserActions from '../../../../../actions/user_actions';
import PieceActions from '../../../../../actions/piece_actions';
import PieceListStore from '../../../../../stores/piece_list_store';
import PieceListActions from '../../../../../actions/piece_list_actions';
+import UserStore from '../../../../../stores/user_store';
+import UserActions from '../../../../../actions/user_actions';
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
import SlidesContainer from '../../../../ascribe_slides_container/slides_container';
@@ -32,8 +34,9 @@ let MarketRegisterPiece = React.createClass({
getInitialState(){
return mergeOptions(
- UserStore.getState(),
PieceListStore.getState(),
+ UserStore.getState(),
+ WhitelabelStore.getState(),
{
step: 0
});
@@ -42,7 +45,10 @@ let MarketRegisterPiece = React.createClass({
componentDidMount() {
PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
+ WhitelabelStore.listen(this.onChange);
+
UserActions.fetchCurrentUser();
+ WhitelabelActions.fetchWhitelabel();
// Reset the piece store to make sure that we don't display old data
// if the user repeatedly registers works
@@ -52,6 +58,7 @@ let MarketRegisterPiece = React.createClass({
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
+ WhitelabelStore.unlisten(this.onChange);
},
onChange(state) {
@@ -107,6 +114,12 @@ let MarketRegisterPiece = React.createClass({
},
render() {
+ const {
+ isFineUploaderActive,
+ step,
+ whitelabel: { name: whitelabelName = 'Market' }
+ } = this.state;
+
setDocumentTitle(getLangText('Register a new piece'));
return (
@@ -122,9 +135,9 @@ let MarketRegisterPiece = React.createClass({
0}
+ disabled={step > 0}
enableLocalHashing={false}
- headerMessage={getLangText('Consign to Market')}
+ headerMessage={getLangText('Consign to %s', whitelabelName)}
submitMessage={getLangText('Proceed to additional details')}
isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
From 123e2a4d13aa6db04a0f5a2a3f145e4bbc74c712 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 14:31:42 +0100
Subject: [PATCH 067/115] Add functionality to avoid sending error messages to
sentry
---
js/constants/application_constants.js | 7 ++++++-
js/utils/error_utils.js | 3 +--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js
index a58a8cc6..67b8614d 100644
--- a/js/constants/application_constants.js
+++ b/js/constants/application_constants.js
@@ -114,7 +114,12 @@ const constants = {
},
'twitter': {
'sdkUrl': 'https://platform.twitter.com/widgets.js'
- }
+ },
+
+ 'errorMessagesToIgnore': [
+ 'Authentication credentials were not provided.',
+ 'Informations d\'authentification non fournies.'
+ ]
};
export default constants;
diff --git a/js/utils/error_utils.js b/js/utils/error_utils.js
index 4e9de6e2..6306ece4 100644
--- a/js/utils/error_utils.js
+++ b/js/utils/error_utils.js
@@ -13,8 +13,7 @@ import AppConstants from '../constants/application_constants';
* @param {boolean} ignoreSentry Defines whether or not the error should be submitted to Sentry
* @param {string} comment Will also be submitted to Sentry, but will not be logged
*/
-function logGlobal(error, ignoreSentry, comment) {
-
+function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1, comment) {
console.error(error);
if(!ignoreSentry) {
From ad736ad12f4151a57299fa26f6884d983f1064cc Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 14:32:34 +0100
Subject: [PATCH 068/115] Remove unnecessary hover styling on the edition list
widget
---
sass/ascribe_accordion_list.scss | 4 ----
1 file changed, 4 deletions(-)
diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss
index c0b81096..675bfa80 100644
--- a/sass/ascribe_accordion_list.scss
+++ b/sass/ascribe_accordion_list.scss
@@ -211,10 +211,6 @@ $ascribe-accordion-list-item-height: 100px;
-ms-user-select: none;
-webkit-user-select: none;
- &:hover {
- color: $ascribe-dark-blue;
- }
-
.glyphicon {
font-size: .8em;
top: 1px !important;
From d01acea9cef5538154f2f938693446faa3625af5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 14:34:31 +0100
Subject: [PATCH 069/115] Nicer formatting for long parametrized function
---
js/utils/error_utils.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/js/utils/error_utils.js b/js/utils/error_utils.js
index 6306ece4..753bbf61 100644
--- a/js/utils/error_utils.js
+++ b/js/utils/error_utils.js
@@ -13,7 +13,8 @@ import AppConstants from '../constants/application_constants';
* @param {boolean} ignoreSentry Defines whether or not the error should be submitted to Sentry
* @param {string} comment Will also be submitted to Sentry, but will not be logged
*/
-function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1, comment) {
+function logGlobal(error, ignoreSentry = AppConstants.errorMessagesToIgnore.indexOf(error.message) > -1,
+ comment) {
console.error(error);
if(!ignoreSentry) {
From 8e837f8149039f6694367a95164c5c54c900decc Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 14:47:03 +0100
Subject: [PATCH 070/115] Make dropdown items have padding inside them as
opposed to outside margin
Avoids weird highlighting when the items are selected.
---
sass/ascribe_custom_style.scss | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/sass/ascribe_custom_style.scss b/sass/ascribe_custom_style.scss
index 98cce937..1b6bb02f 100644
--- a/sass/ascribe_custom_style.scss
+++ b/sass/ascribe_custom_style.scss
@@ -68,10 +68,15 @@ hr {
.dropdown-menu {
background-color: $ascribe--nav-bg-color;
}
+ .navbar-nav > li > .dropdown-menu {
+ padding: 0;
+ }
.dropdown-menu > li > a {
color: $ascribe--nav-fg-prim-color;
font-weight: $ascribe--font-weight-light;
+ padding-bottom: 9px;
+ padding-top: 9px;
}
.dropdown-menu > li > a:hover,
@@ -79,6 +84,10 @@ hr {
background-color: rgba($ascribe--button-default-color, .05);
}
+ .dropdown-menu > .divider {
+ margin: 0;
+ }
+
.notification-menu {
.dropdown-menu {
background-color: white;
From 384d597405bda4d28b3d1c3b61edff8bb722413e Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 14:47:19 +0100
Subject: [PATCH 071/115] First cut of 23vivi styling
---
.../wallet/23vivi/23vivi_custom_style.scss | 325 ++++++++++++++++++
sass/whitelabel/wallet/index.scss | 1 +
2 files changed, 326 insertions(+)
create mode 100644 sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
diff --git a/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
new file mode 100644
index 00000000..79be4a23
--- /dev/null
+++ b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
@@ -0,0 +1,325 @@
+/** Sass cannot use a number as the first character of a variable, so we'll have to settle with vivi23 **/
+$vivi23--fg-color: black;
+$vivi23--bg-color: white;
+$vivi23--nav-fg-prim-color: $vivi23--fg-color;
+$vivi23--nav-fg-sec-color: #3a3a3a;
+$vivi23--nav-bg-color: $vivi23--bg-color;
+$vivi23--nav-highlight-color: #f8f8f8;
+$vivi23--button-default-color: $vivi23--fg-color;
+$vivi23--highlight-color: #de2600;
+
+
+.client--23vivi {
+ /** Navbar **/
+ .navbar-default {
+ background-color: $vivi23--nav-fg-prim-color;
+
+ .navbar-brand .icon-ascribe-logo {
+ color: $vivi23--bg-color;
+ &:hover {
+ color: darken($vivi23--bg-color, 20%);
+ }
+ }
+
+ }
+
+ .navbar-nav > li > a,
+ .navbar-nav > li > a:focus,
+ .navbar-nav > li > .active a,
+ .navbar-nav > li > .active a:focus {
+ color: $vivi23--nav-bg-color;
+ }
+
+ .navbar-nav > li > a:hover {
+ color: darken($vivi23--nav-bg-color, 20%);
+ }
+
+ .navbar-nav > .active a,
+ .navbar-nav > .active a:hover,
+ .navbar-nav > .active a:focus {
+ background-color: $vivi23--nav-fg-prim-color;
+ border-bottom-color: $vivi23--nav-bg-color;
+ color: $vivi23--nav-bg-color;
+ }
+
+ .navbar-nav > .open > a,
+ .dropdown-menu > .active > a,
+ .dropdown-menu > li > a {
+ color: $vivi23--nav-fg-prim-color;
+ background-color: $vivi23--nav-bg-color;
+ }
+
+ .navbar-nav > .open > a:hover,
+ .navbar-nav > .open > a:focus,
+ .dropdown-menu > .active > a:hover,
+ .dropdown-menu > .active > a:focus,
+ .dropdown-menu > li > a:hover,
+ .dropdown-menu > li > a:focus {
+ color: lighten($vivi23--nav-fg-prim-color, 20%);
+ background-color: $vivi23--nav-highlight-color;
+ }
+
+ .navbar-collapse.collapsing,
+ .navbar-collapse.collapse.in {
+ background-color: $vivi23--nav-bg-color;
+
+ .navbar-nav > .open > a,
+ .navbar-nav > .active > a {
+ background-color: $vivi23--nav-highlight-color;
+ }
+ }
+
+ .navbar-collapse.collapsing li a,
+ .navbar-collapse.collapse.in li a {
+ color: $vivi23--nav-fg-prim-color;
+ }
+ .navbar-collapse.collapse.in li a:not(.ascribe-powered-by):hover {
+ color: lighten($vivi23--nav-fg-prim-color, 20%);
+ background-color: $vivi23--nav-highlight-color;
+ }
+
+ .navbar-toggle {
+ border-color: $vivi23--highlight-color;
+
+ .icon-bar {
+ background-color: $vivi23--highlight-color;
+ }
+ }
+
+ .navbar-toggle:hover,
+ .navbar-toggle:focus {
+ border-color: lighten($vivi23--highlight-color, 10%);
+ background-color: $vivi23--nav-fg-prim-color;
+
+ .icon-bar {
+ background-color: lighten($vivi23--highlight-color, 10%);
+ }
+ }
+
+ .notification-menu {
+ .dropdown-menu {
+ background-color: $vivi23--nav-bg-color;
+ }
+
+ .notification-header {
+ background-color: $vivi23--nav-fg-sec-color;
+ border-top-width: 0;
+ color: $vivi23--nav-bg-color;
+ }
+
+ .notification-action {
+ color: $vivi23--highlight-color;
+ }
+ }
+
+ /** Buttons **/
+ // reset disabled button styling for btn-default
+ .btn-default.disabled,
+ .btn-default.disabled:hover,
+ .btn-default.disabled:focus,
+ .btn-default.disabled.focus,
+ .btn-default.disabled:active,
+ .btn-default.disabled.active,
+ .btn-default[disabled],
+ .btn-default[disabled]:hover,
+ .btn-default[disabled]:focus,
+ .btn-default[disabled].focus,
+ .btn-default[disabled]:active,
+ .btn-default[disabled].active,
+ fieldset[disabled] .btn-default,
+ fieldset[disabled] .btn-default:hover,
+ fieldset[disabled] .btn-default:focus,
+ fieldset[disabled] .btn-default.focus,
+ fieldset[disabled] .btn-default:active,
+ fieldset[disabled] .btn-default.active {
+ background-color: lighten($vivi23--button-default-color, 30%);
+ border-color: lighten($vivi23--button-default-color, 30%);
+ }
+
+ .btn-default {
+ background-color: $vivi23--button-default-color;
+ border-color: $vivi23--button-default-color;
+
+ &:hover,
+ &:active,
+ &:focus,
+ &:active:hover,
+ &:active:focus,
+ &:active.focus,
+ &.active:hover,
+ &.active:focus,
+ &.active.focus {
+ background-color: lighten($vivi23--button-default-color, 30%);
+ border-color: lighten($vivi23--button-default-color, 30%);
+ }
+ }
+
+ // disabled buttons
+ .btn-secondary.disabled,
+ .btn-secondary.disabled:hover,
+ .btn-secondary.disabled:focus,
+ .btn-secondary.disabled.focus,
+ .btn-secondary.disabled:active,
+ .btn-secondary.disabled.active,
+ .btn-secondary[disabled],
+ .btn-secondary[disabled]:hover,
+ .btn-secondary[disabled]:focus,
+ .btn-secondary[disabled].focus,
+ .btn-secondary[disabled]:active,
+ .btn-secondary[disabled].active,
+ fieldset[disabled] .btn-secondary,
+ fieldset[disabled] .btn-secondary:hover,
+ fieldset[disabled] .btn-secondary:focus,
+ fieldset[disabled] .btn-secondary.focus,
+ fieldset[disabled] .btn-secondary:active,
+ fieldset[disabled] .btn-secondary.active {
+ background-color: darken($vivi23--bg-color, 20%);
+ border-color: $vivi23--button-default-color;
+ }
+
+ .btn-secondary {
+ border-color: $vivi23--button-default-color;
+
+ &:hover,
+ &:active,
+ &:focus,
+ &:active:hover,
+ &:active:focus,
+ &:active.focus,
+ &.active:hover,
+ &.active:focus,
+ &.active.focus {
+ background-color: $vivi23--button-default-color;
+ border-color: $vivi23--button-default-color;
+ }
+ }
+
+ .btn-tertiary {
+ &:hover,
+ &:active,
+ &ctive:hover,
+ &.active:hover{
+ background-color: $vivi23--highlight-color;
+ border-color: $vivi23--highlight-color;
+ color: $vivi23--highlight-color;
+ }
+ }
+
+ /** Other components **/
+ .ascribe-piece-list-toolbar .btn-ascribe-add {
+ display: none;
+ }
+
+ .ascribe-footer {
+ display: none;
+ }
+
+ .ascribe-accordion-list-table-toggle:hover {
+ color: $vivi23--fg-color;
+ }
+
+ .request-action-badge {
+ color: $vivi23--fg-color;
+ }
+
+ .acl-information-dropdown-list .title {
+ color: $vivi23--fg-color;
+ }
+
+ // filter widget
+ .ascribe-piece-list-toolbar-filter-widget button {
+ background-color: transparent !important;
+ border-color: transparent !important;
+ color: $vivi23--button-default-color !important;
+
+ &:hover,
+ &:active {
+ background-color: $vivi23--button-default-color !important;
+ border-color: $vivi23--button-default-color !important;
+ color: $vivi23--bg-color !important;
+ }
+ }
+
+ .icon-ascribe-search {
+ color: $vivi23--fg-color;
+ }
+
+ // forms
+ .ascribe-property-wrapper:hover {
+ border-left-color: rgba($vivi23--fg-color, 0.5);
+ }
+
+ .ascribe-property textarea,
+ .ascribe-property input,
+ .search-bar > .form-group > .input-group input {
+ &::-webkit-input-placeholder {
+ color: rgba($vivi23--fg-color, 0.5);
+ }
+ &::-moz-placeholder {
+ color: rgba($vivi23--fg-color, 0.5);
+ }
+ &:-ms-input-placeholder {
+ color: rgba($vivi23--fg-color, 0.5);
+ }
+ &:-moz-placeholder {
+ color: rgba($vivi23--fg-color, 0.5);
+ }
+ }
+
+ .ascribe-property {
+ > div,
+ > input,
+ > pre,
+ > select,
+ > span:not(.glyphicon),
+ > p,
+ > p > span,
+ > textarea {
+ color: $vivi23--fg-color;
+ }
+ }
+
+ // global notification
+ .ascribe-global-notification-success {
+ background-color: lighten($vivi23--fg-color, 20%);
+ }
+
+ // uploader progress
+ .ascribe-progress-bar > .progress-bar {
+ background-color: lighten($vivi23--fg-color, 20%);
+ }
+
+ // spinner
+ .spinner-circle {
+ border-color: $vivi23--fg-color;
+ }
+ .spinner-inner {
+ display: none;
+ }
+
+ // video player
+ .ascribe-media-player .vjs-default-skin {
+ .vjs-play-progress,
+ .vjs-volume-level {
+ background-color: $vivi23--highlight-color;
+ }
+ }
+
+ // pager
+ .pager li > a,
+ .pager li > span {
+ background-color: $vivi23--fg-color;
+ border-color: $vivi23--fg-color;
+ }
+ .pager .disabled > a,
+ .pager .disabled > span {
+ background-color: $vivi23--fg-color !important;
+ border-color: $vivi23--fg-color;
+ }
+
+ // intercom
+ #intercom-container .intercom-launcher-button {
+ background-color: $vivi23--button-default-color !important;
+ border-color: $vivi23--button-default-color !important;
+ }
+}
diff --git a/sass/whitelabel/wallet/index.scss b/sass/whitelabel/wallet/index.scss
index 024fb3cc..01c374d9 100644
--- a/sass/whitelabel/wallet/index.scss
+++ b/sass/whitelabel/wallet/index.scss
@@ -1,6 +1,7 @@
@import 'cc/cc_custom_style';
@import 'cyland/cyland_custom_style';
@import 'ikonotv/ikonotv_custom_style';
+@import '23vivi/23vivi_custom_style';
.ascribe-wallet-app {
border-radius: 0;
From 2381bd22ac1cc1181fed2356b6599664f60479de Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 16:05:21 +0100
Subject: [PATCH 072/115] Change nested destructuring formatting
---
.../wallet/components/market/market_piece_list.js | 6 ++++--
.../wallet/components/market/market_register_piece.js | 5 +++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index e45da164..647a84be 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -51,8 +51,10 @@ let MarketPieceList = React.createClass({
render() {
const {
currentUser: { email: userEmail },
- whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail }
- } = this.state;
+ whitelabel: {
+ name: whitelabelName = 'Market',
+ user: whitelabelAdminEmail
+ } } = this.state;
let filterParams = null;
let canLoadPieceList = false;
diff --git a/js/components/whitelabel/wallet/components/market/market_register_piece.js b/js/components/whitelabel/wallet/components/market/market_register_piece.js
index d68be85d..e02df80c 100644
--- a/js/components/whitelabel/wallet/components/market/market_register_piece.js
+++ b/js/components/whitelabel/wallet/components/market/market_register_piece.js
@@ -117,8 +117,9 @@ let MarketRegisterPiece = React.createClass({
const {
isFineUploaderActive,
step,
- whitelabel: { name: whitelabelName = 'Market' }
- } = this.state;
+ whitelabel: {
+ name: whitelabelName = 'Market'
+ } } = this.state;
setDocumentTitle(getLangText('Register a new piece'));
From 8fcb7fcb014d20959651831721eeed233ef64b06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Wed, 2 Dec 2015 16:51:56 +0100
Subject: [PATCH 073/115] Fix render bug for personal piece note
---
js/components/ascribe_collapsible/collapsible_paragraph.js | 4 +++-
js/components/ascribe_detail/edition.js | 2 +-
js/components/ascribe_detail/piece_container.js | 5 ++++-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/js/components/ascribe_collapsible/collapsible_paragraph.js b/js/components/ascribe_collapsible/collapsible_paragraph.js
index e146b42b..7ad8d0af 100644
--- a/js/components/ascribe_collapsible/collapsible_paragraph.js
+++ b/js/components/ascribe_collapsible/collapsible_paragraph.js
@@ -12,7 +12,9 @@ const CollapsibleParagraph = React.createClass({
React.PropTypes.object,
React.PropTypes.array
]),
- iconName: React.PropTypes.string
+ iconName: React.PropTypes.string,
+ show: React.PropTypes.bool,
+ defaultExpanded: React.PropTypes.bool
},
getDefaultProps() {
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index 254746a6..78989648 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -136,7 +136,7 @@ let Edition = React.createClass({
currentUser={this.state.currentUser}/>
{return {'bitcoin_id': this.props.edition.bitcoin_id}; }}
- label={getLangText('Edition note (public)')}
+ label={getLangText('Personal note (public)')}
defaultValue={this.props.edition.public_note ? this.props.edition.public_note : null}
placeholder={getLangText('Enter your comments ...')}
editable={!!this.props.edition.acl.acl_edit}
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 8cfbd1c7..73d44c66 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -258,7 +258,9 @@ let PieceContainer = React.createClass({
+ show={!!(this.state.currentUser.username
+ || this.state.piece.acl.acl_edit
+ || this.state.piece.public_note)}>
From ed6b80df891c229dede268b55a066916e27c8dd7 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 17:54:31 +0100
Subject: [PATCH 074/115] Fix weird word breaks on edition action panel
---
sass/ascribe_panel.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss
index 09d773ad..af1366cd 100644
--- a/sass/ascribe_panel.scss
+++ b/sass/ascribe_panel.scss
@@ -26,7 +26,7 @@
vertical-align: middle;
&:first-child {
- word-break: break-all;
+ word-break: break-word;
font-size: .9em;
}
}
From 4664a488988eb50b315a290211be859ded2157a1 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 18:18:20 +0100
Subject: [PATCH 075/115] Change additional form's button text when not in
registration flow
---
.../market/market_buttons/market_submit_button.js | 3 ++-
.../market_forms/market_additional_data_form.js | 11 +++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index d75282af..60a071d8 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -129,7 +129,8 @@ let MarketSubmitButton = React.createClass({
handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
title={getLangText('Add additional information')}>
+ pieceId={solePieceId}
+ submitLabel={getLangText('Continue to consignment')} />
- {getLangText('Register work')}
+ {submitLabel}
);
From 594853535b7e592cbdf99b3d5ae6b114672be4fb Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 18:28:30 +0100
Subject: [PATCH 076/115] Fix trailing comma from previous PR merge
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Turns out this is actually illegal in ES6 but on some version of babel,
they don’t care.
Might be an ES7 thing though:
http://www.2ality.com/2015/11/trailing-comma-parameters.html
---
js/components/register_piece.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/register_piece.js b/js/components/register_piece.js
index bc0639e3..9cd1779c 100644
--- a/js/components/register_piece.js
+++ b/js/components/register_piece.js
@@ -44,7 +44,7 @@ let RegisterPiece = React.createClass( {
return mergeOptions(
UserStore.getState(),
WhitelabelStore.getState(),
- PieceListStore.getState(),
+ PieceListStore.getState()
);
},
From 743c11df5b16a47f8fcad7a39c024c1fe1443a2f Mon Sep 17 00:00:00 2001
From: diminator
Date: Wed, 2 Dec 2015 18:56:48 +0100
Subject: [PATCH 077/115] fixed cyland/ikono serializers
---
js/components/register_piece.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/register_piece.js b/js/components/register_piece.js
index bc0639e3..9cd1779c 100644
--- a/js/components/register_piece.js
+++ b/js/components/register_piece.js
@@ -44,7 +44,7 @@ let RegisterPiece = React.createClass( {
return mergeOptions(
UserStore.getState(),
WhitelabelStore.getState(),
- PieceListStore.getState(),
+ PieceListStore.getState()
);
},
From 3be033cdd5893eefe79e2dd9187b6ee73e0a8e2e Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Wed, 2 Dec 2015 19:31:50 +0100
Subject: [PATCH 078/115] Add thumbnail placeholder for 23vivi
---
.../accordion_list_item_piece.js | 28 +++++++++++++------
...cordion_list_item_thumbnail_placeholder.js | 15 ++++++++++
.../accordion_list_item_wallet.js | 23 +++++++++------
js/components/piece_list.js | 22 ++++++++++-----
...cordion_list_item_thumbnail_placeholder.js | 15 ++++++++++
.../components/23vivi/23vivi_piece_list.js | 24 ++++++++++++++++
.../components/market/market_piece_list.js | 5 +++-
.../whitelabel/wallet/wallet_routes.js | 7 +++--
sass/ascribe-fonts/ascribe-fonts.scss | 22 ---------------
sass/ascribe_accordion_list.scss | 28 +++++++++++++++++++
10 files changed, 140 insertions(+), 49 deletions(-)
create mode 100644 js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
create mode 100644 js/components/whitelabel/wallet/components/23vivi/23vivi_accordion_list/23vivi_accordion_list_item_thumbnail_placeholder.js
create mode 100644 js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
index 4547ce3b..74322e51 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
@@ -4,6 +4,7 @@ import React from 'react';
import { Link } from 'react-router';
import AccordionListItem from './accordion_list_item';
+import AccordionListItemThumbnailPlacholder from './accordion_list_item_thumbnail_placeholder';
import { getLangText } from '../../utils/lang_utils';
@@ -19,7 +20,14 @@ let AccordionListItemPiece = React.createClass({
]),
subsubheading: React.PropTypes.object,
buttons: React.PropTypes.object,
- badge: React.PropTypes.object
+ badge: React.PropTypes.object,
+ thumbnailPlaceholder: React.PropTypes.element
+ },
+
+ getDefaultProps() {
+ return {
+ thumbnailPlaceholder: AccordionListItemThumbnailPlacholder
+ };
},
getLinkData() {
@@ -34,19 +42,23 @@ let AccordionListItemPiece = React.createClass({
},
render() {
- const { className, piece, artistName, buttons, badge, children, subsubheading } = this.props;
+ const {
+ artistName,
+ badge,
+ buttons,
+ children,
+ className,
+ piece,
+ subsubheading,
+ thumbnailPlaceholder: ThumbnailPlaceholder } = this.props;
const { url, url_safe } = piece.thumbnail;
let thumbnail;
// Since we're going to refactor the thumbnail generation anyway at one point,
// for not use the annoying ascribe_spiral.png, we're matching the url against
// this name and replace it with a CSS version of the new logo.
- if(url.match(/https:\/\/.*\/media\/thumbnails\/ascribe_spiral.png/)) {
- thumbnail = (
-
- A
-
- );
+ if (url.match(/https:\/\/.*\/media\/thumbnails\/ascribe_spiral.png/)) {
+ thumbnail = ( );
} else {
thumbnail = (
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js b/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
new file mode 100644
index 00000000..6ba4d6ab
--- /dev/null
+++ b/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
@@ -0,0 +1,15 @@
+'use strict'
+
+import React from 'react';
+
+let accordionListItemThumbnailPlaceholder = React.createClass({
+ render() {
+ return (
+
+ A
+
+ );
+ }
+});
+
+export default accordionListItemThumbnailPlaceholder;
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
index da45d1e8..6fb3abeb 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
@@ -31,6 +31,7 @@ let AccordionListItemWallet = React.createClass({
propTypes: {
className: React.PropTypes.string,
content: React.PropTypes.object,
+ thumbnailPlaceholder: React.PropTypes.element,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
@@ -123,32 +124,36 @@ let AccordionListItemWallet = React.createClass({
},
render() {
+ const { children, className, content, thumbnailPlaceholder } = this.props;
return (
- {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()}
+ {Moment(content.date_created, 'YYYY-MM-DD').year()}
{this.getLicences()}
-
}
+
+ }
buttons={
}
- badge={this.getGlyphicon()}>
+
+ }
+ badge={this.getGlyphicon()}
+ thumbnailPlaceholder={thumbnailPlaceholder}>
{this.getCreateEditionsDialog()}
{/* this.props.children is AccordionListItemTableEditions */}
- {this.props.children}
+ {children}
);
}
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 9208df92..229fb078 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -38,6 +38,7 @@ let PieceList = React.createClass({
canLoadPieceList: React.PropTypes.bool,
redirectTo: React.PropTypes.string,
customSubmitButton: React.PropTypes.element,
+ customThumbnailPlaceholder: React.PropTypes.element,
filterParams: React.PropTypes.array,
orderParams: React.PropTypes.array,
orderBy: React.PropTypes.string,
@@ -251,9 +252,15 @@ let PieceList = React.createClass({
},
render() {
+ const {
+ accordionListItemType: AccordionListItemType,
+ bulkModalButtonListType: BulkModalButtonListType,
+ customSubmitButton,
+ customThumbnailPlaceholder,
+ filterParams,
+ orderParams } = this.props;
+
const loadingElement =
;
- const AccordionListItemType = this.props.accordionListItemType;
- const BulkModalButtonListType = this.props.bulkModalButtonListType;
const selectedEditions = this.fetchSelectedEditionList();
const availableAcls = getAvailableAcls(selectedEditions, (aclName) => aclName !== 'acl_view');
@@ -265,14 +272,14 @@ let PieceList = React.createClass({
className="ascribe-piece-list-toolbar"
searchFor={this.searchFor}
searchQuery={this.state.search}
- filterParams={this.props.filterParams}
- orderParams={this.props.orderParams}
+ filterParams={filterParams}
+ orderParams={orderParams}
filterBy={this.state.filterBy}
orderBy={this.state.orderBy}
applyFilterBy={this.applyFilterBy}
applyOrderBy={this.applyOrderBy}>
- {this.props.customSubmitButton ?
- this.props.customSubmitButton :
+ {customSubmitButton ?
+ customSubmitButton :
@@ -294,7 +301,7 @@ let PieceList = React.createClass({
+ filterParams={filterParams}/>
+ 23
+
+ );
+ }
+});
+
+export default Vivi23AccordionListItemThumbnailPlaceholder;
diff --git a/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js b/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
new file mode 100644
index 00000000..d889a9a0
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
@@ -0,0 +1,24 @@
+'use strict'
+
+import React from 'react';
+
+import Vivi23AccordionListItemThumbnailPlaceholder from './23vivi_accordion_list/23vivi_accordion_list_item_thumbnail_placeholder';
+
+import MarketPieceList from '../market/market_piece_list';
+
+let vivi23PieceList = React.createClass({
+ propTypes: {
+ location: React.PropTypes.object
+ },
+
+ render() {
+ return (
+
+ );
+ }
+
+});
+
+export default vivi23PieceList;
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index 8ffab5a5..a6198b4a 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -17,6 +17,7 @@ import { getLangText } from '../../../../../utils/lang_utils';
let MarketPieceList = React.createClass({
propTypes: {
+ customThumbnailPlaceholder: React.PropTypes.element,
location: React.PropTypes.object
},
@@ -49,6 +50,7 @@ let MarketPieceList = React.createClass({
},
render() {
+ const { customThumbnailPlaceholder, location } = this.props;
const { currentUser, whitelabel } = this.state;
let filterParams = null;
let canLoadPieceList = false;
@@ -72,8 +74,9 @@ let MarketPieceList = React.createClass({
canLoadPieceList={canLoadPieceList}
redirectTo="/register_piece?slide_num=0"
bulkModalButtonListType={MarketAclButtonList}
+ customThumbnailPlaceholder={customThumbnailPlaceholder}
filterParams={filterParams}
- location={this.props.location} />
+ location={location} />
);
}
});
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 92b53dc6..fbb124bf 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -37,6 +37,9 @@ import MarketEditionContainer from './components/market/market_detail/market_edi
import LumenusLanding from './components/lumenus/lumenus_landing';
+import Vivi23Landing from './components/23vivi/23vivi_landing';
+import Vivi23PieceList from './components/23vivi/23vivi_piece_list';
+
import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
import WalletApp from './wallet_app';
@@ -193,7 +196,7 @@ let ROUTES = {
),
'23vivi': (
-
+
@@ -218,7 +221,7 @@ let ROUTES = {
headerTitle='+ NEW WORK'/>
diff --git a/sass/ascribe-fonts/ascribe-fonts.scss b/sass/ascribe-fonts/ascribe-fonts.scss
index 8b66627d..a770d556 100644
--- a/sass/ascribe-fonts/ascribe-fonts.scss
+++ b/sass/ascribe-fonts/ascribe-fonts.scss
@@ -248,25 +248,3 @@
font-size: 18px;
padding: 4px 12px 0 10px
}
-
-.ascribe-logo-circle {
- border: 6px solid #F6F6F6;
- border-radius: 10em;
- position: relative;
- top: 10%;
- left: 10%;
-
- display: block;
- width: 80%;
- height: 80%;
-
- > span {
- color: #F6F6F6;
- position: absolute;
- top: -.29em;
- left: .16em;
-
- font-size: 5em;
- font-weight: normal;
- }
-}
\ No newline at end of file
diff --git a/sass/ascribe_accordion_list.scss b/sass/ascribe_accordion_list.scss
index 675bfa80..791743fc 100644
--- a/sass/ascribe_accordion_list.scss
+++ b/sass/ascribe_accordion_list.scss
@@ -60,6 +60,34 @@ $ascribe-accordion-list-item-height: 100px;
background-size: cover;
}
+ .ascribe-logo-circle {
+ border: 6px solid #F6F6F6;
+ border-radius: 10em;
+ position: relative;
+ top: 10%;
+ left: 10%;
+
+ display: block;
+ width: 80%;
+ height: 80%;
+
+ > span {
+ color: #F6F6F6;
+ position: absolute;
+ top: -.29em;
+ left: .16em;
+
+ font-size: 5em;
+ font-weight: normal;
+ }
+ }
+
+ .ascribe-thumbnail-placeholder {
+ color: #F6F6F6;
+ font-size: 5em;
+ font-weight: normal;
+ }
+
//&::before {
// content: ' ';
// display: inline-block;
From 565bf308aedee0fc845a8fb1c1b8de93961f0232 Mon Sep 17 00:00:00 2001
From: diminator
Date: Wed, 2 Dec 2015 21:42:35 +0100
Subject: [PATCH 079/115] tested and fixed ikonotv
---
.../components/ikonotv/ikonotv_register_piece.js | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
index 16d893b7..c6f59a53 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
@@ -16,6 +16,9 @@ import UserActions from '../../../../../actions/user_actions';
import PieceStore from '../../../../../stores/piece_store';
import PieceActions from '../../../../../actions/piece_actions';
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
+
import GlobalNotificationModel from '../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../actions/global_notification_actions';
@@ -47,6 +50,7 @@ let IkonotvRegisterPiece = React.createClass({
UserStore.getState(),
PieceListStore.getState(),
PieceStore.getState(),
+ WhitelabelStore.getState(),
{
step: 0,
pageExitWarning: getLangText("If you leave this form now, your work will not be loaned to Ikono TV.")
@@ -57,7 +61,9 @@ let IkonotvRegisterPiece = React.createClass({
PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
PieceStore.listen(this.onChange);
+ WhitelabelStore.listen(this.onChange);
UserActions.fetchCurrentUser();
+ WhitelabelActions.fetchWhitelabel();
// Before we load the new piece, we reset the piece store to delete old data that we do
// not want to display to the user.
@@ -81,6 +87,7 @@ let IkonotvRegisterPiece = React.createClass({
PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
PieceStore.unlisten(this.onChange);
+ WhitelabelStore.listen(this.onChange);
},
onChange(state) {
@@ -152,7 +159,8 @@ let IkonotvRegisterPiece = React.createClass({
canSubmit() {
let currentUser = this.state.currentUser;
- return currentUser && currentUser.acl && currentUser.acl.acl_wallet_submit;
+ let whitelabel = this.state.whitelabel;
+ return currentUser && currentUser.acl && currentUser.acl.acl_wallet_submit && whitelabel && whitelabel.user;
},
getSlideArtistDetails() {
@@ -194,15 +202,16 @@ let IkonotvRegisterPiece = React.createClass({
let today = new Moment();
let enddate = new Moment();
enddate.add(2, 'years');
+ const {piece, whitelabel} = this.state;
return (
Date: Thu, 3 Dec 2015 00:48:21 +0100
Subject: [PATCH 080/115] Fix prop type for MarketAdditionalDataForm's
submitLabel
---
.../market/market_forms/market_additional_data_form.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
index f43f906f..1c9b8a54 100644
--- a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
@@ -35,7 +35,7 @@ let MarketAdditionalDataForm = React.createClass({
isInline: React.PropTypes.bool,
showHeading: React.PropTypes.bool,
showNotification: React.PropTypes.bool,
- submitLabel: React.PropTypes.bool,
+ submitLabel: React.PropTypes.string,
handleSuccess: React.PropTypes.func
},
From 55bdd4e03f72f58348c19e0c985d5fd5a3b7b8e0 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 00:49:26 +0100
Subject: [PATCH 081/115] Only show the label or errors part of a Property if
they exist
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fix weird spacing for properties that don’t have labels (ie. checkboxes
for terms of service, etc)
---
js/components/ascribe_forms/property.js | 54 ++++++++++++-------------
1 file changed, 26 insertions(+), 28 deletions(-)
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index 8039e636..dce6b49b 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -2,15 +2,13 @@
import React from 'react';
import ReactAddons from 'react/addons';
+import classNames from 'classnames';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
import AppConstants from '../../constants/application_constants';
-import { mergeOptions } from '../../utils/general_utils';
-
-
let Property = React.createClass({
propTypes: {
hidden: React.PropTypes.bool,
@@ -231,44 +229,44 @@ let Property = React.createClass({
},
render() {
- let footer = null;
- let tooltip = ;
- let style = this.props.style ? mergeOptions({}, this.props.style) : {};
+ const { className, editable, footer, label, tooltip } = this.props;
+ const style = Object.assign({}, this.props.style, { cursor: !editable ? 'not-allowed' : null });
- if(this.props.tooltip){
- tooltip = (
-
- {this.props.tooltip}
- );
+ let tooltipEl = tooltip ? {tooltip}
+ : ;
+
+ let labelEl;
+ if (label || this.state.errors) {
+ labelEl = (
+
+ {label}
+ {this.state.errors}
+
+ );
}
-
- if(this.props.footer){
- footer = (
+
+ let footerEl;
+ if (footer) {
+ footerEl = (
- {this.props.footer}
-
);
- }
-
- if(!this.props.editable) {
- style.cursor = 'not-allowed';
+ {footer}
+
+ );
}
return (
-
-
- {this.props.label}
- {this.state.errors}
-
+ overlay={tooltipEl}>
+
+ {labelEl}
{this.renderChildren(style)}
- {footer}
+ {footerEl}
From 0084dbb8e4c23d3dc2a04a3486068f166a366d48 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 11:54:23 +0100
Subject: [PATCH 082/115] Change piece filter text to be normal font-weight
---
sass/main.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sass/main.scss b/sass/main.scss
index 8a732e96..5cc91e9a 100644
--- a/sass/main.scss
+++ b/sass/main.scss
@@ -350,7 +350,7 @@ hr {
> span {
font-size: 1.1em;
- font-weight: 600;
+ font-weight: normal;
color: #616161;
padding-left: .3em;
From cec652551eaf5ee33acb4f56fbe91649ea6c5820 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 12:41:27 +0100
Subject: [PATCH 083/115] Add 23vivi landing page
---
.../components/23vivi/23vivi_landing.js | 78 +++++++++++++++++++
.../wallet/23vivi/23vivi_custom_style.scss | 35 +++++++++
2 files changed, 113 insertions(+)
create mode 100644 js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
diff --git a/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js b/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
new file mode 100644
index 00000000..ebf2108d
--- /dev/null
+++ b/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
@@ -0,0 +1,78 @@
+'use strict';
+
+import React from 'react';
+
+import Button from 'react-bootstrap/lib/Button';
+import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
+
+import WhitelabelActions from '../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../stores/whitelabel_store';
+
+import { mergeOptions } from '../../../../../utils/general_utils';
+import { getLangText } from '../../../../../utils/lang_utils';
+import { setDocumentTitle } from '../../../../../utils/dom_utils';
+
+let Vivi23Landing = React.createClass({
+ getInitialState() {
+ return WhitelabelStore.getState();
+ },
+
+ componentWillMount() {
+ setDocumentTitle('23vivi Marketplace');
+ },
+
+ componentDidMount() {
+ WhitelabelStore.listen(this.onChange);
+ WhitelabelActions.fetchWhitelabel();
+ },
+
+ componentWillUnmount() {
+ WhitelabelStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
+ render() {
+ return (
+
+
+
+
+
+
+ {getLangText('Artwork from the 23vivi Marketplace is powered by') + ' '}
+
+
+
+
+
+
+ {getLangText('Existing ascribe user?')}
+
+
+
+ {getLangText('Log in')}
+
+
+
+
+
+ {getLangText('Do you need an account?')}
+
+
+
+ {getLangText('Sign up')}
+
+
+
+
+
+
+
+ );
+ }
+});
+
+export default Vivi23Landing;
diff --git a/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
index 79be4a23..37269bd6 100644
--- a/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
+++ b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
@@ -10,6 +10,41 @@ $vivi23--highlight-color: #de2600;
.client--23vivi {
+ /** Landing page **/
+ .route--landing {
+ display: table;
+
+ > .container {
+ display: table-cell;
+ padding-bottom: 100px;
+ vertical-align: middle;
+ }
+
+ .vivi23-landing {
+ font-weight: normal;
+ text-align: center;
+ }
+
+ .vivi23-landing--header {
+ background-color: $vivi23--fg-color;
+ border: 1px solid $vivi23--fg-color;
+ color: $vivi23--bg-color;
+ padding: 2em;
+
+ .vivi23-landing--header-logo {
+ margin-top: 1em;
+ margin-bottom: 2em;
+ height: 75px;
+ }
+ }
+
+ .vivi23-landing--content {
+ border: 1px solid darken($vivi23--bg-color, 20%);
+ border-top: none;
+ padding: 2em;
+ }
+ }
+
/** Navbar **/
.navbar-default {
background-color: $vivi23--nav-fg-prim-color;
From 43916625bd6e83830c93b56ca56496b46c1ce408 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 12:41:59 +0100
Subject: [PATCH 084/115] Remove header from white labels that have landing
pages
---
js/components/whitelabel/wallet/wallet_app.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/wallet_app.js b/js/components/whitelabel/wallet/wallet_app.js
index 5056716a..c2810fd0 100644
--- a/js/components/whitelabel/wallet/wallet_app.js
+++ b/js/components/whitelabel/wallet/wallet_app.js
@@ -32,7 +32,7 @@ let WalletApp = React.createClass({
// if the path of the current activeRoute is not defined, then this is the IndexRoute
if ((!path || history.isActive('/login') || history.isActive('/signup') || history.isActive('/contract_notifications'))
- && (['ikonotv']).indexOf(subdomain) > -1) {
+ && (['cyland', 'ikonotv', 'lumenus', '23vivi']).indexOf(subdomain) > -1) {
header = (
);
} else {
header = ;
From 78b8887fbf65b5e550ce3b49fddcbc2ab48f8616 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 12:44:12 +0100
Subject: [PATCH 085/115] Fix Cyland landing page
Fix font family to be Gibson, center vertically.
---
.../components/cyland/cyland_landing.js | 4 ++--
.../wallet/cyland/cyland_custom_style.scss | 21 +++++++++++++++++--
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
index 63085fc9..dc6420f4 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
@@ -57,9 +57,9 @@ let CylandLanding = React.createClass({
setDocumentTitle('CYLAND MediaArtLab');
return (
-
+
-
+
diff --git a/sass/whitelabel/wallet/cyland/cyland_custom_style.scss b/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
index eaf45621..c91239da 100644
--- a/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
+++ b/sass/whitelabel/wallet/cyland/cyland_custom_style.scss
@@ -59,7 +59,6 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
display: none;
}
-
.client--cyland .icon-ascribe-search{
color: $cyland--button-color;
}
@@ -148,6 +147,24 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
}
}
+// landing page
+.client--cyland {
+ .route--landing {
+ display: table;
+
+ > .container {
+ display: table-cell;
+ padding-bottom: 100px;
+ vertical-align: middle;
+ }
+
+ .cyland-landing {
+ font-weight: normal;
+ text-align: center;
+ }
+ }
+}
+
// spinner!
.client--cyland {
.btn-spinner {
@@ -182,4 +199,4 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
.client--cyland .acl-information-dropdown-list .title {
color: $cyland--button-color;
-}
\ No newline at end of file
+}
From bde1e454ed690e53140f3e258175c788774fad08 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 13:34:00 +0100
Subject: [PATCH 086/115] Change loan form's startdate and enddate props to be
camel case
---
js/components/ascribe_forms/form_loan.js | 75 ++++++++++++-------
.../ascribe_forms/form_loan_request_answer.js | 6 +-
.../ascribe_detail/prize_piece_container.js | 4 +-
.../cyland/cyland_register_piece.js | 4 +-
.../ikonotv/ikonotv_register_piece.js | 8 +-
5 files changed, 58 insertions(+), 39 deletions(-)
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index 7a0af7fd..84d4d58d 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -26,8 +26,8 @@ let LoanForm = React.createClass({
loanHeading: React.PropTypes.string,
email: React.PropTypes.string,
gallery: React.PropTypes.string,
- startdate: React.PropTypes.object,
- enddate: React.PropTypes.object,
+ startDate: React.PropTypes.object,
+ endDate: React.PropTypes.object,
showPersonalMessage: React.PropTypes.bool,
showEndDate: React.PropTypes.bool,
showStartDate: React.PropTypes.bool,
@@ -36,7 +36,11 @@ let LoanForm = React.createClass({
id: React.PropTypes.object,
message: React.PropTypes.string,
createPublicContractAgreement: React.PropTypes.bool,
- handleSuccess: React.PropTypes.func
+ handleSuccess: React.PropTypes.func,
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.object,
+ React.PropTypes.array
+ ])
},
getDefaultProps() {
@@ -214,14 +218,29 @@ let LoanForm = React.createClass({
},
render() {
+ const {
+ children,
+ email,
+ handleSuccess,
+ gallery,
+ loanHeading,
+ message,
+ showPersonalMessage,
+ endDate,
+ startDate,
+ showEndDate,
+ showStartDate,
+ showPassword,
+ url } = this.props;
+
return (
@@ -229,18 +248,18 @@ let LoanForm = React.createClass({
}>
-
-
{this.props.loanHeading}
+
+
{loanHeading}
+ overrideForm={!!email}>
@@ -248,31 +267,31 @@ let LoanForm = React.createClass({
+ editable={!gallery}
+ overrideForm={!!gallery}>
+ editable={!startDate}
+ overrideForm={!!startDate}
+ hidden={!showStartDate}>
+ hidden={!showEndDate}>
+ hidden={!showPersonalMessage}>
+ required={showPersonalMessage}/>
{this.getContractCheckbox()}
{this.getAppendix()}
+ hidden={!showPassword}>
+ required={showPassword ? 'required' : ''}/>
- {this.props.children}
+ {children}
);
}
diff --git a/js/components/ascribe_forms/form_loan_request_answer.js b/js/components/ascribe_forms/form_loan_request_answer.js
index 1bfe90db..349b4efc 100644
--- a/js/components/ascribe_forms/form_loan_request_answer.js
+++ b/js/components/ascribe_forms/form_loan_request_answer.js
@@ -65,8 +65,8 @@ let LoanRequestAnswerForm = React.createClass({
url={this.props.url}
email={this.state.loanRequest ? this.state.loanRequest.new_owner : null}
gallery={this.state.loanRequest ? this.state.loanRequest.gallery : null}
- startdate={startDate}
- enddate={endDate}
+ startDate={startDate}
+ endDate={endDate}
showPassword={true}
showPersonalMessage={false}
handleSuccess={this.props.handleSuccess}/>
@@ -76,4 +76,4 @@ let LoanRequestAnswerForm = React.createClass({
}
});
-export default LoanRequestAnswerForm;
\ No newline at end of file
+export default LoanRequestAnswerForm;
diff --git a/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js
index 93ca50f3..7becb847 100644
--- a/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js
+++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_detail/prize_piece_container.js
@@ -292,8 +292,8 @@ let PrizePieceRatings = React.createClass({
url={ApiUrls.ownership_loans_pieces_request}
email={this.props.currentUser.email}
gallery={this.props.piece.prize.name}
- startdate={today}
- enddate={endDate}
+ startDate={today}
+ endDate={endDate}
showPersonalMessage={true}
showPassword={false}
handleSuccess={this.handleLoanSuccess} />
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
index 85cd01bd..42b7c1ad 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
@@ -214,8 +214,8 @@ let CylandRegisterPiece = React.createClass({
url={ApiUrls.ownership_loans_pieces}
email={this.state.whitelabel.user}
gallery="Cyland Archive"
- startdate={today}
- enddate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain}
+ startDate={today}
+ endDate={datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain}
showStartDate={false}
showEndDate={false}
showPersonalMessage={false}
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
index 16d893b7..c5a8b8ec 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
@@ -192,8 +192,8 @@ let IkonotvRegisterPiece = React.createClass({
getSlideLoan() {
if (this.canSubmit()) {
let today = new Moment();
- let enddate = new Moment();
- enddate.add(2, 'years');
+ let endDate = new Moment();
+ endDate.add(2, 'years');
return (
@@ -203,8 +203,8 @@ let IkonotvRegisterPiece = React.createClass({
id={{piece_id: this.state.piece.id}}
url={ApiUrls.ownership_loans_pieces}
email="submissions@ikono.org"
- startdate={today}
- enddate={enddate}
+ startDate={today}
+ endDate={endDate}
showStartDate={false}
showEndDate={false}
gallery="IkonoTV archive"
From e1477be3936b67d8b06e21eadd50f150cc163c07 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 13:34:24 +0100
Subject: [PATCH 087/115] Fix typo in PropertyCollapsible declaration
---
js/components/ascribe_forms/property_collapsible.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/components/ascribe_forms/property_collapsible.js b/js/components/ascribe_forms/property_collapsible.js
index 92970583..db74868b 100644
--- a/js/components/ascribe_forms/property_collapsible.js
+++ b/js/components/ascribe_forms/property_collapsible.js
@@ -8,7 +8,7 @@ import Tooltip from 'react-bootstrap/lib/Tooltip';
import Panel from 'react-bootstrap/lib/Panel';
-let PropertyCollapsile = React.createClass({
+let PropertyCollapsible = React.createClass({
propTypes: {
children: React.PropTypes.arrayOf(React.PropTypes.element),
checkboxLabel: React.PropTypes.string,
@@ -93,4 +93,4 @@ let PropertyCollapsile = React.createClass({
}
});
-export default PropertyCollapsile;
\ No newline at end of file
+export default PropertyCollapsible;
From e442e6bcec919918869669cbee384df85ab914c0 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 15:21:14 +0100
Subject: [PATCH 088/115] Make email input be react controlled in loan and
consign forms
---
js/components/ascribe_forms/form_consign.js | 33 +++++++++++++++++----
js/components/ascribe_forms/form_loan.js | 21 +++++++------
2 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index d88add94..0d4fa899 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -4,11 +4,12 @@ import React from 'react';
import Button from 'react-bootstrap/lib/Button';
+import InputTextAreaToggable from './input_textarea_toggable';
import Form from './form';
import Property from './property';
-import InputTextAreaToggable from './input_textarea_toggable';
import AscribeSpinner from '../ascribe_spinner';
+
import AclInformation from '../ascribe_buttons/acl_information';
import { getLangText } from '../../utils/lang_utils.js';
@@ -30,12 +31,33 @@ let ConsignForm = React.createClass({
};
},
+ getInitialState() {
+ return {
+ email: this.props.email
+ };
+ },
+
getFormData() {
return this.props.id;
},
+ handleEmailOnChange(event) {
+ // event.target.value is the submitted email of the consignee
+ this.setState({
+ email: event && event.target && event.target.value || ''
+ });
+ },
+
render() {
- const { autoFocusProperty, email, id, handleSuccess, message, labels, url } = this.props;
+ const { email } = this.state;
+ const {
+ autoFocusProperty,
+ email: defaultEmail,
+ handleSuccess,
+ id,
+ message,
+ labels,
+ url } = this.props;
return (
+ editable={!defaultEmail}
+ onChange={this.handleEmailOnChange}
+ overrideForm={!!defaultEmail}>
+ editable={!defaultEmail}
+ onChange={this.handleEmailOnChange}
+ overrideForm={!!defaultEmail}>
Date: Thu, 3 Dec 2015 15:22:17 +0100
Subject: [PATCH 089/115] Refactor contract agreement to be a self contained
component that can be used in forms
---
js/actions/contract_agreement_list_actions.js | 40 ++---
js/components/ascribe_forms/form_consign.js | 9 +
js/components/ascribe_forms/form_loan.js | 149 ++--------------
.../property_contract_agreement.js | 168 ++++++++++++++++++
js/utils/regex_utils.js | 7 +
5 files changed, 217 insertions(+), 156 deletions(-)
create mode 100644 js/components/ascribe_forms/property_contract_agreement.js
create mode 100644 js/utils/regex_utils.js
diff --git a/js/actions/contract_agreement_list_actions.js b/js/actions/contract_agreement_list_actions.js
index 4993b129..1eedf5b0 100644
--- a/js/actions/contract_agreement_list_actions.js
+++ b/js/actions/contract_agreement_list_actions.js
@@ -22,8 +22,7 @@ class ContractAgreementListActions {
if (contractAgreementList.count > 0) {
this.actions.updateContractAgreementList(contractAgreementList.results);
resolve(contractAgreementList.results);
- }
- else{
+ } else {
resolve(null);
}
})
@@ -35,13 +34,13 @@ class ContractAgreementListActions {
);
}
- fetchAvailableContractAgreementList(issuer, createContractAgreement) {
+ fetchAvailableContractAgreementList(issuer, createPublicContractAgreement) {
return Q.Promise((resolve, reject) => {
OwnershipFetcher.fetchContractAgreementList(issuer, true, null)
.then((acceptedContractAgreementList) => {
// if there is at least an accepted contract agreement, we're going to
// use it
- if(acceptedContractAgreementList.count > 0) {
+ if (acceptedContractAgreementList.count > 0) {
this.actions.updateContractAgreementList(acceptedContractAgreementList.results);
} else {
// otherwise, we're looking for contract agreements that are still pending
@@ -50,15 +49,13 @@ class ContractAgreementListActions {
// overcomplicate the method
OwnershipFetcher.fetchContractAgreementList(issuer, null, true)
.then((pendingContractAgreementList) => {
- if(pendingContractAgreementList.count > 0) {
+ if (pendingContractAgreementList.count > 0) {
this.actions.updateContractAgreementList(pendingContractAgreementList.results);
- } else {
+ } else if (createPublicContractAgreement) {
// if there was neither a pending nor an active contractAgreement
- // found and createContractAgreement is set to true, we create a
- // new contract agreement
- if(createContractAgreement) {
- this.actions.createContractAgreementFromPublicContract(issuer);
- }
+ // found and createPublicContractAgreement is set to true, we create a
+ // new public contract agreement
+ this.actions.createContractAgreementFromPublicContract(issuer);
}
})
.catch((err) => {
@@ -81,8 +78,7 @@ class ContractAgreementListActions {
// create an agreement with the public contract if there is one
if (publicContract && publicContract.length > 0) {
return this.actions.createContractAgreement(null, publicContract[0]);
- }
- else {
+ } else {
/*
contractAgreementList in the store is already set to null;
*/
@@ -91,21 +87,17 @@ class ContractAgreementListActions {
if (publicContracAgreement) {
this.actions.updateContractAgreementList([publicContracAgreement]);
}
- }).catch((err) => {
- console.logGlobal(err);
- });
+ }).catch(console.logGlobal);
}
createContractAgreement(issuer, contract){
return Q.Promise((resolve, reject) => {
- OwnershipFetcher.createContractAgreement(issuer, contract).then(
- (contractAgreement) => {
- resolve(contractAgreement);
- }
- ).catch((err) => {
- console.logGlobal(err);
- reject(err);
- });
+ OwnershipFetcher
+ .createContractAgreement(issuer, contract).then(resolve)
+ .catch((err) => {
+ console.logGlobal(err);
+ reject(err);
+ });
});
}
}
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index 0d4fa899..77f81a69 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -4,6 +4,7 @@ import React from 'react';
import Button from 'react-bootstrap/lib/Button';
+import ContractAgreementProperty from './property_contract_agreement';
import InputTextAreaToggable from './input_textarea_toggable';
import Form from './form';
import Property from './property';
@@ -22,6 +23,7 @@ let ConsignForm = React.createClass({
email: React.PropTypes.string,
message: React.PropTypes.string,
labels: React.PropTypes.object,
+ createPublicContractAgreement: React.PropTypes.bool,
handleSuccess: React.PropTypes.func
},
@@ -52,6 +54,7 @@ let ConsignForm = React.createClass({
const { email } = this.state;
const {
autoFocusProperty,
+ createPublicContractAgreement,
email: defaultEmail,
handleSuccess,
id,
@@ -107,6 +110,12 @@ let ConsignForm = React.createClass({
placeholder={getLangText('Enter a message...')}
required />
+
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index 022d81d9..a0b1240f 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -6,20 +6,18 @@ import classnames from 'classnames';
import Button from 'react-bootstrap/lib/Button';
+import ContractAgreementProperty from './property_contract_agreement';
import Form from './form';
-import Property from './property';
import InputTextAreaToggable from './input_textarea_toggable';
import InputDate from './input_date';
-import InputCheckbox from './input_checkbox';
-
-import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
-import ContractAgreementListActions from '../../actions/contract_agreement_list_actions';
+import Property from './property';
import AscribeSpinner from '../ascribe_spinner';
+import AclInformation from '../ascribe_buttons/acl_information';
+
import { mergeOptions } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
-import AclInformation from '../ascribe_buttons/acl_information';
let LoanForm = React.createClass({
propTypes: {
@@ -49,55 +47,20 @@ let LoanForm = React.createClass({
showPersonalMessage: true,
showEndDate: true,
showStartDate: true,
- showPassword: true,
- createPublicContractAgreement: true
+ showPassword: true
};
},
getInitialState() {
- return ContractAgreementListStore.getState();
- },
-
- componentDidMount() {
- ContractAgreementListStore.listen(this.onChange);
- this.getContractAgreementsOrCreatePublic(this.props.email);
- },
-
- /**
- * This method needs to be in form_loan as some whitelabel pages (Cyland) load
- * the loanee's email async!
- *
- * SO LEAVE IT IN!
- */
- componentWillReceiveProps(nextProps) {
- if(nextProps && nextProps.email && this.props.email !== nextProps.email) {
- this.getContractAgreementsOrCreatePublic(nextProps.email);
- }
- },
-
- componentWillUnmount() {
- ContractAgreementListStore.unlisten(this.onChange);
- },
-
- onChange(state) {
- this.setState(state);
- },
-
- getContractAgreementsOrCreatePublic(email){
- ContractAgreementListActions.flushContractAgreementList.defer();
- if (email) {
- // fetch the available contractagreements (pending/accepted)
- ContractAgreementListActions.fetchAvailableContractAgreementList(email, true);
- }
return {
email: this.props.email || ''
};
},
- getFormData(){
+ getFormData() {
return mergeOptions(
this.props.id,
- this.getContractAgreementId()
+ this.refs.contractAgreement.getFormDataForProperty()
);
},
@@ -108,90 +71,8 @@ let LoanForm = React.createClass({
});
},
- getContractAgreementId() {
- if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
- return {'contract_agreement_id': this.state.contractAgreementList[0].id};
- }
- return {};
- },
-
- getContractCheckbox() {
- if(this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
- // we need to define a key on the InputCheckboxes as otherwise
- // react is not rerendering them on a store switch and is keeping
- // the default value of the component (which is in that case true)
- let contractAgreement = this.state.contractAgreementList[0];
- let contract = contractAgreement.contract;
-
- if(contractAgreement.datetime_accepted) {
- return (
-
-
-
- {getLangText('Download contract')}
-
- {/* We still need to send the server information that we're accepting */}
-
-
- );
- } else {
- return (
-
-
-
- {getLangText('I agree to the')}
-
- {getLangText('terms of ')} {contract.issuer}
-
-
-
-
- );
- }
- } else {
- return (
-
-
-
- );
- }
- },
-
- getAppendix() {
- if(this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
- let appendix = this.state.contractAgreementList[0].appendix;
- if (appendix && appendix.default) {
- return (
-
- {appendix.default}
-
- );
- }
- }
- return null;
+ handleReset(event) {
+ this.handleEmailOnChange();
},
getButtons() {
@@ -222,7 +103,7 @@ let LoanForm = React.createClass({
const { email } = this.state;
const {
children,
- email,
+ createPublicContractAgreement,
email: defaultEmail,
handleSuccess,
gallery,
@@ -242,7 +123,7 @@ let LoanForm = React.createClass({
ref='form'
url={url}
getFormData={this.getFormData}
- onReset={this.handleOnChange}
+ onReset={this.handleReset}
handleSuccess={handleSuccess}
buttons={this.getButtons()}
spinner={
@@ -309,8 +190,12 @@ let LoanForm = React.createClass({
placeholder={getLangText('Enter a message...')}
required={showPersonalMessage}/>
- {this.getContractCheckbox()}
- {this.getAppendix()}
+
0) {
+ ContractAgreementListActions.flushContractAgreementList();
+ }
+ },
+
+ componentWillUnmount() {
+ ContractAgreementListStore.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
+ getFormDataForProperty() {
+ return this.getContractAgreementId();
+ },
+
+ getContractAgreementId() {
+ if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
+ return { 'contract_agreement_id': this.state.contractAgreementList[0].id };
+ } else {
+ return {};
+ }
+ },
+
+ getContractAgreementsOrCreatePublic(email) {
+ ContractAgreementListActions.flushContractAgreementList.defer();
+
+ if (email) {
+ // fetch the available contractagreements (pending/accepted)
+ ContractAgreementListActions.fetchAvailableContractAgreementList(email, this.props.createPublicContractAgreement);
+ }
+ },
+
+ getAppendix() {
+ const { contractAgreementList } = this.state;
+
+ if (contractAgreementList && contractAgreementList.length > 0) {
+ const appendix = contractAgreementList[0].appendix;
+ if (appendix && appendix.default) {
+ return (
+
+ {appendix.default}
+
+ );
+ }
+ }
+ },
+
+ getContractCheckbox() {
+ const { contractAgreementList } = this.state;
+
+ if (contractAgreementList && contractAgreementList.length > 0) {
+ // we need to define a key on the InputCheckboxes as otherwise
+ // react is not rerendering them on a store switch and is keeping
+ // the default value of the component (which is in that case true)
+ const contractAgreement = contractAgreementList[0];
+ const { issuer: contractIssuer, blob: { url_safe: contractUrl } } = contractAgreement.contract;
+
+ if (contractAgreement.datetime_accepted) {
+ return (
+
+
+
+ {getLangText('Download contract')}
+
+ {/* We still need to send the server information that we're accepting */}
+
+
+ );
+ } else {
+ return (
+
+
+
+ {getLangText('I agree to the')}
+
+ {getLangText('terms of ')} {contractIssuer}
+
+
+
+
+ );
+ }
+ } else {
+ return (
+
+
+
+ );
+ }
+ },
+
+ render() {
+ return (
+
+ {this.getContractCheckbox()}
+ {this.getAppendix()}
+
+ );
+ }
+});
+
+export default ContractAgreementProperty;
diff --git a/js/utils/regex_utils.js b/js/utils/regex_utils.js
new file mode 100644
index 00000000..af948b2b
--- /dev/null
+++ b/js/utils/regex_utils.js
@@ -0,0 +1,7 @@
+'use strict'
+
+export function isEmail(string) {
+ // This is a bit of a weak test for an email, but you really can't win them all
+ // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address
+ return !!string && string.match(/.*@.*\..*/);
+}
From 328d60b279d51328656f22f1087f862769e6e426 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 15:22:37 +0100
Subject: [PATCH 090/115] Rename ContractAgreementForm to avoid confusion with
ContractAgreementProperty
---
...ontract_agreement.js => form_send_contract_agreement.js} | 6 +++---
js/components/whitelabel/wallet/wallet_routes.js | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
rename js/components/ascribe_forms/{form_contract_agreement.js => form_send_contract_agreement.js} (97%)
diff --git a/js/components/ascribe_forms/form_contract_agreement.js b/js/components/ascribe_forms/form_send_contract_agreement.js
similarity index 97%
rename from js/components/ascribe_forms/form_contract_agreement.js
rename to js/components/ascribe_forms/form_send_contract_agreement.js
index fa73fe42..8d0170fd 100644
--- a/js/components/ascribe_forms/form_contract_agreement.js
+++ b/js/components/ascribe_forms/form_send_contract_agreement.js
@@ -21,7 +21,7 @@ import { getLangText } from '../../utils/lang_utils';
import { mergeOptions } from '../../utils/general_utils';
-let ContractAgreementForm = React.createClass({
+let SendContractAgreementForm = React.createClass({
propTypes: {
handleSuccess: React.PropTypes.func
},
@@ -55,7 +55,7 @@ let ContractAgreementForm = React.createClass({
},
handleSubmitSuccess() {
- let notification = 'Contract agreement send';
+ let notification = 'Contract agreement sent';
notification = new GlobalNotificationModel(notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
@@ -148,4 +148,4 @@ let ContractAgreementForm = React.createClass({
}
});
-export default ContractAgreementForm;
\ No newline at end of file
+export default SendContractAgreementForm;
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index 92b53dc6..f65e20fb 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -25,7 +25,7 @@ import CylandPieceList from './components/cyland/cyland_piece_list';
import IkonotvLanding from './components/ikonotv/ikonotv_landing';
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
-import ContractAgreementForm from '../../../components/ascribe_forms/form_contract_agreement';
+import SendContractAgreementForm from '../../../components/ascribe_forms/form_send_contract_agreement';
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
@@ -135,7 +135,7 @@ let ROUTES = {
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
Date: Thu, 3 Dec 2015 17:17:52 +0100
Subject: [PATCH 091/115] Add hot fix from AD-1313 for using refs in properties
https://github.com/ascribe/onion/blob/AD-1313-Attach-thumbnail-to-piece-
in-register-form/js/components/ascribe_forms/form.js
---
js/components/ascribe_forms/form.js | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js
index 0e3517a2..850de032 100644
--- a/js/components/ascribe_forms/form.js
+++ b/js/components/ascribe_forms/form.js
@@ -238,7 +238,15 @@ let Form = React.createClass({
renderChildren() {
return ReactAddons.Children.map(this.props.children, (child, i) => {
if (child) {
- return ReactAddons.addons.cloneWithProps(child, {
+ // Since refs will be overwritten by this functions return statement,
+ // we still want to be able to define refs for nested `Form` or `Property`
+ // children, which is why we're upfront simply invoking the callback-ref-
+ // function before overwriting it.
+ if(typeof child.ref === 'function' && this.refs[child.props.name]) {
+ child.ref(this.refs[child.props.name]);
+ }
+
+ return React.cloneElement(child, {
handleChange: this.handleChangeChild,
ref: child.props.name,
key: i,
From f5a527b251b1518f7958b60828a4bf08f58b5fbe Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Thu, 3 Dec 2015 17:19:17 +0100
Subject: [PATCH 092/115] Fix references to form due to nested property
elements
---
js/components/ascribe_forms/form.js | 8 ++-
js/components/ascribe_forms/form_loan.js | 17 +++---
.../property_contract_agreement.js | 55 +++++++++++++------
sass/ascribe_notification_page.scss | 4 +-
4 files changed, 57 insertions(+), 27 deletions(-)
diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js
index 850de032..6be7fa2d 100644
--- a/js/components/ascribe_forms/form.js
+++ b/js/components/ascribe_forms/form.js
@@ -124,8 +124,12 @@ let Form = React.createClass({
getFormData() {
let data = {};
- for (let ref in this.refs) {
- data[this.refs[ref].props.name] = this.refs[ref].state.value;
+ for (let refName in this.refs) {
+ const ref = this.refs[refName];
+
+ if (ref.state && 'value' in ref.state) {
+ data[ref.props.name] = ref.state.value;
+ }
}
if (typeof this.props.getFormData === 'function') {
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index a0b1240f..0b4f4775 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -57,13 +57,6 @@ let LoanForm = React.createClass({
};
},
- getFormData() {
- return mergeOptions(
- this.props.id,
- this.refs.contractAgreement.getFormDataForProperty()
- );
- },
-
handleEmailOnChange(event) {
// event.target.value is the submitted email of the loanee
this.setState({
@@ -75,6 +68,13 @@ let LoanForm = React.createClass({
this.handleEmailOnChange();
},
+ getFormData() {
+ return mergeOptions(
+ this.props.id,
+ this.refs.contractAgreement.getFormDataForProperty()
+ );
+ },
+
getButtons() {
if(this.props.loanHeading) {
return (
@@ -191,10 +191,11 @@ let LoanForm = React.createClass({
required={showPersonalMessage}/>
this.refs.contractAgreement = ref}
createPublicContractAgreement={createPublicContractAgreement}
email={email}
embedClassName={'loan-form'}
+ name='contract_agreement'
label={getLangText('Loan Contract')} />
0) {
- ContractAgreementListActions.flushContractAgreementList();
+ if (this.props.email !== nextEmail) {
+ if (isEmail(nextEmail)) {
+ this.getContractAgreementsOrCreatePublic(nextEmail);
+ } else if (contractAgreementList && contractAgreementList.length > 0) {
+ ContractAgreementListActions.flushContractAgreementList();
+ }
}
},
@@ -53,14 +61,21 @@ let ContractAgreementProperty = React.createClass({
},
getFormDataForProperty() {
- return this.getContractAgreementId();
+ const contractAgreementId = this.getContractAgreementId();
+ const formData = {
+ 'terms': this.refs.terms.state.value
+ };
+
+ if (contractAgreementId) {
+ formData.contract_agreement_id = contractAgreementId;
+ }
+
+ return formData;
},
getContractAgreementId() {
if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
- return { 'contract_agreement_id': this.state.contractAgreementList[0].id };
- } else {
- return {};
+ return this.state.contractAgreementList[0].id;
}
},
@@ -82,7 +97,8 @@ let ContractAgreementProperty = React.createClass({
return (
+ label={getLangText('Appendix')}
+ handleChange={this.props.handleChange}>
{appendix.default}
);
@@ -91,24 +107,27 @@ let ContractAgreementProperty = React.createClass({
},
getContractCheckbox() {
+ const { embedClassName, handleChange, label } = this.props;
const { contractAgreementList } = this.state;
if (contractAgreementList && contractAgreementList.length > 0) {
- // we need to define a key on the InputCheckboxes as otherwise
- // react is not rerendering them on a store switch and is keeping
- // the default value of the component (which is in that case true)
const contractAgreement = contractAgreementList[0];
const { issuer: contractIssuer, blob: { url_safe: contractUrl } } = contractAgreement.contract;
+ // we need to define a key on the InputCheckboxes as otherwise
+ // react is not rerendering them on a store switch and is keeping
+ // the default value of the component (which is in that case true)
if (contractAgreement.datetime_accepted) {
return (
@@ -125,8 +144,10 @@ let ContractAgreementProperty = React.createClass({
} else {
return (
Date: Thu, 3 Dec 2015 17:43:15 +0100
Subject: [PATCH 093/115] Revert "Merge with AD-1443"
Revert https://github.com/ascribe/onion/pull/40, as that needs more
work.
---
js/components/piece_list.js | 5 ++--
js/stores/edition_list_store.js | 43 +++++++++++++++++++++++----------
2 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 9208df92..4a96cbd8 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -189,14 +189,13 @@ let PieceList = React.createClass({
this.state.pieceList
.forEach((piece) => {
// but only if they're actually open
- const isEditionListOpenForPiece = this.state.isEditionListOpenForPieceId[piece.id];
-
- if (isEditionListOpenForPiece && isEditionListOpenForPiece.show) {
+ if(this.state.isEditionListOpenForPieceId[piece.id].show) {
EditionListActions.refreshEditionList({
pieceId: piece.id,
filterBy
});
}
+
});
});
diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js
index 6b4d64f9..107f9af4 100644
--- a/js/stores/edition_list_store.js
+++ b/js/stores/edition_list_store.js
@@ -32,7 +32,7 @@ class EditionListStore {
// page
let storeEditionIndex = (page - 1) * pageSize + i;
let editionsForPieces = this.editionList[pieceId];
-
+
// if edition already exists, just merge
if(editionsForPieces[storeEditionIndex]) {
editionsForPieces[storeEditionIndex] = React.addons.update(editionsForPieces[storeEditionIndex], {$merge: editionListOfPiece[i]});
@@ -60,29 +60,46 @@ class EditionListStore {
* We often just have to refresh the edition list for a certain pieceId,
* this method provides exactly that functionality without any side effects
*/
- onRefreshEditionList({pieceId, filterBy = this.editionList[pieceId].filterBy}) {
- const pieceEditionList = this.editionList[pieceId];
-
+ onRefreshEditionList({pieceId, filterBy = {}}) {
// It may happen that the user enters the site logged in already
// through /editions
// If he then tries to delete a piece/edition and this method is called,
// we'll not be able to refresh his edition list since its not yet there.
// Therefore we can just return, since there is no data to be refreshed
- if (!pieceEditionList) {
+ if(!this.editionList[pieceId]) {
return;
}
+ let prevEditionListLength = this.editionList[pieceId].length;
+ let prevEditionListPage = this.editionList[pieceId].page;
+ let prevEditionListPageSize = this.editionList[pieceId].pageSize;
+
+ // we can also refresh the edition list using filterBy,
+ // if we decide not to do that then the old filter will just be applied.
+ if(filterBy && Object.keys(filterBy).length <= 0) {
+ filterBy = this.editionList[pieceId].filterBy;
+ prevEditionListLength = 10;
+ prevEditionListPage = 1;
+ prevEditionListPageSize = 10;
+ }
+
// to clear an array, david walsh recommends to just set it's length to zero
// http://davidwalsh.name/empty-array
- pieceEditionList.length = 0;
+ this.editionList[pieceId].length = 0;
- // refetch editions from the beginning with the previous settings
- EditionsListActions
- .fetchEditionList(pieceId, 1, pieceEditionList.pageSize,
- pieceEditionList.orderBy,
- pieceEditionList.orderAsc,
- filterBy)
- .catch(console.logGlobal);
+ // refetch editions with adjusted page size
+ EditionsListActions.fetchEditionList(pieceId, 1, prevEditionListLength,
+ this.editionList[pieceId].orderBy,
+ this.editionList[pieceId].orderAsc,
+ filterBy)
+ .then(() => {
+ // reset back to the normal pageSize and page
+ this.editionList[pieceId].page = prevEditionListPage;
+ this.editionList[pieceId].pageSize = prevEditionListPageSize;
+ })
+ .catch((err) => {
+ console.logGlobal(err);
+ });
}
onSelectEdition({pieceId, editionId, toValue}) {
From cb19c46dac9cfc499547512ec629f6729bc0f4ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Thu, 3 Dec 2015 20:09:27 +0100
Subject: [PATCH 094/115] Implement PropertyCollapsible's functionality into
Property
---
js/components/ascribe_forms/property.js | 206 +++++++++++++++---------
1 file changed, 129 insertions(+), 77 deletions(-)
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index dce6b49b..d0b6ef37 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -2,61 +2,69 @@
import React from 'react';
import ReactAddons from 'react/addons';
-import classNames from 'classnames';
-import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
-import Tooltip from 'react-bootstrap/lib/Tooltip';
+import Panel from 'react-bootstrap/lib/Panel';
import AppConstants from '../../constants/application_constants';
-let Property = React.createClass({
- propTypes: {
- hidden: React.PropTypes.bool,
+import { mergeOptions } from '../../utils/general_utils';
- autoFocus: React.PropTypes.bool,
- editable: React.PropTypes.bool,
+
+const { bool, element, string, oneOfType, func, object, arrayOf } = React.PropTypes;
+
+const Property = React.createClass({
+ propTypes: {
+ editable: bool,
// If we want Form to have a different value for disabled as Property has one for
// editable, we need to set overrideForm to true, as it will then override Form's
// disabled value for individual Properties
- overrideForm: React.PropTypes.bool,
+ overrideForm: bool,
- tooltip: React.PropTypes.element,
- label: React.PropTypes.string,
- value: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.element
+ label: string,
+ value: oneOfType([
+ string,
+ element
]),
- footer: React.PropTypes.element,
- handleChange: React.PropTypes.func,
- ignoreFocus: React.PropTypes.bool,
- name: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.number
- ]).isRequired,
- className: React.PropTypes.string,
+ footer: element,
+ handleChange: func,
+ ignoreFocus: bool,
+ name: string.isRequired,
+ className: string,
- onClick: React.PropTypes.func,
- onChange: React.PropTypes.func,
- onBlur: React.PropTypes.func,
+ onClick: func,
+ onChange: func,
+ onBlur: func,
- children: React.PropTypes.oneOfType([
- React.PropTypes.arrayOf(React.PropTypes.element),
- React.PropTypes.element
+ children: oneOfType([
+ arrayOf(element),
+ element
]),
- style: React.PropTypes.object
+ style: object,
+ expanded: bool,
+ checkboxLabel: string
},
getDefaultProps() {
return {
editable: true,
- hidden: false,
+ expanded: true,
className: ''
};
},
getInitialState() {
+ const { expanded, ignoreFocus, checkboxLabel } = this.props;
+
return {
+ // We're mirroring expanded here as a state
+ // React's docs do NOT consider this an antipattern as long as it's
+ // not a "source of truth"-duplication
+ expanded,
+
+ // When a checkboxLabel is defined in the props, we want to set
+ // `ignoreFocus` to true
+ ignoreFocus: ignoreFocus || checkboxLabel,
// Please don't confuse initialValue with react's defaultValue.
// initialValue is set by us to ensure that a user can reset a specific
// property (after editing) to its initial value
@@ -67,15 +75,19 @@ let Property = React.createClass({
};
},
- componentDidMount() {
- if (this.props.autoFocus) {
- this.handleFocus();
- }
- },
-
- componentWillReceiveProps() {
+ componentWillReceiveProps(nextProps) {
let childInput = this.refs.input;
+ // For expanded there are actually two use cases:
+ //
+ // 1. Control its value from the outside completely (do not define `checkboxLabel`)
+ // 2. Let it be controlled from the inside (default value can be set though via `expanded`)
+ //
+ // This handles case 1.
+ if(nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
+ this.setState({ expanded: nextProps.expanded });
+ }
+
// In order to set this.state.value from another component
// the state of value should only be set if its not undefined and
// actually references something
@@ -88,13 +100,13 @@ let Property = React.createClass({
// from native HTML elements.
// To enable developers to create input elements, they can expose a property called value
// in their state that will be picked up by property.js
- } else if(childInput.state && typeof childInput.state.value !== 'undefined') {
+ } else if(childInput && childInput.state && typeof childInput.state.value !== 'undefined') {
this.setState({
value: childInput.state.value
});
}
- if(!this.state.initialValue && childInput.props.defaultValue) {
+ if(!this.state.initialValue && childInput && childInput.props.defaultValue) {
this.setState({
initialValue: childInput.props.defaultValue
});
@@ -146,7 +158,7 @@ let Property = React.createClass({
handleFocus() {
// if ignoreFocus (bool) is defined, then just ignore focusing on
// the property and input
- if(this.props.ignoreFocus) {
+ if(this.state.ignoreFocus) {
return;
}
@@ -198,7 +210,7 @@ let Property = React.createClass({
},
getClassName() {
- if(this.props.hidden){
+ if(!this.state.expanded && !this.props.checkboxLabel){
return 'is-hidden';
}
if(!this.props.editable){
@@ -215,63 +227,103 @@ let Property = React.createClass({
},
renderChildren(style) {
- return ReactAddons.Children.map(this.props.children, (child) => {
- return ReactAddons.addons.cloneWithProps(child, {
- style,
- onChange: this.handleChange,
- onFocus: this.handleFocus,
- onBlur: this.handleBlur,
- disabled: !this.props.editable,
- ref: 'input',
- name: this.props.name
+ // Input's props should only be cloned and propagated down the tree,
+ // if the component is actually being shown (!== 'expanded === false')
+ if((this.state.expanded && this.props.checkboxLabel) || !this.props.checkboxLabel) {
+ return ReactAddons.Children.map(this.props.children, (child) => {
+
+ // Since refs will be overriden by this functions return statement,
+ // we still want to be able to define refs for nested `Form` or `Property`
+ // children, which is why we're upfront simply invoking the callback-ref-
+ // function before overriding it.
+ if(typeof child.ref === 'function' && this.refs.input) {
+ child.ref(this.refs.input);
+ }
+
+ return React.cloneElement(child, {
+ style,
+ onChange: this.handleChange,
+ onFocus: this.handleFocus,
+ onBlur: this.handleBlur,
+ disabled: !this.props.editable,
+ ref: 'input',
+ name: this.props.name
+ });
});
- });
+ }
},
- render() {
- const { className, editable, footer, label, tooltip } = this.props;
- const style = Object.assign({}, this.props.style, { cursor: !editable ? 'not-allowed' : null });
-
- let tooltipEl = tooltip ? {tooltip}
- : ;
-
- let labelEl;
- if (label || this.state.errors) {
- labelEl = (
+ getLabelAndErrors() {
+ if(this.props.label || this.state.errors) {
+ return (
- {label}
+ {this.props.label}
{this.state.errors}
);
+ } else {
+ return null;
}
+ },
- let footerEl;
- if (footer) {
- footerEl = (
-
- {footer}
+ handleCheckboxToggle() {
+ this.setState({expanded: !this.state.expanded});
+ },
+
+ getCheckbox() {
+ const { checkboxLabel } = this.props;
+
+ if(checkboxLabel) {
+ return (
+
+
+ {' ' + checkboxLabel}
);
+ } else {
+ return null;
}
+ },
+
+ render() {
+ let footer = null;
+ let style = this.props.style ? mergeOptions({}, this.props.style) : {};
+
+ if(this.props.footer){
+ footer = (
+
+ {this.props.footer}
+
);
+ }
+
+ style.paddingBottom = !this.state.expanded ? 0 : null;
+ style.cursor = !this.props.editable ? 'not-allowed' : null;
return (
-
-
- {labelEl}
+ {this.getCheckbox()}
+
+
+ {this.getLabelAndErrors()}
{this.renderChildren(style)}
- {footerEl}
+ {footer}
-
+
);
}
});
-export default Property;
+export default Property;
\ No newline at end of file
From 8ec0634d2edb2da281d5ea66870f71c82b3e5b3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Thu, 3 Dec 2015 20:26:53 +0100
Subject: [PATCH 095/115] Cherry-pick from
1ac2fe7f9694254c75f0cff46222d895d97dd791:
- Integrate PropertyCollapsible's functionality to Property
---
.../ascribe_detail/edition_action_panel.js | 4 ++--
.../ascribe_forms/form_create_contract.js | 4 ++--
js/components/ascribe_forms/form_loan.js | 10 +++++-----
.../cyland_forms/cyland_additional_data_form.js | 14 +++++++-------
.../ikonotv_forms/ikonotv_artist_details_form.js | 8 ++++----
.../ikonotv_forms/ikonotv_artwork_details_form.js | 12 ++++++------
6 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/js/components/ascribe_detail/edition_action_panel.js b/js/components/ascribe_detail/edition_action_panel.js
index 07827fcd..fbc56bee 100644
--- a/js/components/ascribe_detail/edition_action_panel.js
+++ b/js/components/ascribe_detail/edition_action_panel.js
@@ -127,7 +127,7 @@ let EditionActionPanel = React.createClass({
isInline={true}>
+ expanded={false}>
+ expanded={false}>
+ expanded={false}>
+ expanded={false}>
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index 0b4f4775..1381bf28 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -64,7 +64,7 @@ let LoanForm = React.createClass({
});
},
- handleReset(event) {
+ handleReset() {
this.handleEmailOnChange();
},
@@ -163,7 +163,7 @@ let LoanForm = React.createClass({
label={getLangText('Start date')}
editable={!startDate}
overrideForm={!!startDate}
- hidden={!showStartDate}>
+ expanded={showStartDate}>
@@ -173,7 +173,7 @@ let LoanForm = React.createClass({
editable={!endDate}
overrideForm={!!endDate}
label={getLangText('End date')}
- hidden={!showEndDate}>
+ expanded={showEndDate}>
@@ -183,7 +183,7 @@ let LoanForm = React.createClass({
label={getLangText('Personal Message')}
editable={true}
overrideForm={true}
- hidden={!showPersonalMessage}>
+ expanded={showPersonalMessage}>
+ expanded={showPassword}>
+ expanded={!disabled && piece.extra_data.artist_bio}>
+ expanded={!disabled && piece.extra_data.artist_contact_information}>
+ expanded={!disabled && piece.extra_data.conceptual_overview}>
+ expanded={!disabled && piece.extra_data.medium}>
+ expanded={!disabled && piece.extra_data.size_duration}>
+ expanded={!disabled && piece.extra_data.display_instructions}>
+ expanded={!disabled && piece.extra_data.additional_details}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.artist_website}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.gallery_website}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.additional_websites}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.conceptual_overview}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.medium}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.size_duration}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.copyright}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.courtesy_of}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.copyright_of_photography}>
+ expanded={!this.props.disabled && this.props.piece.extra_data.additional_details}>
Date: Thu, 3 Dec 2015 21:29:56 +0100
Subject: [PATCH 096/115] Refactor ContractAgreementProperty to
InputContractAgreementCheckbox. Thx to @Brett
---
js/components/ascribe_forms/form.js | 9 +-
js/components/ascribe_forms/form_consign.js | 20 +-
js/components/ascribe_forms/form_loan.js | 35 ++--
.../input_contract_agreement_checkbox.js | 194 ++++++++++++++++++
js/components/ascribe_forms/property.js | 15 +-
.../property_contract_agreement.js | 191 -----------------
6 files changed, 245 insertions(+), 219 deletions(-)
create mode 100644 js/components/ascribe_forms/input_contract_agreement_checkbox.js
delete mode 100644 js/components/ascribe_forms/property_contract_agreement.js
diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js
index 6be7fa2d..37750010 100644
--- a/js/components/ascribe_forms/form.js
+++ b/js/components/ascribe_forms/form.js
@@ -128,7 +128,14 @@ let Form = React.createClass({
const ref = this.refs[refName];
if (ref.state && 'value' in ref.state) {
- data[ref.props.name] = ref.state.value;
+ // An input can also provide an `Object` as a value
+ // which we're going to merge with `data` (overwrites)
+ if(ref.state.value.constructor === Object) {
+ console.log(ref.state.value);
+ Object.assign(data, ref.state.value);
+ } else {
+ data[ref.props.name] = ref.state.value;
+ }
}
}
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index 77f81a69..c4942f30 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -4,11 +4,13 @@ import React from 'react';
import Button from 'react-bootstrap/lib/Button';
-import ContractAgreementProperty from './property_contract_agreement';
-import InputTextAreaToggable from './input_textarea_toggable';
import Form from './form';
import Property from './property';
+import InputContractAgreementCheckbox from './input_contract_agreement_checkbox';
+import InputTextAreaToggable from './input_textarea_toggable';
+
+
import AscribeSpinner from '../ascribe_spinner';
import AclInformation from '../ascribe_buttons/acl_information';
@@ -110,12 +112,14 @@ let ConsignForm = React.createClass({
placeholder={getLangText('Enter a message...')}
required />
-
+
+
+
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index 1381bf28..b8370016 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -1,23 +1,26 @@
'use strict';
import React from 'react';
-
import classnames from 'classnames';
import Button from 'react-bootstrap/lib/Button';
-import ContractAgreementProperty from './property_contract_agreement';
+import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
+
import Form from './form';
-import InputTextAreaToggable from './input_textarea_toggable';
-import InputDate from './input_date';
import Property from './property';
+import InputDate from './input_date';
+import InputTextAreaToggable from './input_textarea_toggable';
+import InputContractAgreementCheckbox from './input_contract_agreement_checkbox';
+
import AscribeSpinner from '../ascribe_spinner';
import AclInformation from '../ascribe_buttons/acl_information';
-import { mergeOptions } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
+import { mergeOptions } from '../../utils/general_utils';
+
let LoanForm = React.createClass({
propTypes: {
@@ -57,6 +60,10 @@ let LoanForm = React.createClass({
};
},
+ onChange(state) {
+ this.setState(state);
+ },
+
handleEmailOnChange(event) {
// event.target.value is the submitted email of the loanee
this.setState({
@@ -69,10 +76,7 @@ let LoanForm = React.createClass({
},
getFormData() {
- return mergeOptions(
- this.props.id,
- this.refs.contractAgreement.getFormDataForProperty()
- );
+ return this.props.id;
},
getButtons() {
@@ -190,13 +194,14 @@ let LoanForm = React.createClass({
placeholder={getLangText('Enter a message...')}
required={showPersonalMessage}/>
- this.refs.contractAgreement = ref}
- createPublicContractAgreement={createPublicContractAgreement}
- email={email}
- embedClassName={'loan-form'}
+
+ label={getLangText('Loan Contract')}
+ className="ascribe-property-collapsible-toggle">
+
+
0) {
+ ContractAgreementListActions.flushContractAgreementList();
+ }
+ }
+ },
+
+ componentWillUnmount() {
+ ContractAgreementListStore.unlisten(this.onStoreChange);
+ },
+
+ onStoreChange(state) {
+ const contractAgreement = this.getContractAgreement(state.contractAgreementList);
+ this.props.setExpanded(!!contractAgreement);
+
+ state = mergeOptions(state, {
+ value: {
+ contract_agreement_id: contractAgreement ? contractAgreement.id : null,
+ terms: !contractAgreement || !!contractAgreement.datetime_accepted
+ }
+ });
+
+ this.setState(state);
+ },
+
+ onChange(event) {
+ this.setState({
+ value: React.addons.update(this.state.value, {
+ terms: { $set: event.target.value }
+ })
+ });
+ this.props.onChange(event);
+ },
+
+ getContractAgreement(contractAgreementList) {
+ if (contractAgreementList && contractAgreementList.length > 0) {
+ return contractAgreementList[0];
+ }
+ },
+
+ getContractAgreementsOrCreatePublic(email) {
+ ContractAgreementListActions.flushContractAgreementList.defer();
+
+ if (email) {
+ // fetch the available contractagreements (pending/accepted)
+ ContractAgreementListActions.fetchAvailableContractAgreementList(email, this.props.createPublicContractAgreement);
+ }
+ },
+
+ getAppendix() {
+ const { contractAgreementList } = this.state;
+
+ if (contractAgreementList && contractAgreementList.length > 0) {
+ const appendix = contractAgreementList[0].appendix;
+ if (appendix && appendix.default) {
+ return (
+ {appendix.default}
+ );
+ }
+ }
+ },
+
+ getContractCheckbox() {
+ const { name,
+ disabled,
+ style } = this.props;
+ const { contractAgreementList } = this.state;
+ const inputCheckboxProps = {
+ name,
+ disabled,
+ style,
+ onChange: this.onChange
+ };
+
+ if (contractAgreementList && contractAgreementList.length > 0) {
+ const contractAgreement = contractAgreementList[0];
+ const { issuer: contractIssuer, blob: { url_safe: contractUrl } } = contractAgreement.contract;
+
+
+ if (contractAgreement.datetime_accepted) {
+ // For `InputCheckbox` we want to override style in this case
+ Object.assign(inputCheckboxProps, { style: { 'display': 'none' } });
+
+ return (
+
+ );
+ } else {
+ return (
+
+
+ {getLangText('I agree to the')}
+
+ {getLangText('terms of ')} {contractIssuer}
+
+
+
+ );
+ }
+ } else {
+ return (
+
+ );
+ }
+ },
+
+ render() {
+ return (
+
+ {this.getContractCheckbox()}
+ {this.getAppendix()}
+
+ );
+ }
+});
+
+export default InputContractAgreementCheckbox;
\ No newline at end of file
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index d0b6ef37..8ed7362b 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -78,13 +78,15 @@ const Property = React.createClass({
componentWillReceiveProps(nextProps) {
let childInput = this.refs.input;
- // For expanded there are actually two use cases:
+ // For expanded there are actually three use cases:
//
// 1. Control its value from the outside completely (do not define `checkboxLabel`)
// 2. Let it be controlled from the inside (default value can be set though via `expanded`)
+ // 3. Let it be controlled from a child by using `setExpanded` (`expanded` must not be
+ // set from the outside as a prop then(!!!))
//
- // This handles case 1.
- if(nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
+ // This handles case 1. and 3.
+ if(typeof nextProps.expanded === this.props.expanded && nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
this.setState({ expanded: nextProps.expanded });
}
@@ -226,6 +228,10 @@ const Property = React.createClass({
}
},
+ setExpanded(expanded) {
+ this.setState({ expanded });
+ },
+
renderChildren(style) {
// Input's props should only be cloned and propagated down the tree,
// if the component is actually being shown (!== 'expanded === false')
@@ -247,7 +253,8 @@ const Property = React.createClass({
onBlur: this.handleBlur,
disabled: !this.props.editable,
ref: 'input',
- name: this.props.name
+ name: this.props.name,
+ setExpanded: this.setExpanded
});
});
}
diff --git a/js/components/ascribe_forms/property_contract_agreement.js b/js/components/ascribe_forms/property_contract_agreement.js
deleted file mode 100644
index cbb8924d..00000000
--- a/js/components/ascribe_forms/property_contract_agreement.js
+++ /dev/null
@@ -1,191 +0,0 @@
-'use strict'
-
-import React from 'react'
-
-import InputCheckbox from './input_checkbox';
-import Property from './property';
-
-import ContractAgreementListStore from '../../stores/contract_agreement_list_store';
-import ContractAgreementListActions from '../../actions/contract_agreement_list_actions';
-
-import { getLangText } from '../../utils/lang_utils';
-import { isEmail } from '../../utils/regex_utils';
-
-let ContractAgreementProperty = React.createClass({
- propTypes: {
- createPublicContractAgreement: React.PropTypes.bool,
- email: React.PropTypes.string,
- embedClassName: React.PropTypes.string,
- label: React.PropTypes.string,
-
- // Necessary for Form to pick this element up as a ref
- name: React.PropTypes.string,
-
- // Passed down from Form element
- handleChange: React.PropTypes.func
- },
-
- getDefaultProps() {
- return {
- createPublicContractAgreement: true
- };
- },
-
- getInitialState() {
- return ContractAgreementListStore.getState();
- },
-
- componentDidMount() {
- ContractAgreementListStore.listen(this.onChange);
- this.getContractAgreementsOrCreatePublic(this.props.email);
- },
-
- componentWillReceiveProps({ email: nextEmail }) {
- const { contractAgreementList } = this.state;
-
- if (this.props.email !== nextEmail) {
- if (isEmail(nextEmail)) {
- this.getContractAgreementsOrCreatePublic(nextEmail);
- } else if (contractAgreementList && contractAgreementList.length > 0) {
- ContractAgreementListActions.flushContractAgreementList();
- }
- }
- },
-
- componentWillUnmount() {
- ContractAgreementListStore.unlisten(this.onChange);
- },
-
- onChange(state) {
- this.setState(state);
- },
-
- getFormDataForProperty() {
- const contractAgreementId = this.getContractAgreementId();
- const formData = {
- 'terms': this.refs.terms.state.value
- };
-
- if (contractAgreementId) {
- formData.contract_agreement_id = contractAgreementId;
- }
-
- return formData;
- },
-
- getContractAgreementId() {
- if (this.state.contractAgreementList && this.state.contractAgreementList.length > 0) {
- return this.state.contractAgreementList[0].id;
- }
- },
-
- getContractAgreementsOrCreatePublic(email) {
- ContractAgreementListActions.flushContractAgreementList.defer();
-
- if (email) {
- // fetch the available contractagreements (pending/accepted)
- ContractAgreementListActions.fetchAvailableContractAgreementList(email, this.props.createPublicContractAgreement);
- }
- },
-
- getAppendix() {
- const { contractAgreementList } = this.state;
-
- if (contractAgreementList && contractAgreementList.length > 0) {
- const appendix = contractAgreementList[0].appendix;
- if (appendix && appendix.default) {
- return (
-
- {appendix.default}
-
- );
- }
- }
- },
-
- getContractCheckbox() {
- const { embedClassName, handleChange, label } = this.props;
- const { contractAgreementList } = this.state;
-
- if (contractAgreementList && contractAgreementList.length > 0) {
- const contractAgreement = contractAgreementList[0];
- const { issuer: contractIssuer, blob: { url_safe: contractUrl } } = contractAgreement.contract;
-
- // we need to define a key on the InputCheckboxes as otherwise
- // react is not rerendering them on a store switch and is keeping
- // the default value of the component (which is in that case true)
- if (contractAgreement.datetime_accepted) {
- return (
-
-
-
- {getLangText('Download contract')}
-
- {/* We still need to send the server information that we're accepting */}
-
-
- );
- } else {
- return (
-
-
-
- {getLangText('I agree to the')}
-
- {getLangText('terms of ')} {contractIssuer}
-
-
-
-
- );
- }
- } else {
- return (
-
-
-
- );
- }
- },
-
- render() {
- return (
-
- {this.getContractCheckbox()}
- {this.getAppendix()}
-
- );
- }
-});
-
-export default ContractAgreementProperty;
From 34126c2254a45a4d715cb429e210d6fb6dfd4abe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Fri, 4 Dec 2015 10:49:41 +0100
Subject: [PATCH 097/115] Fix negation of expanded prop of Property
---
.../input_contract_agreement_checkbox.js | 29 ++++++-------------
.../cyland_additional_data_form.js | 14 ++++-----
.../ikonotv_artist_details_form.js | 8 ++---
.../ikonotv_artwork_details_form.js | 12 ++++----
.../ikonotv/ikonotv_register_piece.js | 2 +-
5 files changed, 27 insertions(+), 38 deletions(-)
diff --git a/js/components/ascribe_forms/input_contract_agreement_checkbox.js b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
index 848523bf..b95f598b 100644
--- a/js/components/ascribe_forms/input_contract_agreement_checkbox.js
+++ b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
@@ -124,6 +124,7 @@ const InputContractAgreementCheckbox = React.createClass({
disabled,
style } = this.props;
const { contractAgreementList } = this.state;
+ const contractAgreement = this.getContractAgreement(contractAgreementList);
const inputCheckboxProps = {
name,
disabled,
@@ -131,29 +132,24 @@ const InputContractAgreementCheckbox = React.createClass({
onChange: this.onChange
};
- if (contractAgreementList && contractAgreementList.length > 0) {
- const contractAgreement = contractAgreementList[0];
- const { issuer: contractIssuer, blob: { url_safe: contractUrl } } = contractAgreement.contract;
-
-
- if (contractAgreement.datetime_accepted) {
- // For `InputCheckbox` we want to override style in this case
- Object.assign(inputCheckboxProps, { style: { 'display': 'none' } });
+ if(contractAgreement) {
+ const {
+ datetime_accepted: datetimeAccepted,
+ issuer: contractIssuer,
+ blob: { url_safe: contractUrl },
+ } = contractAgreement.contract;
+ if(datetimeAccepted) {
return (
);
} else {
@@ -171,13 +167,6 @@ const InputContractAgreementCheckbox = React.createClass({
);
}
- } else {
- return (
-
- );
}
},
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js
index a24c860b..54ac501b 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_forms/cyland_additional_data_form.js
@@ -122,7 +122,7 @@ let CylandAdditionalDataForm = React.createClass({
+ expanded={!disabled || !!piece.extra_data.artist_bio}>
+ expanded={!disabled || !!piece.extra_data.artist_contact_information}>
+ expanded={!disabled || !!piece.extra_data.conceptual_overview}>
+ expanded={!disabled || !!piece.extra_data.medium}>
+ expanded={!disabled || !!piece.extra_data.size_duration}>
+ expanded={!disabled || !!piece.extra_data.display_instructions}>
+ expanded={!disabled || !!piece.extra_data.additional_details}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.artist_website}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.gallery_website}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.additional_websites}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.conceptual_overview}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.medium}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.size_duration}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.copyright}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.courtesy_of}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.copyright_of_photography}>
+ expanded={!this.props.disabled || !!this.props.piece.extra_data.additional_details}>
Date: Fri, 4 Dec 2015 10:57:57 +0100
Subject: [PATCH 098/115] Destructure correct contractAgreement prop
---
.../ascribe_forms/input_contract_agreement_checkbox.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/js/components/ascribe_forms/input_contract_agreement_checkbox.js b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
index b95f598b..2547d2d5 100644
--- a/js/components/ascribe_forms/input_contract_agreement_checkbox.js
+++ b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
@@ -135,9 +135,11 @@ const InputContractAgreementCheckbox = React.createClass({
if(contractAgreement) {
const {
datetime_accepted: datetimeAccepted,
- issuer: contractIssuer,
- blob: { url_safe: contractUrl },
- } = contractAgreement.contract;
+ contract: {
+ issuer: contractIssuer,
+ blob: { url_safe: contractUrl }
+ }
+ } = contractAgreement;
if(datetimeAccepted) {
return (
From 33350326095d757e2f877a156a123e780045cc34 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Fri, 4 Dec 2015 12:06:08 +0100
Subject: [PATCH 099/115] Finalize InputContractAgreementCheckbox
---
js/components/ascribe_forms/form.js | 1 -
.../input_contract_agreement_checkbox.js | 60 ++++++++++++-------
js/components/ascribe_forms/property.js | 13 +++-
sass/ascribe_notification_page.scss | 13 ++--
4 files changed, 52 insertions(+), 35 deletions(-)
diff --git a/js/components/ascribe_forms/form.js b/js/components/ascribe_forms/form.js
index 37750010..98b7cfe5 100644
--- a/js/components/ascribe_forms/form.js
+++ b/js/components/ascribe_forms/form.js
@@ -131,7 +131,6 @@ let Form = React.createClass({
// An input can also provide an `Object` as a value
// which we're going to merge with `data` (overwrites)
if(ref.state.value.constructor === Object) {
- console.log(ref.state.value);
Object.assign(data, ref.state.value);
} else {
data[ref.props.name] = ref.state.value;
diff --git a/js/components/ascribe_forms/input_contract_agreement_checkbox.js b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
index 2547d2d5..b5a2167a 100644
--- a/js/components/ascribe_forms/input_contract_agreement_checkbox.js
+++ b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
@@ -74,7 +74,21 @@ const InputContractAgreementCheckbox = React.createClass({
state = mergeOptions(state, {
value: {
+ // If `email` is defined in this component, `getContractAgreementsOrCreatePublic`
+ // is either:
+ //
+ // - fetching a already existing contract agreement; or
+ // - trying to create a contract agreement
+ //
+ // If both attempts result in `contractAgreement` being not defined,
+ // it means that the receiver hasn't defined a contract, which means
+ // a contract agreement cannot be created, which means we don't have to
+ // specify `contract_agreement_id` when sending a request to the server.
contract_agreement_id: contractAgreement ? contractAgreement.id : null,
+ // If the receiver hasn't set a contract or the contract was
+ // previously accepted, we set the terms to `true`
+ // as we always need to at least give a boolean value for `terms`
+ // to the API endpoint
terms: !contractAgreement || !!contractAgreement.datetime_accepted
}
});
@@ -91,7 +105,7 @@ const InputContractAgreementCheckbox = React.createClass({
this.props.onChange(event);
},
- getContractAgreement(contractAgreementList) {
+ getContractAgreement(contractAgreementList = this.state.contractAgreementList) {
if (contractAgreementList && contractAgreementList.length > 0) {
return contractAgreementList[0];
}
@@ -107,30 +121,22 @@ const InputContractAgreementCheckbox = React.createClass({
},
getAppendix() {
- const { contractAgreementList } = this.state;
+ const contractAgreement = this.getContractAgreement();
- if (contractAgreementList && contractAgreementList.length > 0) {
- const appendix = contractAgreementList[0].appendix;
- if (appendix && appendix.default) {
- return (
- {appendix.default}
- );
- }
+ if (contractAgreement &&
+ contractAgreement.appendix &&
+ contractAgreement.appendix.default) {
+ return (
+
+
{getLangText('Appendix')}
+
{contractAgreement.appendix.default}
+
+ );
}
},
getContractCheckbox() {
- const { name,
- disabled,
- style } = this.props;
- const { contractAgreementList } = this.state;
- const contractAgreement = this.getContractAgreement(contractAgreementList);
- const inputCheckboxProps = {
- name,
- disabled,
- style,
- onChange: this.onChange
- };
+ const contractAgreement = this.getContractAgreement();
if(contractAgreement) {
const {
@@ -145,19 +151,27 @@ const InputContractAgreementCheckbox = React.createClass({
return (
);
} else {
+ const {
+ name,
+ disabled,
+ style } = this.props;
+
return (
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index 8ed7362b..a8266a58 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -42,7 +42,8 @@ const Property = React.createClass({
]),
style: object,
expanded: bool,
- checkboxLabel: string
+ checkboxLabel: string,
+ autoFocus: bool
},
getDefaultProps() {
@@ -75,6 +76,12 @@ const Property = React.createClass({
};
},
+ componentDidMount() {
+ if(this.props.autoFocus) {
+ this.handleFocus();
+ }
+ },
+
componentWillReceiveProps(nextProps) {
let childInput = this.refs.input;
@@ -82,11 +89,11 @@ const Property = React.createClass({
//
// 1. Control its value from the outside completely (do not define `checkboxLabel`)
// 2. Let it be controlled from the inside (default value can be set though via `expanded`)
- // 3. Let it be controlled from a child by using `setExpanded` (`expanded` must not be
+ // 3. Let it be controlled from a child by using `setExpanded` (`expanded` must not be
// set from the outside as a prop then(!!!))
//
// This handles case 1. and 3.
- if(typeof nextProps.expanded === this.props.expanded && nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
+ if(nextProps.expanded !== this.props.expanded && nextProps.expanded !== this.state.expanded && !this.props.checkboxLabel) {
this.setState({ expanded: nextProps.expanded });
}
diff --git a/sass/ascribe_notification_page.scss b/sass/ascribe_notification_page.scss
index 51d23a80..7bb37446 100644
--- a/sass/ascribe_notification_page.scss
+++ b/sass/ascribe_notification_page.scss
@@ -31,18 +31,11 @@
margin-top: .5em;
margin-bottom: 1em;
- .consign-form,
- .loan-form {
- margin-top: .5em;
+ &.embed-form {
height: 45vh;
}
}
- .consign-form,
- .loan-form {
- height: 40vh;
- }
-
.notification-contract-pdf-download {
text-align: left;
margin-left: 1em;
@@ -72,3 +65,7 @@
width: 100%;
}
}
+
+.ascribe-property.contract-appendix-form {
+ padding-left: 0;
+}
\ No newline at end of file
From 510318c319325dfcb4369c6dd640302167b2e72a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Fri, 4 Dec 2015 12:28:11 +0100
Subject: [PATCH 100/115] Fix styling issues related to Panel in Property
---
sass/ascribe_panel.scss | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/sass/ascribe_panel.scss b/sass/ascribe_panel.scss
index 09d773ad..0f675605 100644
--- a/sass/ascribe_panel.scss
+++ b/sass/ascribe_panel.scss
@@ -1,3 +1,8 @@
+.panel {
+ /* Here we are overriding bootstrap to show the is-focused background color */
+ background-color: transparent;
+}
+
.ascribe-panel-wrapper {
border: 1px solid #ddd;
height: 5em;
From 4b17225783b1fd4383213225e3c474e324294228 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 4 Dec 2015 13:32:29 +0100
Subject: [PATCH 101/115] Fix padding in InputContractAgreementCheckbox
---
js/components/ascribe_forms/form_consign.js | 3 ++-
js/components/ascribe_forms/form_loan.js | 3 ++-
.../input_contract_agreement_checkbox.js | 12 +++++++-----
js/components/ascribe_forms/property.js | 15 ++++++++++-----
4 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index c4942f30..a7c8f016 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -115,7 +115,8 @@ let ConsignForm = React.createClass({
+ className="ascribe-property-collapsible-toggle"
+ style={{paddingBottom: 0}}>
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index b8370016..eb709714 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -197,7 +197,8 @@ let LoanForm = React.createClass({
+ className="ascribe-property-collapsible-toggle"
+ style={{paddingBottom: 0}}>
diff --git a/js/components/ascribe_forms/input_contract_agreement_checkbox.js b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
index b5a2167a..c609786e 100644
--- a/js/components/ascribe_forms/input_contract_agreement_checkbox.js
+++ b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
@@ -16,7 +16,7 @@ const InputContractAgreementCheckbox = React.createClass({
propTypes: {
createPublicContractAgreement: React.PropTypes.bool,
email: React.PropTypes.string,
-
+
required: React.PropTypes.bool,
// provided by Property
@@ -69,7 +69,7 @@ const InputContractAgreementCheckbox = React.createClass({
},
onStoreChange(state) {
- const contractAgreement = this.getContractAgreement(state.contractAgreementList);
+ const contractAgreement = this.getContractAgreement(state.contractAgreementList);
this.props.setExpanded(!!contractAgreement);
state = mergeOptions(state, {
@@ -92,7 +92,7 @@ const InputContractAgreementCheckbox = React.createClass({
terms: !contractAgreement || !!contractAgreement.datetime_accepted
}
});
-
+
this.setState(state);
},
@@ -149,7 +149,9 @@ const InputContractAgreementCheckbox = React.createClass({
if(datetimeAccepted) {
return (
-
+ );
}
- style.paddingBottom = !this.state.expanded ? 0 : null;
- style.cursor = !this.props.editable ? 'not-allowed' : null;
+ if (!this.state.expanded) {
+ style.paddingBottom = 0;
+ }
+ if (!this.props.editable) {
+ style.cursor = 'not-allowed';
+ }
return (
Date: Fri, 4 Dec 2015 13:52:17 +0100
Subject: [PATCH 102/115] Fix customThumbnailPlacholder propType
---
.../ascribe_accordion_list/accordion_list_item_piece.js | 2 +-
.../ascribe_accordion_list/accordion_list_item_wallet.js | 2 +-
js/components/piece_list.js | 2 +-
.../whitelabel/wallet/components/market/market_piece_list.js | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
index 74322e51..006479c5 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
@@ -21,7 +21,7 @@ let AccordionListItemPiece = React.createClass({
subsubheading: React.PropTypes.object,
buttons: React.PropTypes.object,
badge: React.PropTypes.object,
- thumbnailPlaceholder: React.PropTypes.element
+ thumbnailPlaceholder: React.PropTypes.func
},
getDefaultProps() {
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
index 6fb3abeb..a8cab166 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
@@ -31,7 +31,7 @@ let AccordionListItemWallet = React.createClass({
propTypes: {
className: React.PropTypes.string,
content: React.PropTypes.object,
- thumbnailPlaceholder: React.PropTypes.element,
+ thumbnailPlaceholder: React.PropTypes.func,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 1d1875bd..9424117c 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -38,7 +38,7 @@ let PieceList = React.createClass({
canLoadPieceList: React.PropTypes.bool,
redirectTo: React.PropTypes.string,
customSubmitButton: React.PropTypes.element,
- customThumbnailPlaceholder: React.PropTypes.element,
+ customThumbnailPlaceholder: React.PropTypes.func,
filterParams: React.PropTypes.array,
orderParams: React.PropTypes.array,
orderBy: React.PropTypes.string,
diff --git a/js/components/whitelabel/wallet/components/market/market_piece_list.js b/js/components/whitelabel/wallet/components/market/market_piece_list.js
index 8adaa6d9..1c74e6de 100644
--- a/js/components/whitelabel/wallet/components/market/market_piece_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_piece_list.js
@@ -17,7 +17,7 @@ import { getLangText } from '../../../../../utils/lang_utils';
let MarketPieceList = React.createClass({
propTypes: {
- customThumbnailPlaceholder: React.PropTypes.element,
+ customThumbnailPlaceholder: React.PropTypes.func,
location: React.PropTypes.object
},
From 5a6026d0ca1a489a676e11b3f48e22d4d5187534 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 4 Dec 2015 14:34:59 +0100
Subject: [PATCH 103/115] Fix ListItemEditionWidget spinner's colour
---
.../accordion_list_item_edition_widget.js | 3 +--
js/components/ascribe_spinner.js | 18 +++++++++---------
sass/ascribe_spinner.scss | 9 ++++++++-
.../wallet/23vivi/23vivi_custom_style.scss | 3 +++
4 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js
index 5d3e033f..8033f239 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js
@@ -78,7 +78,6 @@ let AccordionListItemEditionWidget = React.createClass({
return (
);
} else {
@@ -137,4 +136,4 @@ let AccordionListItemEditionWidget = React.createClass({
}
});
-export default AccordionListItemEditionWidget;
\ No newline at end of file
+export default AccordionListItemEditionWidget;
diff --git a/js/components/ascribe_spinner.js b/js/components/ascribe_spinner.js
index e1daf5b2..ad97d484 100644
--- a/js/components/ascribe_spinner.js
+++ b/js/components/ascribe_spinner.js
@@ -7,26 +7,26 @@ let AscribeSpinner = React.createClass({
propTypes: {
classNames: React.PropTypes.string,
size: React.PropTypes.oneOf(['sm', 'md', 'lg']),
- color: React.PropTypes.oneOf(['blue', 'dark-blue', 'light-blue', 'pink', 'black', 'loop'])
+ color: React.PropTypes.oneOf(['black', 'blue', 'dark-blue', 'light-blue', 'pink', 'white', 'loop'])
},
getDefaultProps() {
return {
inline: false,
- size: 'md',
- color: 'loop'
+ size: 'md'
};
},
render() {
+ const { classNames: classes, color, size } = this.props;
+
return (
-
-
A
+ className={classNames('spinner-wrapper-' + size,
+ color ? 'spinner-wrapper-' + color : null,
+ classes)}>
+
+
A
);
}
diff --git a/sass/ascribe_spinner.scss b/sass/ascribe_spinner.scss
index 7f02a383..543b1463 100644
--- a/sass/ascribe_spinner.scss
+++ b/sass/ascribe_spinner.scss
@@ -52,6 +52,13 @@ $ascribe--spinner-size-sm: 15px;
}
}
+.spinner-wrapper-white {
+ color: $ascribe-white;
+ .spinner-circle {
+ border-color: $ascribe-white;
+ }
+}
+
.spinner-wrapper-lg {
width: $ascribe--spinner-size-lg;
height: $ascribe--spinner-size-lg;
@@ -146,4 +153,4 @@ $ascribe--spinner-size-sm: 15px;
40% { color: $ascribe-blue; }
60% { color: $ascribe-light-blue; }
80% { color: $ascribe-pink; }
-}
\ No newline at end of file
+}
diff --git a/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
index 37269bd6..32783a7a 100644
--- a/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
+++ b/sass/whitelabel/wallet/23vivi/23vivi_custom_style.scss
@@ -331,6 +331,9 @@ $vivi23--highlight-color: #de2600;
.spinner-inner {
display: none;
}
+ .btn-secondary .spinner-circle {
+ border-color: $vivi23--bg-color;
+ }
// video player
.ascribe-media-player .vjs-default-skin {
From 0763c45548c9e8cc35c22a53b6c5115f272d40d1 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 4 Dec 2015 15:35:01 +0100
Subject: [PATCH 104/115] Disable form when acl_edit is turned off
---
.../market_additional_data_form.js | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
index 1c9b8a54..b762022c 100644
--- a/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
+++ b/js/components/whitelabel/wallet/components/market/market_forms/market_additional_data_form.js
@@ -32,6 +32,7 @@ let MarketAdditionalDataForm = React.createClass({
React.PropTypes.number,
React.PropTypes.string
]),
+ editable: React.PropTypes.bool,
isInline: React.PropTypes.bool,
showHeading: React.PropTypes.bool,
showNotification: React.PropTypes.bool,
@@ -41,6 +42,7 @@ let MarketAdditionalDataForm = React.createClass({
getDefaultProps() {
return {
+ editable: true,
submitLabel: getLangText('Register work')
};
},
@@ -130,7 +132,7 @@ let MarketAdditionalDataForm = React.createClass({
},
render() {
- const { isInline, handleSuccess, showHeading, showNotification, submitLabel } = this.props;
+ const { editable, isInline, handleSuccess, showHeading, showNotification, submitLabel } = this.props;
const { piece } = this.state;
let buttons, spinner, heading;
@@ -169,7 +171,8 @@ let MarketAdditionalDataForm = React.createClass({
handleSuccess={showNotification ? this.handleSuccessWithNotification : handleSuccess}
getFormData={this.getFormData}
buttons={buttons}
- spinner={spinner}>
+ spinner={spinner}
+ disabled={!this.props.editable || !piece.acl.acl_edit}>
{heading}
+ otherData={piece.other_data}
+ editable={editable} />
+ label={getLangText('Artist Bio')}
+ expanded={editable || !!piece.extra_data.artist_bio}>
+ label={getLangText('Work Description')}
+ expanded={editable || !!piece.extra_data.work_description}>
+ label={getLangText('Technology Details')}
+ expanded={editable || !!piece.extra_data.technology_details}>
+ label={getLangText('Display Instructions')}
+ expanded={editable || !!piece.extra_data.display_instructions}>
Date: Fri, 4 Dec 2015 16:29:57 +0100
Subject: [PATCH 105/115] Fix multiple edition statuses
---
js/components/ascribe_detail/edition.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index 24266e43..2de5eacf 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -195,7 +195,7 @@ let EditionSummary = React.createClass({
getStatus(){
let status = null;
if (this.props.edition.status.length > 0){
- let statusStr = this.props.edition.status.join().replace(/_/, ' ');
+ let statusStr = this.props.edition.status.join(', ').replace(/_/g, ' ');
status = ;
if (this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer){
status = (
From c1959033c04fee739dda1fb10f38ef8f1fedf91a Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 4 Dec 2015 16:34:25 +0100
Subject: [PATCH 106/115] Fix comments in PR
---
...cordion_list_item_thumbnail_placeholder.js | 4 +--
.../ascribe_detail/edition_action_panel.js | 6 +++--
js/components/ascribe_forms/form_consign.js | 4 +--
js/components/ascribe_forms/form_loan.js | 2 +-
.../input_contract_agreement_checkbox.js | 15 +++++++----
.../ascribe_forms/input_fineuploader.js | 27 ++++++++++---------
js/components/ascribe_forms/property.js | 8 +++---
.../piece_list_bulk_modal.js | 2 +-
.../components/23vivi/23vivi_piece_list.js | 4 +--
.../ikonotv/ikonotv_register_piece.js | 2 +-
.../market_buttons/market_submit_button.js | 3 +--
.../market_additional_data_form.js | 18 ++++++++-----
.../market/market_register_piece.js | 2 +-
13 files changed, 55 insertions(+), 42 deletions(-)
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js b/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
index 6ba4d6ab..37c98371 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_thumbnail_placeholder.js
@@ -2,7 +2,7 @@
import React from 'react';
-let accordionListItemThumbnailPlaceholder = React.createClass({
+let AccordionListItemThumbnailPlaceholder = React.createClass({
render() {
return (
@@ -12,4 +12,4 @@ let accordionListItemThumbnailPlaceholder = React.createClass({
}
});
-export default accordionListItemThumbnailPlaceholder;
+export default AccordionListItemThumbnailPlaceholder;
diff --git a/js/components/ascribe_detail/edition_action_panel.js b/js/components/ascribe_detail/edition_action_panel.js
index fbc56bee..36a79e7c 100644
--- a/js/components/ascribe_detail/edition_action_panel.js
+++ b/js/components/ascribe_detail/edition_action_panel.js
@@ -94,8 +94,10 @@ let EditionActionPanel = React.createClass({
},
render(){
- let { edition, currentUser } = this.props;
- let ActionPanelButtonListType = this.props.actionPanelButtonListType;
+ const {
+ actionPanelButtonListType: ActionPanelButtonListType,
+ edition,
+ currentUser } = this.props;
if (edition &&
edition.notifications &&
diff --git a/js/components/ascribe_forms/form_consign.js b/js/components/ascribe_forms/form_consign.js
index a7c8f016..2f0ebf05 100644
--- a/js/components/ascribe_forms/form_consign.js
+++ b/js/components/ascribe_forms/form_consign.js
@@ -37,7 +37,7 @@ let ConsignForm = React.createClass({
getInitialState() {
return {
- email: this.props.email
+ email: this.props.email || ''
};
},
@@ -69,7 +69,7 @@ let ConsignForm = React.createClass({
ref='form'
url={url}
getFormData={this.getFormData}
- handleSuccess={this.props.handleSuccess}
+ handleSuccess={handleSuccess}
buttons={
diff --git a/js/components/ascribe_forms/form_loan.js b/js/components/ascribe_forms/form_loan.js
index eb709714..a204fb87 100644
--- a/js/components/ascribe_forms/form_loan.js
+++ b/js/components/ascribe_forms/form_loan.js
@@ -210,7 +210,7 @@ let LoanForm = React.createClass({
+ required={showPassword}/>
{children}
diff --git a/js/components/ascribe_forms/input_contract_agreement_checkbox.js b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
index c609786e..61235631 100644
--- a/js/components/ascribe_forms/input_contract_agreement_checkbox.js
+++ b/js/components/ascribe_forms/input_contract_agreement_checkbox.js
@@ -53,12 +53,10 @@ const InputContractAgreementCheckbox = React.createClass({
},
componentWillReceiveProps({ email: nextEmail }) {
- const { contractAgreementList } = this.state;
-
if (this.props.email !== nextEmail) {
if (isEmail(nextEmail)) {
this.getContractAgreementsOrCreatePublic(nextEmail);
- } else if (contractAgreementList && contractAgreementList.length > 0) {
+ } else if (this.getContractAgreement()) {
ContractAgreementListActions.flushContractAgreementList();
}
}
@@ -69,7 +67,9 @@ const InputContractAgreementCheckbox = React.createClass({
},
onStoreChange(state) {
- const contractAgreement = this.getContractAgreement(state.contractAgreementList);
+ const contractAgreement = this.getContractAgreement(state.contractAgreementList);
+
+ // If there is no contract available, hide this `Property` from the user
this.props.setExpanded(!!contractAgreement);
state = mergeOptions(state, {
@@ -97,16 +97,21 @@ const InputContractAgreementCheckbox = React.createClass({
},
onChange(event) {
+ // Sync the value between our `InputCheckbox` and this component's `terms`
+ // so the parent `Property` is able to get the correct value of this component
+ // when the `Form` queries it.
this.setState({
value: React.addons.update(this.state.value, {
terms: { $set: event.target.value }
})
});
+
+ // Propagate change events from the checkbox up to the parent `Property`
this.props.onChange(event);
},
getContractAgreement(contractAgreementList = this.state.contractAgreementList) {
- if (contractAgreementList && contractAgreementList.length > 0) {
+ if (contractAgreementList && contractAgreementList.length) {
return contractAgreementList[0];
}
},
diff --git a/js/components/ascribe_forms/input_fineuploader.js b/js/components/ascribe_forms/input_fineuploader.js
index 1a9889db..6d3a3e81 100644
--- a/js/components/ascribe_forms/input_fineuploader.js
+++ b/js/components/ascribe_forms/input_fineuploader.js
@@ -96,18 +96,21 @@ const InputFineUploader = React.createClass({
},
render() {
- const { fileInputElement,
- keyRoutine,
- createBlobRoutine,
- validation,
- setIsUploadReady,
- isReadyForFormSubmission,
- areAssetsDownloadable,
- enableLocalHashing,
- uploadMethod,
- fileClassToUpload,
- disabled } = this.props;
- let editable = this.props.isFineUploaderActive;
+ const {
+ areAssetsDownloadable,
+ enableLocalHashing,
+ createBlobRoutine,
+ disabled,
+ fileClassToUpload,
+ fileInputElement,
+ isFineUploaderActive,
+ isReadyForFormSubmission,
+ keyRoutine,
+ setIsUploadReady,
+ uploadMethod,
+ validation } = this.props;
+
+ let editable = isFineUploaderActive;
// if disabled is actually set by property, we want to override
// isFineUploaderActive
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index e57c8b3c..479c9602 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -239,6 +239,10 @@ const Property = React.createClass({
this.setState({ expanded });
},
+ handleCheckboxToggle() {
+ this.setExpanded(!this.state.expanded);
+ },
+
renderChildren(style) {
// Input's props should only be cloned and propagated down the tree,
// if the component is actually being shown (!== 'expanded === false')
@@ -280,10 +284,6 @@ const Property = React.createClass({
}
},
- handleCheckboxToggle() {
- this.setState({expanded: !this.state.expanded});
- },
-
getCheckbox() {
const { checkboxLabel } = this.props;
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 bb8d4ccc..c9c7f9f4 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
@@ -30,7 +30,7 @@ let PieceListBulkModal = React.createClass({
},
render() {
- if (Object.keys(this.props.availableAcls).length > 0) {
+ if (Object.keys(this.props.availableAcls).length) {
return (
diff --git a/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js b/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
index d889a9a0..0bfb8aa0 100644
--- a/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
+++ b/js/components/whitelabel/wallet/components/23vivi/23vivi_piece_list.js
@@ -6,7 +6,7 @@ import Vivi23AccordionListItemThumbnailPlaceholder from './23vivi_accordion_list
import MarketPieceList from '../market/market_piece_list';
-let vivi23PieceList = React.createClass({
+let Vivi23PieceList = React.createClass({
propTypes: {
location: React.PropTypes.object
},
@@ -21,4 +21,4 @@ let vivi23PieceList = React.createClass({
});
-export default vivi23PieceList;
+export default Vivi23PieceList;
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
index c4636911..c40d779d 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_register_piece.js
@@ -199,7 +199,7 @@ let IkonotvRegisterPiece = React.createClass({
getSlideLoan() {
if (this.canSubmit()) {
- const {piece, whitelabel} = this.state;
+ const { piece, whitelabel } = this.state;
let today = new Moment();
let endDate = new Moment();
endDate.add(2, 'years');
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index 8e7775a2..d8ef4c41 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -144,8 +144,7 @@ let MarketSubmitButton = React.createClass({
} else {
return (
+ show={availableAcls.acl_consign && canSubmit}>
;
if (!isInline) {
buttons = (
@@ -148,7 +150,9 @@ let MarketAdditionalDataForm = React.createClass({
spinner = (
-
+
+ {spinner}
+
);
@@ -228,7 +232,7 @@ let MarketAdditionalDataForm = React.createClass({
} else {
return (
);
}
diff --git a/js/components/whitelabel/wallet/components/market/market_register_piece.js b/js/components/whitelabel/wallet/components/market/market_register_piece.js
index e02df80c..eed17477 100644
--- a/js/components/whitelabel/wallet/components/market/market_register_piece.js
+++ b/js/components/whitelabel/wallet/components/market/market_register_piece.js
@@ -82,7 +82,7 @@ let MarketRegisterPiece = React.createClass({
handleAdditionalDataSuccess() {
this.refreshPieceList();
- this.history.pushState(null, `/collection`);
+ this.history.pushState(null, '/collection');
},
// We need to increase the step to lock the forms that are already filled out
From cb972eb448e3d8eb2643a3a3b12f219644c7479f Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Fri, 4 Dec 2015 18:30:45 +0100
Subject: [PATCH 107/115] Add consign error to market white labels
Can you beliebe? Magical 100th commit.
---
.../market_buttons/market_submit_button.js | 62 +++++++++++++------
.../components/market/market_consign_error.js | 51 +++++++++++++++
sass/ascribe_form.scss | 9 ++-
3 files changed, 103 insertions(+), 19 deletions(-)
create mode 100644 js/components/whitelabel/wallet/components/market/market_consign_error.js
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index d8ef4c41..bd333850 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -3,6 +3,8 @@
import React from 'react';
import classNames from 'classnames';
+import MarketConsignError from '../market_consign_error';
+
import MarketAdditionalDataForm from '../market_forms/market_additional_data_form';
import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
@@ -12,6 +14,7 @@ import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import AclProxy from '../../../../../acl_proxy';
+import EditionListActions from '../../../../../../actions/edition_list_actions';
import PieceActions from '../../../../../../actions/piece_actions';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
@@ -89,6 +92,11 @@ let MarketSubmitButton = React.createClass({
this.refs.consignModal.show();
},
+ handleConsignError() {
+ // Unselect failed editions
+ EditionListActions.clearAllEditionSelections();
+ },
+
render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state;
@@ -120,27 +128,45 @@ let MarketSubmitButton = React.createClass({
);
if (solePieceId && !canSubmit) {
- return (
-
+ if (availableAcls.acl_edit) {
+ return (
+
+
+
+
+
+
+ {consignForm}
+
+
+ );
+ } else {
+ // Oops, well this is a difficult situation...
+ // The user's likely already transferred another edition from the piece so
+ // they can't update the missing fields that are necessary for consignment
+ // to marketplaces.
+ // Let's show an error in response to explain the problem and let them
+ // contact the whitelabel themselves.
+ return (
-
+ handleSuccess={this.handleConsignError}
+ title={getLangText("Oops, we can't consign this piece to %s", whitelabelName)}>
+
-
-
- {consignForm}
-
-
- );
+ );
+ }
} else {
return (
+
+
+ {getLangText('Unfortunately, %s requires you to provide more information ' +
+ "about this edition, but it appears that you don't have the " +
+ 'permissions to edit the piece associated with this edition.', whitelabelName)}
+
+
+ {getLangText('Please contact us if you would still like to consign this piece to %s.', whitelabelName)}
+
+
+
+ {getLangText('Contact us for help')}
+
+
+ );
+ }
+});
+
+export default MarketConsignError;
diff --git a/sass/ascribe_form.scss b/sass/ascribe_form.scss
index 1b265e91..84be8be9 100644
--- a/sass/ascribe_form.scss
+++ b/sass/ascribe_form.scss
@@ -23,4 +23,11 @@
@media (max-width: 550px) {
width: 100%;
}
-}
\ No newline at end of file
+}
+
+.ascribe-form-error-popup {
+ .error-popup-content {
+ margin-bottom: 30px;
+ margin-top: 20px;
+ }
+}
From 41ef51c4782615e53d5b9b0509af378743107503 Mon Sep 17 00:00:00 2001
From: Brett Sun
Date: Mon, 7 Dec 2015 10:17:42 +0100
Subject: [PATCH 108/115] Revert "Add consign error to market white labels"
This reverts commit cb972eb448e3d8eb2643a3a3b12f219644c7479f.
Unfortunately, the edition's `acl_edit` can still be true when
the piece's `acl_edit` is false, so there is no good way on
the frontend right now to tell when to show the error message.
For now we'll assume submissions to marketplaces are all new
and ignore this edge case.
---
.../market_buttons/market_submit_button.js | 62 ++++++-------------
.../components/market/market_consign_error.js | 51 ---------------
sass/ascribe_form.scss | 9 +--
3 files changed, 19 insertions(+), 103 deletions(-)
delete mode 100644 js/components/whitelabel/wallet/components/market/market_consign_error.js
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
index bd333850..d8ef4c41 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_submit_button.js
@@ -3,8 +3,6 @@
import React from 'react';
import classNames from 'classnames';
-import MarketConsignError from '../market_consign_error';
-
import MarketAdditionalDataForm from '../market_forms/market_additional_data_form';
import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
@@ -14,7 +12,6 @@ import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import AclProxy from '../../../../../acl_proxy';
-import EditionListActions from '../../../../../../actions/edition_list_actions';
import PieceActions from '../../../../../../actions/piece_actions';
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
@@ -92,11 +89,6 @@ let MarketSubmitButton = React.createClass({
this.refs.consignModal.show();
},
- handleConsignError() {
- // Unselect failed editions
- EditionListActions.clearAllEditionSelections();
- },
-
render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state;
@@ -128,45 +120,27 @@ let MarketSubmitButton = React.createClass({
);
if (solePieceId && !canSubmit) {
- if (availableAcls.acl_edit) {
- return (
-
-
-
-
-
-
- {consignForm}
-
-
- );
- } else {
- // Oops, well this is a difficult situation...
- // The user's likely already transferred another edition from the piece so
- // they can't update the missing fields that are necessary for consignment
- // to marketplaces.
- // Let's show an error in response to explain the problem and let them
- // contact the whitelabel themselves.
- return (
+ return (
+
-
+ handleSuccess={this.handleAdditionalDataSuccess.bind(this, solePieceId)}
+ title={getLangText('Add additional information')}>
+
- );
- }
+
+
+ {consignForm}
+
+
+ );
} else {
return (
-
-
- {getLangText('Unfortunately, %s requires you to provide more information ' +
- "about this edition, but it appears that you don't have the " +
- 'permissions to edit the piece associated with this edition.', whitelabelName)}
-
-
- {getLangText('Please contact us if you would still like to consign this piece to %s.', whitelabelName)}
-
-
-
- {getLangText('Contact us for help')}
-
-
- );
- }
-});
-
-export default MarketConsignError;
diff --git a/sass/ascribe_form.scss b/sass/ascribe_form.scss
index 84be8be9..1b265e91 100644
--- a/sass/ascribe_form.scss
+++ b/sass/ascribe_form.scss
@@ -23,11 +23,4 @@
@media (max-width: 550px) {
width: 100%;
}
-}
-
-.ascribe-form-error-popup {
- .error-popup-content {
- margin-bottom: 30px;
- margin-top: 20px;
- }
-}
+}
\ No newline at end of file
From 9392a71b33f389b74b8731bb8597cfa312844ec8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 7 Dec 2015 10:48:46 +0100
Subject: [PATCH 109/115] Add comment for bug fix hiding actions from detail
pages
---
js/components/ascribe_detail/edition.js | 5 +++++
js/components/ascribe_detail/piece_container.js | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index ef5207d9..f0910b51 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -210,6 +210,11 @@ let EditionSummary = React.createClass({
value={ edition.owner } />
{this.getStatus()}
+ {/*
+ `acl_view` is always available in `edition.acl`, therefore if it has
+ no more than 1 key, we're hiding the `DetailProperty` actions as otherwise
+ `AclInformation` would show up
+ */}
1}>
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index d78999fb..7b577fa9 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -197,6 +197,11 @@ let PieceContainer = React.createClass({
return (
1}>
+ {/*
+ `acl_view` is always available in `edition.acl`, therefore if it has
+ no more than 1 key, we're hiding the `DetailProperty` actions as otherwise
+ `AclInformation` would show up
+ */}
Date: Mon, 7 Dec 2015 10:52:00 +0100
Subject: [PATCH 110/115] Change show condition on public note to be more
stylistically similar
---
js/components/ascribe_detail/piece_container.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 73d44c66..ca7c83a7 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -277,7 +277,7 @@ let PieceContainer = React.createClass({
defaultValue={this.state.piece.public_note || null}
placeholder={getLangText('Enter your comments ...')}
editable={!!this.state.piece.acl.acl_edit}
- show={!!this.state.piece.public_note || !!this.state.piece.acl.acl_edit}
+ show={!!(this.state.piece.public_note || this.state.piece.acl.acl_edit)}
successMessage={getLangText('Public note saved')}
url={ApiUrls.note_public_piece}
currentUser={this.state.currentUser}/>
From 3374862edfc6eea8c5a38db72e2e515ef1f9ac83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 7 Dec 2015 10:57:49 +0100
Subject: [PATCH 111/115] Make monkeyPatched key specific to component's
displayName
---
js/components/ascribe_detail/edition_container.js | 2 +-
js/components/ascribe_detail/piece_container.js | 2 +-
js/models/errors.js | 8 ++++++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index eac8fcb3..c49b87ba 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -55,7 +55,7 @@ let EditionContainer = React.createClass({
const { editionError } = this.state;
if(editionError && editionError.status === 404) {
- this.throws(new ResourceNotFoundError(getLangText('Ups, the edition you\'re looking for doesn\'t exist.')));
+ this.throws(new ResourceNotFoundError(getLangText('Oops, the edition you\'re looking for doesn\'t exist.')));
}
},
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 86c7fc74..0b4cfbb1 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -86,7 +86,7 @@ let PieceContainer = React.createClass({
const { pieceError } = this.state;
if(pieceError && pieceError.status === 404) {
- this.throws(new ResourceNotFoundError(getLangText('Ups, the piece you\'re looking for doesn\'t exist.')));
+ this.throws(new ResourceNotFoundError(getLangText('Oops, the piece you\'re looking for doesn\'t exist.')));
}
},
diff --git a/js/models/errors.js b/js/models/errors.js
index 68d97c86..d7843d30 100644
--- a/js/models/errors.js
+++ b/js/models/errors.js
@@ -14,10 +14,14 @@ export class ResourceNotFoundError extends Error {
}
handler(component, err) {
- if(!component.state._monkeyPatched) {
+ const { displayName } = component.constructor;
+ const monkeyPatchedKey = typeof displayName === 'string' ? `_${displayName}MonkeyPatched`
+ : '_monkeyPatched';
+
+ if(!component.state[monkeyPatchedKey]) {
component.render = () => ;
component.setState({
- _monkeyPatched: true
+ [monkeyPatchedKey]: true
});
}
}
From 4f39103baf44d9ebbe280afd26dc83293df23aaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 7 Dec 2015 10:59:07 +0100
Subject: [PATCH 112/115] Use Oops
---
js/components/error_not_found_page.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/components/error_not_found_page.js b/js/components/error_not_found_page.js
index 670f8629..64776f2f 100644
--- a/js/components/error_not_found_page.js
+++ b/js/components/error_not_found_page.js
@@ -12,7 +12,7 @@ let ErrorNotFoundPage = React.createClass({
getDefaultProps() {
return {
- message: getLangText('Ups, the page you are looking for does not exist.')
+ message: getLangText('Oops, the page you are looking for does not exist.')
};
},
From f76ebffbe238478288a37aef3dd97f46f8dc649d Mon Sep 17 00:00:00 2001
From: diminator
Date: Mon, 7 Dec 2015 11:17:42 +0100
Subject: [PATCH 113/115] fix: acl_wallet_submit on 23vivi register piece
---
js/components/whitelabel/wallet/wallet_routes.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/js/components/whitelabel/wallet/wallet_routes.js b/js/components/whitelabel/wallet/wallet_routes.js
index e75bfab2..0a4e3a58 100644
--- a/js/components/whitelabel/wallet/wallet_routes.js
+++ b/js/components/whitelabel/wallet/wallet_routes.js
@@ -218,7 +218,8 @@ let ROUTES = {
+ headerTitle='+ NEW WORK'
+ aclName='acl_wallet_submit'/>
Date: Mon, 7 Dec 2015 11:30:45 +0100
Subject: [PATCH 114/115] Include PR Feedback: Check if Error.captureStackTrace
is available
---
js/mixins/react_error.js | 3 ++-
js/models/errors.js | 7 ++++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/js/mixins/react_error.js b/js/mixins/react_error.js
index 0b7669de..1169a069 100644
--- a/js/mixins/react_error.js
+++ b/js/mixins/react_error.js
@@ -4,7 +4,8 @@ import invariant from 'invariant';
const ReactError = {
throws(err) {
- invariant(err.handler, 'You need to specify a `handler` for this error');
+ invariant(err.handler, 'Error thrown to ReactError did not have a `handler` function');
+ console.logGlobal('Error thrown to ReactError did not have a `handler` function');
err.handler(this, err);
}
};
diff --git a/js/models/errors.js b/js/models/errors.js
index d7843d30..e748d953 100644
--- a/js/models/errors.js
+++ b/js/models/errors.js
@@ -10,7 +10,12 @@ export class ResourceNotFoundError extends Error {
super(message);
this.name = this.constructor.name;
this.message = message;
- Error.captureStackTrace(this, this.constructor.name);
+
+ // `captureStackTrace` might not be available in IE:
+ // - http://stackoverflow.com/a/8460753/1263876
+ if(Error.captureStackTrace) {
+ Error.captureStackTrace(this, this.constructor.name);
+ }
}
handler(component, err) {
From 3ce63c33bf9999a989c757e551eed0155c13529b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?=
Date: Mon, 7 Dec 2015 11:48:28 +0100
Subject: [PATCH 115/115] Finalize ReactError component
---
js/components/ascribe_detail/edition_container.js | 2 +-
js/components/ascribe_detail/piece_container.js | 2 +-
js/components/error_not_found_page.js | 2 +-
js/mixins/react_error.js | 9 ++++++---
js/models/errors.js | 4 +---
5 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index c49b87ba..fdc18c39 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -55,7 +55,7 @@ let EditionContainer = React.createClass({
const { editionError } = this.state;
if(editionError && editionError.status === 404) {
- this.throws(new ResourceNotFoundError(getLangText('Oops, the edition you\'re looking for doesn\'t exist.')));
+ this.throws(new ResourceNotFoundError(getLangText("Oops, the edition you're looking for doesn't exist.")));
}
},
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 0b4cfbb1..44b9357c 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -86,7 +86,7 @@ let PieceContainer = React.createClass({
const { pieceError } = this.state;
if(pieceError && pieceError.status === 404) {
- this.throws(new ResourceNotFoundError(getLangText('Oops, the piece you\'re looking for doesn\'t exist.')));
+ this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist.")));
}
},
diff --git a/js/components/error_not_found_page.js b/js/components/error_not_found_page.js
index 64776f2f..0e111ce7 100644
--- a/js/components/error_not_found_page.js
+++ b/js/components/error_not_found_page.js
@@ -12,7 +12,7 @@ let ErrorNotFoundPage = React.createClass({
getDefaultProps() {
return {
- message: getLangText('Oops, the page you are looking for does not exist.')
+ message: getLangText("Oops, the page you are looking for doesn't exist.")
};
},
diff --git a/js/mixins/react_error.js b/js/mixins/react_error.js
index 1169a069..14f33a61 100644
--- a/js/mixins/react_error.js
+++ b/js/mixins/react_error.js
@@ -4,9 +4,12 @@ import invariant from 'invariant';
const ReactError = {
throws(err) {
- invariant(err.handler, 'Error thrown to ReactError did not have a `handler` function');
- console.logGlobal('Error thrown to ReactError did not have a `handler` function');
- err.handler(this, err);
+ if(!err.handler) {
+ invariant(err.handler, 'Error thrown to ReactError did not have a `handler` function');
+ console.logGlobal('Error thrown to ReactError did not have a `handler` function');
+ } else {
+ err.handler(this, err);
+ }
}
};
diff --git a/js/models/errors.js b/js/models/errors.js
index e748d953..4573afe4 100644
--- a/js/models/errors.js
+++ b/js/models/errors.js
@@ -19,9 +19,7 @@ export class ResourceNotFoundError extends Error {
}
handler(component, err) {
- const { displayName } = component.constructor;
- const monkeyPatchedKey = typeof displayName === 'string' ? `_${displayName}MonkeyPatched`
- : '_monkeyPatched';
+ const monkeyPatchedKey = `_${this.name}MonkeyPatched`;
if(!component.state[monkeyPatchedKey]) {
component.render = () => ;