+
api |
diff --git a/js/components/global_action.js b/js/components/global_action.js
deleted file mode 100644
index 80df0c75..00000000
--- a/js/components/global_action.js
+++ /dev/null
@@ -1,43 +0,0 @@
-'use strict';
-
-import React from 'react';
-
-let GlobalAction = React.createClass({
- propTypes: {
- requestActions: React.PropTypes.object
- },
-
- render() {
- let pieceActions = null;
- if (this.props.requestActions && this.props.requestActions.pieces){
- pieceActions = this.props.requestActions.pieces.map((item) => {
- return (
-
- {item}
-
);
- });
- }
- let editionActions = null;
- if (this.props.requestActions && this.props.requestActions.editions){
- editionActions = Object.keys(this.props.requestActions.editions).map((pieceId) => {
- return this.props.requestActions.editions[pieceId].map((item) => {
- return (
-
- {item}
-
);
- });
- });
- }
-
- if (pieceActions || editionActions) {
- return (
-
- {pieceActions}
- {editionActions}
-
);
- }
- return null;
- }
-});
-
-export default GlobalAction;
\ No newline at end of file
diff --git a/js/components/header.js b/js/components/header.js
index b3fd543e..c16cba86 100644
--- a/js/components/header.js
+++ b/js/components/header.js
@@ -16,12 +16,13 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import AclProxy from './acl_proxy';
+import EventActions from '../actions/event_actions';
+
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 EventActions from '../actions/event_actions';
import HeaderNotifications from './header_notification';
@@ -37,16 +38,9 @@ import { constructHead } from '../utils/dom_utils';
let Header = React.createClass({
propTypes: {
- showAddWork: React.PropTypes.bool,
routes: React.PropTypes.arrayOf(React.PropTypes.object)
},
- getDefaultProps() {
- return {
- showAddWork: true
- };
- },
-
getInitialState() {
return mergeOptions(
WhitelabelStore.getState(),
@@ -55,15 +49,29 @@ let Header = React.createClass({
},
componentDidMount() {
- UserActions.fetchCurrentUser();
UserStore.listen(this.onChange);
- WhitelabelActions.fetchWhitelabel();
+ UserActions.fetchCurrentUser.defer();
+
WhitelabelStore.listen(this.onChange);
+ WhitelabelActions.fetchWhitelabel.defer();
// 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);
+
+ if (this.state.currentUser && this.state.currentUser.email) {
+ EventActions.profileDidLoad.defer(this.state.currentUser);
+ }
+ },
+
+ componentWillUpdate(nextProps, nextState) {
+ const { currentUser: { email: curEmail } = {} } = this.state;
+ const { currentUser: { email: nextEmail } = {} } = nextState;
+
+ if (nextEmail && curEmail !== nextEmail) {
+ EventActions.profileDidLoad.defer(nextState.currentUser);
+ }
},
componentWillUnmount() {
@@ -111,10 +119,6 @@ let Header = React.createClass({
onChange(state) {
this.setState(state);
-
- if(this.state.currentUser && this.state.currentUser.email) {
- EventActions.profileDidLoad.defer(this.state.currentUser);
- }
},
onMenuItemClick() {
@@ -146,7 +150,9 @@ let Header = React.createClass({
// 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;
+ if (this.refs.navbar) {
+ this.refs.navbar.state.navExpanded = false;
+ }
},
render() {
@@ -213,17 +219,18 @@ let Header = React.createClass({
return (
+ className="hidden-print">
@@ -231,6 +238,9 @@ let Header = React.createClass({
{navRoutesLinks}
+
+
+
);
}
diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js
index 31275a08..6d2d089e 100644
--- a/js/components/password_reset_container.js
+++ b/js/components/password_reset_container.js
@@ -130,8 +130,9 @@ let PasswordResetForm = React.createClass({
},
handleSuccess() {
- this.history.pushState(null, '/collection');
- let notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000);
+ this.history.push('/collection');
+
+ const notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
diff --git a/js/components/piece_list.js b/js/components/piece_list.js
index 9424117c..666d1b54 100644
--- a/js/components/piece_list.js
+++ b/js/components/piece_list.js
@@ -37,6 +37,7 @@ let PieceList = React.createClass({
bulkModalButtonListType: React.PropTypes.func,
canLoadPieceList: React.PropTypes.bool,
redirectTo: React.PropTypes.string,
+ shouldRedirect: React.PropTypes.func,
customSubmitButton: React.PropTypes.element,
customThumbnailPlaceholder: React.PropTypes.func,
filterParams: React.PropTypes.array,
@@ -114,9 +115,13 @@ let PieceList = React.createClass({
},
componentDidUpdate() {
- if (this.props.redirectTo && this.state.unfilteredPieceListCount === 0) {
+ const { location: { query }, redirectTo, shouldRedirect } = this.props;
+ const { unfilteredPieceListCount } = this.state;
+
+ if (redirectTo && unfilteredPieceListCount === 0 &&
+ (typeof shouldRedirect === 'function' && shouldRedirect(unfilteredPieceListCount))) {
// FIXME: hack to redirect out of the dispatch cycle
- window.setTimeout(() => this.history.pushState(null, this.props.redirectTo, this.props.location.query), 0);
+ window.setTimeout(() => this.history.push({ query, pathname: redirectTo }), 0);
}
},
@@ -169,15 +174,16 @@ let PieceList = React.createClass({
}
},
- searchFor(searchTerm) {
- this.loadPieceList({
- page: 1,
- search: searchTerm
- });
- this.history.pushState(null, this.props.location.pathname, {page: 1});
+ searchFor(search) {
+ const { location: { pathname } } = this.props;
+
+ this.loadPieceList({ search, page: 1 });
+ this.history.push({ pathname, query: { page: 1 } });
},
- applyFilterBy(filterBy){
+ applyFilterBy(filterBy) {
+ const { location: { pathname } } = this.props;
+
this.setState({
isFilterDirty: true
});
@@ -190,31 +196,32 @@ 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
});
}
-
});
});
// we have to redirect the user always to page one as it could be that there is no page two
// for filtered pieces
- this.history.pushState(null, this.props.location.pathname, {page: 1});
+ this.history.push({ pathname, query: { page: 1 } });
},
applyOrderBy(orderBy) {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, page, pageSize, search } = this.state;
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
loadPieceList({ page, filterBy = this.state.filterBy, search = this.state.search }) {
+ const { orderAsc, pageSize } = this.state;
const orderBy = this.state.orderBy || this.props.orderBy;
- return PieceListActions.fetchPieceList(page, this.state.pageSize, search,
- orderBy, this.state.orderAsc, filterBy);
+ return PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
fetchSelectedPieceEditionList() {
@@ -240,8 +247,9 @@ let PieceList = React.createClass({
},
handleAclSuccess() {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderBy, orderAsc, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
this.fetchSelectedPieceEditionList()
.forEach((pieceId) => {
diff --git a/js/components/register_piece.js b/js/components/register_piece.js
index 8211e91e..19a340ba 100644
--- a/js/components/register_piece.js
+++ b/js/components/register_piece.js
@@ -65,26 +65,21 @@ let RegisterPiece = React.createClass( {
this.setState(state);
},
- handleSuccess(response){
- let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
+ handleSuccess(response) {
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ const notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
// once the user was able to register a piece successfully, we need to make sure to keep
// the piece list up to date
- PieceListActions.fetchPieceList(
- this.state.page,
- this.state.pageSize,
- this.state.searchTerm,
- this.state.orderBy,
- this.state.orderAsc,
- this.state.filterBy
- );
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
- this.history.pushState(null, `/pieces/${response.piece.id}`);
+ this.history.push(`/pieces/${response.piece.id}`);
},
getSpecifyEditions() {
- if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) {
+ if (this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) {
return (
{
- if(success) {
- this.setState({
- piece
- }, () => {
- supportingMaterials.refs.input.createBlobRoutine();
- proofOfPayment.refs.input.createBlobRoutine();
- });
+ .then(({ piece, notification }) => {
+ this.setState({piece}, () => {
+ supportingMaterials.refs.input.createBlobRoutine();
+ proofOfPayment.refs.input.createBlobRoutine();
+ });
- setCookie(currentUser.email, piece.id);
+ setCookie(currentUser.email, piece.id);
- return requests.post(ApiUrls.piece_extradata, {
+ return requests
+ .post(ApiUrls.piece_extradata, {
body: {
extradata: additionalDataFormData,
piece_id: piece.id
},
piece_id: piece.id
+ })
+ .then(() => {
+ const notificationMessage = new GlobalNotificationModel(notification || getLangText('You have successfully submitted "%s" to Portfolio Review 2015', piece.title), 'success', 5000);
+ GlobalNotificationActions.appendGlobalNotification(notificationMessage);
});
- } else {
- const notificationMessage = new GlobalNotificationModel(notification, 'danger', 5000);
- GlobalNotificationActions.appendGlobalNotification(notificationMessage);
- }
})
- .then(() => this.history.pushState(null, `/pieces/${this.state.piece.id}`))
- .catch(() => {
- const notificationMessage = new GlobalNotificationModel(getLangText("Ups! We weren't able to send your submission. Contact: support@ascribe.io"), 'danger', 5000);
+ .then(() => this.history.push(`/pieces/${this.state.piece.id}`))
+ .catch((err) => {
+ const errMessage = (getErrorNotificationMessage(err) || getLangText("Oops! We weren't able to send your submission.")) +
+ getLangText(' Please contact support@ascribe.io');
+
+ const notificationMessage = new GlobalNotificationModel(errMessage, 'danger', 10000);
GlobalNotificationActions.appendGlobalNotification(notificationMessage);
+
+ console.logGlobal(new Error('Portfolio Review piece registration failed'), err);
+
+ // Reset the submit button
+ this.setState({
+ submitted: false
+ });
});
},
@@ -118,11 +128,7 @@ const PRRegisterPieceForm = React.createClass({
additionalDataForm,
uploadersForm } = this.refs;
- const registerPieceFormValidation = registerPieceForm.validate();
- const additionalDataFormValidation = additionalDataForm.validate();
- const uploaderFormValidation = uploadersForm.validate();
-
- return registerPieceFormValidation && additionalDataFormValidation && uploaderFormValidation;
+ return validateForms([registerPieceForm, additionalDataForm, uploadersForm], true);
},
getCreateBlobRoutine() {
@@ -139,7 +145,7 @@ const PRRegisterPieceForm = React.createClass({
},
/**
- * This method is overloaded so that we can track the ready-state
+ * These two methods are overloaded so that we can track the ready-state
* of each uploader in the component
* @param {string} uploaderKey Name of the uploader's key to track
*/
@@ -151,6 +157,14 @@ const PRRegisterPieceForm = React.createClass({
};
},
+ handleOptionalFileValidationFailed(uploaderKey) {
+ return () => {
+ this.setState({
+ [uploaderKey]: true
+ });
+ };
+ },
+
getSubmitButton() {
const { digitalWorkKeyReady,
thumbnailKeyReady,
@@ -167,7 +181,7 @@ const PRRegisterPieceForm = React.createClass({
} else {
return (
@@ -224,25 +238,51 @@ const PRRegisterPieceForm = React.createClass({
className="ascribe-form-bordered"
ref="additionalDataForm">
+
+
+
-
+ name='4-phone_number'
+ label={getLangText('Phone Number')}>
+
+
+
+
+
+
+
);
}
});
-export default PRHero;
\ No newline at end of file
+export default PRHero;
diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js b/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js
index cdada68b..9e86ecf9 100644
--- a/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js
+++ b/js/components/whitelabel/prize/portfolioreview/components/pr_landing.js
@@ -14,7 +14,7 @@ import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import UserStore from '../../../../../stores/user_store';
import UserActions from '../../../../../actions/user_actions';
-import { mergeOptions } from '../../../../../utils/general_utils';
+import { mergeOptions, omitFromObject } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
@@ -34,15 +34,18 @@ const PRLanding = React.createClass({
componentDidMount() {
const { location } = this.props;
+
UserStore.listen(this.onChange);
- UserActions.fetchCurrentUser();
PrizeStore.listen(this.onChange);
+
+ UserActions.fetchCurrentUser();
PrizeActions.fetchPrize();
- if(location && location.query && location.query.redirect) {
- let queryCopy = JSON.parse(JSON.stringify(location.query));
- delete queryCopy.redirect;
- window.setTimeout(() => this.history.replaceState(null, `/${location.query.redirect}`, queryCopy));
+ if (location && location.query && location.query.redirect) {
+ window.setTimeout(() => this.history.replace({
+ pathname: `/${location.query.redirect}`,
+ query: omitFromObject(location.query, ['redirect'])
+ }));
}
},
@@ -125,4 +128,4 @@ const PRLanding = React.createClass({
}
});
-export default PRLanding;
\ No newline at end of file
+export default PRLanding;
diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_login_container.js b/js/components/whitelabel/prize/portfolioreview/components/pr_login_container.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js
index 0fbca419..99c9a401 100644
--- a/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js
+++ b/js/components/whitelabel/prize/portfolioreview/components/pr_register_piece.js
@@ -39,7 +39,7 @@ const PRRegisterPiece = React.createClass({
if(currentUser && currentUser.email) {
const submittedPieceId = getCookie(currentUser.email);
if(submittedPieceId) {
- this.history.pushState(null, `/pieces/${submittedPieceId}`);
+ this.history.push(`/pieces/${submittedPieceId}`);
}
}
},
@@ -62,7 +62,7 @@ const PRRegisterPiece = React.createClass({
Portfolio Review
-
{getLangText('Submission closing on %s', ' 22 Dec 2015')}
+
{getLangText('Submission closing on %s', ' 27 Dec 2015')}
For more information, visit:
portfolio-review.de
@@ -84,4 +84,4 @@ const PRRegisterPiece = React.createClass({
}
});
-export default PRRegisterPiece;
\ No newline at end of file
+export default PRRegisterPiece;
diff --git a/js/components/whitelabel/prize/portfolioreview/components/pr_routes/pr_proxy_handler.js b/js/components/whitelabel/prize/portfolioreview/components/pr_routes/pr_proxy_handler.js
new file mode 100644
index 00000000..f81c4539
--- /dev/null
+++ b/js/components/whitelabel/prize/portfolioreview/components/pr_routes/pr_proxy_handler.js
@@ -0,0 +1,26 @@
+'use strict';
+
+import history from '../../../../../../history';
+
+
+export function AuthPrizeRoleRedirect({ to, when }) {
+ if (when.constructor !== Array || !when.length) {
+ throw new Error('`when` of AuthPrizeRoleRedirect must be an array containing values');
+ }
+ if (!to || to.indexOf('/') === -1) {
+ throw new Error('`to` of AuthPrizeRoleRedirect must be defined and contain a valid route');
+ }
+
+ return function(currentUser, query) {
+ const exprToValidate = when
+ .map(role => currentUser[role])
+ .reduce((a, b) => a || b);
+
+ if (exprToValidate) {
+ window.setTimeout(() => history.replace({ query, pathname: to }));
+ return true;
+ } else {
+ return false;
+ }
+ };
+}
diff --git a/js/components/whitelabel/prize/portfolioreview/pr_app.js b/js/components/whitelabel/prize/portfolioreview/pr_app.js
index 7e66c43c..c672bdf5 100644
--- a/js/components/whitelabel/prize/portfolioreview/pr_app.js
+++ b/js/components/whitelabel/prize/portfolioreview/pr_app.js
@@ -4,6 +4,9 @@ import React from 'react';
import GlobalNotification from '../../../global_notification';
import Hero from './components/pr_hero';
+import Header from '../../../header';
+
+import EventActions from '../../../../actions/event_actions';
import UserStore from '../../../../stores/user_store';
import UserActions from '../../../../actions/user_actions';
@@ -29,6 +32,19 @@ let PRApp = React.createClass({
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
+
+ if (this.state.currentUser && this.state.currentUser.email) {
+ EventActions.profileDidLoad.defer(this.state.currentUser);
+ }
+ },
+
+ componentWillUpdate(nextProps, nextState) {
+ const { currentUser: { email: curEmail } = {} } = this.state;
+ const { currentUser: { email: nextEmail } = {} } = nextState;
+
+ if (nextEmail && curEmail !== nextEmail) {
+ EventActions.profileDidLoad.defer(nextState.currentUser);
+ }
},
componentWillUnmount() {
@@ -40,19 +56,28 @@ let PRApp = React.createClass({
},
render() {
- const { history, children } = this.props;
+ const { history, children, routes } = this.props;
const { currentUser } = this.state;
+ let style = {};
let subdomain = getSubdomain();
let header;
+
if (currentUser && currentUser.email && history.isActive(`/pieces/${getCookie(currentUser.email)}`)) {
- header = ;
+ header = ;
+ style = { paddingTop: '0 !important' };
+ } else if(currentUser && (currentUser.is_admin || currentUser.is_jury || currentUser.is_judge)) {
+ header = ;
+ } else {
+ style = { paddingTop: '0 !important' };
}
return (
{header}
-
+
{children}
diff --git a/js/components/whitelabel/prize/prize_routes.js b/js/components/whitelabel/prize/prize_routes.js
index ec0269a5..5f80b30c 100644
--- a/js/components/whitelabel/prize/prize_routes.js
+++ b/js/components/whitelabel/prize/prize_routes.js
@@ -12,6 +12,8 @@ import SPPieceContainer from './simple_prize/components/ascribe_detail/prize_pie
import SPSettingsContainer from './simple_prize/components/prize_settings_container';
import SPApp from './simple_prize/prize_app';
+import SluicePieceContainer from './sluice/components/sluice_detail/sluice_piece_container';
+
import PRApp from './portfolioreview/pr_app';
import PRLanding from './portfolioreview/components/pr_landing';
import PRRegisterPiece from './portfolioreview/components/pr_register_piece';
@@ -22,7 +24,8 @@ import PasswordResetContainer from '../../password_reset_container';
import CoaVerifyContainer from '../../coa_verify_container';
import ErrorNotFoundPage from '../../error_not_found_page';
-import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
+import { ProxyHandler, AuthRedirect } from '../../../components/ascribe_routes/proxy_handler';
+import { AuthPrizeRoleRedirect } from './portfolioreview/components/pr_routes/pr_proxy_handler';
const ROUTES = {
@@ -31,29 +34,28 @@ const ROUTES = {
+ component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SPLoginContainer)} />
+ component={ProxyHandler(AuthRedirect({to: '/', when: 'loggedOut'}))(LogoutContainer)}/>
+ component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(SPSignupContainer)} />
+ component={ProxyHandler(AuthRedirect({to: '/collection', when: 'loggedIn'}))(PasswordResetContainer)} />
+ component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(SPSettingsContainer)}/>
-
-
+
@@ -61,24 +63,41 @@ const ROUTES = {
),
portfolioreview: (
-
+
+ component={ProxyHandler(AuthRedirect({to: '/login', when: 'loggedOut'}))(PRRegisterPiece)}/>
+
+ component={ProxyHandler(
+ AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
+ AuthRedirect({to: '/register_piece', when: 'loggedIn'})
+ )(SPLoginContainer)} />
+ component={ProxyHandler(AuthRedirect({to: '/', when: 'loggedOut'}))(LogoutContainer)} />
+ component={ProxyHandler(
+ AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
+ AuthRedirect({to: '/register_piece', when: 'loggedIn'})
+ )(SPSignupContainer)} />
+ component={ProxyHandler(
+ AuthPrizeRoleRedirect({ to: '/collection', when: ['is_admin', 'is_judge', 'is_jury'] }),
+ AuthRedirect({to: '/register_piece', when: 'loggedIn'})
+ )(PasswordResetContainer)} />
+
+
+
)
diff --git a/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js
index dbca1b5d..242bb846 100644
--- a/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js
+++ b/js/components/whitelabel/prize/simple_prize/actions/prize_actions.js
@@ -16,7 +16,7 @@ class PrizeActions {
.fetch()
.then((res) => {
this.actions.updatePrize({
- prize: res.prize
+ prize: res
});
})
.catch((err) => {
diff --git a/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js b/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js
index 68b5334b..91852704 100644
--- a/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js
+++ b/js/components/whitelabel/prize/simple_prize/actions/prize_rating_actions.js
@@ -10,14 +10,15 @@ class PrizeRatingActions {
this.generateActions(
'updatePrizeRatings',
'updatePrizeRatingAverage',
- 'updatePrizeRating'
+ 'updatePrizeRating',
+ 'resetPrizeRatings'
);
}
- fetchAverage(pieceId) {
+ fetchAverage(pieceId, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
- .fetchAverage(pieceId)
+ .fetchAverage(pieceId, round)
.then((res) => {
this.actions.updatePrizeRatingAverage(res.data);
resolve(res);
@@ -29,10 +30,10 @@ class PrizeRatingActions {
});
}
- fetchOne(pieceId) {
+ fetchOne(pieceId, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
- .fetchOne(pieceId)
+ .fetchOne(pieceId, round)
.then((res) => {
this.actions.updatePrizeRating(res.rating.rating);
resolve(res);
@@ -43,10 +44,10 @@ class PrizeRatingActions {
});
}
- createRating(pieceId, rating) {
+ createRating(pieceId, rating, round) {
return Q.Promise((resolve, reject) => {
PrizeRatingFetcher
- .rate(pieceId, rating)
+ .rate(pieceId, rating, round)
.then((res) => {
this.actions.updatePrizeRating(res.rating.rating);
resolve(res);
@@ -70,10 +71,6 @@ class PrizeRatingActions {
});
});
}
-
- updateRating(rating) {
- this.actions.updatePrizeRating(rating);
- }
}
-export default alt.createActions(PrizeRatingActions);
\ No newline at end of file
+export default alt.createActions(PrizeRatingActions);
diff --git a/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js b/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js
index 965b9012..e34f8347 100644
--- a/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js
+++ b/js/components/whitelabel/prize/simple_prize/components/ascribe_accordion_list/accordion_list_item_prize.js
@@ -58,8 +58,9 @@ let AccordionListItemPrize = React.createClass({
},
handleSubmitPrizeSuccess(response) {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
@@ -138,8 +139,9 @@ let AccordionListItemPrize = React.createClass({
},
refreshPieceData() {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
onSelectChange(){
@@ -171,23 +173,25 @@ let AccordionListItemPrize = React.createClass({
},
render() {
+ const { children, className, content } = this.props;
+ const { currentUser } = this.state;
+
// Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted
- let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) ||
- (this.state.currentUser.is_judge && !this.props.content.selected )) ?
-
: this.props.content.artist_name;
+ let artistName = ((currentUser.is_jury && !currentUser.is_judge) || (currentUser.is_judge && !content.selected )) ?
+
: content.artist_name;
return (
- {Moment(this.props.content.date_created, 'YYYY-MM-DD').year()}
+ {Moment(content.date_created, 'YYYY-MM-DD').year()}
}
buttons={this.getPrizeButtons()}
badge={this.getPrizeBadge()}>
- {this.props.children}
+ {children}
);
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 982af7b0..5b6897d5 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
@@ -6,15 +6,19 @@ import Moment from 'moment';
import StarRating from 'react-star-rating';
-import PieceActions from '../../../../../../actions/piece_actions';
-import PieceStore from '../../../../../../stores/piece_store';
-
-import PieceListStore from '../../../../../../stores/piece_list_store';
-import PieceListActions from '../../../../../../actions/piece_list_actions';
+import ReactError from '../../../../../../mixins/react_error';
+import { ResourceNotFoundError } from '../../../../../../models/errors';
+import PrizeActions from '../../actions/prize_actions';
+import PrizeStore from '../../stores/prize_store';
import PrizeRatingActions from '../../actions/prize_rating_actions';
import PrizeRatingStore from '../../stores/prize_rating_store';
+import PieceActions from '../../../../../../actions/piece_actions';
+import PieceStore from '../../../../../../stores/piece_store';
+import PieceListStore from '../../../../../../stores/piece_list_store';
+import PieceListActions from '../../../../../../actions/piece_list_actions';
+
import UserStore from '../../../../../../stores/user_store';
import UserActions from '../../../../../../actions/user_actions';
@@ -31,9 +35,7 @@ import CollapsibleParagraph from '../../../../../../components/ascribe_collapsib
import FurtherDetailsFileuploader from '../../../../../ascribe_detail/further_details_fileuploader';
import InputCheckbox from '../../../../../ascribe_forms/input_checkbox';
-import LoanForm from '../../../../../ascribe_forms/form_loan';
import ListRequestActions from '../../../../../ascribe_forms/list_form_request_actions';
-import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
@@ -49,36 +51,44 @@ import { setDocumentTitle } from '../../../../../../utils/dom_utils';
/**
* This is the component that implements resource/data specific functionality
*/
-let PieceContainer = React.createClass({
+let PrizePieceContainer = React.createClass({
propTypes: {
- params: React.PropTypes.object
+ params: React.PropTypes.object,
+ selectedPrizeActionButton: React.PropTypes.func
},
+ mixins: [ReactError],
+
getInitialState() {
return mergeOptions(
- PieceStore.getState(),
+ PieceStore.getInitialState(),
UserStore.getState()
);
},
componentDidMount() {
PieceStore.listen(this.onChange);
- PieceActions.fetchOne(this.props.params.pieceId);
UserStore.listen(this.onChange);
- UserActions.fetchCurrentUser();
- // 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({});
+ UserActions.fetchCurrentUser();
+ this.loadPiece();
},
// This is done to update the container when the user clicks on the prev or next
- // button to update the URL parameter (and therefore to switch pieces)
+ // button to update the URL parameter (and therefore to switch pieces) or
+ // when the user clicks on a notification while being in another piece view
componentWillReceiveProps(nextProps) {
- if(this.props.params.pieceId !== nextProps.params.pieceId) {
- PieceActions.updatePiece({});
- PieceActions.fetchOne(nextProps.params.pieceId);
+ if (this.props.params.pieceId !== nextProps.params.pieceId) {
+ PieceActions.flushPiece();
+ this.loadPiece(nextProps.params.pieceId);
+ }
+ },
+
+ componentDidUpdate() {
+ const { pieceMeta: { err: pieceErr } } = this.state;
+
+ if (pieceErr && pieceErr.status === 404) {
+ this.throws(new ResourceNotFoundError(getLangText("Oops, the piece you're looking for doesn't exist.")));
}
},
@@ -87,81 +97,82 @@ let PieceContainer = React.createClass({
UserStore.unlisten(this.onChange);
},
-
onChange(state) {
this.setState(state);
},
- loadPiece() {
- PieceActions.fetchOne(this.props.params.pieceId);
- },
-
getActions() {
- if (this.state.piece &&
- this.state.piece.notifications &&
- this.state.piece.notifications.length > 0) {
+ const { currentUser, piece } = this.state;
+
+ if (piece.notifications && piece.notifications.length > 0) {
return (
);
+ notifications={piece.notifications} />);
}
},
+ loadPiece(pieceId = this.props.params.pieceId) {
+ PieceActions.fetchPiece(pieceId);
+ },
+
render() {
- if(this.state.piece && this.state.piece.id) {
+ const { selectedPrizeActionButton } = this.props;
+ const { currentUser, piece } = this.state;
+
+ if (piece.id) {
/*
-
+
This really needs a refactor!
- Tim
*/
// Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted
- let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) ||
- (this.state.currentUser.is_judge && !this.state.piece.selected )) ?
- null : this.state.piece.artist_name;
-
- // Only show the artist email if you are a judge and the piece is shortlisted
- let artistEmail = (this.state.currentUser.is_judge && this.state.piece.selected ) ?
- : null;
-
- if (artistName === null) {
- setDocumentTitle(this.state.piece.title);
+ let artistName;
+ if ((currentUser.is_jury && !currentUser.is_judge) || (currentUser.is_judge && !piece.selected )) {
+ artistName = ;
+ setDocumentTitle(piece.title);
} else {
- setDocumentTitle([artistName, this.state.piece.title].join(', '));
+ artistName = piece.artist_name;
+ setDocumentTitle(`${artistName}, ${piece.title}`);
}
- if (artistName === null) {
- artistName = ;
- }
+ // Only show the artist email if you are a judge and the piece is shortlisted
+ const artistEmail = currentUser.is_judge && piece.selected ? (
+
+ ) : null;
return (
-
- {this.state.piece.title}
+ piece={piece}
+ currentUser={currentUser} />
+
+ {piece.title}
-
+
{artistEmail}
{this.getActions()}
-
+
- }
+ }
subheader={
+ piece={piece}
+ currentUser={currentUser}
+ selectedPrizeActionButton={selectedPrizeActionButton} />
}>
-
+
);
} else {
@@ -183,9 +194,8 @@ let NavigationHeader = React.createClass({
render() {
const { currentUser, piece } = this.props;
- if (currentUser && currentUser.email && currentUser.is_judge && currentUser.is_jury &&
- !currentUser.is_admin && piece && piece.navigation) {
- let nav = piece.navigation;
+ if (currentUser.email && currentUser.is_judge && currentUser.is_jury && !currentUser.is_admin && piece.navigation) {
+ const nav = piece.navigation;
return (
@@ -205,8 +215,9 @@ let NavigationHeader = React.createClass({
);
+ } else {
+ return null;
}
- return null;
}
});
@@ -215,31 +226,31 @@ let PrizePieceRatings = React.createClass({
propTypes: {
loadPiece: React.PropTypes.func,
piece: React.PropTypes.object,
- currentUser: React.PropTypes.object
+ currentUser: React.PropTypes.object,
+ selectedPrizeActionButton: React.PropTypes.func
},
getInitialState() {
return mergeOptions(
PieceListStore.getState(),
- PrizeRatingStore.getState()
+ PrizeStore.getState(),
+ PrizeRatingStore.getInitialState()
);
},
componentDidMount() {
- PrizeRatingStore.listen(this.onChange);
- PrizeRatingActions.fetchOne(this.props.piece.id);
- PrizeRatingActions.fetchAverage(this.props.piece.id);
PieceListStore.listen(this.onChange);
+ PrizeStore.listen(this.onChange);
+ PrizeRatingStore.listen(this.onChange);
+
+ PrizeActions.fetchPrize();
+ this.fetchPrizeRatings();
},
componentWillUnmount() {
- // Every time we're leaving the piece detail page,
- // just reset the piece that is saved in the piece store
- // as it will otherwise display wrong/old data once the user loads
- // the piece detail a second time
- PrizeRatingActions.updateRating({});
- PrizeRatingStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
+ PrizeStore.unlisten(this.onChange);
+ PrizeRatingStore.unlisten(this.onChange);
},
// The StarRating component does not have a property that lets us set
@@ -247,7 +258,12 @@ let PrizePieceRatings = React.createClass({
// every mouseover be overridden, we need to set it ourselves initially to deal
// with the problem.
onChange(state) {
+ if (state.prize && state.prize.active_round != this.state.prize.active_round) {
+ this.fetchPrizeRatings(state);
+ }
+
this.setState(state);
+
if (this.refs.rating) {
this.refs.rating.state.ratingCache = {
pos: this.refs.rating.state.pos,
@@ -258,74 +274,54 @@ let PrizePieceRatings = React.createClass({
}
},
+ fetchPrizeRatings(state = this.state) {
+ PrizeRatingActions.fetchOne(this.props.piece.id, state.prize.active_round);
+ PrizeRatingActions.fetchAverage(this.props.piece.id, state.prize.active_round);
+ },
+
onRatingClick(event, args) {
event.preventDefault();
- PrizeRatingActions.createRating(this.props.piece.id, args.rating).then(
- this.refreshPieceData()
- );
+ PrizeRatingActions
+ .createRating(this.props.piece.id, args.rating, this.state.prize.active_round)
+ .then(this.refreshPieceData);
},
- handleLoanRequestSuccess(message){
- let notification = new GlobalNotificationModel(message, 'success', 4000);
- GlobalNotificationActions.appendGlobalNotification(notification);
- },
+ getSelectedActionButton() {
+ const { currentUser, piece, selectedPrizeActionButton: SelectedPrizeActionButton } = this.props;
- getLoanButton(){
- let today = new Moment();
- let endDate = new Moment();
- endDate.add(6, 'months');
- return (
-
- {getLangText('SEND LOAN REQUEST')}
-
- }
- handleSuccess={this.handleLoanRequestSuccess}
- title='REQUEST LOAN'>
-
- );
- },
-
- handleShortlistSuccess(message){
- let notification = new GlobalNotificationModel(message, 'success', 2000);
- GlobalNotificationActions.appendGlobalNotification(notification);
+ if (piece.selected && SelectedPrizeActionButton) {
+ return (
+
+
+
+ );
+ }
},
refreshPieceData() {
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
this.props.loadPiece();
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
onSelectChange() {
- PrizeRatingActions.toggleShortlist(this.props.piece.id)
- .then(
- (res) => {
+ PrizeRatingActions
+ .toggleShortlist(this.props.piece.id)
+ .then((res) => {
this.refreshPieceData();
- return res;
- })
- .then(
- (res) => {
- this.handleShortlistSuccess(res.notification);
- }
- );
+
+ if (res && res.notification) {
+ const notification = new GlobalNotificationModel(res.notification, 'success', 2000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+ }
+ });
},
- render(){
- if (this.props.piece && this.props.currentUser && this.props.currentUser.is_judge && this.state.average) {
+ render() {
+ if (this.props.piece.id && this.props.currentUser.is_judge && this.state.average) {
// Judge sees shortlisting, average and per-jury notes
return (
@@ -342,9 +338,7 @@ let PrizePieceRatings = React.createClass({
-
- {this.props.piece.selected ? this.getLoanButton() : null}
-
+ {this.getSelectedActionButton()}
@@ -359,17 +353,23 @@ let PrizePieceRatings = React.createClass({
size='md'
step={0.5}
rating={this.state.average}
- ratingAmount={5}/>
+ ratingAmount={5} />
{this.state.ratings.map((item, i) => {
- let note = item.note ?
+ let note = item.note ? (
note: {item.note}
-
: null;
+
+ ) : null;
+
return (
-
-
+
+
+ ratingAmount={5} />
{item.user}
{note}
@@ -389,8 +389,7 @@ let PrizePieceRatings = React.createClass({
);
- }
- else if (this.props.currentUser && this.props.currentUser.is_jury) {
+ } else if (this.props.currentUser.is_jury) {
// Jury can set rating and note
return (
{return {'piece_id': this.props.piece.id}; }}
+ id={() => ({ 'piece_id': this.props.piece.id })}
label={getLangText('Jury note')}
- defaultValue={this.props.piece && this.props.piece.note_from_user ? this.props.piece.note_from_user.note : null}
+ defaultValue={this.props.piece.note_from_user || null}
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Jury note saved')}
url={ApiUrls.notes}
- currentUser={this.props.currentUser}/>
+ currentUser={this.props.currentUser} />
);
+ } else {
+ return null;
}
- return null;
}
});
@@ -429,46 +429,52 @@ let PrizePieceDetails = React.createClass({
},
render() {
- if (this.props.piece
- && this.props.piece.prize
- && this.props.piece.prize.name
- && Object.keys(this.props.piece.extra_data).length !== 0){
+ const { piece } = this.props;
+
+ if (piece.prize && piece.prize.name && Object.keys(piece.extra_data).length) {
return (
-
);
+ } else {
+ return null;
}
- return null;
}
});
-export default PieceContainer;
+export default PrizePieceContainer;
diff --git a/js/components/whitelabel/prize/simple_prize/components/prize_landing.js b/js/components/whitelabel/prize/simple_prize/components/prize_landing.js
index e26a05b5..82a21eab 100644
--- a/js/components/whitelabel/prize/simple_prize/components/prize_landing.js
+++ b/js/components/whitelabel/prize/simple_prize/components/prize_landing.js
@@ -46,7 +46,7 @@ let Landing = React.createClass({
// if user is already logged in, redirect him to piece list
if(this.state.currentUser && this.state.currentUser.email) {
// FIXME: hack to redirect out of the dispatch cycle
- window.setTimeout(() => this.history.replaceState(null, '/collection'), 0);
+ window.setTimeout(() => this.history.replace('/collection'), 0);
}
},
diff --git a/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js b/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js
index 8e602012..23cdbb23 100644
--- a/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js
+++ b/js/components/whitelabel/prize/simple_prize/components/prize_piece_list.js
@@ -48,7 +48,8 @@ let PrizePieceList = React.createClass({
},
getButtonSubmit() {
- if (this.state.prize && this.state.prize.active && !this.state.currentUser.is_jury){
+ const { currentUser, prize } = this.state;
+ if (prize && prize.active && !currentUser.is_jury && !currentUser.is_admin && !currentUser.is_judge) {
return (
);
}
- else if (this.state.prize && this.state.currentUser.is_judge){
- return null;
- }
return null;
},
diff --git a/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js b/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js
index 145a9d24..b91f9789 100644
--- a/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js
+++ b/js/components/whitelabel/prize/simple_prize/components/prize_settings_container.js
@@ -135,14 +135,15 @@ let PrizeJurySettings = React.createClass({
handleCreateSuccess(response) {
PrizeJuryActions.fetchJury();
- let notification = new GlobalNotificationModel(response.notification, 'success', 5000);
- GlobalNotificationActions.appendGlobalNotification(notification);
+ this.displayNotification(response);
this.refs.form.refs.email.refs.input.getDOMNode().value = null;
},
handleActivate(event) {
let email = event.target.getAttribute('data-id');
- PrizeJuryActions.activateJury(email).then((response) => {
+ PrizeJuryActions
+ .activateJury(email)
+ .then((response) => {
PrizeJuryActions.fetchJury();
this.displayNotification(response);
});
diff --git a/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js b/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js
index 38d0576e..e2f20d93 100644
--- a/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js
+++ b/js/components/whitelabel/prize/simple_prize/fetchers/prize_rating_fetcher.js
@@ -4,16 +4,41 @@ import requests from '../../../../../utils/requests';
let PrizeRatingFetcher = {
- fetchAverage(pieceId) {
- return requests.get('rating_average', {'piece_id': pieceId});
+ fetchAverage(pieceId, round) {
+ const params = {
+ 'piece_id': pieceId
+ };
+
+ if (typeof round === 'number') {
+ params['prize_round'] = round;
+ }
+
+ return requests.get('rating_average', params);
},
- fetchOne(pieceId) {
- return requests.get('rating', {'piece_id': pieceId});
+ fetchOne(pieceId, round) {
+ const params = {
+ 'piece_id': pieceId
+ };
+
+ if (typeof round === 'number') {
+ params['prize_round'] = round;
+ }
+
+ return requests.get('rating', params);
},
- rate(pieceId, rating) {
- return requests.post('ratings', {body: {'piece_id': pieceId, 'note': rating}});
+ rate(pieceId, rating, round) {
+ const body = {
+ 'piece_id': pieceId,
+ 'note': rating
+ };
+
+ if (typeof round === 'number') {
+ body['prize_round'] = round;
+ }
+
+ return requests.post('ratings', { body });
},
select(pieceId) {
diff --git a/js/components/whitelabel/prize/simple_prize/prize_app.js b/js/components/whitelabel/prize/simple_prize/prize_app.js
index d95d7772..d5b55d5f 100644
--- a/js/components/whitelabel/prize/simple_prize/prize_app.js
+++ b/js/components/whitelabel/prize/simple_prize/prize_app.js
@@ -32,7 +32,7 @@ let PrizeApp = React.createClass({
if (!path || history.isActive('/login') || history.isActive('/signup')) {
header = ;
} else {
- header = ;
+ header = ;
}
return (
diff --git a/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js b/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js
index 9f1552bb..d3544f71 100644
--- a/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js
+++ b/js/components/whitelabel/prize/simple_prize/stores/prize_rating_store.js
@@ -6,10 +6,24 @@ import PrizeRatingActions from '../actions/prize_rating_actions';
class PrizeRatingStore {
constructor() {
+ this.getInitialState();
+
+ this.bindActions(PrizeRatingActions);
+ this.exportPublicMethods({
+ getInitialState: this.getInitialState.bind(this)
+ });
+ }
+
+ getInitialState() {
this.ratings = [];
this.currentRating = null;
this.average = null;
- this.bindActions(PrizeRatingActions);
+
+ return {
+ ratings: this.ratings,
+ currentRating: this.currentRating,
+ average: this.average
+ };
}
onUpdatePrizeRatings(ratings) {
@@ -24,6 +38,10 @@ class PrizeRatingStore {
this.average = data.average;
this.ratings = data.ratings;
}
+
+ onResetPrizeRatings() {
+ this.getInitialState();
+ }
}
-export default alt.createStore(PrizeRatingStore, 'PrizeRatingStore');
\ No newline at end of file
+export default alt.createStore(PrizeRatingStore, 'PrizeRatingStore');
diff --git a/js/components/whitelabel/prize/simple_prize/stores/prize_store.js b/js/components/whitelabel/prize/simple_prize/stores/prize_store.js
index 8d9c4bbe..d54ab549 100644
--- a/js/components/whitelabel/prize/simple_prize/stores/prize_store.js
+++ b/js/components/whitelabel/prize/simple_prize/stores/prize_store.js
@@ -6,7 +6,7 @@ import PrizeActions from '../actions/prize_actions';
class PrizeStore {
constructor() {
- this.prize = [];
+ this.prize = {};
this.bindActions(PrizeActions);
}
@@ -15,4 +15,4 @@ class PrizeStore {
}
}
-export default alt.createStore(PrizeStore, 'PrizeStore');
\ No newline at end of file
+export default alt.createStore(PrizeStore, 'PrizeStore');
diff --git a/js/components/whitelabel/prize/sluice/components/sluice_buttons/sluice_selected_prize_action_button.js b/js/components/whitelabel/prize/sluice/components/sluice_buttons/sluice_selected_prize_action_button.js
new file mode 100644
index 00000000..7778a8de
--- /dev/null
+++ b/js/components/whitelabel/prize/sluice/components/sluice_buttons/sluice_selected_prize_action_button.js
@@ -0,0 +1,70 @@
+'use strict'
+
+import React from 'react';
+import Moment from 'moment';
+
+import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
+
+import LoanForm from '../../../../../ascribe_forms/form_loan';
+
+import GlobalNotificationModel from '../../../../../../models/global_notification_model';
+import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
+
+import ApiUrls from '../../../../../../constants/api_urls';
+
+import { getLangText } from '../../../../../../utils/lang_utils';
+
+const SluiceSelectedPrizeActionButton = React.createClass({
+ propTypes: {
+ piece: React.PropTypes.object,
+ currentUser: React.PropTypes.object,
+ startLoanDate: React.PropTypes.object,
+ endLoanDate: React.PropTypes.object,
+ className: React.PropTypes.string,
+ handleSuccess: React.PropTypes.func
+ },
+
+ handleSuccess(res) {
+ const notification = new GlobalNotificationModel(res && res.notification || getLangText('You have successfully requested the loan, pending their confirmation.'), 'success', 4000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
+
+ if (typeof this.props.handleSuccess === 'function') {
+ this.props.handleSuccess(res);
+ }
+ },
+
+ render() {
+ const { currentUser, piece } = this.props;
+
+ // Can't use default props since those are only created once
+ const startLoanDate = this.props.startLoanDate || new Moment();
+ const endLoanDate = this.props.endLoanDate || (new Moment()).add(6, 'months');
+
+ return (
+
+ {getLangText('SEND LOAN REQUEST')}
+
+ }
+ handleSuccess={this.handleSuccess}
+ title={getLangText('REQUEST LOAN')}>
+
+
+ );
+ }
+});
+
+export default SluiceSelectedPrizeActionButton;
+
diff --git a/js/components/whitelabel/prize/sluice/components/sluice_detail/sluice_piece_container.js b/js/components/whitelabel/prize/sluice/components/sluice_detail/sluice_piece_container.js
new file mode 100644
index 00000000..2d9debca
--- /dev/null
+++ b/js/components/whitelabel/prize/sluice/components/sluice_detail/sluice_piece_container.js
@@ -0,0 +1,23 @@
+'use strict';
+
+import React from 'react';
+
+import SluiceSelectedPrizeActionButton from '../sluice_buttons/sluice_selected_prize_action_button';
+
+import PrizePieceContainer from '../../../simple_prize/components/ascribe_detail/prize_piece_container';
+
+const SluicePieceContainer = React.createClass({
+ propTypes: {
+ params: React.PropTypes.object
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+
+export default SluicePieceContainer;
diff --git a/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js b/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
index 302495a0..f6b2d50c 100644
--- a/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
+++ b/js/components/whitelabel/wallet/components/23vivi/23vivi_landing.js
@@ -47,7 +47,7 @@ let Vivi23Landing = React.createClass({
-
+
{getLangText('Existing ascribe user?')}
@@ -57,7 +57,7 @@ let Vivi23Landing = React.createClass({
-
+
{getLangText('Do you need an account?')}
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 26a186ca..ed8da83b 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
@@ -25,63 +25,72 @@ let WalletPieceContainer = React.createClass({
currentUser: React.PropTypes.object.isRequired,
loadPiece: React.PropTypes.func.isRequired,
handleDeleteSuccess: React.PropTypes.func.isRequired,
- submitButtonType: React.PropTypes.func.isRequired
+ submitButtonType: React.PropTypes.func.isRequired,
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.object,
+ React.PropTypes.array
+ ])
},
-
render() {
- if(this.props.piece && this.props.piece.id) {
+ const {
+ children,
+ currentUser,
+ handleDeleteSuccess,
+ loadPiece,
+ piece,
+ submitButtonType } = this.props;
+
+ if (piece && piece.id) {
return (
- {this.props.piece.title}
-
-
+ {piece.title}
+
+
}
subheader={
-
-
-
-
-
- }>
+
+
+
+
+
+ }>
+ piece={piece}
+ currentUser={currentUser}
+ loadPiece={loadPiece}
+ handleDeleteSuccess={handleDeleteSuccess}
+ submitButtonType={submitButtonType}/>
0}>
+ show={piece.loan_history && piece.loan_history.length > 0}>
+ history={piece.loan_history}/>
+ show={!!(currentUser.username || piece.public_note)}>
{return {'id': this.props.piece.id}; }}
+ id={() => {return {'id': piece.id}; }}
label={getLangText('Personal note (private)')}
- defaultValue={this.props.piece.private_note || null}
+ defaultValue={piece.private_note || null}
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_piece}
- currentUser={this.props.currentUser}/>
+ currentUser={currentUser}/>
-
- {this.props.children}
+ {children}
);
- }
- else {
+ } else {
return (
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 9d88408f..ebdef4f4 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
@@ -52,8 +52,9 @@ let CylandAccordionListItem = React.createClass({
},
handleSubmitSuccess(response) {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js b/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js
index d211d3e8..5fc3901f 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_detail/cyland_piece_container.js
@@ -40,7 +40,7 @@ let CylandPieceContainer = React.createClass({
getInitialState() {
return mergeOptions(
- PieceStore.getState(),
+ PieceStore.getInitialState(),
UserStore.getState(),
PieceListStore.getState()
);
@@ -51,14 +51,17 @@ let CylandPieceContainer = React.createClass({
UserStore.listen(this.onChange);
PieceListStore.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();
},
+ // We need this for when the user clicks on a notification while being in another piece view
+ componentWillReceiveProps(nextProps) {
+ if (this.props.params.pieceId !== nextProps.params.pieceId) {
+ PieceActions.flushPiece();
+ this.loadPiece();
+ }
+ },
+
componentWillUnmount() {
PieceStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
@@ -70,31 +73,34 @@ let CylandPieceContainer = React.createClass({
},
loadPiece() {
- PieceActions.fetchOne(this.props.params.pieceId);
+ PieceActions.fetchPiece(this.props.params.pieceId);
},
handleDeleteSuccess(response) {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
// since we're deleting a piece, we just need to close
// all editions dialogs and not reload them
EditionListActions.closeAllEditionLists();
EditionListActions.clearAllEditionSelections();
- let notification = new GlobalNotificationModel(response.notification, 'success');
+ const notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
- this.history.pushState(null, '/collection');
+ this.history.push('/collection');
},
render() {
- if(this.state.piece && this.state.piece.id) {
- setDocumentTitle([this.state.piece.artist_name, this.state.piece.title].join(', '));
+ const { piece } = this.state;
+
+ if (piece.id) {
+ setDocumentTitle(`${piece.artist_name}, ${piece.title}`);
return (
);
- }
- else {
+ } 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 93cc515a..6e643134 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
@@ -23,9 +23,10 @@ import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_
let CylandAdditionalDataForm = React.createClass({
propTypes: {
- handleSuccess: React.PropTypes.func,
piece: React.PropTypes.object.isRequired,
+
disabled: React.PropTypes.bool,
+ handleSuccess: React.PropTypes.func,
isInline: React.PropTypes.bool
},
@@ -42,13 +43,13 @@ let CylandAdditionalDataForm = React.createClass({
},
handleSuccess() {
- let notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
+ const notification = new GlobalNotificationModel(getLangText('Further details successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
getFormData() {
- let extradata = {};
- let formRefs = this.refs.form.refs;
+ const extradata = {};
+ const formRefs = this.refs.form.refs;
// Put additional fields in extra data object
Object
@@ -71,10 +72,13 @@ let CylandAdditionalDataForm = React.createClass({
},
render() {
- let { piece, isInline, disabled, handleSuccess, location } = this.props;
- let buttons, spinner, heading;
+ const { disabled, handleSuccess, isInline, piece } = this.props;
- if(!isInline) {
+ let buttons;
+ let spinner;
+ let heading;
+
+ if (!isInline) {
buttons = (
);
@@ -101,13 +105,15 @@ let CylandAdditionalDataForm = React.createClass({
);
}
- if(piece && piece.id) {
+ if (piece.id) {
+ const { extra_data: extraData = {} } = piece;
+
return (
);
}
diff --git a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
index dc6420f4..0a8dadd1 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_landing.js
@@ -49,7 +49,7 @@ let CylandLanding = React.createClass({
// if user is already logged in, redirect him to piece list
if(this.state.currentUser && this.state.currentUser.email) {
// FIXME: hack to redirect out of the dispatch cycle
- window.setTimeout(() => this.history.replaceState(null, '/collection'), 0);
+ window.setTimeout(() => this.history.replace('/collection'), 0);
}
},
@@ -70,7 +70,7 @@ let CylandLanding = React.createClass({
-
+
{getLangText('Existing ascribe user?')}
@@ -80,7 +80,7 @@ let CylandLanding = React.createClass({
-
+
{getLangText('Do you need an account?')}
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 42b7c1ad..88088e9d 100644
--- a/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
+++ b/js/components/whitelabel/wallet/components/cyland/cyland_register_piece.js
@@ -8,6 +8,8 @@ import Moment from 'moment';
import Col from 'react-bootstrap/lib/Col';
import Row from 'react-bootstrap/lib/Row';
+import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
+
import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
@@ -50,7 +52,7 @@ let CylandRegisterPiece = React.createClass({
return mergeOptions(
UserStore.getState(),
PieceListStore.getState(),
- PieceStore.getState(),
+ PieceStore.getInitialState(),
WhitelabelStore.getState(),
{
step: 0
@@ -65,7 +67,7 @@ let CylandRegisterPiece = React.createClass({
UserActions.fetchCurrentUser();
WhitelabelActions.fetchWhitelabel();
- let queryParams = this.props.location.query;
+ 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.
@@ -74,8 +76,8 @@ let CylandRegisterPiece = React.createClass({
//
// 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);
+ if ('piece_id' in queryParams) {
+ PieceActions.fetchPiece(queryParams.piece_id);
}
},
@@ -90,79 +92,78 @@ let CylandRegisterPiece = React.createClass({
this.setState(state);
},
- handleRegisterSuccess(response){
-
+ handleRegisterSuccess(response) {
this.refreshPieceList();
- // also start loading the piece for the next step
- if(response && response.piece) {
- PieceActions.updatePiece({});
+ // Also load the newly registered piece for the next step
+ if (response && response.piece) {
PieceActions.updatePiece(response.piece);
}
- this.incrementStep();
-
- this.refs.slidesContainer.nextSlide({ piece_id: response.piece.id });
+ this.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
+ // since we want its otherData to be displayed when the user choses to click
// on the browsers back button.
- PieceActions.fetchOne(this.state.piece.id);
+ PieceActions.fetchPiece(this.state.piece.id);
this.refreshPieceList();
- this.incrementStep();
-
- this.refs.slidesContainer.nextSlide();
+ this.nextSlide();
},
handleLoanSuccess(response) {
- let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
+ const notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
this.refreshPieceList();
- PieceActions.fetchOne(this.state.piece.id);
-
- this.history.pushState(null, `/pieces/${this.state.piece.id}`);
+ this.history.push(`/pieces/${this.state.piece.id}`);
},
- // 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;
+ nextSlide(queryParams) {
+ // We need to increase the step to lock the forms that are already filled out
this.setState({
- step: newStep
+ step: this.state.step + 1
});
+
+ this.refs.slidesContainer.nextSlide(queryParams);
},
refreshPieceList() {
- PieceListActions.fetchPieceList(
- this.state.page,
- this.state.pageSize,
- this.state.searchTerm,
- this.state.orderBy,
- this.state.orderAsc,
- this.state.filterBy
- );
- },
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
- 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();
- }
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
},
render() {
+ const { location } = this.props;
+ const { currentUser, piece, step, whitelabel } = this.state;
- let today = new Moment();
- let datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain = new Moment();
- datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain.add(1000, 'years');
+ const today = new Moment();
+ const datetimeWhenWeAllWillBeFlyingCoolHoverboardsAndDinosaursWillLiveAgain = new Moment().add(1000, 'years');
+
+ const loanHeading = getLangText('Loan to Cyland archive');
+ const loanButtons = (
+
+
+
+
+
+
+
+
+
+
+ );
setDocumentTitle(getLangText('Register a new piece'));
@@ -174,18 +175,18 @@ let CylandRegisterPiece = React.createClass({
pending: 'glyphicon glyphicon-chevron-right',
completed: 'glyphicon glyphicon-lock'
}}
- location={this.props.location}>
+ location={location}>
0}
+ disabled={step > 0}
enableLocalHashing={false}
headerMessage={getLangText('Submit to Cyland Archive')}
submitMessage={getLangText('Submit')}
isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
- location={this.props.location}/>
+ location={location} />
@@ -193,9 +194,9 @@ let CylandRegisterPiece = React.createClass({
1}
+ disabled={step > 1}
handleSuccess={this.handleAdditionalDataSuccess}
- piece={this.state.piece} />
+ piece={piece} />
@@ -204,15 +205,16 @@ let CylandRegisterPiece = React.createClass({
this.handleConfirmSuccess()
- );
+ OwnershipFetcher
+ .confirmContractAgreement(contractAgreement)
+ .then(this.handleConfirmSuccess);
},
handleConfirmSuccess() {
let notification = new GlobalNotificationModel(getLangText('You have accepted the conditions'), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
- this.history.pushState(null, '/collection');
+
+ // Flush contract notifications and refetch
+ NotificationActions.flushContractAgreementListNotifications();
+ NotificationActions.fetchContractAgreementListNotifications();
+
+ this.history.push('/collection');
},
handleDeny() {
let contractAgreement = this.state.contractAgreementListNotifications[0].contract_agreement;
- OwnershipFetcher.denyContractAgreement(contractAgreement).then(
- () => this.handleDenySuccess()
- );
+ OwnershipFetcher
+ .denyContractAgreement(contractAgreement)
+ .then(this.handleDenySuccess);
},
handleDenySuccess() {
let notification = new GlobalNotificationModel(getLangText('You have denied the conditions'), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
- this.history.pushState(null, '/collection');
+ this.history.push('/collection');
},
getCopyrightAssociationForm(){
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_detail/ikonotv_piece_container.js
index df58b7c7..a1280cc8 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_detail/ikonotv_piece_container.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_detail/ikonotv_piece_container.js
@@ -41,7 +41,7 @@ let IkonotvPieceContainer = React.createClass({
getInitialState() {
return mergeOptions(
- PieceStore.getState(),
+ PieceStore.getInitialState(),
UserStore.getState(),
PieceListStore.getState()
);
@@ -52,19 +52,14 @@ let IkonotvPieceContainer = React.createClass({
UserStore.listen(this.onChange);
PieceListStore.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();
},
- // We need this for when the user clicks on a notification while being in another piece view
+ // We need this for when the user clicks on a notification while being in another piece view
componentWillReceiveProps(nextProps) {
- if(this.props.params.pieceId !== nextProps.params.pieceId) {
- PieceActions.updatePiece({});
- PieceActions.fetchOne(nextProps.params.pieceId);
+ if (this.props.params.pieceId !== nextProps.params.pieceId) {
+ PieceActions.flushPiece();
+ this.loadPiece();
}
},
@@ -79,25 +74,28 @@ let IkonotvPieceContainer = React.createClass({
},
loadPiece() {
- PieceActions.fetchOne(this.props.params.pieceId);
+ PieceActions.fetchPiece(this.props.params.pieceId);
},
handleDeleteSuccess(response) {
- PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.search,
- this.state.orderBy, this.state.orderAsc, this.state.filterBy);
+ const { filterBy, orderAsc, orderBy, page, pageSize, search } = this.state;
+
+ PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
// since we're deleting a piece, we just need to close
// all editions dialogs and not reload them
EditionListActions.closeAllEditionLists();
EditionListActions.clearAllEditionSelections();
- let notification = new GlobalNotificationModel(response.notification, 'success');
+ const notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
- this.history.pushState(null, '/collection');
+ this.history.push('/collection');
},
render() {
+ const { piece } = this.state;
+
let furtherDetails = (
);
- if(this.state.piece.extra_data && Object.keys(this.state.piece.extra_data).length > 0 && this.state.piece.acl) {
+ if (piece.extra_data && Object.keys(piece.extra_data).length && piece.acl) {
furtherDetails = (
+ disabled={!piece.acl.acl_edit} />
+ disabled={!piece.acl.acl_edit} />
);
}
- if(this.state.piece && this.state.piece.id) {
- setDocumentTitle([this.state.piece.artist_name, this.state.piece.title].join(', '));
+ if (piece.id) {
+ setDocumentTitle(`${piece.artist_name}, ${piece.title}`);
+
return (
);
- }
- else {
+ } else {
return (
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artist_details_form.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artist_details_form.js
index 7aec7ff4..598f5bd0 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artist_details_form.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artist_details_form.js
@@ -20,11 +20,10 @@ import { getLangText } from '../../../../../../utils/lang_utils';
let IkonotvArtistDetailsForm = React.createClass({
propTypes: {
- handleSuccess: React.PropTypes.func,
piece: React.PropTypes.object.isRequired,
disabled: React.PropTypes.bool,
-
+ handleSuccess: React.PropTypes.func,
isInline: React.PropTypes.bool
},
@@ -35,8 +34,8 @@ let IkonotvArtistDetailsForm = React.createClass({
},
getFormData() {
- let extradata = {};
- let formRefs = this.refs.form.refs;
+ const extradata = {};
+ const formRefs = this.refs.form.refs;
// Put additional fields in extra data object
Object
@@ -53,21 +52,23 @@ let IkonotvArtistDetailsForm = React.createClass({
},
handleSuccess() {
- let notification = new GlobalNotificationModel('Artist details successfully updated', 'success', 10000);
+ const notification = new GlobalNotificationModel(getLangText('Artist details successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
- let buttons, spinner, heading;
- let { isInline, handleSuccess } = this.props;
-
+ const { disabled, isInline, handleSuccess, piece } = this.props;
- if(!isInline) {
+ let buttons;
+ let spinner;
+ let heading;
+
+ if (!isInline) {
buttons = (
);
@@ -75,7 +76,7 @@ let IkonotvArtistDetailsForm = React.createClass({
spinner = (
);
@@ -89,13 +90,15 @@ let IkonotvArtistDetailsForm = React.createClass({
);
}
- if(this.props.piece && this.props.piece.id && this.props.piece.extra_data) {
+ if (piece.id) {
+ const { extra_data: extraData = {} } = piece;
+
return (
);
@@ -150,4 +152,4 @@ let IkonotvArtistDetailsForm = React.createClass({
}
});
-export default IkonotvArtistDetailsForm;
\ No newline at end of file
+export default IkonotvArtistDetailsForm;
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artwork_details_form.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artwork_details_form.js
index 97b1adc7..28c67c94 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artwork_details_form.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_forms/ikonotv_artwork_details_form.js
@@ -20,11 +20,10 @@ import { getLangText } from '../../../../../../utils/lang_utils';
let IkonotvArtworkDetailsForm = React.createClass({
propTypes: {
- handleSuccess: React.PropTypes.func,
piece: React.PropTypes.object.isRequired,
disabled: React.PropTypes.bool,
-
+ handleSuccess: React.PropTypes.func,
isInline: React.PropTypes.bool
},
@@ -35,8 +34,8 @@ let IkonotvArtworkDetailsForm = React.createClass({
},
getFormData() {
- let extradata = {};
- let formRefs = this.refs.form.refs;
+ const extradata = {};
+ const formRefs = this.refs.form.refs;
// Put additional fields in extra data object
Object
@@ -53,20 +52,23 @@ let IkonotvArtworkDetailsForm = React.createClass({
},
handleSuccess() {
- let notification = new GlobalNotificationModel('Artwork details successfully updated', 'success', 10000);
+ const notification = new GlobalNotificationModel(getLangText('Artwork details successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
- let buttons, spinner, heading;
- let { isInline, handleSuccess } = this.props;
+ const { disabled, isInline, handleSuccess, piece } = this.props;
- if(!isInline) {
+ let buttons;
+ let spinner;
+ let heading;
+
+ if (!isInline) {
buttons = (
);
@@ -74,7 +76,7 @@ let IkonotvArtworkDetailsForm = React.createClass({
spinner = (
);
@@ -88,13 +90,15 @@ let IkonotvArtworkDetailsForm = React.createClass({
);
}
- if(this.props.piece && this.props.piece.id && this.props.piece.extra_data) {
+ if (piece.id && piece.extra_data) {
+ const { extra_data: extraData = {} } = piece;
+
return (
);
@@ -166,4 +170,4 @@ let IkonotvArtworkDetailsForm = React.createClass({
}
});
-export default IkonotvArtworkDetailsForm;
\ No newline at end of file
+export default IkonotvArtworkDetailsForm;
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js
index 0b51bdbd..5b489d09 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ikonotv_piece_list.js
@@ -1,15 +1,18 @@
'use strict';
import React from 'react';
+
import PieceList from '../../../../piece_list';
import UserActions from '../../../../../actions/user_actions';
import UserStore from '../../../../../stores/user_store';
+import NotificationStore from '../../../../../stores/notification_store';
import IkonotvAccordionListItem from './ikonotv_accordion_list/ikonotv_accordion_list_item';
-import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
+import { mergeOptions } from '../../../../../utils/general_utils';
+import { getLangText } from '../../../../../utils/lang_utils';
let IkonotvPieceList = React.createClass({
@@ -18,20 +21,33 @@ let IkonotvPieceList = React.createClass({
},
getInitialState() {
- return UserStore.getState();
+ return mergeOptions(
+ NotificationStore.getState(),
+ UserStore.getState()
+ );
},
componentDidMount() {
+ NotificationStore.listen(this.onChange);
UserStore.listen(this.onChange);
+
UserActions.fetchCurrentUser();
},
componentWillUnmount() {
+ NotificationStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
+
+ },
+
+ redirectIfNoContractNotifications() {
+ const { contractAgreementListNotifications } = this.state;
+
+ return contractAgreementListNotifications && !contractAgreementListNotifications.length;
},
render() {
@@ -41,6 +57,7 @@ let IkonotvPieceList = React.createClass({
+ piece={this.state.piece} />
);
+ } else {
+ return null;
}
- return null;
},
getSlideArtworkDetails() {
@@ -188,21 +175,21 @@ let IkonotvRegisterPiece = React.createClass({
+ piece={this.state.piece} />
);
+ } else {
+ return null;
}
- return null;
},
getSlideLoan() {
if (this.canSubmit()) {
const { piece, whitelabel } = this.state;
- let today = new Moment();
- let endDate = new Moment();
- endDate.add(2, 'years');
+ const today = new Moment();
+ const endDate = new Moment().add(2, 'years');
return (
@@ -225,8 +212,9 @@ let IkonotvRegisterPiece = React.createClass({
);
+ } else {
+ return null;
}
- return null;
},
render() {
@@ -252,7 +240,7 @@ let IkonotvRegisterPiece = React.createClass({
submitMessage={getLangText('Register')}
isFineUploaderActive={true}
handleSuccess={this.handleRegisterSuccess}
- location={this.props.location}/>
+ location={this.props.location} />
diff --git a/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
index e68b1781..23289276 100644
--- a/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
+++ b/js/components/whitelabel/wallet/components/lumenus/lumenus_landing.js
@@ -53,7 +53,7 @@ let LumenusLanding = React.createClass({
-
+
{getLangText('Existing ascribe user?')}
@@ -63,7 +63,7 @@ let LumenusLanding = React.createClass({
-
+
{getLangText('Do you need an account?')}
diff --git a/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js b/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
index 1dcdd4e5..4d4f8918 100644
--- a/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
+++ b/js/components/whitelabel/wallet/components/market/market_buttons/market_acl_button_list.js
@@ -30,7 +30,7 @@ let MarketAclButtonList = React.createClass({
componentDidMount() {
UserStore.listen(this.onChange);
- UserActions.fetchCurrentUser();
+ UserActions.fetchCurrentUser.defer();
},
componentWillUnmount() {
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..c839dea0 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,11 @@
import React from 'react';
import classNames from 'classnames';
+import EditionActions from '../../../../../../actions/edition_actions';
+
+import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
+import WhitelabelStore from '../../../../../../stores/whitelabel_store';
+
import MarketAdditionalDataForm from '../market_forms/market_additional_data_form';
import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
@@ -11,10 +16,7 @@ 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';
+import AscribeSpinner from '../../../../../ascribe_spinner';
import ApiUrls from '../../../../../../constants/api_urls';
@@ -26,8 +28,9 @@ let MarketSubmitButton = React.createClass({
availableAcls: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object,
editions: React.PropTypes.array.isRequired,
- handleSuccess: React.PropTypes.func.isRequired,
+
className: React.PropTypes.string,
+ handleSuccess: React.PropTypes.func
},
getInitialState() {
@@ -50,22 +53,21 @@ let MarketSubmitButton = React.createClass({
canEditionBeSubmitted(edition) {
if (edition && edition.extra_data && edition.other_data) {
- const { extra_data, other_data } = edition;
+ const {
+ extra_data: {
+ artist_bio: artistBio,
+ display_instructions: displayInstructions,
+ technology_details: technologyDetails,
+ work_description: workDescription
+ },
+ other_data: otherData } = 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 artistBio && displayInstructions && technologyDetails && workDescription && otherData.length;
}
return false;
},
- getFormDataId() {
- return getAclFormDataId(false, this.props.editions);
- },
-
getAggregateEditionDetails() {
const { editions } = this.props;
@@ -82,13 +84,20 @@ let MarketSubmitButton = React.createClass({
});
},
- handleAdditionalDataSuccess(pieceId) {
- // Fetch newly updated piece to update the views
- PieceActions.fetchOne(pieceId);
+ getFormDataId() {
+ return getAclFormDataId(false, this.props.editions);
+ },
+ handleAdditionalDataSuccess() {
this.refs.consignModal.show();
},
+ refreshEdition() {
+ if (this.props.editions.length === 1) {
+ EditionActions.fetchEdition(this.props.editions[0].bitcoin_id);
+ }
+ },
+
render() {
const { availableAcls, currentUser, className, editions, handleSuccess } = this.props;
const { whitelabel: { name: whitelabelName = 'Market', user: whitelabelAdminEmail } } = this.state;
@@ -101,6 +110,10 @@ let MarketSubmitButton = React.createClass({
senderName: currentUser.username
});
+ // If only a single piece is selected, all the edition's extra_data and other_data will
+ // be the same, so we just take the first edition's
+ const { extra_data: extraData, other_data: otherData } = solePieceId ? editions[0] : {};
+
const triggerButton = (