1
0
mirror of https://github.com/ascribe/onion.git synced 2025-02-14 21:10:27 +01:00

Convert currentUser to be passed down through context and withCurrentUser HOC

Similar to what react-router did with their router and withRouter HOC.
This commit is contained in:
Brett Sun 2016-06-06 18:52:05 +02:00
parent 6b67a8462f
commit d1dba86b1a
57 changed files with 330 additions and 248 deletions

View File

@ -1,5 +1,3 @@
'use strict';
import React from 'react';
import UserActions from '../actions/user_actions';
@ -9,6 +7,7 @@ import WhitelabelActions from '../actions/whitelabel_actions';
import WhitelabelStore from '../stores/whitelabel_store';
import GlobalNotification from './global_notification';
import { currentUserShape } from './prop_types';
import { mergeOptions } from '../utils/general_utils';
@ -23,6 +22,10 @@ export default function AppBase(App) {
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
},
childContextTypes: {
currentUser: currentUserShape
},
getInitialState() {
return mergeOptions(
UserStore.getState(),
@ -30,6 +33,12 @@ export default function AppBase(App) {
);
},
getChildContext() {
const { currentUser } = this.state;
return { currentUser };
},
componentDidMount() {
UserStore.listen(this.onChange);
WhitelabelStore.listen(this.onChange);
@ -49,7 +58,7 @@ export default function AppBase(App) {
render() {
const { routes } = this.props;
const { currentUser, whitelabel } = this.state;
const { whitelabel } = this.state;
// The second element of the routes prop given to us by react-router is always the
// active second-level component object (ie. after App).
@ -60,7 +69,6 @@ export default function AppBase(App) {
<App
{...this.props}
activeRoute={activeRoute}
currentUser={currentUser}
whitelabel={whitelabel} />
<GlobalNotification />
<div id="modal" className="container" />

View File

@ -1,5 +1,3 @@
'use strict';
import React from 'react';
import AppBase from './app_base';
@ -8,34 +6,31 @@ import Footer from './footer';
import Header from './header';
let AscribeApp = React.createClass({
const AscribeApp = React.createClass({
propTypes: {
activeRoute: React.PropTypes.object.isRequired,
children: React.PropTypes.element.isRequired,
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
// Provided from AppBase
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object
},
render() {
const { activeRoute, children, currentUser, routes, whitelabel } = this.props;
const Footer = activeRoute && activeRoute.footer;
const { activeRoute, children, routes, whitelabel } = this.props;
const showFooter = activeRoute && activeRoute.footer;
return (
<div className="ascribe-app ascribe-default-app">
<Header
currentUser={currentUser}
routes={routes}
whitelabel={whitelabel} />
<AppRouteWrapper
currentUser={currentUser}
whitelabel={whitelabel}>
{/* Routes are injected here */}
{children}
</AppRouteWrapper>
{Footer ? <Footer /> : null}
{showFooter ? <Footer /> : null}
</div>
);
}

View File

@ -14,7 +14,6 @@ import { selectFromObject } from '../../utils/general_utils';
let AclButtonList = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
handleSuccess: React.PropTypes.func.isRequired,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
@ -69,13 +68,11 @@ let AclButtonList = React.createClass({
const { availableAcls,
buttonsStyle,
className,
currentUser,
handleSuccess,
pieceOrEditions } = this.props;
const buttonProps = selectFromObject(this.props, [
'availableAcls',
'currentUser',
'handleSuccess',
'pieceOrEditions'
]);

View File

@ -31,7 +31,6 @@ export default function AclButton({ action, displayName, title, tooltip }) {
buttonAcceptName: React.PropTypes.string,
buttonAcceptClassName: React.PropTypes.string,
currentUser: React.PropTypes.object,
email: React.PropTypes.string,
handleSuccess: React.PropTypes.func
},
@ -43,7 +42,6 @@ export default function AclButton({ action, displayName, title, tooltip }) {
render() {
const { availableAcls,
buttonAcceptClassName,
currentUser,
email,
pieceOrEditions,
handleSuccess } = this.props;
@ -63,7 +61,6 @@ export default function AclButton({ action, displayName, title, tooltip }) {
title={title}>
<AclFormFactory
action={action}
currentUser={currentUser}
email={email}
pieceOrEditions={pieceOrEditions}
showNotification />

View File

@ -5,21 +5,26 @@ import React from 'react';
import Button from 'react-bootstrap/lib/Button';
import ModalWrapper from '../ascribe_modal/modal_wrapper';
import UnConsignRequestForm from './../ascribe_forms/form_unconsign_request';
import UnConsignRequestForm from '../ascribe_forms/form_unconsign_request';
import { getLangText } from '../../utils/lang_utils.js';
import { currentUserShape } from '../prop_types';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
import ApiUrls from '../../constants/api_urls';
let UnConsignRequestButton = React.createClass({
const UnConsignRequestButton = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
edition: React.PropTypes.object.isRequired,
handleSuccess: React.PropTypes.func
handleSuccess: React.PropTypes.func,
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
render: function () {
render() {
const { currentUser, edition, handleSuccess } = this.props;
return (
<ModalWrapper
@ -45,5 +50,4 @@ ${currentUser.username}`
}
});
export default UnConsignRequestButton;
export default withCurrentUser(UnConsignRequestButton);

View File

@ -8,8 +8,6 @@ import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import EditionActions from '../../actions/edition_actions';
import DetailProperty from './detail_property';
import EditionActionPanel from './edition_action_panel';
import FurtherDetails from './further_details';
@ -25,18 +23,21 @@ import Property from '../ascribe_forms/property';
import AclProxy from '../acl_proxy';
import { currentUserShape } from '../prop_types';
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
/**
* This is the component that implements display-specific functionality
*/
let Edition = React.createClass({
const Edition = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
currentUser: currentUserShape.isRequired,
edition: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
@ -66,7 +67,6 @@ let Edition = React.createClass({
<Col md={6} className="ascribe-print-col-left">
<MediaContainer
content={edition}
currentUser={currentUser}
refreshObject={loadEdition} />
</Col>
<Col md={6} className="ascribe-edition-details ascribe-print-col-right">
@ -82,7 +82,6 @@ let Edition = React.createClass({
<EditionSummary
actionPanelButtonListType={actionPanelButtonListType}
edition={edition}
currentUser={currentUser}
handleSuccess={loadEdition}
whitelabel={whitelabel} />
<CollapsibleParagraph
@ -122,8 +121,7 @@ let Edition = React.createClass({
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_edition}
currentUser={currentUser} />
url={ApiUrls.note_private_edition} />
<Note
id={() => {return {'bitcoin_id': edition.bitcoin_id}; }}
label={getLangText('Personal note (public)')}
@ -132,8 +130,7 @@ let Edition = React.createClass({
editable={!!edition.acl.acl_edit}
show={!!(edition.public_note || edition.acl.acl_edit)}
successMessage={getLangText('Public edition note saved')}
url={ApiUrls.note_public_edition}
currentUser={currentUser} />
url={ApiUrls.note_public_edition} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Further Details')}
@ -155,9 +152,9 @@ let Edition = React.createClass({
});
let EditionSummary = React.createClass({
let EditionSummary = withCurrentUser(React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
currentUser: currentUserShape.isRequired,
edition: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
@ -206,7 +203,6 @@ let EditionSummary = React.createClass({
className="hidden-print">
<EditionActionPanel
actionPanelButtonListType={actionPanelButtonListType}
currentUser={currentUser}
edition={edition}
handleSuccess={handleSuccess}
whitelabel={whitelabel} />
@ -216,7 +212,7 @@ let EditionSummary = React.createClass({
</div>
);
}
});
}));
let CoaDetails = React.createClass({
@ -354,9 +350,9 @@ let SpoolDetails = React.createClass({
<pre className="ascribe-pre">{ownerAddress}</pre>
</Property>
<hr />
</Form>);
</Form>
);
}
});
export default Edition;
export default withCurrentUser(Edition);

View File

@ -36,7 +36,6 @@ import { getLangText } from '../../utils/lang_utils';
*/
const EditionActionPanel = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
edition: React.PropTypes.object.isRequired,
router: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
@ -101,14 +100,12 @@ const EditionActionPanel = React.createClass({
render() {
const { actionPanelButtonListType: ActionPanelButtonListType,
currentUser,
edition,
whitelabel } = this.props;
if (edition.notifications && edition.notifications.length) {
return (
<ListRequestActions
currentUser={currentUser}
notifications={edition.notifications}
pieceOrEditions={[edition]}
handleSuccess={this.handleSuccess} />);
@ -119,7 +116,6 @@ const EditionActionPanel = React.createClass({
<ActionPanelButtonListType
availableAcls={edition.acl}
className="ascribe-button-list"
currentUser={currentUser}
handleSuccess={this.handleSuccess}
pieceOrEditions={[edition]}
whitelabel={whitelabel}>
@ -169,7 +165,6 @@ const EditionActionPanel = React.createClass({
aclObject={edition.acl}
aclName="acl_request_unconsign">
<UnConsignRequestButton
currentUser={currentUser}
edition={edition}
handleSuccess={this.handleSuccess} />
</AclProxy>

View File

@ -25,7 +25,6 @@ let EditionContainer = React.createClass({
furtherDetailsType: React.PropTypes.func,
// Provided from AscribeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -76,7 +75,7 @@ let EditionContainer = React.createClass({
},
render() {
const { actionPanelButtonListType, currentUser, furtherDetailsType, whitelabel } = this.props;
const { actionPanelButtonListType, furtherDetailsType, whitelabel } = this.props;
const { edition, coaMeta } = this.state;
if (edition.id) {
@ -86,7 +85,6 @@ let EditionContainer = React.createClass({
<Edition
actionPanelButtonListType={actionPanelButtonListType}
coaError={coaMeta.err}
currentUser={currentUser}
edition={edition}
furtherDetailsType={furtherDetailsType}
loadEdition={this.loadEdition}

View File

@ -18,11 +18,13 @@ import AscribeSpinner from '../ascribe_spinner';
import AclProxy from '../acl_proxy';
import { currentUserShape } from '../prop_types';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils';
import { extractFileExtensionFromUrl } from '../../utils/file_utils';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
const EMBED_IFRAME_HEIGHT = {
@ -36,7 +38,8 @@ let MediaContainer = React.createClass({
content: React.PropTypes.object.isRequired,
refreshObject: React.PropTypes.func.isRequired,
currentUser: React.PropTypes.object
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
getInitialState() {
@ -118,7 +121,7 @@ let MediaContainer = React.createClass({
// the information in content will be updated if a user updates their username.
// We also force uniqueness of usernames, so this check is safe to dtermine if the
// content was registered by the current user.
const didUserRegisterContent = currentUser && (currentUser.username === content.user_registered);
const didUserRegisterContent = currentUser.username === content.user_registered;
const thumbnail = content.thumbnail.thumbnail_sizes && content.thumbnail.thumbnail_sizes['600x600'] ? content.thumbnail.thumbnail_sizes['600x600']
: content.thumbnail.url_safe;
@ -181,4 +184,4 @@ let MediaContainer = React.createClass({
}
});
export default MediaContainer;
export default withCurrentUser(MediaContainer);

View File

@ -5,15 +5,18 @@ import React from 'react';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import Form from './../ascribe_forms/form';
import Property from './../ascribe_forms/property';
import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable';
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
import InputTextAreaToggable from '../ascribe_forms/input_textarea_toggable';
import { currentUserShape } from '../prop_types';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
let Note = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
currentUser: currentUserShape.isRequired,
id: React.PropTypes.func.isRequired,
url: React.PropTypes.string.isRequired,
@ -66,4 +69,4 @@ let Note = React.createClass({
}
});
export default Note;
export default withCurrentUser(Note);

View File

@ -18,7 +18,6 @@ let Piece = React.createClass({
piece: React.PropTypes.object.isRequired,
buttons: React.PropTypes.object,
currentUser: React.PropTypes.object,
header: React.PropTypes.object,
subheader: React.PropTypes.object,
children: React.PropTypes.oneOfType([
@ -32,14 +31,13 @@ let Piece = React.createClass({
},
render() {
const { buttons, children, currentUser, header, piece, subheader } = this.props;
const { buttons, children, header, piece, subheader } = this.props;
return (
<Row>
<Col md={6} className="ascribe-print-col-left">
<MediaContainer
content={piece}
currentUser={currentUser}
refreshObject={this.updatePiece} />
</Col>
<Col md={6} className="ascribe-edition-details ascribe-print-col-right">

View File

@ -25,7 +25,7 @@ import LicenseDetail from './license_detail';
import Note from './note';
import Piece from './piece';
import AclButtonList from './../ascribe_buttons/acl_button_list';
import AclButtonList from '../ascribe_buttons/acl_button_list';
import AclInformation from '../ascribe_buttons/acl_information';
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
import DeleteButton from '../ascribe_buttons/delete_button';
@ -36,25 +36,28 @@ import CreateEditionsForm from '../ascribe_forms/create_editions_form';
import ListRequestActions from '../ascribe_forms/list_form_request_actions';
import AclProxy from '../acl_proxy';
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
import { currentUserShape } from '../prop_types';
import ApiUrls from '../../constants/api_urls';
import { setDocumentTitle } from '../../utils/dom_utils';
import { mergeOptions } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils';
import { withCurrentUser } from '../../utils/react_utils';
/**
* This is the component that implements resource/data specific functionality
*/
const PieceContainer = React.createClass({
propTypes: {
currentUser: currentUserShape.isRequired,
router: React.PropTypes.object.isRequired,
furtherDetailsType: React.PropTypes.func,
// Provided from AscribeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
@ -214,7 +217,6 @@ const PieceContainer = React.createClass({
if (piece.notifications && piece.notifications.length > 0) {
return (
<ListRequestActions
currentUser={currentUser}
handleSuccess={this.loadPiece}
notifications={piece.notifications}
pieceOrEditions={piece} />
@ -222,7 +224,7 @@ const PieceContainer = React.createClass({
} else {
return (
<AclProxy
show={currentUser && currentUser.email && Object.keys(piece.acl).length > 1}>
show={currentUser.email && Object.keys(piece.acl).length > 1}>
{/*
`acl_view` is always available in `edition.acl`, therefore if it has
no more than 1 key, we're hiding the `DetailProperty` actions as otherwise
@ -234,7 +236,6 @@ const PieceContainer = React.createClass({
<AclButtonList
availableAcls={piece.acl}
className="ascribe-button-list"
currentUser={currentUser}
pieceOrEditions={piece}
handleSuccess={this.loadPiece}>
<CreateEditionsButton
@ -259,7 +260,7 @@ const PieceContainer = React.createClass({
},
render() {
const { currentUser, furtherDetailsType: FurtherDetailsType } = this.props;
const { furtherDetailsType: FurtherDetailsType } = this.props;
const { piece } = this.state;
if (piece.id) {
@ -268,7 +269,6 @@ const PieceContainer = React.createClass({
return (
<Piece
piece={piece}
currentUser={currentUser}
header={
<div className="ascribe-detail-header">
<hr className="hidden-print" style={{marginTop: 0}} />
@ -307,8 +307,7 @@ const PieceContainer = React.createClass({
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_piece}
currentUser={currentUser} />
url={ApiUrls.note_private_piece} />
<Note
id={this.getId}
label={getLangText('Personal note (public)')}
@ -317,8 +316,7 @@ const PieceContainer = React.createClass({
editable={!!piece.acl.acl_edit}
show={!!(piece.public_note || piece.acl.acl_edit)}
successMessage={getLangText('Public note saved')}
url={ApiUrls.note_public_piece}
currentUser={currentUser} />
url={ApiUrls.note_public_piece} />
</CollapsibleParagraph>
<CollapsibleParagraph
title={getLangText('Further Details')}
@ -346,4 +344,4 @@ const PieceContainer = React.createClass({
}
});
export default withRouter(PieceContainer);
export default withRouter(withCurrentUser(PieceContainer));

View File

@ -2,6 +2,9 @@
import React from 'react';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import ConsignForm from '../ascribe_forms/form_consign';
import UnConsignForm from '../ascribe_forms/form_unconsign';
import TransferForm from '../ascribe_forms/form_transfer';
@ -9,13 +12,13 @@ import LoanForm from '../ascribe_forms/form_loan';
import LoanRequestAnswerForm from '../ascribe_forms/form_loan_request_answer';
import ShareForm from '../ascribe_forms/form_share_email';
import { currentUserShape } from '../prop_types';
import AppConstants from '../../constants/application_constants';
import ApiUrls from '../../constants/api_urls';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import { getAclFormMessage, getAclFormDataId } from '../../utils/form_utils';
import { withCurrentUser } from '../../utils/react_utils';
let AclFormFactory = React.createClass({
propTypes: {
@ -26,12 +29,14 @@ let AclFormFactory = React.createClass({
]).isRequired,
autoFocusProperty: React.PropTypes.string,
currentUser: React.PropTypes.object,
email: React.PropTypes.string,
handleSuccess: React.PropTypes.func,
message: React.PropTypes.string,
labels: React.PropTypes.object,
showNotification: React.PropTypes.bool
message: React.PropTypes.string,
showNotification: React.PropTypes.bool,
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
isPiece() {
@ -54,21 +59,23 @@ let AclFormFactory = React.createClass({
},
render() {
const { action,
autoFocusProperty,
pieceOrEditions,
currentUser,
email,
message,
labels,
handleSuccess,
showNotification } = this.props;
const {
action,
autoFocusProperty,
pieceOrEditions,
email,
message,
labels,
handleSuccess,
showNotification,
currentUser: { username: senderName }
} = this.props;
const formMessage = message || getAclFormMessage({
senderName,
aclName: action,
entities: pieceOrEditions,
isPiece: this.isPiece(),
senderName: currentUser && currentUser.username
isPiece: this.isPiece()
});
if (action === 'acl_consign') {
@ -131,4 +138,4 @@ let AclFormFactory = React.createClass({
}
});
export default AclFormFactory;
export default withCurrentUser(AclFormFactory);

View File

@ -8,14 +8,21 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import Form from './form';
import Property from './property';
import { currentUserShape } from '../prop_types';
import ApiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
let CopyrightAssociationForm = React.createClass({
const { bool } = React.PropTypes;
const CopyrightAssociationForm = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
// Injected through HOCs
currentUser: currentUserShape.isRequired,
},
handleSubmitSuccess() {
@ -77,4 +84,4 @@ let CopyrightAssociationForm = React.createClass({
}
});
export default CopyrightAssociationForm;
export default withCurrentUser(CopyrightAssociationForm);

View File

@ -8,23 +8,22 @@ import InputFineUploader from './input_fineuploader';
import FormSubmitButton from '../ascribe_buttons/form_submit_button';
import { FileStatus } from '../ascribe_uploader/react_s3_fine_uploader_utils';
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
import AscribeSpinner from '../ascribe_spinner';
import { currentUserShape } from '../prop_types';
import ApiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants';
import { validationParts, validationTypes } from '../../constants/uploader_constants';
import { FileStatus, formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
import { getLangText } from '../../utils/lang_utils';
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
import { withCurrentUser } from '../../utils/react_utils';
let RegisterPieceForm = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
headerMessage: React.PropTypes.string,
submitMessage: React.PropTypes.string,
enableLocalHashing: React.PropTypes.bool,
@ -40,7 +39,10 @@ let RegisterPieceForm = React.createClass({
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
])
]),
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
getDefaultProps() {
@ -128,7 +130,7 @@ let RegisterPieceForm = React.createClass({
location,
submitMessage } = this.props;
const profileHashLocally = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false;
const profileHashLocally = currentUser.profile ? currentUser.profile.hash_locally : false;
const hashLocally = profileHashLocally && enableLocalHashing;
return (
@ -238,4 +240,4 @@ let RegisterPieceForm = React.createClass({
}
});
export default RegisterPieceForm;
export default withCurrentUser(RegisterPieceForm);

View File

@ -27,7 +27,6 @@ let RequestActionForm = React.createClass({
React.PropTypes.array
]).isRequired,
currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
@ -99,7 +98,6 @@ let RequestActionForm = React.createClass({
availableAcls={{'acl_unconsign': true}}
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser}
handleSuccess={this.handleSuccess} />
);
} else if (this.props.notifications.action === 'loan_request') {
@ -109,7 +107,6 @@ let RequestActionForm = React.createClass({
buttonAcceptName="LOAN"
buttonAcceptClassName='inline pull-right btn-sm ascribe-margin-1px'
pieceOrEditions={this.props.pieceOrEditions}
currentUser={this.props.currentUser}
handleSuccess={this.handleSuccess} />
);
} else {

View File

@ -21,7 +21,6 @@ let ShareForm = React.createClass({
id: React.PropTypes.object,
message: React.PropTypes.string,
editions: React.PropTypes.array,
currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},

View File

@ -11,19 +11,17 @@ let ListRequestActions = React.createClass({
React.PropTypes.array
]).isRequired,
currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
render () {
const { currentUser, handleSuccess, notifications, pieceOrEditions } = this.props;
const { handleSuccess, notifications, pieceOrEditions } = this.props;
if (notifications.length) {
return (
<div>
{notifications.map((notification) =>
<RequestActionForm
currentUser={currentUser}
handleSuccess={handleSuccess}
notifications={notification}
pieceOrEditions={pieceOrEditions} />

View File

@ -5,8 +5,12 @@ import withRouter from 'react-router/es6/withRouter';
import UserStore from '../../stores/user_store';
import { currentUserShape } from '../prop_types';
import AppConstants from '../../constants/application_constants';
import { withCurrentUser } from '../../utils/react_utils';
const { object } = React.PropTypes;
const WHEN_ENUM = ['loggedIn', 'loggedOut'];
@ -33,7 +37,7 @@ export function AuthRedirect({ to, when }) {
//
// So if when === 'loggedIn', we're checking if the user is logged in (and
// vice versa)
const isLoggedIn = Object.keys(currentUser).length && currentUser.email;
const isLoggedIn = !!currentUser.email;
const exprToValidate = when === 'loggedIn' ? isLoggedIn : !isLoggedIn;
// and redirect if `true`.
@ -75,15 +79,17 @@ export function AuthRedirect({ to, when }) {
* @param {[function]} redirectFn A function that conditionally redirects
*/
export function ProxyHandler(...redirectFunctions) {
return (Component) => (
withRouter(React.createClass({
return (Component) => {
const ProxyHandlerComponent = React.createClass({
displayName: 'ProxyHandler',
propTypes: {
router: React.PropTypes.object.isRequired,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from AscribeApp, after the routes have been initialized
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
@ -130,6 +136,8 @@ export function ProxyHandler(...redirectFunctions) {
<Component {...this.props} />
);
}
})
));
});
return withRouter(withCurrentUser(ProxyHandlerComponent));
};
}

View File

@ -5,25 +5,29 @@ import React from 'react';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import CopyrightAssociationForm from '../ascribe_forms/form_copyright_association';
import Form from '../ascribe_forms/form';
import Property from '../ascribe_forms/property';
import InputCheckbox from '../ascribe_forms/input_checkbox';
import Property from '../ascribe_forms/property';
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
import AclProxy from '../acl_proxy';
import CopyrightAssociationForm from '../ascribe_forms/form_copyright_association';
import AscribeSpinner from '../ascribe_spinner';
import { currentUserShape } from '../prop_types';
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
let AccountSettings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
loadUser: React.PropTypes.func.isRequired,
whitelabel: React.PropTypes.object.isRequired
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
handleSuccess() {
@ -100,7 +104,7 @@ let AccountSettings = React.createClass({
<AclProxy
aclObject={whitelabel}
aclName="acl_view_settings_copyright_association">
<CopyrightAssociationForm currentUser={currentUser} />
<CopyrightAssociationForm />
</AclProxy>
{profile}
</CollapsibleParagraph>
@ -108,4 +112,4 @@ let AccountSettings = React.createClass({
}
});
export default AccountSettings;
export default withCurrentUser(AccountSettings);

View File

@ -2,29 +2,34 @@
import React from 'react';
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
import CreateContractForm from '../ascribe_forms/form_create_contract';
import ContractListStore from '../../stores/contract_list_store';
import ContractListActions from '../../actions/contract_list_actions';
import ActionPanel from '../ascribe_panel/action_panel';
import ContractSettingsUpdateButton from './contract_settings_update_button';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
import AclProxy from '../acl_proxy';
import ContractSettingsUpdateButton from './contract_settings_update_button';
import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
import CreateContractForm from '../ascribe_forms/form_create_contract';
import ActionPanel from '../ascribe_panel/action_panel';
import AclProxy from '../acl_proxy';
import { currentUserShape } from '../prop_types';
import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils';
import { truncateTextAtCharIndex } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
let ContractSettings = React.createClass({
propTypes: {
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from AscribeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -72,7 +77,7 @@ let ContractSettings = React.createClass({
},
render() {
const { currentUser, location, whitelabel } = this.props;
const { currentUser, whitelabel } = this.props;
const publicContracts = this.getPublicContracts();
const privateContracts = this.getPrivateContracts();
let createPublicContractForm = null;

View File

@ -5,26 +5,28 @@ import React from 'react';
import UserActions from '../../actions/user_actions';
import AccountSettings from './account_settings';
import ApiSettings from './api_settings';
import BitcoinWalletSettings from './bitcoin_wallet_settings';
import APISettings from './api_settings';
import WebhookSettings from './webhook_settings';
import AclProxy from '../acl_proxy';
import { currentUserShape } from '../prop_types';
import { mergeOptions } from '../../utils/general_utils';
import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils';
import { getLangText } from '../../utils/lang_utils';
import { withCurrentUser } from '../../utils/react_utils';
let SettingsContainer = React.createClass({
propTypes: {
currentUser: currentUserShape.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
]),
// Provided from AscribeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -44,14 +46,13 @@ let SettingsContainer = React.createClass({
return (
<div className="settings-container">
<AccountSettings
currentUser={currentUser}
loadUser={this.loadUser}
whitelabel={whitelabel} />
{children}
<AclProxy
aclObject={whitelabel}
aclName="acl_view_settings_api">
<APISettings />
<ApiSettings />
</AclProxy>
<WebhookSettings />
<AclProxy
@ -66,4 +67,4 @@ let SettingsContainer = React.createClass({
}
});
export default SettingsContainer;
export default withCurrentUser(SettingsContainer);

View File

@ -19,7 +19,6 @@ import { setDocumentTitle } from '../utils/dom_utils';
let CoaVerifyContainer = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -11,24 +11,26 @@ import NavItem from 'react-bootstrap/lib/NavItem';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import EventActions from '../actions/event_actions';
import PieceListStore from '../stores/piece_list_store';
import AclProxy from './acl_proxy';
import HeaderNotifications from './header_notifications';
import HeaderNotificationDebug from './header_notification_debug';
import NavRoutesLinks from './nav_routes_links';
import { currentUserShape } from './prop_types';
import { getLangText } from '../utils/lang_utils';
import { constructHead } from '../utils/dom_utils';
import { getLangText } from '../utils/lang_utils';
import { withCurrentUser } from '../utils/react_utils';
let Header = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
whitelabel: React.PropTypes.object.isRequired
whitelabel: React.PropTypes.object.isRequired,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
},
getInitialState() {
@ -39,7 +41,6 @@ let Header = React.createClass({
// Listen to the piece list store, but don't fetch immediately to avoid
// conflicts with routes that may need to wait to load the piece list
PieceListStore.listen(this.onChange);
},
componentWillUnmount() {
@ -205,7 +206,7 @@ let Header = React.createClass({
{account}
{signup}
</Nav>
<HeaderNotifications currentUser={currentUser} />
<HeaderNotifications />
{navRoutesLinks}
</Navbar.Collapse>
</Navbar>
@ -217,4 +218,4 @@ let Header = React.createClass({
}
});
export default Header;
export default withCurrentUser(Header);

View File

@ -10,12 +10,16 @@ import Nav from 'react-bootstrap/lib/Nav';
import NotificationActions from '../actions/notification_actions';
import NotificationStore from '../stores/notification_store';
import { currentUserShape } from './prop_types';
import { getLangText } from '../utils/lang_utils';
import { withCurrentUser } from '../utils/react_utils';
let HeaderNotifications = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
},
getInitialState() {
@ -153,4 +157,4 @@ let NotificationListItem = React.createClass({
}
});
export default HeaderNotifications;
export default withCurrentUser(HeaderNotifications);

View File

@ -12,7 +12,6 @@ import { setDocumentTitle } from '../utils/dom_utils';
let LoginContainer = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -17,7 +17,6 @@ import { setDocumentTitle } from '../utils/dom_utils';
let PasswordResetContainer = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -48,7 +48,6 @@ const PieceList = React.createClass({
orderBy: React.PropTypes.string,
// Provided from AscribeApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -277,7 +276,6 @@ const PieceList = React.createClass({
render() {
const { accordionListItemType: AccordionListItemType,
bulkModalButtonListType: BulkModalButtonListType,
currentUser,
customSubmitButton,
customThumbnailPlaceholder,
filterParams,
@ -311,7 +309,6 @@ const PieceList = React.createClass({
className="ascribe-piece-list-bulk-modal">
<BulkModalButtonListType
availableAcls={availableAcls}
currentUser={currentUser}
handleSuccess={this.handleAclSuccess}
pieceOrEditions={selectedEditions}
whitelabel={whitelabel}
@ -342,7 +339,6 @@ const PieceList = React.createClass({
key={piece.id}
className="col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 ascribe-accordion-list-item"
content={piece}
currentUser={currentUser}
thumbnailPlaceholder={customThumbnailPlaceholder}
whitelabel={whitelabel}>
<AccordionListItemTableEditions

View File

@ -0,0 +1,12 @@
import React from 'react';
const { number, object, shape, string } = React.PropTypes;
export default shape({
acl: object,
email: string,
id: number,
profile: object,
username: string
});

View File

@ -0,0 +1 @@
export { default as currentUserShape } from './current_user_shape';

View File

@ -30,7 +30,6 @@ const RegisterPiece = React.createClass( {
]),
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router

View File

@ -10,7 +10,6 @@ import { setDocumentTitle } from '../utils/dom_utils';
let SignupContainer = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -14,7 +14,6 @@ let Vivi23Landing = React.createClass({
customThumbnailPlaceholder: React.PropTypes.func,
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router

View File

@ -9,7 +9,6 @@ import MarketPieceList from '../market/market_piece_list';
let Vivi23PieceList = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -12,7 +12,6 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let ArtcityLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired
},

View File

@ -7,17 +7,21 @@ import AclButtonList from '../../../../ascribe_buttons/acl_button_list';
import DeleteButton from '../../../../ascribe_buttons/delete_button';
import AclProxy from '../../../../acl_proxy';
import { currentUserShape } from '../../../../prop_types';
import { mergeOptions } from '../../../../../utils/general_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let WalletActionPanel = React.createClass({
propTypes: {
piece: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
handleDeleteSuccess: React.PropTypes.func.isRequired,
loadPiece: React.PropTypes.func.isRequired,
submitButtonType: React.PropTypes.func.isRequired
piece: React.PropTypes.object.isRequired,
submitButtonType: React.PropTypes.func.isRequired,
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
render() {
@ -27,7 +31,6 @@ let WalletActionPanel = React.createClass({
return (
<ListRequestActions
pieceOrEditions={piece}
currentUser={currentUser}
handleSuccess={loadPiece}
notifications={piece.notifications}/>);
} else {
@ -46,7 +49,6 @@ let WalletActionPanel = React.createClass({
<AclButtonList
availableAcls={availableAcls}
className="text-center ascribe-button-list"
currentUser={currentUser}
pieceOrEditions={piece}
handleSuccess={loadPiece}>
<AclProxy
@ -69,4 +71,4 @@ let WalletActionPanel = React.createClass({
}
});
export default WalletActionPanel;
export default withCurrentUser(WalletActionPanel);

View File

@ -13,16 +13,18 @@ import Note from '../../../../ascribe_detail/note';
import Piece from '../../../../../components/ascribe_detail/piece';
import AscribeSpinner from '../../../../ascribe_spinner';
import { currentUserShape } from '../../../../prop_types';
import ApiUrls from '../../../../../constants/api_urls';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let WalletPieceContainer = React.createClass({
propTypes: {
piece: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
currentUser: currentUserShape.isRequired,
handleDeleteSuccess: React.PropTypes.func.isRequired,
loadPiece: React.PropTypes.func.isRequired,
submitButtonType: React.PropTypes.func.isRequired,
@ -45,7 +47,6 @@ let WalletPieceContainer = React.createClass({
return (
<Piece
piece={piece}
currentUser={currentUser}
header={
<div className="ascribe-detail-header">
<hr style={{marginTop: 0}}/>
@ -64,7 +65,6 @@ let WalletPieceContainer = React.createClass({
}>
<WalletActionPanel
piece={piece}
currentUser={currentUser}
loadPiece={loadPiece}
handleDeleteSuccess={handleDeleteSuccess}
submitButtonType={submitButtonType}/>
@ -84,8 +84,7 @@ let WalletPieceContainer = React.createClass({
placeholder={getLangText('Enter your comments ...')}
editable={true}
successMessage={getLangText('Private note saved')}
url={ApiUrls.note_private_piece}
currentUser={currentUser}/>
url={ApiUrls.note_private_piece} />
</CollapsibleParagraph>
{children}
</Piece>
@ -101,4 +100,4 @@ let WalletPieceContainer = React.createClass({
}
});
export default WalletPieceContainer;
export default withCurrentUser(WalletPieceContainer);

View File

@ -14,7 +14,6 @@ import { mergeOptions } from '../../../../../utils/general_utils';
let CCRegisterPiece = React.createClass({
propTypes: {
// Provided from AscribeApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router

View File

@ -32,7 +32,6 @@ const CylandPieceContainer = React.createClass({
router: React.PropTypes.object.isRequired,
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
@ -95,15 +94,12 @@ const CylandPieceContainer = React.createClass({
const { piece } = this.state;
if (piece.id) {
const { currentUser } = this.props;
setDocumentTitle(`${piece.artist_name}, ${piece.title}`);
return (
<WalletPieceContainer
{...this.props}
piece={this.state.piece}
currentUser={currentUser}
loadPiece={this.loadPiece}
handleDeleteSuccess={this.handleDeleteSuccess}
submitButtonType={CylandSubmitButton}>

View File

@ -5,13 +5,18 @@ import PieceList from '../../../../piece_list';
import CylandAccordionListItem from './cyland_accordion_list/cyland_accordion_list_item';
import { getLangText } from '../../../../../utils/lang_utils';
import { currentUserShape } from '../../../../prop_types';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let CylandPieceList = React.createClass({
propTypes: {
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -19,12 +24,14 @@ let CylandPieceList = React.createClass({
},
shouldRedirect(pieceCount) {
const { currentUser: { email: userEmail },
whitelabel: {
user: whitelabelAdminEmail
} } = this.props;
const {
currentUser: { email: userEmail },
whitelabel: {
user: whitelabelAdminEmail
}
} = this.props;
return userEmail !== whitelabelAdminEmail && !pieceCount;
return userEmail !== whitelabelAdminEmail && !pieceCount;
},
render() {
@ -52,4 +59,4 @@ let CylandPieceList = React.createClass({
}
});
export default CylandPieceList;
export default withCurrentUser(CylandPieceList);

View File

@ -24,20 +24,25 @@ import RegisterPieceForm from '../../../../ascribe_forms/form_register_piece';
import SlidesContainer from '../../../../ascribe_slides_container/slides_container';
import { currentUserShape } from '../../../../prop_types';
import ApiUrls from '../../../../../constants/api_urls';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { mergeOptions } from '../../../../../utils/general_utils';
import { getAclFormMessage } from '../../../../../utils/form_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../utils/general_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
const CylandRegisterPiece = React.createClass({
propTypes: {
router: React.PropTypes.object.isRequired,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -218,4 +223,4 @@ const CylandRegisterPiece = React.createClass({
}
});
export default withRouter(CylandRegisterPiece);
export default withRouter(withCurrentUser(CylandRegisterPiece));

View File

@ -15,7 +15,6 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let DemoLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired
},

View File

@ -14,21 +14,25 @@ import IkonotvSubmitButton from '../ikonotv_buttons/ikonotv_submit_button';
import AccordionListItemPiece from '../../../../../ascribe_accordion_list/accordion_list_item_piece';
import AclProxy from '../../../../../acl_proxy';
import { currentUserShape } from '../../../../../prop_types';
import { getLangText } from '../../../../../../utils/lang_utils';
import { mergeOptions } from '../../../../../../utils/general_utils';
import { withCurrentUser } from '../../../../../../utils/react_utils';
let IkonotvAccordionListItem = React.createClass({
propTypes: {
content: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
]),
className: React.PropTypes.string
className: React.PropTypes.string,
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
getInitialState() {
@ -116,4 +120,4 @@ let IkonotvAccordionListItem = React.createClass({
}
});
export default IkonotvAccordionListItem;
export default withCurrentUser(IkonotvAccordionListItem);

View File

@ -15,18 +15,23 @@ import OwnershipFetcher from '../../../../../fetchers/ownership_fetcher';
import CopyrightAssociationForm from '../../../../ascribe_forms/form_copyright_association';
import Property from '../../../../ascribe_forms/property';
import { currentUserShape } from '../../../../../prop_types';
import AppConstants from '../../../../../constants/application_constants';
import { getLangText } from '../../../../../utils/lang_utils';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../../utils/react_utils';
const IkonotvContractNotifications = React.createClass({
propTypes: {
router: React.PropTypes.object.isRequired,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -130,10 +135,10 @@ const IkonotvContractNotifications = React.createClass({
this.props.router.push('/collection');
},
getCopyrightAssociationForm(){
const { currentUser } = this.props;
getCopyrightAssociationForm() {
const { profile } = this.props.currentUser;
if (currentUser.profile && !currentUser.profile.copyright_association) {
if (profile && !profile.copyright_association) {
return (
<div className='notification-contract-footer'>
<h1>{getLangText('Are you a member of any copyright societies?')}</h1>
@ -141,7 +146,7 @@ const IkonotvContractNotifications = React.createClass({
<p>
{AppConstants.copyrightAssociations.join(', ')}
</p>
<CopyrightAssociationForm currentUser={currentUser}/>
<CopyrightAssociationForm />
</div>
);
} else {
@ -198,4 +203,4 @@ const IkonotvContractNotifications = React.createClass({
}
});
export default withRouter(IkonotvContractNotifications);
export default withRouter(withCurrentUser(IkonotvContractNotifications));

View File

@ -33,7 +33,6 @@ const IkonotvPieceContainer = React.createClass({
router: React.PropTypes.object.isRequired,
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object,
// Provided from router
@ -93,7 +92,6 @@ const IkonotvPieceContainer = React.createClass({
},
render() {
const { currentUser } = this.props;
const { piece } = this.state;
let furtherDetails = (
@ -127,7 +125,6 @@ const IkonotvPieceContainer = React.createClass({
return (
<WalletPieceContainer
piece={piece}
currentUser={currentUser}
loadPiece={this.loadPiece}
handleDeleteSuccess={this.handleDeleteSuccess}
submitButtonType={IkonotvSubmitButton}>

View File

@ -6,14 +6,17 @@ import Button from 'react-bootstrap/lib/Button';
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
import { getLangText } from '../../../../../utils/lang_utils';
import { currentUserShape } from '../../../../prop_types';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let IkonotvLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
currentUser: currentUserShape.isRequired,
whitelabel: React.PropTypes.object,
// Provided from router
@ -101,4 +104,4 @@ let IkonotvLanding = React.createClass({
}
});
export default IkonotvLanding;
export default withCurrentUser(IkonotvLanding);

View File

@ -8,14 +8,19 @@ import NotificationStore from '../../../../../stores/notification_store';
import IkonotvAccordionListItem from './ikonotv_accordion_list/ikonotv_accordion_list_item';
import { currentUserShape } from '../../../../prop_types';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let IkonotvPieceList = React.createClass({
propTypes: {
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -39,10 +44,12 @@ let IkonotvPieceList = React.createClass({
},
shouldRedirect(pieceCount) {
const { currentUser: { email: userEmail },
whitelabel: {
user: whitelabelAdminEmail
} } = this.props;
const {
currentUser: { email: userEmail },
whitelabel: {
user: whitelabelAdminEmail
}
} = this.props;
const { contractAgreementListNotifications } = this.state;
return contractAgreementListNotifications &&
@ -84,4 +91,4 @@ let IkonotvPieceList = React.createClass({
}
});
export default IkonotvPieceList;
export default withCurrentUser(IkonotvPieceList);

View File

@ -22,10 +22,13 @@ import LoanForm from '../../../../ascribe_forms/form_loan';
import SlidesContainer from '../../../../ascribe_slides_container/slides_container';
import { currentUserShape } from '../../../../prop_types';
import ApiUrls from '../../../../../constants/api_urls';
import { mergeOptions } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
const IkonotvRegisterPiece = React.createClass({
@ -34,8 +37,10 @@ const IkonotvRegisterPiece = React.createClass({
handleSuccess: React.PropTypes.func,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -243,4 +248,4 @@ const IkonotvRegisterPiece = React.createClass({
}
});
export default withRouter(IkonotvRegisterPiece);
export default withRouter(withCurrentUser(IkonotvRegisterPiece));

View File

@ -12,7 +12,6 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let LumenusLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router

View File

@ -14,7 +14,6 @@ import { selectFromObject } from '../../../../../../utils/general_utils';
let MarketAclButtonList = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
handleSuccess: React.PropTypes.func.isRequired,
pieceOrEditions: React.PropTypes.array.isRequired,
whitelabel: React.PropTypes.object.isRequired,
@ -30,14 +29,12 @@ let MarketAclButtonList = React.createClass({
const { availableAcls,
children,
className,
currentUser,
handleSuccess,
pieceOrEditions,
whitelabel } = this.props;
const buttonProps = selectFromObject(this.props, [
'availableAcls',
'currentUser',
'handleSuccess',
'pieceOrEditions'
]);
@ -46,7 +43,6 @@ let MarketAclButtonList = React.createClass({
<div className={className}>
<MarketSubmitButton
availableAcls={availableAcls}
currentUser={currentUser}
editions={pieceOrEditions}
handleSuccess={handleSuccess}
whitelabel={whitelabel} />

View File

@ -10,26 +10,27 @@ import MarketAdditionalDataForm from '../market_forms/market_additional_data_for
import MarketErrorConsignUnavailable from '../market_error_consign_unavailable';
import AclFormFactory from '../../../../../ascribe_forms/acl_form_factory';
import ConsignForm from '../../../../../ascribe_forms/form_consign';
import ModalWrapper from '../../../../../ascribe_modal/modal_wrapper';
import AclProxy from '../../../../../acl_proxy';
import ApiUrls from '../../../../../../constants/api_urls';
import { currentUserShape } from '../../../../../prop_types';
import { getAclFormMessage, getAclFormDataId } from '../../../../../../utils/form_utils';
import { getLangText } from '../../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../../utils/react_utils';
let MarketSubmitButton = React.createClass({
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
currentUser: React.PropTypes.object.isRequired,
editions: React.PropTypes.array.isRequired,
whitelabel: React.PropTypes.object.isRequired,
className: React.PropTypes.string,
handleSuccess: React.PropTypes.func
handleSuccess: React.PropTypes.func,
// Injected through HOCs
currentUser: currentUserShape.isRequired // eslint-disable-line react/sort-prop-types
},
canEditionBeSubmitted(edition) {
@ -184,4 +185,4 @@ let MarketSubmitButton = React.createClass({
}
});
export default MarketSubmitButton;
export default withCurrentUser(MarketSubmitButton);

View File

@ -15,13 +15,12 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let MarketLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired
},
componentDidUpdate() {
const { name } = this.props.whitelabel;
if (name) {
setDocumentTitle(`${name} Marketplace`);
}

View File

@ -5,17 +5,20 @@ import React from 'react';
import MarketAclButtonList from './market_buttons/market_acl_button_list';
import PieceList from '../../../../piece_list';
import { currentUserShape } from '../../../../prop_types';
import { setDocumentTitle } from '../../../../../utils/dom_utils';
import { mergeOptions } from '../../../../../utils/general_utils';
import { getLangText } from '../../../../../utils/lang_utils';
import { withCurrentUser } from '../../../../../utils/react_utils';
let MarketPieceList = React.createClass({
propTypes: {
customThumbnailPlaceholder: React.PropTypes.func,
// Injected through HOCs
currentUser: currentUserShape.isRequired, // eslint-disable-line react/sort-prop-types
// Provided from WalletApp
currentUser: React.PropTypes.object.isRequired,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router
@ -27,11 +30,13 @@ let MarketPieceList = React.createClass({
},
render() {
const { currentUser: { email: userEmail },
whitelabel: {
name: whitelabelName = 'Market',
user: whitelabelAdminEmail
} } = this.props;
const {
currentUser: { email: userEmail },
whitelabel: {
name: whitelabelName = 'Market',
user: whitelabelAdminEmail
}
} = this.props;
let filterParams = null;
let isUserAdmin = null;
@ -68,4 +73,4 @@ let MarketPieceList = React.createClass({
}
});
export default MarketPieceList;
export default withCurrentUser(MarketPieceList);

View File

@ -26,7 +26,6 @@ let MarketRegisterPiece = React.createClass({
router: React.PropTypes.object.isRequired,
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired,
// Provided from router

View File

@ -15,7 +15,6 @@ import { setDocumentTitle } from '../../../../../utils/dom_utils';
let PollineLanding = React.createClass({
propTypes: {
// Provided from WalletApp
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object.isRequired
},

View File

@ -17,12 +17,11 @@ let WalletApp = React.createClass({
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
// Provided from AppBase
currentUser: React.PropTypes.object,
whitelabel: React.PropTypes.object
},
render() {
const { activeRoute, children, currentUser, router, routes, whitelabel } = this.props;
const { activeRoute, children, router, routes, whitelabel } = this.props;
const subdomain = getSubdomain();
const path = activeRoute && activeRoute.path;
const Footer = activeRoute && activeRoute.footer;
@ -35,7 +34,6 @@ let WalletApp = React.createClass({
} else {
header = (
<Header
currentUser={currentUser}
routes={routes}
whitelabel={whitelabel} />
);
@ -47,7 +45,6 @@ let WalletApp = React.createClass({
<div className={classNames('ascribe-app', 'ascribe-wallet-app', `route--${(path ? path.split('/')[0] : 'landing')}`)}>
{header}
<AppRouteWrapper
currentUser={currentUser}
whitelabel={whitelabel}>
{/* Routes are injected here */}
{children}

33
js/utils/react_utils.js Normal file
View File

@ -0,0 +1,33 @@
import React from 'react';
import { currentUserShape } from '../components/prop_types';
/**
* Taken from react-router (https://github.com/reactjs/react-router/blob/master/modules/withRouter.js)
* FIXME: should be put into react-component's utils
*/
export function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
/**
* Similar to react-router's `withRouter`, this injects the `currentUser` from the Component's
* context into the Component as a prop.
*
* @param {Component} Component Component to inject `context.currentUser` into
* @return {Component} Wrapped component
*/
export function withCurrentUser(Component) {
const contextTypes = {
currentUser: currentUserShape.isRequired
};
const WithCurrentUser = (props, { currentUser }) => (
<Component {...props} currentUser={currentUser} />
);
WithCurrentUser.displayName = `WithCurrentUser(${getDisplayName(Component)})`;
WithCurrentUser.contextTypes = contextTypes;
return WithCurrentUser;
}