1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 17:33:14 +01:00

Load current user and whitelabel settings in AscribeApp

This commit is contained in:
Brett Sun 2016-01-11 12:54:15 +01:00
parent 19841ce6c4
commit d622ddac06
14 changed files with 216 additions and 181 deletions

View File

@ -2,10 +2,18 @@
import React from 'react'; import React from 'react';
import Header from '../components/header'; import UserActions from '../actions/user_actions';
import Footer from '../components/footer'; import UserStore from '../stores/user_store';
import WhitelabelActions from '../actions/whitelabel_actions';
import WhitelabelStore from '../stores/whitelabel_store';
import Header from './header';
import Footer from './footer';
import GlobalNotification from './global_notification'; import GlobalNotification from './global_notification';
import { mergeOptions } from '../utils/general_utils';
let AscribeApp = React.createClass({ let AscribeApp = React.createClass({
propTypes: { propTypes: {
@ -16,15 +24,48 @@ let AscribeApp = React.createClass({
routes: React.PropTypes.arrayOf(React.PropTypes.object) routes: React.PropTypes.arrayOf(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);
WhitelabelActions.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() { render() {
let { children, routes } = this.props; const { children, routes } = this.props;
const { currentUser, whitelabel } = this.state;
// Add the current user and whitelabel settings to all child routes
const childrenWithProps = React.Children.map(children, (child) => {
return React.cloneElement(child, {
currentUser,
whitelabel
});
});
return ( return (
<div className="container ascribe-default-app"> <div className="container ascribe-default-app">
<Header routes={routes} /> <Header routes={routes} />
{/* Routes are injected here */}
<div className="ascribe-body"> <div className="ascribe-body">
{children} {/* Routes are injected here */}
{childrenWithProps}
</div> </div>
<Footer /> <Footer />
<GlobalNotification /> <GlobalNotification />

View File

@ -9,16 +9,12 @@ import { ResourceNotFoundError } from '../../models/errors';
import EditionActions from '../../actions/edition_actions'; import EditionActions from '../../actions/edition_actions';
import EditionStore from '../../stores/edition_store'; import EditionStore from '../../stores/edition_store';
import UserActions from '../../actions/user_actions';
import UserStore from '../../stores/user_store';
import Edition from './edition'; import Edition from './edition';
import AscribeSpinner from '../ascribe_spinner'; import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils'; import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils'; import { setDocumentTitle } from '../../utils/dom_utils';
import { mergeOptions } from '../../utils/general_utils';
/** /**
@ -28,21 +24,24 @@ let EditionContainer = React.createClass({
propTypes: { propTypes: {
actionPanelButtonListType: React.PropTypes.func, actionPanelButtonListType: React.PropTypes.func,
furtherDetailsType: React.PropTypes.func, furtherDetailsType: React.PropTypes.func,
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object,
params: React.PropTypes.object params: React.PropTypes.object
}, },
mixins: [History, ReactError], mixins: [History, ReactError],
getInitialState() { getInitialState() {
return mergeOptions( return EditionStore.getState();
EditionStore.getState(),
UserStore.getState()
);
}, },
componentDidMount() { componentDidMount() {
EditionStore.listen(this.onChange); EditionStore.listen(this.onChange);
UserStore.listen(this.onChange);
// Every time we're entering the edition detail page, // Every time we're entering the edition detail page,
// just reset the edition that is saved in the edition store // just reset the edition that is saved in the edition store
@ -50,21 +49,19 @@ let EditionContainer = React.createClass({
// the edition detail a second time // the edition detail a second time
EditionActions.flushEdition(); EditionActions.flushEdition();
EditionActions.fetchEdition(this.props.params.editionId); EditionActions.fetchEdition(this.props.params.editionId);
UserActions.fetchCurrentUser();
}, },
// This is done to update the container when the user clicks on the prev or next // 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)
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if(this.props.params.editionId !== nextProps.params.editionId) { if (this.props.params.editionId !== nextProps.params.editionId) {
EditionActions.fetchEdition(this.props.params.editionId); EditionActions.fetchEdition(this.props.params.editionId);
} }
}, },
componentDidUpdate() { componentDidUpdate() {
const { editionMeta } = this.state; const { editionMeta } = this.state;
if(editionMeta.err && editionMeta.err.json && editionMeta.err.json.status === 404) { if (editionMeta.err && editionMeta.err.json && editionMeta.err.json.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.")));
} }
}, },
@ -72,7 +69,6 @@ let EditionContainer = React.createClass({
componentWillUnmount() { componentWillUnmount() {
window.clearInterval(this.state.timerId); window.clearInterval(this.state.timerId);
EditionStore.unlisten(this.onChange); EditionStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
}, },
onChange(state) { onChange(state) {
@ -88,8 +84,8 @@ let EditionContainer = React.createClass({
}, },
render() { render() {
const { edition, currentUser, coaMeta } = this.state; const { edition, coaMeta } = this.state;
const { actionPanelButtonListType, furtherDetailsType } = this.props; const { actionPanelButtonListType, currentUser, furtherDetailsType } = this.props;
if (Object.keys(edition).length && edition.id) { if (Object.keys(edition).length && edition.id) {
setDocumentTitle([edition.artist_name, edition.title].join(', ')); setDocumentTitle([edition.artist_name, edition.title].join(', '));

View File

@ -54,6 +54,13 @@ import { setDocumentTitle } from '../../utils/dom_utils';
let PieceContainer = React.createClass({ let PieceContainer = React.createClass({
propTypes: { propTypes: {
furtherDetailsType: React.PropTypes.func, furtherDetailsType: React.PropTypes.func,
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object,
params: React.PropTypes.object params: React.PropTypes.object
}, },
@ -67,7 +74,6 @@ let PieceContainer = React.createClass({
getInitialState() { getInitialState() {
return mergeOptions( return mergeOptions(
UserStore.getState(),
PieceListStore.getState(), PieceListStore.getState(),
PieceStore.getState(), PieceStore.getState(),
{ {
@ -77,7 +83,6 @@ let PieceContainer = React.createClass({
}, },
componentDidMount() { componentDidMount() {
UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange); PieceListStore.listen(this.onChange);
PieceStore.listen(this.onChange); PieceStore.listen(this.onChange);
@ -87,7 +92,6 @@ let PieceContainer = React.createClass({
PieceActions.updatePiece({}); PieceActions.updatePiece({});
this.loadPiece(); this.loadPiece();
UserActions.fetchCurrentUser();
}, },
componentDidUpdate() { componentDidUpdate() {
@ -100,7 +104,6 @@ let PieceContainer = React.createClass({
componentWillUnmount() { componentWillUnmount() {
PieceStore.unlisten(this.onChange); PieceStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange);
}, },
@ -201,7 +204,8 @@ let PieceContainer = React.createClass({
}, },
getActions() { getActions() {
const { piece, currentUser } = this.state; const { piece } = this.state;
const { currentUser } = this.props;
if (piece && piece.notifications && piece.notifications.length > 0) { if (piece && piece.notifications && piece.notifications.length > 0) {
return ( return (
@ -284,19 +288,19 @@ let PieceContainer = React.createClass({
</CollapsibleParagraph> </CollapsibleParagraph>
<CollapsibleParagraph <CollapsibleParagraph
title={getLangText('Notes')} title={getLangText('Notes')}
show={!!(this.state.currentUser.username show={!!(this.props.currentUser.username
|| this.state.piece.acl.acl_edit || this.state.piece.acl.acl_edit
|| this.state.piece.public_note)}> || this.state.piece.public_note)}>
<Note <Note
id={this.getId} id={this.getId}
label={getLangText('Personal note (private)')} label={getLangText('Personal note (private)')}
defaultValue={this.state.piece.private_note || null} defaultValue={this.state.piece.private_note || null}
show = {!!this.state.currentUser.username} show = {!!this.props.currentUser.username}
placeholder={getLangText('Enter your comments ...')} placeholder={getLangText('Enter your comments ...')}
editable={true} editable={true}
successMessage={getLangText('Private note saved')} successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_piece} url={ApiUrls.note_private_piece}
currentUser={this.state.currentUser}/> currentUser={this.props.currentUser}/>
<Note <Note
id={this.getId} id={this.getId}
label={getLangText('Personal note (public)')} label={getLangText('Personal note (public)')}
@ -306,7 +310,7 @@ let PieceContainer = React.createClass({
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')} successMessage={getLangText('Public note saved')}
url={ApiUrls.note_public_piece} url={ApiUrls.note_public_piece}
currentUser={this.state.currentUser}/> currentUser={this.props.currentUser}/>
</CollapsibleParagraph> </CollapsibleParagraph>
<CollapsibleParagraph <CollapsibleParagraph
title={getLangText('Further Details')} title={getLangText('Further Details')}

View File

@ -5,7 +5,6 @@ import { RouteContext } from 'react-router';
import history from '../../history'; import history from '../../history';
import UserStore from '../../stores/user_store'; import UserStore from '../../stores/user_store';
import UserActions from '../../actions/user_actions';
import AppConstants from '../../constants/application_constants'; import AppConstants from '../../constants/application_constants';
@ -35,23 +34,22 @@ export function AuthRedirect({to, when}) {
// //
// So if when === 'loggedIn', we're checking if the user is logged in (and // So if when === 'loggedIn', we're checking if the user is logged in (and
// vice versa) // vice versa)
let exprToValidate = when === 'loggedIn' ? currentUser && currentUser.email const exprToValidate = when === 'loggedIn' ? currentUser && currentUser.email
: currentUser && !currentUser.email; : currentUser && !currentUser.email;
// and redirect if `true`. // and redirect if `true`.
if(exprToValidate) { if (exprToValidate) {
window.setTimeout(() => history.replaceState(null, to, query)); window.setTimeout(() => history.replaceState(null, to, query));
return true; return true;
// Otherwise there can also be the case that the backend // Otherwise there can also be the case that the backend
// wants to redirect the user to a specific route when the user is logged out already // wants to redirect the user to a specific route when the user is logged out already
} else if(!exprToValidate && when === 'loggedIn' && redirect) { } else if (!exprToValidate && when === 'loggedIn' && redirect) {
delete query.redirect; delete query.redirect;
window.setTimeout(() => history.replaceState(null, '/' + redirect, query)); window.setTimeout(() => history.replaceState(null, '/' + redirect, query));
return true; return true;
} else if(!exprToValidate && when === 'loggedOut' && redirectAuthenticated) { } else if (!exprToValidate && when === 'loggedOut' && redirectAuthenticated) {
/* /*
* redirectAuthenticated contains an arbitrary path * redirectAuthenticated contains an arbitrary path
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ... * eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
@ -64,6 +62,7 @@ export function AuthRedirect({to, when}) {
window.location = AppConstants.baseUrl + redirectAuthenticated; window.location = AppConstants.baseUrl + redirectAuthenticated;
return true; return true;
} }
return false; return false;
}; };
} }
@ -81,6 +80,7 @@ export function ProxyHandler(...redirectFunctions) {
displayName: 'ProxyHandler', displayName: 'ProxyHandler',
propTypes: { propTypes: {
currentUser: object,
location: object location: object
}, },
@ -88,40 +88,22 @@ export function ProxyHandler(...redirectFunctions) {
// to use the `Lifecycle` widget in further down nested components // to use the `Lifecycle` widget in further down nested components
mixins: [RouteContext], mixins: [RouteContext],
getInitialState() {
return UserStore.getState();
},
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
},
componentDidUpdate() { componentDidUpdate() {
if(!UserStore.isLoading()) { const { currentUser, location: { query } } = this.props;
const { currentUser } = this.state;
const { query } = this.props.location;
for(let i = 0; i < redirectFunctions.length; i++) { if (!UserStore.isLoading()) {
for (let i = 0; i < redirectFunctions.length; i++) {
// if a redirectFunction redirects the user, // if a redirectFunction redirects the user,
// it should return `true` and therefore // it should return `true` and therefore
// stop/avoid the execution of all functions // stop/avoid the execution of all functions
// that follow // that follow
if(redirectFunctions[i](currentUser, query)) { if (redirectFunctions[i](currentUser, query)) {
break; break;
} }
} }
} }
}, },
componentWillUnmount() {
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() { render() {
return ( return (
<Component {...this.props}/> <Component {...this.props}/>

View File

@ -29,29 +29,24 @@ import { mergeOptions, truncateTextAtCharIndex } from '../../utils/general_utils
let ContractSettings = React.createClass({ let ContractSettings = React.createClass({
propTypes: { propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
getInitialState(){ getInitialState() {
return mergeOptions( return ContractListStore.getState();
ContractListStore.getState(),
UserStore.getState()
);
}, },
componentDidMount() { componentDidMount() {
ContractListStore.listen(this.onChange); ContractListStore.listen(this.onChange);
UserStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
UserActions.fetchCurrentUser();
ContractListActions.fetchContractList(true); ContractListActions.fetchContractList(true);
}, },
componentWillUnmount() { componentWillUnmount() {
WhitelabelStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
ContractListStore.unlisten(this.onChange); ContractListStore.unlisten(this.onChange);
}, },
@ -74,22 +69,23 @@ let ContractSettings = React.createClass({
}; };
}, },
getPublicContracts(){ getPublicContracts() {
return this.state.contractList.filter((contract) => contract.is_public); return this.state.contractList.filter((contract) => contract.is_public);
}, },
getPrivateContracts(){ getPrivateContracts() {
return this.state.contractList.filter((contract) => !contract.is_public); return this.state.contractList.filter((contract) => !contract.is_public);
}, },
render() { render() {
let publicContracts = this.getPublicContracts(); const { currentUser, location, whitelabel } = this.props;
let privateContracts = this.getPrivateContracts(); const publicContracts = this.getPublicContracts();
const privateContracts = this.getPrivateContracts();
let createPublicContractForm = null; let createPublicContractForm = null;
setDocumentTitle(getLangText('Contracts settings')); setDocumentTitle(getLangText('Contracts settings'));
if(publicContracts.length === 0) { if (publicContracts.length === 0) {
createPublicContractForm = ( createPublicContractForm = (
<CreateContractForm <CreateContractForm
isPublic={true} isPublic={true}
@ -97,7 +93,7 @@ let ContractSettings = React.createClass({
singular: 'new contract', singular: 'new contract',
plural: 'new contracts' plural: 'new contracts'
}} }}
location={this.props.location}/> location={location} />
); );
} }
@ -108,7 +104,7 @@ let ContractSettings = React.createClass({
defaultExpanded={true}> defaultExpanded={true}>
<AclProxy <AclProxy
aclName="acl_edit_public_contract" aclName="acl_edit_public_contract"
aclObject={this.state.currentUser.acl}> aclObject={currentUser.acl}>
<div> <div>
{createPublicContractForm} {createPublicContractForm}
{publicContracts.map((contract, i) => { {publicContracts.map((contract, i) => {
@ -120,11 +116,11 @@ let ContractSettings = React.createClass({
buttons={ buttons={
<div className="pull-right"> <div className="pull-right">
<AclProxy <AclProxy
aclObject={this.state.whitelabel} aclObject={whitelabel}
aclName="acl_update_public_contract"> aclName="acl_update_public_contract">
<ContractSettingsUpdateButton <ContractSettingsUpdateButton
contract={contract} contract={contract}
location={this.props.location}/> location={location}/>
</AclProxy> </AclProxy>
<a <a
className="btn btn-default btn-sm margin-left-2px" className="btn btn-default btn-sm margin-left-2px"
@ -147,7 +143,7 @@ let ContractSettings = React.createClass({
</AclProxy> </AclProxy>
<AclProxy <AclProxy
aclName="acl_edit_private_contract" aclName="acl_edit_private_contract"
aclObject={this.state.currentUser.acl}> aclObject={currentUser.acl}>
<div> <div>
<CreateContractForm <CreateContractForm
isPublic={false} isPublic={false}
@ -155,7 +151,7 @@ let ContractSettings = React.createClass({
singular: getLangText('new contract'), singular: getLangText('new contract'),
plural: getLangText('new contracts') plural: getLangText('new contracts')
}} }}
location={this.props.location}/> location={location}/>
{privateContracts.map((contract, i) => { {privateContracts.map((contract, i) => {
return ( return (
<ActionPanel <ActionPanel
@ -165,11 +161,11 @@ let ContractSettings = React.createClass({
buttons={ buttons={
<div className="pull-right"> <div className="pull-right">
<AclProxy <AclProxy
aclObject={this.state.whitelabel} aclObject={whitelabel}
aclName="acl_update_private_contract"> aclName="acl_update_private_contract">
<ContractSettingsUpdateButton <ContractSettingsUpdateButton
contract={contract} contract={contract}
location={this.props.location}/> location={location}/>
</AclProxy> </AclProxy>
<a <a
className="btn btn-default btn-sm margin-left-2px" className="btn btn-default btn-sm margin-left-2px"

View File

@ -2,12 +2,8 @@
import React from 'react'; import React from 'react';
import UserStore from '../../stores/user_store';
import UserActions from '../../actions/user_actions'; import UserActions from '../../actions/user_actions';
import WhitelabelStore from '../../stores/whitelabel_store';
import WhitelabelActions from '../../actions/whitelabel_actions';
import AccountSettings from './account_settings'; import AccountSettings from './account_settings';
import BitcoinWalletSettings from './bitcoin_wallet_settings'; import BitcoinWalletSettings from './bitcoin_wallet_settings';
import APISettings from './api_settings'; import APISettings from './api_settings';
@ -24,56 +20,42 @@ let SettingsContainer = React.createClass({
propTypes: { propTypes: {
children: React.PropTypes.oneOfType([ children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element), React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element]) React.PropTypes.element
]),
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object
}, },
getInitialState() { loadUser(invalidateCache) {
return mergeOptions(
UserStore.getState(),
WhitelabelStore.getState()
);
},
componentDidMount() {
UserStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
UserActions.fetchCurrentUser();
},
componentWillUnmount() {
WhitelabelStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
},
loadUser(invalidateCache){
UserActions.fetchCurrentUser(invalidateCache); UserActions.fetchCurrentUser(invalidateCache);
}, },
onChange(state) {
this.setState(state);
},
render() { render() {
const { currentUser, whitelabel } = this.props;
setDocumentTitle(getLangText('Account settings')); setDocumentTitle(getLangText('Account settings'));
if (this.state.currentUser && this.state.currentUser.username) { if (currentUser && currentUser.username) {
return ( return (
<div className="settings-container"> <div className="settings-container">
<AccountSettings <AccountSettings
currentUser={this.state.currentUser} currentUser={currentUser}
loadUser={this.loadUser} loadUser={this.loadUser}
whitelabel={this.state.whitelabel}/> whitelabel={whitelabel} />
{this.props.children} {this.props.children}
<AclProxy <AclProxy
aclObject={this.state.whitelabel} aclObject={whitelabel}
aclName="acl_view_settings_api"> aclName="acl_view_settings_api">
<APISettings /> <APISettings />
</AclProxy> </AclProxy>
<WebhookSettings /> <WebhookSettings />
<AclProxy <AclProxy
aclObject={this.state.whitelabel} aclObject={whitelabel}
aclName="acl_view_settings_bitcoin"> aclName="acl_view_settings_bitcoin">
<BitcoinWalletSettings /> <BitcoinWalletSettings />
</AclProxy> </AclProxy>

View File

@ -18,6 +18,11 @@ import { setDocumentTitle } from '../utils/dom_utils';
let CoaVerifyContainer = React.createClass({ let CoaVerifyContainer = React.createClass({
propTypes: { propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
@ -60,9 +65,8 @@ let CoaVerifyForm = React.createClass({
}, },
handleSuccess(response){ handleSuccess(response){
let notification = null;
if (response.verdict) { if (response.verdict) {
notification = new GlobalNotificationModel(getLangText('Certificate of Authenticity successfully verified'), 'success'); const notification = new GlobalNotificationModel(getLangText('Certificate of Authenticity successfully verified'), 'success');
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
} }
}, },

View File

@ -7,7 +7,14 @@ import { getLangText } from '../utils/lang_utils';
let ErrorNotFoundPage = React.createClass({ let ErrorNotFoundPage = React.createClass({
propTypes: { propTypes: {
message: React.PropTypes.string message: React.PropTypes.string,
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object
}, },
getDefaultProps() { getDefaultProps() {
@ -32,4 +39,4 @@ let ErrorNotFoundPage = React.createClass({
} }
}); });
export default ErrorNotFoundPage; export default ErrorNotFoundPage;

View File

@ -15,6 +15,12 @@ let LoginContainer = React.createClass({
redirectOnLoggedIn: React.PropTypes.bool, redirectOnLoggedIn: React.PropTypes.bool,
redirectOnLoginSuccess: React.PropTypes.bool, redirectOnLoginSuccess: React.PropTypes.bool,
onLogin: React.PropTypes.func, onLogin: React.PropTypes.func,
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },

View File

@ -12,6 +12,15 @@ import { setDocumentTitle } from '../utils/dom_utils';
let LogoutContainer = React.createClass({ let LogoutContainer = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object
},
mixins: [History], mixins: [History],
componentDidMount() { componentDidMount() {

View File

@ -16,39 +16,43 @@ import { setDocumentTitle } from '../utils/dom_utils';
let PasswordResetContainer = React.createClass({ let PasswordResetContainer = React.createClass({
propTypes: { propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
getInitialState() { getInitialState() {
return {isRequested: false}; return { isRequested: false };
}, },
handleRequestSuccess(email) { handleRequestSuccess(email) {
this.setState({isRequested: email}); this.setState({ isRequested: email });
}, },
render() { render() {
let { location } = this.props; const { email: emailQuery, token: tokenQuery } = this.props.location.query;
const { isRequested } = this.state;
if (location.query.email && location.query.token) { if (emailQuery && tokenQuery) {
return ( return (
<div> <div>
<PasswordResetForm <PasswordResetForm
email={location.query.email} email={emailQuery}
token={location.query.token}/> token={tokenQuery} />
</div> </div>
); );
} } else {
else { if (isRequested === false) {
if (this.state.isRequested === false) {
return ( return (
<div> <div>
<PasswordRequestResetForm <PasswordRequestResetForm
handleRequestSuccess={this.handleRequestSuccess}/> handleRequestSuccess={this.handleRequestSuccess} />
</div> </div>
); );
} } else if (isRequested) {
else if (this.state.isRequested) {
return ( return (
<div> <div>
<div className="ascribe-login-text ascribe-login-header"> <div className="ascribe-login-text ascribe-login-header">
@ -56,12 +60,11 @@ let PasswordResetContainer = React.createClass({
</div> </div>
</div> </div>
); );
} } else {
else {
return <span />; return <span />;
} }
} }
} }
}); });
let PasswordRequestResetForm = React.createClass({ let PasswordRequestResetForm = React.createClass({
@ -70,9 +73,10 @@ let PasswordRequestResetForm = React.createClass({
}, },
handleSuccess() { handleSuccess() {
let notificationText = getLangText('If your email address exists in our database, you will receive a password recovery link in a few minutes.'); const notificationText = getLangText('If your email address exists in our database, you will receive a password recovery link in a few minutes.');
let notification = new GlobalNotificationModel(notificationText, 'success', 50000); const notification = new GlobalNotificationModel(notificationText, 'success', 50000);
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
this.props.handleRequestSuccess(this.refs.form.refs.email.state.value); this.props.handleRequestSuccess(this.refs.form.refs.email.state.value);
}, },
@ -90,12 +94,13 @@ let PasswordRequestResetForm = React.createClass({
type="submit" type="submit"
className="btn btn-default btn-wide"> className="btn btn-default btn-wide">
{getLangText('Reset your password')} {getLangText('Reset your password')}
</button>} </button>
}
spinner={ spinner={
<span className="btn btn-default btn-wide btn-spinner"> <span className="btn btn-default btn-wide btn-spinner">
<AscribeSpinner color="dark-blue" size="md" /> <AscribeSpinner color="dark-blue" size="md" />
</span> </span>
}> }>
<div className="ascribe-form-header"> <div className="ascribe-form-header">
<h3>{getLangText('Reset your password')}</h3> <h3>{getLangText('Reset your password')}</h3>
</div> </div>
@ -131,7 +136,7 @@ let PasswordResetForm = React.createClass({
handleSuccess() { handleSuccess() {
this.history.pushState(null, '/collection'); this.history.pushState(null, '/collection');
let notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000); const notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
}, },
@ -148,12 +153,13 @@ let PasswordResetForm = React.createClass({
type="submit" type="submit"
className="btn btn-default btn-wide"> className="btn btn-default btn-wide">
{getLangText('Reset your password')} {getLangText('Reset your password')}
</button>} </button>
}
spinner={ spinner={
<span className="btn btn-default btn-wide btn-spinner"> <span className="btn btn-default btn-wide btn-spinner">
<AscribeSpinner color="dark-blue" size="md" /> <AscribeSpinner color="dark-blue" size="md" />
</span> </span>
}> }>
<div className="ascribe-form-header"> <div className="ascribe-form-header">
<h3>{getLangText('Reset the password for')} {this.props.email}</h3> <h3>{getLangText('Reset the password for')} {this.props.email}</h3>
</div> </div>

View File

@ -43,6 +43,12 @@ let PieceList = React.createClass({
filterParams: React.PropTypes.array, filterParams: React.PropTypes.array,
orderParams: React.PropTypes.array, orderParams: React.PropTypes.array,
orderBy: React.PropTypes.string, orderBy: React.PropTypes.string,
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
@ -85,7 +91,7 @@ let PieceList = React.createClass({
PieceListStore.listen(this.onChange); PieceListStore.listen(this.onChange);
EditionListStore.listen(this.onChange); EditionListStore.listen(this.onChange);
let page = this.props.location.query.page || 1; const page = this.props.location.query.page || 1;
if (this.props.canLoadPieceList && (this.state.pieceList.length === 0 || this.state.page !== page)) { if (this.props.canLoadPieceList && (this.state.pieceList.length === 0 || this.state.page !== page)) {
this.loadPieceList({ page }); this.loadPieceList({ page });
} }
@ -161,8 +167,8 @@ let PieceList = React.createClass({
}, },
getPagination() { getPagination() {
let currentPage = parseInt(this.props.location.query.page, 10) || 1; const currentPage = parseInt(this.props.location.query.page, 10) || 1;
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize); const totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
if (this.state.pieceListCount > 20) { if (this.state.pieceListCount > 20) {
return ( return (
@ -188,8 +194,7 @@ let PieceList = React.createClass({
}); });
// first we need to apply the filter on the piece list // first we need to apply the filter on the piece list
this this.loadPieceList({ page: 1, filterBy })
.loadPieceList({ page: 1, filterBy })
.then(() => { .then(() => {
// but also, we need to filter all the open edition lists // but also, we need to filter all the open edition lists
this.state.pieceList this.state.pieceList
@ -223,23 +228,22 @@ let PieceList = React.createClass({
}, },
fetchSelectedPieceEditionList() { fetchSelectedPieceEditionList() {
let filteredPieceIdList = Object.keys(this.state.editionList) const filteredPieceIdList = Object.keys(this.state.editionList)
.filter((pieceId) => { .filter((pieceId) => {
return this.state.editionList[pieceId] return this.state.editionList[pieceId]
.filter((edition) => edition.selected).length > 0; .filter((edition) => edition.selected)
}); .length;
});
return filteredPieceIdList; return filteredPieceIdList;
}, },
fetchSelectedEditionList() { fetchSelectedEditionList() {
let selectedEditionList = []; const selectedEditionList = Object.keys(this.state.editionList)
.reduce((selectedList, pieceId) => {
Object const selectedEditionsForPiece = this.state.editionList[pieceId]
.keys(this.state.editionList) .filter((edition) => edition.selected);
.forEach((pieceId) => { return selectedList.concat(selectedEditionsForPiece);
let filteredEditionsForPiece = this.state.editionList[pieceId].filter((edition) => edition.selected); }, []);
selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece);
});
return selectedEditionList; return selectedEditionList;
}, },
@ -250,7 +254,7 @@ let PieceList = React.createClass({
this.fetchSelectedPieceEditionList() this.fetchSelectedPieceEditionList()
.forEach((pieceId) => { .forEach((pieceId) => {
EditionListActions.refreshEditionList({pieceId}); EditionListActions.refreshEditionList({ pieceId });
}); });
EditionListActions.clearAllEditionSelections(); EditionListActions.clearAllEditionSelections();
}, },

View File

@ -12,21 +12,17 @@ import WhitelabelStore from '../stores/whitelabel_store';
import PieceListStore from '../stores/piece_list_store'; import PieceListStore from '../stores/piece_list_store';
import PieceListActions from '../actions/piece_list_actions'; import PieceListActions from '../actions/piece_list_actions';
import UserStore from '../stores/user_store';
import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationModel from '../models/global_notification_model';
import GlobalNotificationActions from '../actions/global_notification_actions'; import GlobalNotificationActions from '../actions/global_notification_actions';
import Property from './ascribe_forms/property'; import Property from './ascribe_forms/property';
import RegisterPieceForm from './ascribe_forms/form_register_piece'; import RegisterPieceForm from './ascribe_forms/form_register_piece';
import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils'; import { getLangText } from '../utils/lang_utils';
import { setDocumentTitle } from '../utils/dom_utils'; import { setDocumentTitle } from '../utils/dom_utils';
let RegisterPiece = React.createClass( { let RegisterPiece = React.createClass( {
propTypes: { propTypes: {
headerMessage: React.PropTypes.string, headerMessage: React.PropTypes.string,
submitMessage: React.PropTypes.string, submitMessage: React.PropTypes.string,
@ -35,30 +31,27 @@ let RegisterPiece = React.createClass( {
React.PropTypes.element, React.PropTypes.element,
React.PropTypes.string React.PropTypes.string
]), ]),
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
mixins: [History], mixins: [History],
getInitialState(){ getInitialState(){
return mergeOptions( return PieceListStore.getState();
UserStore.getState(),
WhitelabelStore.getState(),
PieceListStore.getState()
);
}, },
componentDidMount() { componentDidMount() {
PieceListStore.listen(this.onChange); PieceListStore.listen(this.onChange);
UserStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
WhitelabelActions.fetchWhitelabel();
}, },
componentWillUnmount() { componentWillUnmount() {
PieceListStore.unlisten(this.onChange); PieceListStore.unlisten(this.onChange);
UserStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange);
}, },
onChange(state) { onChange(state) {
@ -66,7 +59,7 @@ let RegisterPiece = React.createClass( {
}, },
handleSuccess(response){ handleSuccess(response){
let notification = new GlobalNotificationModel(response.notification, 'success', 10000); const notification = new GlobalNotificationModel(response.notification, 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification); GlobalNotificationActions.appendGlobalNotification(notification);
// once the user was able to register a piece successfully, we need to make sure to keep // once the user was able to register a piece successfully, we need to make sure to keep
@ -84,7 +77,7 @@ let RegisterPiece = React.createClass( {
}, },
getSpecifyEditions() { getSpecifyEditions() {
if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) { if (this.props.whitelabel && this.props.whitelabel.acl_create_editions || Object.keys(this.props.whitelabel).length === 0) {
return ( return (
<Property <Property
name="num_editions" name="num_editions"

View File

@ -11,6 +11,11 @@ import { setDocumentTitle } from '../utils/dom_utils';
let SignupContainer = React.createClass({ let SignupContainer = React.createClass({
propTypes: { propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
//Provided from router
location: React.PropTypes.object location: React.PropTypes.object
}, },
@ -31,7 +36,7 @@ let SignupContainer = React.createClass({
render() { render() {
setDocumentTitle(getLangText('Sign up')); setDocumentTitle(getLangText('Sign up'));
if (this.state.submitted){ if (this.state.submitted) {
return ( return (
<div className="ascribe-login-wrapper"> <div className="ascribe-login-wrapper">
<br/> <br/>