diff --git a/js/actions/event_actions.js b/js/actions/event_actions.js
index 6d8ee12f..24889f4e 100644
--- a/js/actions/event_actions.js
+++ b/js/actions/event_actions.js
@@ -8,9 +8,8 @@ class EventActions {
this.generateActions(
'applicationWillBoot',
'applicationDidBoot',
- 'profileDidLoad',
- //'userDidLogin',
- //'userDidLogout',
+ 'userDidAuthenticate',
+ 'userDidLogout',
'routeDidChange'
);
}
diff --git a/js/actions/user_actions.js b/js/actions/user_actions.js
index a661b8de..9d59044f 100644
--- a/js/actions/user_actions.js
+++ b/js/actions/user_actions.js
@@ -1,6 +1,6 @@
'use strict';
-import { altUser } from '../alt';
+import { alt } from '../alt';
class UserActions {
@@ -15,4 +15,4 @@ class UserActions {
}
}
-export default altUser.createActions(UserActions);
+export default alt.createActions(UserActions);
diff --git a/js/alt.js b/js/alt.js
index 141248c1..3e1d3fae 100644
--- a/js/alt.js
+++ b/js/alt.js
@@ -4,5 +4,4 @@ import Alt from 'alt';
export let alt = new Alt();
export let altThirdParty = new Alt();
-export let altUser = new Alt();
export let altWhitelabel = new Alt();
diff --git a/js/components/app_base.js b/js/components/app_base.js
index c188e628..3d14fae5 100644
--- a/js/components/app_base.js
+++ b/js/components/app_base.js
@@ -4,10 +4,18 @@ import React from 'react';
import classNames from 'classnames';
import { History } from 'react-router';
+import UserActions from '../actions/user_actions';
+import UserStore from '../stores/user_store';
+
+import WhitelabelActions from '../actions/whitelabel_actions';
+import WhitelabelStore from '../stores/whitelabel_store';
+
import GlobalNotification from './global_notification';
import AppConstants from '../constants/application_constants';
+import { mergeOptions } from '../utils/general_utils';
+
export default function AppBase(App) {
return React.createClass({
@@ -20,9 +28,22 @@ export default function AppBase(App) {
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
},
+ getInitialState() {
+ return mergeOptions(
+ UserStore.getState(),
+ WhitelabelStore.getState()
+ );
+ },
+
mixins: [History],
componentDidMount() {
+ UserStore.listen(this.onChange);
+ WhitelabelStore.listen(this.onChange);
+
+ UserActions.fetchCurrentUser();
+ WhitelabelActions.fetchWhitelabel();
+
this.history.locationQueue.push(this.props.location);
},
@@ -36,8 +57,18 @@ export default function AppBase(App) {
}
},
+ componentWillUnmount() {
+ UserStore.unlisten(this.onChange);
+ WhitelabelActions.unlisten(this.onChange);
+ },
+
+ onChange(state) {
+ this.setState(state);
+ },
+
render() {
const { routes } = this.props;
+ const { currentUser, 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).
@@ -47,7 +78,9 @@ export default function AppBase(App) {
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_piece.js b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
index 9f876388..3a21c2ea 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_piece.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_piece.js
@@ -34,11 +34,10 @@ let AccordionListItemPiece = React.createClass({
},
getLinkData() {
- let { piece } = this.props;
+ const { piece } = this.props;
- if(piece && piece.first_edition) {
+ if (piece && piece.first_edition) {
return `/editions/${piece.first_edition.bitcoin_id}`;
-
} else {
return `/pieces/${piece.id}`;
}
diff --git a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
index f6712d37..e752451e 100644
--- a/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
+++ b/js/components/ascribe_accordion_list/accordion_list_item_wallet.js
@@ -7,20 +7,19 @@ import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
-import AccordionListItemPiece from './accordion_list_item_piece';
-import AccordionListItemEditionWidget from './accordion_list_item_edition_widget';
-import CreateEditionsForm from '../ascribe_forms/create_editions_form';
-
-import PieceListActions from '../../actions/piece_list_actions';
-import PieceListStore from '../../stores/piece_list_store';
-
-import WhitelabelStore from '../../stores/whitelabel_store';
-
import EditionListActions from '../../actions/edition_list_actions';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
+import PieceListActions from '../../actions/piece_list_actions';
+import PieceListStore from '../../stores/piece_list_store';
+
+import AccordionListItemPiece from './accordion_list_item_piece';
+import AccordionListItemEditionWidget from './accordion_list_item_edition_widget';
+import CreateEditionsForm from '../ascribe_forms/create_editions_form';
+
+
import AclProxy from '../acl_proxy';
import { getLangText } from '../../utils/lang_utils';
@@ -29,50 +28,51 @@ import { mergeOptions } from '../../utils/general_utils';
let AccordionListItemWallet = React.createClass({
propTypes: {
- className: React.PropTypes.string,
- content: React.PropTypes.object,
- thumbnailPlaceholder: React.PropTypes.func,
+ content: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object.isRequired,
+
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
- ])
+ ]),
+ className: React.PropTypes.string,
+ thumbnailPlaceholder: React.PropTypes.func
},
getInitialState() {
return mergeOptions(
+ PieceListStore.getState(),
{
showCreateEditionsDialog: false
- },
- PieceListStore.getState(),
- WhitelabelStore.getState()
+ }
);
},
componentDidMount() {
PieceListStore.listen(this.onChange);
- WhitelabelStore.listen(this.onChange);
},
componentWillUnmount() {
PieceListStore.unlisten(this.onChange);
- WhitelabelStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
- getGlyphicon(){
- if ((this.props.content.notifications && this.props.content.notifications.length > 0)){
+ getGlyphicon() {
+ if (this.props.content.notifications && this.props.content.notifications.length) {
return (
{getLangText('You have actions pending')}}>
-
- );
+
+
+ );
+ } else {
+ return null;
}
- return null;
},
toggleCreateEditionsDialog() {
@@ -93,7 +93,7 @@ let AccordionListItemWallet = React.createClass({
PieceListActions.fetchPieceList({ page, pageSize, search, orderBy, orderAsc, filterBy });
EditionListActions.toggleEditionList(pieceId);
- const notification = new GlobalNotificationModel('Editions successfully created', 'success', 10000);
+ const notification = new GlobalNotificationModel(getLangText('Editions successfully created'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
@@ -111,13 +111,15 @@ let AccordionListItemWallet = React.createClass({
},
getLicences() {
+ const { content, whitelabel } = this.props;
+
// convert this to acl_view_licences later
- if (this.state.whitelabel && this.state.whitelabel.name === 'Creative Commons France') {
+ if (whitelabel.name === 'Creative Commons France') {
return (
,
-
- {getLangText('%s license', this.props.content.license_type.code)}
+
+ {getLangText('%s license', content.license_type.code)}
);
diff --git a/js/components/ascribe_app.js b/js/components/ascribe_app.js
index 737a35f5..87ab1daf 100644
--- a/js/components/ascribe_app.js
+++ b/js/components/ascribe_app.js
@@ -3,6 +3,7 @@
import React from 'react';
import AppBase from './app_base';
+import AppRouteWrapper from './app_route_wrapper';
import Footer from './footer';
import Header from './header';
@@ -11,19 +12,28 @@ let AscribeApp = React.createClass({
propTypes: {
activeRoute: React.PropTypes.object.isRequired,
children: React.PropTypes.element.isRequired,
- routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
+ routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
+
+ // Provided from AppBase
+ currentUser: React.PropTypes.object,
+ whitelabel: React.PropTypes.object
},
render() {
- const { activeRoute, children, routes } = this.props;
+ const { activeRoute, children, currentUser, routes, whitelabel } = this.props;
return (
-
-
-
+
+
+
{/* Routes are injected here */}
{children}
-
+
);
diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js
index 35e42c20..d059e0f2 100644
--- a/js/components/ascribe_buttons/acl_button_list.js
+++ b/js/components/ascribe_buttons/acl_button_list.js
@@ -2,9 +2,6 @@
import React from 'react/addons';
-import UserActions from '../../actions/user_actions';
-import UserStore from '../../stores/user_store';
-
import ConsignButton from './acls/consign_button';
import EmailButton from './acls/email_button';
import LoanButton from './acls/loan_button';
@@ -12,50 +9,44 @@ import LoanRequestButton from './acls/loan_request_button';
import TransferButton from './acls/transfer_button';
import UnconsignButton from './acls/unconsign_button';
-import { mergeOptions } from '../../utils/general_utils';
+import { selectFromObject } from '../../utils/general_utils';
let AclButtonList = React.createClass({
propTypes: {
- className: React.PropTypes.string,
+ availableAcls: React.PropTypes.object.isRequired,
+ currentUser: React.PropTypes.object.isRequired,
+ handleSuccess: React.PropTypes.func.isRequired,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
- availableAcls: React.PropTypes.object.isRequired,
+
buttonsStyle: React.PropTypes.object,
- handleSuccess: React.PropTypes.func.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
- ])
+ ]),
+ className: React.PropTypes.string
},
getInitialState() {
- return mergeOptions(
- UserStore.getState(),
- {
- buttonListSize: 0
- }
- );
+ return {
+ buttonListSize: 0
+ }
},
componentDidMount() {
- UserStore.listen(this.onChange);
- UserActions.fetchCurrentUser.defer();
-
window.addEventListener('resize', this.handleResize);
window.dispatchEvent(new Event('resize'));
},
componentDidUpdate(prevProps) {
- if(prevProps.availableAcls && prevProps.availableAcls !== this.props.availableAcls) {
+ if (prevProps.availableAcls && prevProps.availableAcls !== this.props.availableAcls) {
window.dispatchEvent(new Event('resize'));
}
},
componentWillUnmount() {
- UserStore.unlisten(this.onChange);
-
window.removeEventListener('resize', this.handleResize);
},
@@ -65,10 +56,6 @@ let AclButtonList = React.createClass({
});
},
- onChange(state) {
- this.setState(state);
- },
-
renderChildren() {
const { children } = this.props;
const { buttonListSize } = this.state;
@@ -79,42 +66,29 @@ let AclButtonList = React.createClass({
},
render() {
- const { className,
- buttonsStyle,
- availableAcls,
- pieceOrEditions,
- handleSuccess } = this.props;
+ const {
+ availableAcls,
+ buttonsStyle,
+ className,
+ currentUser,
+ handleSuccess,
+ pieceOrEditions } = this.props;
- const { currentUser } = this.state;
+ const buttonProps = selectFromObject(this.props, [
+ 'availableAcls',
+ 'currentUser',
+ 'handleSuccess',
+ 'pieceOrEditions'
+ ]);
return (
-
-
-
-
-
+
+
+
+
+
{this.renderChildren()}
diff --git a/js/components/ascribe_buttons/acls/acl_button.js b/js/components/ascribe_buttons/acls/acl_button.js
index 2525c52a..d40a779a 100644
--- a/js/components/ascribe_buttons/acls/acl_button.js
+++ b/js/components/ascribe_buttons/acls/acl_button.js
@@ -24,23 +24,20 @@ export default function AclButton({ action, displayName, title, tooltip }) {
propTypes: {
availableAcls: React.PropTypes.object.isRequired,
- buttonAcceptName: React.PropTypes.string,
- buttonAcceptClassName: React.PropTypes.string,
- currentUser: React.PropTypes.object,
- email: React.PropTypes.string,
pieceOrEditions: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]).isRequired,
- handleSuccess: React.PropTypes.func.isRequired,
- className: React.PropTypes.string
+
+ buttonAcceptName: React.PropTypes.string,
+ buttonAcceptClassName: React.PropTypes.string,
+ currentUser: React.PropTypes.object,
+ email: React.PropTypes.string,
+ handleSuccess: React.PropTypes.func
},
sanitizeAction() {
- if (this.props.buttonAcceptName) {
- return this.props.buttonAcceptName;
- }
- return AclInformationText.titles[action];
+ return this.props.buttonAcceptName || AclInformationText.titles[action];
},
render() {
diff --git a/js/components/ascribe_buttons/unconsign_request_button.js b/js/components/ascribe_buttons/unconsign_request_button.js
index e5e1c661..c324ff28 100644
--- a/js/components/ascribe_buttons/unconsign_request_button.js
+++ b/js/components/ascribe_buttons/unconsign_request_button.js
@@ -15,10 +15,12 @@ let UnConsignRequestButton = React.createClass({
propTypes: {
currentUser: React.PropTypes.object.isRequired,
edition: React.PropTypes.object.isRequired,
- handleSuccess: React.PropTypes.func.isRequired
+
+ handleSuccess: React.PropTypes.func
},
render: function () {
+ const { currentUser, edition, handleSuccess } = this.props;
return (
}
- handleSuccess={this.props.handleSuccess}
+ handleSuccess={handleSuccess}
title='Request to Un-Consign'>
+${currentUser.username}`
+ } />
);
}
diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js
index df9d41a0..f2110e10 100644
--- a/js/components/ascribe_detail/edition.js
+++ b/js/components/ascribe_detail/edition.js
@@ -8,23 +8,23 @@ import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
-import HistoryIterator from './history_iterator';
+import EditionActions from '../../actions/edition_actions';
-import MediaContainer from './media_container';
-
-import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
-
-import Form from './../ascribe_forms/form';
-import Property from './../ascribe_forms/property';
import DetailProperty from './detail_property';
-import LicenseDetail from './license_detail';
-import FurtherDetails from './further_details';
-
import EditionActionPanel from './edition_action_panel';
-import AclProxy from '../acl_proxy';
-
+import FurtherDetails from './further_details';
+import HistoryIterator from './history_iterator';
+import LicenseDetail from './license_detail';
+import MediaContainer from './media_container';
import Note from './note';
+import CollapsibleParagraph from '../ascribe_collapsible/collapsible_paragraph';
+
+import Form from '../ascribe_forms/form';
+import Property from '../ascribe_forms/property';
+
+import AclProxy from '../acl_proxy';
+
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
@@ -36,11 +36,13 @@ import { getLangText } from '../../utils/lang_utils';
*/
let Edition = React.createClass({
propTypes: {
+ currentUser: React.PropTypes.object.isRequired,
+ edition: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object.isRequired,
+
actionPanelButtonListType: React.PropTypes.func,
- furtherDetailsType: React.PropTypes.func,
- edition: React.PropTypes.object,
coaError: React.PropTypes.object,
- currentUser: React.PropTypes.object,
+ furtherDetailsType: React.PropTypes.func,
loadEdition: React.PropTypes.func
},
@@ -57,56 +59,56 @@ let Edition = React.createClass({
currentUser,
edition,
furtherDetailsType: FurtherDetailsType,
- loadEdition } = this.props;
+ loadEdition,
+ whitelabel } = this.props;
return (
+ currentUser={currentUser}
+ refreshObject={loadEdition} />
-
+
{edition.title}
-
+
+ handleSuccess={loadEdition}
+ whitelabel={whitelabel} />
+ editionId={edition.bitcoin_id} />
0}>
-
+ show={edition.ownership_history && edition.ownership_history.length}>
+
0}>
-
+
0}>
-
+
+ currentUser={currentUser} />
{return {'bitcoin_id': edition.bitcoin_id}; }}
label={getLangText('Personal note (public)')}
@@ -130,13 +132,11 @@ let Edition = React.createClass({
show={!!edition.public_note || !!edition.acl.acl_edit}
successMessage={getLangText('Public edition note saved')}
url={ApiUrls.note_public_edition}
- currentUser={currentUser}/>
+ currentUser={currentUser} />
0 ||
- edition.other_data.length > 0}>
+ show={edition.acl.acl_edit || Object.keys(edition.extra_data).length || edition.other_data.length}>
-
-
+
+
@@ -158,60 +156,56 @@ let Edition = React.createClass({
let EditionSummary = React.createClass({
propTypes: {
+ currentUser: React.PropTypes.object.isRequired,
+ edition: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object.isRequired,
+
actionPanelButtonListType: React.PropTypes.func,
- edition: React.PropTypes.object,
- currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
- handleSuccess() {
- this.props.handleSuccess();
- },
+ getStatus() {
+ const { status } = this.props.edition;
- getStatus(){
- let status = null;
- if (this.props.edition.status.length > 0){
- let statusStr = this.props.edition.status.join(', ').replace(/_/g, ' ');
- status =
;
- if (this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer){
- status = (
-
- );
- }
- }
- return status;
+ return status.length ? (
+
+ ) : null;
},
render() {
- let { actionPanelButtonListType, edition, currentUser } = this.props;
+ const { actionPanelButtonListType, currentUser, edition, handleSuccess, whitelabel } = this.props;
+
return (
+ value={edition.edition_number + ' ' + getLangText('of') + ' ' + edition.num_editions} />
-
+ value={edition.owner} />
+
{this.getStatus()}
{/*
`acl_view` is always available in `edition.acl`, therefore if it has
no more than 1 key, we're hiding the `DetailProperty` actions as otherwise
`AclInformation` would show up
*/}
- 1}>
+ 1}>
+ edition={edition}
+ handleSuccess={handleSuccess}
+ whitelabel={whitelabel} />
@@ -360,4 +354,5 @@ let SpoolDetails = React.createClass({
}
});
+
export default Edition;
diff --git a/js/components/ascribe_detail/edition_action_panel.js b/js/components/ascribe_detail/edition_action_panel.js
index 71bf38fe..dd5c117b 100644
--- a/js/components/ascribe_detail/edition_action_panel.js
+++ b/js/components/ascribe_detail/edition_action_panel.js
@@ -36,9 +36,11 @@ import { getLangText } from '../../utils/lang_utils';
*/
let EditionActionPanel = React.createClass({
propTypes: {
+ currentUser: React.PropTypes.object.isRequired,
+ edition: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object.isRequired,
+
actionPanelButtonListType: React.PropTypes.func,
- edition: React.PropTypes.object,
- currentUser: React.PropTypes.object,
handleSuccess: React.PropTypes.func
},
@@ -87,39 +89,42 @@ let EditionActionPanel = React.createClass({
handleSuccess(response) {
this.refreshCollection();
- this.props.handleSuccess();
- if (response){
- let notification = new GlobalNotificationModel(response.notification, 'success');
+
+ if (response) {
+ const notification = new GlobalNotificationModel(response.notification, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
}
+
+ if (typeof this.props.handleSuccess === 'function') {
+ this.props.handleSuccess();
+ }
},
render() {
const {
actionPanelButtonListType: ActionPanelButtonListType,
+ currentUser,
edition,
- currentUser } = this.props;
+ whitelabel } = this.props;
- if (edition &&
- edition.notifications &&
- edition.notifications.length > 0){
+ if (edition.notifications && edition.notifications.length) {
return (
);
- }
-
- else {
+ notifications={edition.notifications}
+ pieceOrEditions={[edition]}
+ handleSuccess={this.handleSuccess} />);
+ } else {
return (
+ whitelabel={whitelabel}>
diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js
index d0adadf0..77ebed48 100644
--- a/js/components/ascribe_detail/edition_container.js
+++ b/js/components/ascribe_detail/edition_container.js
@@ -9,16 +9,12 @@ import { ResourceNotFoundError } from '../../models/errors';
import EditionActions from '../../actions/edition_actions';
import EditionStore from '../../stores/edition_store';
-import UserActions from '../../actions/user_actions';
-import UserStore from '../../stores/user_store';
-
import Edition from './edition';
import AscribeSpinner from '../ascribe_spinner';
import { getLangText } from '../../utils/lang_utils';
import { setDocumentTitle } from '../../utils/dom_utils';
-import { mergeOptions } from '../../utils/general_utils';
/**
@@ -28,24 +24,26 @@ let EditionContainer = React.createClass({
propTypes: {
actionPanelButtonListType: React.PropTypes.func,
furtherDetailsType: React.PropTypes.func,
+
+ // Provided from AscribeApp
+ currentUser: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object.isRequired,
+
+ // Provided from router
+ location: React.PropTypes.object,
params: React.PropTypes.object
},
mixins: [History, ReactError],
getInitialState() {
- return mergeOptions(
- EditionStore.getInitialState(),
- UserStore.getState()
- );
+ return EditionStore.getInitialState();
},
componentDidMount() {
EditionStore.listen(this.onChange);
- UserStore.listen(this.onChange);
this.loadEdition();
- UserActions.fetchCurrentUser();
},
// This is done to update the container when the user clicks on the prev or next
@@ -68,19 +66,10 @@ let EditionContainer = React.createClass({
componentWillUnmount() {
window.clearInterval(this.state.timerId);
EditionStore.unlisten(this.onChange);
- UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
-
- if(state && state.edition && state.edition.digital_work) {
- let isEncoding = state.edition.digital_work.isEncoding;
- if (state.edition.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
- let timerId = window.setInterval(() => EditionActions.fetchEdition(this.props.params.editionId), 10000);
- this.setState({timerId: timerId});
- }
- }
},
loadEdition(editionId = this.props.params.editionId) {
@@ -88,8 +77,8 @@ let EditionContainer = React.createClass({
},
render() {
- const { edition, currentUser, coaMeta } = this.state;
- const { actionPanelButtonListType, furtherDetailsType } = this.props;
+ const { actionPanelButtonListType, currentUser, furtherDetailsType, whitelabel } = this.props;
+ const { edition, coaMeta } = this.state;
if (edition.id) {
setDocumentTitle(`${edition.artist_name}, ${edition.title}`);
@@ -97,11 +86,12 @@ let EditionContainer = React.createClass({
return (
+ edition={edition}
+ furtherDetailsType={furtherDetailsType}
+ loadEdition={this.loadEdition}
+ whitelabel={whitelabel} />
);
} else {
return (
diff --git a/js/components/ascribe_detail/media_container.js b/js/components/ascribe_detail/media_container.js
index 00ca9164..1e9ba0a1 100644
--- a/js/components/ascribe_detail/media_container.js
+++ b/js/components/ascribe_detail/media_container.js
@@ -22,12 +22,14 @@ const EMBED_IFRAME_HEIGHT = {
video: 315,
audio: 62
};
+const ENCODE_UPDATE_TIME = 5000;
let MediaContainer = React.createClass({
propTypes: {
- content: React.PropTypes.object,
- currentUser: React.PropTypes.object,
- refreshObject: React.PropTypes.func
+ content: React.PropTypes.object.isRequired,
+ refreshObject: React.PropTypes.func.isRequired,
+
+ currentUser: React.PropTypes.object
},
getInitialState() {
@@ -37,14 +39,16 @@ let MediaContainer = React.createClass({
},
componentDidMount() {
- if (!this.props.content.digital_work) {
- return;
- }
+ const { content: { digital_work: digitalWork }, refreshObject } = this.props;
- const isEncoding = this.props.content.digital_work.isEncoding;
- if (this.props.content.digital_work.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
- let timerId = window.setInterval(this.props.refreshObject, 10000);
- this.setState({timerId: timerId});
+ if (digitalWork) {
+ const isEncoding = digitalWork.isEncoding;
+
+ if (digitalWork.mime === 'video' && typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
+ this.setState({
+ timerId: window.setInterval(refreshObject, ENCODE_UPDATE_TIME)
+ });
+ }
}
},
@@ -105,7 +109,7 @@ let MediaContainer = React.createClass({
{''}
- }/>
+ } />
);
}
return (
@@ -136,7 +140,7 @@ let MediaContainer = React.createClass({
If it turns out that `fileExtension` is an empty string, we're just
using the label 'file'.
*/}
- {getLangText('Download')} .{fileExtension || 'file'}
+ {getLangText('Download')} .{fileExtension || 'file'}
{embed}
diff --git a/js/components/ascribe_detail/note.js b/js/components/ascribe_detail/note.js
index c739b937..693a0400 100644
--- a/js/components/ascribe_detail/note.js
+++ b/js/components/ascribe_detail/note.js
@@ -2,64 +2,68 @@
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 GlobalNotificationModel from '../../models/global_notification_model';
-import GlobalNotificationActions from '../../actions/global_notification_actions';
-
import { getLangText } from '../../utils/lang_utils';
let Note = React.createClass({
propTypes: {
- url: React.PropTypes.string,
- id: React.PropTypes.func,
- label: React.PropTypes.string,
- currentUser: React.PropTypes.object,
+ currentUser: React.PropTypes.object.isRequired,
+ id: React.PropTypes.func.isRequired,
+ url: React.PropTypes.string.isRequired,
+
defaultValue: React.PropTypes.string,
editable: React.PropTypes.bool,
- show: React.PropTypes.bool,
+ label: React.PropTypes.string,
placeholder: React.PropTypes.string,
+ show: React.PropTypes.bool,
successMessage: React.PropTypes.string
},
getDefaultProps() {
return {
editable: true,
- show: true,
placeholder: getLangText('Enter a note'),
+ show: true,
successMessage: getLangText('Note saved')
};
},
- showNotification(){
- let notification = new GlobalNotificationModel(this.props.successMessage, 'success');
+ showNotification() {
+ const notification = new GlobalNotificationModel(this.props.successMessage, 'success');
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
- if ((!!this.props.currentUser.username && this.props.editable || !this.props.editable ) && this.props.show) {
+ const { currentUser, defaultValue, editable, id, label, placeholder, show, url } = this.props;
+
+ if ((!!currentUser.username && editable || !editable ) && show) {
return (
);
+ } else {
+ return null;
}
- return null;
}
});
-export default Note;
\ No newline at end of file
+export default Note;
diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js
index e4ff4ea7..9864cf95 100644
--- a/js/components/ascribe_detail/piece.js
+++ b/js/components/ascribe_detail/piece.js
@@ -15,19 +15,19 @@ import MediaContainer from './media_container';
*/
let Piece = React.createClass({
propTypes: {
- piece: React.PropTypes.object,
+ piece: React.PropTypes.object.isRequired,
+
+ buttons: React.PropTypes.object,
currentUser: React.PropTypes.object,
header: React.PropTypes.object,
subheader: React.PropTypes.object,
- buttons: React.PropTypes.object,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
])
},
-
- updateObject() {
+ updatePiece() {
return PieceActions.fetchPiece(this.props.piece.id);
},
@@ -40,7 +40,7 @@ let Piece = React.createClass({
+ refreshObject={this.updatePiece} />
{header}
diff --git a/js/components/ascribe_detail/piece_container.js b/js/components/ascribe_detail/piece_container.js
index 8ee3111f..0f9df8f6 100644
--- a/js/components/ascribe_detail/piece_container.js
+++ b/js/components/ascribe_detail/piece_container.js
@@ -7,39 +7,35 @@ import Moment from 'moment';
import ReactError from '../../mixins/react_error';
import { ResourceNotFoundError } from '../../models/errors';
+import EditionListActions from '../../actions/edition_list_actions';
+
+import GlobalNotificationModel from '../../models/global_notification_model';
+import GlobalNotificationActions from '../../actions/global_notification_actions';
+
import PieceActions from '../../actions/piece_actions';
import PieceStore from '../../stores/piece_store';
import PieceListActions from '../../actions/piece_list_actions';
import PieceListStore from '../../stores/piece_list_store';
-import UserActions from '../../actions/user_actions';
-import UserStore from '../../stores/user_store';
-
-import EditionListActions from '../../actions/edition_list_actions';
-
-import Piece from './piece';
-import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
import FurtherDetails from './further_details';
-
import DetailProperty from './detail_property';
-import LicenseDetail from './license_detail';
import HistoryIterator from './history_iterator';
+import LicenseDetail from './license_detail';
+import Note from './note';
+import Piece from './piece';
import AclButtonList from './../ascribe_buttons/acl_button_list';
-import CreateEditionsForm from '../ascribe_forms/create_editions_form';
+import AclInformation from '../ascribe_buttons/acl_information';
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
import DeleteButton from '../ascribe_buttons/delete_button';
-import AclInformation from '../ascribe_buttons/acl_information';
-import AclProxy from '../acl_proxy';
+import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
+import CreateEditionsForm from '../ascribe_forms/create_editions_form';
import ListRequestActions from '../ascribe_forms/list_form_request_actions';
-import GlobalNotificationModel from '../../models/global_notification_model';
-import GlobalNotificationActions from '../../actions/global_notification_actions';
-
-import Note from './note';
+import AclProxy from '../acl_proxy';
import ApiUrls from '../../constants/api_urls';
import AscribeSpinner from '../ascribe_spinner';
@@ -54,6 +50,13 @@ import { setDocumentTitle } from '../../utils/dom_utils';
let PieceContainer = React.createClass({
propTypes: {
furtherDetailsType: React.PropTypes.func,
+
+ // Provided from AscribeApp
+ currentUser: React.PropTypes.object.isRequired,
+ whitelabel: React.PropTypes.object,
+
+ // Provided from router
+ location: React.PropTypes.object,
params: React.PropTypes.object
},
@@ -67,7 +70,6 @@ let PieceContainer = React.createClass({
getInitialState() {
return mergeOptions(
- UserStore.getState(),
PieceListStore.getState(),
PieceStore.getInitialState(),
{
@@ -77,12 +79,10 @@ let PieceContainer = React.createClass({
},
componentDidMount() {
- UserStore.listen(this.onChange);
PieceListStore.listen(this.onChange);
PieceStore.listen(this.onChange);
this.loadPiece();
- UserActions.fetchCurrentUser();
},
// This is done to update the container when the user clicks on the prev or next
@@ -105,7 +105,6 @@ let PieceContainer = React.createClass({
componentWillUnmount() {
PieceStore.unlisten(this.onChange);
- UserStore.unlisten(this.onChange);
PieceListStore.unlisten(this.onChange);
},
@@ -207,15 +206,17 @@ let PieceContainer = React.createClass({
},
getActions() {
- const { piece, currentUser } = this.state;
+ const { piece } = this.state;
+ const { currentUser } = this.props;
if (piece.notifications && piece.notifications.length > 0) {
return (
);
+ notifications={piece.notifications}
+ pieceOrEditions={piece} />
+ );
} else {
return (
);
} else if (action === 'acl_loan_request') {
@@ -122,7 +123,7 @@ let AclFormFactory = React.createClass({
message={formMessage}
id={this.getFormDataId()}
url={this.isPiece() ? ApiUrls.ownership_shares_pieces
- : ApiUrls.ownership_shares_editions}
+ : ApiUrls.ownership_shares_editions}
handleSuccess={showNotification ? this.showSuccessNotification : handleSuccess} />
);
} else {
diff --git a/js/components/ascribe_forms/form_copyright_association.js b/js/components/ascribe_forms/form_copyright_association.js
index 124a980a..f9b68f48 100644
--- a/js/components/ascribe_forms/form_copyright_association.js
+++ b/js/components/ascribe_forms/form_copyright_association.js
@@ -15,30 +15,30 @@ import { getLangText } from '../../utils/lang_utils';
let CopyrightAssociationForm = React.createClass({
propTypes: {
- currentUser: React.PropTypes.object
+ currentUser: React.PropTypes.object.isRequired
},
- handleSubmitSuccess(){
- let notification = getLangText('Copyright association updated');
- notification = new GlobalNotificationModel(notification, 'success', 10000);
+ handleSubmitSuccess() {
+ const notification = new GlobalNotificationModel(getLangText('Copyright association updated'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
- getProfileFormData(){
- return {email: this.props.currentUser.email};
+ getProfileFormData() {
+ return { email: this.props.currentUser.email };
},
render() {
- let selectedState;
- let selectDefaultValue = ' -- ' + getLangText('select an association') + ' -- ';
+ const { currentUser } = this.props;
+ const selectDefaultValue = ' -- ' + getLangText('select an association') + ' -- ';
- if (this.props.currentUser && this.props.currentUser.profile
- && this.props.currentUser.profile.copyright_association) {
- selectedState = AppConstants.copyrightAssociations.indexOf(this.props.currentUser.profile.copyright_association);
- selectedState = selectedState !== -1 ? AppConstants.copyrightAssociations[selectedState] : selectDefaultValue;
+ let selectedState = selectDefaultValue;
+ if (currentUser.profile && currentUser.profile.copyright_association) {
+ if (AppConstants.copyrightAssociations.indexOf(currentUser.profile.copyright_association) !== -1) {
+ selectedState = AppConstants.copyrightAssociations[selectedState];
+ }
}
- if (this.props.currentUser && this.props.currentUser.email){
+ if (currentUser.email) {
return (
);
+ } else {
+ return null;
}
- return null;
}
});
diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js
index a604850d..67069cac 100644
--- a/js/components/ascribe_forms/form_login.js
+++ b/js/components/ascribe_forms/form_login.js
@@ -6,7 +6,6 @@ import { History } from 'react-router';
import GlobalNotificationModel from '../../models/global_notification_model';
import GlobalNotificationActions from '../../actions/global_notification_actions';
-import UserStore from '../../stores/user_store';
import UserActions from '../../actions/user_actions';
import Form from './form';
@@ -23,8 +22,6 @@ let LoginForm = React.createClass({
propTypes: {
headerMessage: React.PropTypes.string,
submitMessage: React.PropTypes.string,
- redirectOnLoggedIn: React.PropTypes.bool,
- redirectOnLoginSuccess: React.PropTypes.bool,
location: React.PropTypes.object
},
@@ -32,40 +29,26 @@ let LoginForm = React.createClass({
getDefaultProps() {
return {
- headerMessage: getLangText('Enter ascribe'),
- submitMessage: getLangText('Log in'),
- redirectOnLoggedIn: true,
- redirectOnLoginSuccess: true
+ headerMessage: getLangText('Enter') + ' ascribe',
+ submitMessage: getLangText('Log in')
};
},
- getInitialState() {
- return UserStore.getState();
- },
-
- componentDidMount() {
- UserStore.listen(this.onChange);
- },
-
- componentWillUnmount() {
- UserStore.unlisten(this.onChange);
- },
-
- onChange(state) {
- this.setState(state);
- },
-
- handleSuccess({ success }){
- let notification = new GlobalNotificationModel('Login successful', 'success', 10000);
+ handleSuccess({ success }) {
+ const notification = new GlobalNotificationModel(getLangText('Login successful'), 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
- if(success) {
+ if (success) {
UserActions.fetchCurrentUser(true);
}
},
render() {
- let email = this.props.location.query.email || null;
+ const {
+ headerMessage,
+ location: { query: { email: emailQuery } },
+ submitMessage } = this.props;
+
return (