mirror of
https://github.com/ascribe/onion.git
synced 2024-11-15 01:25:17 +01:00
Merge remote-tracking branch 'origin/master' into AD-1080-restyle-webapp-with-new-corporate-identity
Conflicts: js/components/ascribe_accordion_list/accordion_list_item_piece.js js/components/ascribe_app.js js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js js/components/logout_container.js js/components/whitelabel/wallet/wallet_app.js
This commit is contained in:
commit
f0d8e32ecf
@ -5,6 +5,7 @@ import Q from 'q';
|
|||||||
|
|
||||||
import PieceListFetcher from '../fetchers/piece_list_fetcher';
|
import PieceListFetcher from '../fetchers/piece_list_fetcher';
|
||||||
|
|
||||||
|
|
||||||
class PieceListActions {
|
class PieceListActions {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.generateActions(
|
this.generateActions(
|
||||||
@ -21,17 +22,16 @@ class PieceListActions {
|
|||||||
this.actions.updatePieceList({
|
this.actions.updatePieceList({
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
search,
|
|
||||||
orderBy,
|
orderBy,
|
||||||
orderAsc,
|
orderAsc,
|
||||||
filterBy,
|
filterBy,
|
||||||
|
search: '',
|
||||||
pieceList: [],
|
pieceList: [],
|
||||||
pieceListCount: -1,
|
pieceListCount: -1,
|
||||||
unfilteredPieceListCount: -1
|
unfilteredPieceListCount: -1
|
||||||
});
|
});
|
||||||
|
|
||||||
// afterwards, we can load the list
|
// afterwards, we can load the list
|
||||||
|
|
||||||
return Q.Promise((resolve, reject) => {
|
return Q.Promise((resolve, reject) => {
|
||||||
PieceListFetcher
|
PieceListFetcher
|
||||||
.fetch(page, pageSize, search, orderBy, orderAsc, filterBy)
|
.fetch(page, pageSize, search, orderBy, orderAsc, filterBy)
|
||||||
|
@ -13,7 +13,7 @@ class UserActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchCurrentUser() {
|
fetchCurrentUser() {
|
||||||
return UserFetcher.fetchOne()
|
UserFetcher.fetchOne()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.actions.updateCurrentUser(res.users[0]);
|
this.actions.updateCurrentUser(res.users[0]);
|
||||||
})
|
})
|
||||||
@ -24,7 +24,7 @@ class UserActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logoutCurrentUser() {
|
logoutCurrentUser() {
|
||||||
return UserFetcher.logout()
|
UserFetcher.logout()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.actions.deleteCurrentUser();
|
this.actions.deleteCurrentUser();
|
||||||
})
|
})
|
||||||
|
32
js/app.js
32
js/app.js
@ -3,7 +3,8 @@
|
|||||||
require('babel/polyfill');
|
require('babel/polyfill');
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Router, Redirect } from 'react-router';
|
||||||
|
import history from './history';
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import fetch from 'isomorphic-fetch';
|
import fetch from 'isomorphic-fetch';
|
||||||
@ -46,7 +47,6 @@ requests.defaults({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
class AppGateway {
|
class AppGateway {
|
||||||
start() {
|
start() {
|
||||||
let settings;
|
let settings;
|
||||||
@ -68,22 +68,36 @@ class AppGateway {
|
|||||||
load(settings) {
|
load(settings) {
|
||||||
let type = 'default';
|
let type = 'default';
|
||||||
let subdomain = 'www';
|
let subdomain = 'www';
|
||||||
|
let redirectRoute = (<Redirect from="/" to="/collection" />);
|
||||||
|
|
||||||
if (settings) {
|
if (settings) {
|
||||||
type = settings.type;
|
type = settings.type;
|
||||||
subdomain = settings.subdomain;
|
subdomain = settings.subdomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// www and cc do not have a landing page
|
||||||
|
if(subdomain && subdomain !== 'cc') {
|
||||||
|
redirectRoute = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a client specific class to the body for whitelabel styling
|
||||||
window.document.body.classList.add('client--' + subdomain);
|
window.document.body.classList.add('client--' + subdomain);
|
||||||
|
|
||||||
|
// Send the applicationWillBoot event to the third-party stores
|
||||||
EventActions.applicationWillBoot(settings);
|
EventActions.applicationWillBoot(settings);
|
||||||
window.appRouter = Router.run(getRoutes(type, subdomain), Router.HistoryLocation, (App) => {
|
|
||||||
React.render(
|
// `history.listen` is called on every route change, which is perfect for
|
||||||
<App />,
|
// us in that case.
|
||||||
document.getElementById('main')
|
history.listen(EventActions.routeDidChange);
|
||||||
);
|
|
||||||
EventActions.routeDidChange();
|
React.render((
|
||||||
});
|
<Router history={history}>
|
||||||
|
{redirectRoute}
|
||||||
|
{getRoutes(type, subdomain)}
|
||||||
|
</Router>
|
||||||
|
), document.getElementById('main'));
|
||||||
|
|
||||||
|
// Send the applicationDidBoot event to the third-party stores
|
||||||
EventActions.applicationDidBoot(settings);
|
EventActions.applicationDidBoot(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,21 +9,49 @@ let AccordionList = React.createClass({
|
|||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
children: React.PropTypes.arrayOf(React.PropTypes.element).isRequired,
|
children: React.PropTypes.arrayOf(React.PropTypes.element).isRequired,
|
||||||
loadingElement: React.PropTypes.element,
|
loadingElement: React.PropTypes.element,
|
||||||
count: React.PropTypes.number
|
count: React.PropTypes.number,
|
||||||
|
itemList: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
|
search: React.PropTypes.string,
|
||||||
|
searchFor: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSearch() {
|
||||||
|
this.props.searchFor('');
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { search } = this.props;
|
||||||
|
|
||||||
if(this.props.itemList && this.props.itemList.length > 0) {
|
if(this.props.itemList && this.props.itemList.length > 0) {
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className}>
|
<div className={this.props.className}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if(this.props.count === 0) {
|
} else if(this.props.count === 0 && !search) {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-accordion-list-placeholder">
|
<div className="ascribe-accordion-list-placeholder">
|
||||||
<p className="text-center">{getLangText('We could not find any works related to you...')}</p>
|
<p className="text-center">
|
||||||
<p className="text-center">{getLangText('To register one, click')} <a href="register_piece">{getLangText('here')}</a>!</p>
|
{getLangText('We could not find any works related to you...')}
|
||||||
|
</p>
|
||||||
|
<p className="text-center">
|
||||||
|
{getLangText('To register one, click')}
|
||||||
|
<a href="register_piece">{getLangText('here')}</a>!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if(this.props.count === 0 && search) {
|
||||||
|
return (
|
||||||
|
<div className="ascribe-accordion-list-placeholder">
|
||||||
|
<p className="text-center">
|
||||||
|
{getLangText('We could not find any works related to you...')}
|
||||||
|
</p>
|
||||||
|
<p className="text-center">
|
||||||
|
{getLangText('You\'re filtering by the search keyword: \'%s\' ', search)}
|
||||||
|
</p>
|
||||||
|
<p className="text-center">
|
||||||
|
<button className="btn btn-sm btn-default" onClick={this.clearSearch}>{getLangText('Clear search')}</button>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
let AccordionListItem = React.createClass({
|
let AccordionListItem = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -21,42 +20,50 @@ let AccordionListItem = React.createClass({
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { linkData,
|
||||||
|
className,
|
||||||
|
thumbnail,
|
||||||
|
heading,
|
||||||
|
subheading,
|
||||||
|
subsubheading,
|
||||||
|
buttons,
|
||||||
|
badge,
|
||||||
|
children } = this.props;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className={this.props.className}>
|
<div className={className}>
|
||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<div className="pull-left">
|
<div className="pull-left">
|
||||||
<Link {...this.props.linkData()}>
|
<Link to={linkData}>
|
||||||
<div className="thumbnail-wrapper">
|
<div className="thumbnail-wrapper">
|
||||||
{this.props.thumbnail}
|
{thumbnail}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="accordion-list-item-header">
|
<div className="accordion-list-item-header">
|
||||||
<Link {...this.props.linkData()}>
|
<Link to={linkData}>
|
||||||
{this.props.heading}
|
{heading}
|
||||||
</Link>
|
</Link>
|
||||||
<Link {...this.props.linkData()}>
|
<Link to={linkData}>
|
||||||
{this.props.subheading}
|
{subheading}
|
||||||
{this.props.subsubheading}
|
{subsubheading}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="accordion-list-item-buttons">
|
<div className="accordion-list-item-buttons">
|
||||||
{this.props.buttons}
|
{buttons}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span style={{'clear': 'both'}}></span>
|
<span style={{'clear': 'both'}}></span>
|
||||||
|
|
||||||
<div className="request-action-badge">
|
<div className="request-action-badge">
|
||||||
{this.props.badge}
|
{badge}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.props.children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import AccordionListItem from './accordion_list_item';
|
import AccordionListItem from './accordion_list_item';
|
||||||
|
|
||||||
@ -22,26 +22,15 @@ let AccordionListItemPiece = React.createClass({
|
|||||||
badge: React.PropTypes.object
|
badge: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
getLinkData() {
|
getLinkData() {
|
||||||
|
let { piece } = this.props;
|
||||||
|
|
||||||
|
if(piece && piece.first_edition) {
|
||||||
|
return `/editions/${piece.first_edition.bitcoin_id}`;
|
||||||
|
|
||||||
if(this.props.piece && this.props.piece.first_edition) {
|
|
||||||
return {
|
|
||||||
to: 'edition',
|
|
||||||
params: {
|
|
||||||
editionId: this.props.piece.first_edition.bitcoin_id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return {
|
return `/pieces/${piece.id}`;
|
||||||
to: 'piece',
|
|
||||||
params: {
|
|
||||||
pieceId: this.props.piece.id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -59,7 +48,7 @@ let AccordionListItemPiece = React.createClass({
|
|||||||
subsubheading={this.props.subsubheading}
|
subsubheading={this.props.subsubheading}
|
||||||
buttons={this.props.buttons}
|
buttons={this.props.buttons}
|
||||||
badge={this.props.badge}
|
badge={this.props.badge}
|
||||||
linkData={this.getLinkData}
|
linkData={this.getLinkData()}
|
||||||
>
|
>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</AccordionListItem>
|
</AccordionListItem>
|
||||||
|
@ -110,7 +110,7 @@ let AccordionListItemTableEditions = React.createClass({
|
|||||||
showExpandOption = true;
|
showExpandOption = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let transition = new TransitionModel('edition', 'editionId', 'bitcoin_id', (e) => e.stopPropagation() );
|
let transition = new TransitionModel('editions', 'editionId', 'bitcoin_id', (e) => e.stopPropagation() );
|
||||||
|
|
||||||
let columnList = [
|
let columnList = [
|
||||||
new ColumnModel(
|
new ColumnModel(
|
||||||
|
@ -1,23 +1,30 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
import Header from '../components/header';
|
import Header from '../components/header';
|
||||||
import Footer from '../components/footer';
|
import Footer from '../components/footer';
|
||||||
import GlobalNotification from './global_notification';
|
import GlobalNotification from './global_notification';
|
||||||
|
|
||||||
import getRoutes from '../routes';
|
|
||||||
|
|
||||||
|
|
||||||
let RouteHandler = Router.RouteHandler;
|
|
||||||
|
|
||||||
let AscribeApp = React.createClass({
|
let AscribeApp = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
children: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
|
React.PropTypes.element
|
||||||
|
]),
|
||||||
|
routes: React.PropTypes.arrayOf(React.PropTypes.object)
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let { children, routes } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container ascribe-default-app">
|
<div className="container ascribe-default-app">
|
||||||
<Header routes={getRoutes()} />
|
<Header routes={routes} />
|
||||||
|
{/* Routes are injected here */}
|
||||||
<div className="ascribe-body">
|
<div className="ascribe-body">
|
||||||
<RouteHandler />
|
{children}
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
<GlobalNotification />
|
<GlobalNotification />
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import Button from 'react-bootstrap/lib/Button';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
@ -24,8 +23,6 @@ let DeleteButton = React.createClass({
|
|||||||
handleSuccess: React.PropTypes.func
|
handleSuccess: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let availableAcls;
|
let availableAcls;
|
||||||
let btnDelete;
|
let btnDelete;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link, History } from 'react-router';
|
||||||
|
|
||||||
import Row from 'react-bootstrap/lib/Row';
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
import Col from 'react-bootstrap/lib/Col';
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
@ -22,7 +22,7 @@ import Form from './../ascribe_forms/form';
|
|||||||
import Property from './../ascribe_forms/property';
|
import Property from './../ascribe_forms/property';
|
||||||
import EditionDetailProperty from './detail_property';
|
import EditionDetailProperty from './detail_property';
|
||||||
import LicenseDetail from './license_detail';
|
import LicenseDetail from './license_detail';
|
||||||
import EditionFurtherDetails from './further_details';
|
import FurtherDetails from './further_details';
|
||||||
|
|
||||||
import EditionActionPanel from './edition_action_panel';
|
import EditionActionPanel from './edition_action_panel';
|
||||||
|
|
||||||
@ -34,17 +34,18 @@ import AscribeSpinner from '../ascribe_spinner';
|
|||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
/**
|
/**
|
||||||
* This is the component that implements display-specific functionality
|
* This is the component that implements display-specific functionality
|
||||||
*/
|
*/
|
||||||
let Edition = React.createClass({
|
let Edition = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
edition: React.PropTypes.object,
|
edition: React.PropTypes.object,
|
||||||
loadEdition: React.PropTypes.func
|
loadEdition: React.PropTypes.func,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
@ -150,12 +151,13 @@ let Edition = React.createClass({
|
|||||||
show={this.props.edition.acl.acl_edit
|
show={this.props.edition.acl.acl_edit
|
||||||
|| Object.keys(this.props.edition.extra_data).length > 0
|
|| Object.keys(this.props.edition.extra_data).length > 0
|
||||||
|| this.props.edition.other_data.length > 0}>
|
|| this.props.edition.other_data.length > 0}>
|
||||||
<EditionFurtherDetails
|
<FurtherDetails
|
||||||
editable={this.props.edition.acl.acl_edit}
|
editable={this.props.edition.acl.acl_edit}
|
||||||
pieceId={this.props.edition.parent}
|
pieceId={this.props.edition.parent}
|
||||||
extraData={this.props.edition.extra_data}
|
extraData={this.props.edition.extra_data}
|
||||||
otherData={this.props.edition.other_data}
|
otherData={this.props.edition.other_data}
|
||||||
handleSuccess={this.props.loadEdition}/>
|
handleSuccess={this.props.loadEdition}
|
||||||
|
location={this.props.location}/>
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
|
|
||||||
<CollapsibleParagraph
|
<CollapsibleParagraph
|
||||||
@ -260,7 +262,7 @@ let CoaDetails = React.createClass({
|
|||||||
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
|
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
<Link to="coa_verify">
|
<Link to="/coa_verify">
|
||||||
<button className="btn btn-default btn-xs">
|
<button className="btn btn-default btn-xs">
|
||||||
{getLangText('Verify')} <Glyphicon glyph="check"/>
|
{getLangText('Verify')} <Glyphicon glyph="check"/>
|
||||||
</button>
|
</button>
|
||||||
|
@ -9,11 +9,14 @@ import Edition from './edition';
|
|||||||
|
|
||||||
import AscribeSpinner from '../ascribe_spinner';
|
import AscribeSpinner from '../ascribe_spinner';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the component that implements resource/data specific functionality
|
* This is the component that implements resource/data specific functionality
|
||||||
*/
|
*/
|
||||||
let EditionContainer = React.createClass({
|
let EditionContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return EditionStore.getState();
|
return EditionStore.getState();
|
||||||
},
|
},
|
||||||
@ -64,7 +67,8 @@ let EditionContainer = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<Edition
|
<Edition
|
||||||
edition={this.state.edition}
|
edition={this.state.edition}
|
||||||
loadEdition={this.loadEdition}/>
|
loadEdition={this.loadEdition}
|
||||||
|
location={this.props.location}/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
@ -23,7 +23,8 @@ let FurtherDetails = React.createClass({
|
|||||||
pieceId: React.PropTypes.number,
|
pieceId: React.PropTypes.number,
|
||||||
extraData: React.PropTypes.object,
|
extraData: React.PropTypes.object,
|
||||||
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
|
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
handleSuccess: React.PropTypes.func
|
handleSuccess: React.PropTypes.func,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
@ -85,7 +86,8 @@ let FurtherDetails = React.createClass({
|
|||||||
overrideForm={true}
|
overrideForm={true}
|
||||||
pieceId={this.props.pieceId}
|
pieceId={this.props.pieceId}
|
||||||
otherData={this.props.otherData}
|
otherData={this.props.otherData}
|
||||||
multiple={true}/>
|
multiple={true}
|
||||||
|
location={this.props.location}/>
|
||||||
</Form>
|
</Form>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -20,7 +20,8 @@ let FurtherDetailsFileuploader = React.createClass({
|
|||||||
submitFile: React.PropTypes.func,
|
submitFile: React.PropTypes.func,
|
||||||
isReadyForFormSubmission: React.PropTypes.func,
|
isReadyForFormSubmission: React.PropTypes.func,
|
||||||
editable: React.PropTypes.bool,
|
editable: React.PropTypes.bool,
|
||||||
multiple: React.PropTypes.bool
|
multiple: React.PropTypes.bool,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
@ -88,7 +89,8 @@ let FurtherDetailsFileuploader = React.createClass({
|
|||||||
}}
|
}}
|
||||||
areAssetsDownloadable={true}
|
areAssetsDownloadable={true}
|
||||||
areAssetsEditable={this.props.editable}
|
areAssetsEditable={this.props.editable}
|
||||||
multiple={this.props.multiple}/>
|
multiple={this.props.multiple}
|
||||||
|
location={this.props.location}/>
|
||||||
</Property>
|
</Property>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import PieceActions from '../../actions/piece_actions';
|
import PieceActions from '../../actions/piece_actions';
|
||||||
import PieceStore from '../../stores/piece_store';
|
import PieceStore from '../../stores/piece_store';
|
||||||
@ -44,8 +44,11 @@ import { getLangText } from '../../utils/lang_utils';
|
|||||||
* This is the component that implements resource/data specific functionality
|
* This is the component that implements resource/data specific functionality
|
||||||
*/
|
*/
|
||||||
let PieceContainer = React.createClass({
|
let PieceContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -133,7 +136,7 @@ let PieceContainer = React.createClass({
|
|||||||
let notification = new GlobalNotificationModel(response.notification, 'success');
|
let notification = new GlobalNotificationModel(response.notification, 'success');
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
this.transitionTo('pieces');
|
this.history.pushState(null, '/collection');
|
||||||
},
|
},
|
||||||
|
|
||||||
getCreateEditionsDialog() {
|
getCreateEditionsDialog() {
|
||||||
@ -262,7 +265,8 @@ let PieceContainer = React.createClass({
|
|||||||
pieceId={this.state.piece.id}
|
pieceId={this.state.piece.id}
|
||||||
extraData={this.state.piece.extra_data}
|
extraData={this.state.piece.extra_data}
|
||||||
otherData={this.state.piece.other_data}
|
otherData={this.state.piece.other_data}
|
||||||
handleSuccess={this.loadPiece}/>
|
handleSuccess={this.loadPiece}
|
||||||
|
location={this.props.location}/>
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
|
|
||||||
</Piece>
|
</Piece>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import ContractListActions from '../../actions/contract_list_actions';
|
import ContractListActions from '../../actions/contract_list_actions';
|
||||||
import ContractListStore from '../../stores/contract_list_store';
|
import ContractListStore from '../../stores/contract_list_store';
|
||||||
@ -26,7 +26,7 @@ let ContractAgreementForm = React.createClass({
|
|||||||
handleSuccess: React.PropTypes.func
|
handleSuccess: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -58,7 +58,8 @@ let ContractAgreementForm = React.createClass({
|
|||||||
let notification = 'Contract agreement send';
|
let notification = 'Contract agreement send';
|
||||||
notification = new GlobalNotificationModel(notification, 'success', 10000);
|
notification = new GlobalNotificationModel(notification, 'success', 10000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
this.transitionTo('pieces');
|
|
||||||
|
this.history.pushState(null, '/collection');
|
||||||
},
|
},
|
||||||
|
|
||||||
getFormData(){
|
getFormData(){
|
||||||
@ -139,7 +140,7 @@ let ContractAgreementForm = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-center">
|
<p className="text-center">
|
||||||
{getLangText('No contracts uploaded yet, please go to the ')}
|
{getLangText('No contracts uploaded yet, please go to the ')}
|
||||||
<a href="settings">{getLangText('settings page')}</a>
|
<a href="contract_settings">{getLangText('contract settings page')}</a>
|
||||||
{getLangText(' and create them.')}
|
{getLangText(' and create them.')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,7 +28,8 @@ let CreateContractForm = React.createClass({
|
|||||||
fileClassToUpload: React.PropTypes.shape({
|
fileClassToUpload: React.PropTypes.shape({
|
||||||
singular: React.PropTypes.string,
|
singular: React.PropTypes.string,
|
||||||
plural: React.PropTypes.string
|
plural: React.PropTypes.string
|
||||||
})
|
}),
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
@ -86,7 +87,8 @@ let CreateContractForm = React.createClass({
|
|||||||
areAssetsEditable={true}
|
areAssetsEditable={true}
|
||||||
setIsUploadReady={this.setIsUploadReady}
|
setIsUploadReady={this.setIsUploadReady}
|
||||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||||
fileClassToUpload={this.props.fileClassToUpload}/>
|
fileClassToUpload={this.props.fileClassToUpload}
|
||||||
|
location={this.props.location}/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property
|
<Property
|
||||||
name='name'
|
name='name'
|
||||||
|
@ -130,6 +130,9 @@ let LoanForm = React.createClass({
|
|||||||
src={contract.blob.url_safe}
|
src={contract.blob.url_safe}
|
||||||
alt="pdf"
|
alt="pdf"
|
||||||
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
|
pluginspage="http://www.adobe.com/products/acrobat/readstep2.html"/>
|
||||||
|
<a href={contract.blob.url_safe} target="_blank">
|
||||||
|
<span className="glyphicon glyphicon-download" aria-hidden="true"></span> {getLangText('Download contract')}
|
||||||
|
</a>
|
||||||
{/* We still need to send the server information that we're accepting */}
|
{/* We still need to send the server information that we're accepting */}
|
||||||
<InputCheckbox
|
<InputCheckbox
|
||||||
style={{'display': 'none'}}
|
style={{'display': 'none'}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||||
@ -25,10 +25,10 @@ let LoginForm = React.createClass({
|
|||||||
submitMessage: React.PropTypes.string,
|
submitMessage: React.PropTypes.string,
|
||||||
redirectOnLoggedIn: React.PropTypes.bool,
|
redirectOnLoggedIn: React.PropTypes.bool,
|
||||||
redirectOnLoginSuccess: React.PropTypes.bool,
|
redirectOnLoginSuccess: React.PropTypes.bool,
|
||||||
onLogin: React.PropTypes.func
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
@ -45,10 +45,6 @@ let LoginForm = React.createClass({
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
UserStore.listen(this.onChange);
|
UserStore.listen(this.onChange);
|
||||||
let { redirect } = this.getQuery();
|
|
||||||
if (redirect && redirect !== 'login'){
|
|
||||||
this.transitionTo(redirect, null, this.getQuery());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -57,65 +53,19 @@ let LoginForm = React.createClass({
|
|||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
|
|
||||||
// if user is already logged in, redirect him to piece list
|
|
||||||
if(this.state.currentUser && this.state.currentUser.email && this.props.redirectOnLoggedIn) {
|
|
||||||
// FIXME: hack to redirect out of the dispatch cycle
|
|
||||||
let { redirectAuthenticated } = this.getQuery();
|
|
||||||
if ( redirectAuthenticated) {
|
|
||||||
/*
|
|
||||||
* redirectAuthenticated contains an arbirary path
|
|
||||||
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
|
|
||||||
* hence transitionTo cannot be used directly
|
|
||||||
*/
|
|
||||||
window.location = AppConstants.baseUrl + redirectAuthenticated;
|
|
||||||
}
|
|
||||||
window.setTimeout(() => this.transitionTo('pieces'), 0);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSuccess(){
|
handleSuccess({ success }){
|
||||||
let notification = new GlobalNotificationModel('Login successful', 'success', 10000);
|
let notification = new GlobalNotificationModel('Login successful', 'success', 10000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
// register_piece is waiting for a login success as login_container and it is wrapped
|
if(success) {
|
||||||
// in a slides_container component.
|
UserActions.fetchCurrentUser();
|
||||||
// The easiest way to check if the user was successfully logged in is to fetch the user
|
}
|
||||||
// in the user store (which is obviously only possible if the user is logged in), since
|
|
||||||
// register_piece is listening to the changes of the user_store.
|
|
||||||
UserActions.fetchCurrentUser()
|
|
||||||
.then(() => {
|
|
||||||
if(this.props.redirectOnLoginSuccess) {
|
|
||||||
/* Taken from http://stackoverflow.com/a/14916411 */
|
|
||||||
/*
|
|
||||||
We actually have to trick the Browser into showing the "save password" dialog
|
|
||||||
as Chrome expects the login page to be reloaded after the login.
|
|
||||||
Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future.
|
|
||||||
Until then, we redirect the HARD way, but reloading the whole page using window.location
|
|
||||||
*/
|
|
||||||
let { redirectAuthenticated } = this.getQuery();
|
|
||||||
if ( redirectAuthenticated) {
|
|
||||||
window.location = AppConstants.baseUrl + redirectAuthenticated;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.location = AppConstants.baseUrl + 'collection';
|
|
||||||
}
|
|
||||||
} else if(this.props.onLogin) {
|
|
||||||
// In some instances we want to give a callback to an outer container,
|
|
||||||
// to show that the one login action the user triggered actually went through.
|
|
||||||
// We can not do this by listening on a store's state as it wouldn't really tell us
|
|
||||||
// if the user did log in or was just fetching the user's data again
|
|
||||||
this.props.onLogin();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let email = this.getQuery().email || null;
|
let email = this.props.location.query.email || null;
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
className="ascribe-form-bordered"
|
className="ascribe-form-bordered"
|
||||||
|
@ -30,7 +30,8 @@ let RegisterPieceForm = React.createClass({
|
|||||||
onLoggedOut: React.PropTypes.func,
|
onLoggedOut: React.PropTypes.func,
|
||||||
|
|
||||||
// For this form to work with SlideContainer, we sometimes have to disable it
|
// For this form to work with SlideContainer, we sometimes have to disable it
|
||||||
disabled: React.PropTypes.bool
|
disabled: React.PropTypes.bool,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
@ -114,7 +115,8 @@ let RegisterPieceForm = React.createClass({
|
|||||||
isFineUploaderActive={this.props.isFineUploaderActive}
|
isFineUploaderActive={this.props.isFineUploaderActive}
|
||||||
onLoggedOut={this.props.onLoggedOut}
|
onLoggedOut={this.props.onLoggedOut}
|
||||||
disabled={!this.props.isFineUploaderEditable}
|
disabled={!this.props.isFineUploaderEditable}
|
||||||
enableLocalHashing={enableLocalHashing}/>
|
enableLocalHashing={enableLocalHashing}
|
||||||
|
location={this.props.location}/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property
|
<Property
|
||||||
name='artist_name'
|
name='artist_name'
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import UserStore from '../../stores/user_store';
|
import UserStore from '../../stores/user_store';
|
||||||
|
import UserActions from '../../actions/user_actions';
|
||||||
|
|
||||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||||
@ -12,7 +13,6 @@ import Form from './form';
|
|||||||
import Property from './property';
|
import Property from './property';
|
||||||
import InputCheckbox from './input_checkbox';
|
import InputCheckbox from './input_checkbox';
|
||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
|
||||||
import ApiUrls from '../../constants/api_urls';
|
import ApiUrls from '../../constants/api_urls';
|
||||||
import AscribeSpinner from '../ascribe_spinner';
|
import AscribeSpinner from '../ascribe_spinner';
|
||||||
|
|
||||||
@ -20,15 +20,15 @@ import { getLangText } from '../../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let SignupForm = React.createClass({
|
let SignupForm = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
headerMessage: React.PropTypes.string,
|
headerMessage: React.PropTypes.string,
|
||||||
submitMessage: React.PropTypes.string,
|
submitMessage: React.PropTypes.string,
|
||||||
handleSuccess: React.PropTypes.func,
|
handleSuccess: React.PropTypes.func,
|
||||||
children: React.PropTypes.element
|
children: React.PropTypes.element,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
@ -36,16 +36,13 @@ let SignupForm = React.createClass({
|
|||||||
submitMessage: getLangText('Sign up')
|
submitMessage: getLangText('Sign up')
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
UserStore.listen(this.onChange);
|
UserStore.listen(this.onChange);
|
||||||
let { redirect } = this.getQuery();
|
|
||||||
if (redirect && redirect !== 'signup'){
|
|
||||||
this.transitionTo(redirect, null, this.getQuery());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -54,45 +51,23 @@ let SignupForm = React.createClass({
|
|||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
|
|
||||||
// if user is already logged in, redirect him to piece list
|
|
||||||
if(this.state.currentUser && this.state.currentUser.email) {
|
|
||||||
let { redirectAuthenticated } = this.getQuery();
|
|
||||||
if ( redirectAuthenticated) {
|
|
||||||
/*
|
|
||||||
* redirectAuthenticated contains an arbirary path
|
|
||||||
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
|
|
||||||
* hence transitionTo cannot be used directly
|
|
||||||
*/
|
|
||||||
window.location = AppConstants.baseUrl + redirectAuthenticated;
|
|
||||||
}
|
|
||||||
window.setTimeout(() => this.transitionTo('pieces'));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSuccess(response){
|
handleSuccess(response) {
|
||||||
if (response.user) {
|
if (response.user) {
|
||||||
let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000);
|
let notification = new GlobalNotificationModel(getLangText('Sign up successful'), 'success', 50000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
|
// Refactor this to its own component
|
||||||
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.');
|
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.');
|
||||||
}
|
} else {
|
||||||
else if (response.redirect) {
|
UserActions.fetchCurrentUser();
|
||||||
let { redirectAuthenticated } = this.getQuery();
|
|
||||||
if ( redirectAuthenticated) {
|
|
||||||
/*
|
|
||||||
* redirectAuthenticated contains an arbirary path
|
|
||||||
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
|
|
||||||
* hence transitionTo cannot be used directly
|
|
||||||
*/
|
|
||||||
window.location = AppConstants.baseUrl + redirectAuthenticated;
|
|
||||||
}
|
|
||||||
this.transitionTo('pieces');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getFormData() {
|
getFormData() {
|
||||||
if (this.getQuery().token){
|
if (this.props.location.query.token){
|
||||||
return {token: this.getQuery().token};
|
return {token: this.props.location.query.token};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@ -101,7 +76,9 @@ let SignupForm = React.createClass({
|
|||||||
let tooltipPassword = getLangText('Your password must be at least 10 characters') + '.\n ' +
|
let tooltipPassword = getLangText('Your password must be at least 10 characters') + '.\n ' +
|
||||||
getLangText('This password is securing your digital property like a bank account') + '.\n ' +
|
getLangText('This password is securing your digital property like a bank account') + '.\n ' +
|
||||||
getLangText('Store it in a safe place') + '!';
|
getLangText('Store it in a safe place') + '!';
|
||||||
let email = this.getQuery().email || null;
|
|
||||||
|
let email = this.props.location.query.email || null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
className="ascribe-form-bordered"
|
className="ascribe-form-bordered"
|
||||||
|
@ -46,7 +46,8 @@ let InputFineUploader = React.createClass({
|
|||||||
fileClassToUpload: React.PropTypes.shape({
|
fileClassToUpload: React.PropTypes.shape({
|
||||||
singular: React.PropTypes.string,
|
singular: React.PropTypes.string,
|
||||||
plural: React.PropTypes.string
|
plural: React.PropTypes.string
|
||||||
})
|
}),
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
@ -106,7 +107,8 @@ let InputFineUploader = React.createClass({
|
|||||||
}}
|
}}
|
||||||
onInactive={this.props.onLoggedOut}
|
onInactive={this.props.onLoggedOut}
|
||||||
enableLocalHashing={this.props.enableLocalHashing}
|
enableLocalHashing={this.props.enableLocalHashing}
|
||||||
fileClassToUpload={this.props.fileClassToUpload}/>
|
fileClassToUpload={this.props.fileClassToUpload}
|
||||||
|
location={this.props.location}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
let PaginationButton = React.createClass({
|
let PaginationButton = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -44,7 +43,7 @@ let PaginationButton = React.createClass({
|
|||||||
|
|
||||||
if (this.isInRange(page)) {
|
if (this.isInRange(page)) {
|
||||||
anchor = (
|
anchor = (
|
||||||
<Link to="pieces"
|
<Link to="/collection"
|
||||||
query={{page}}
|
query={{page}}
|
||||||
onClick={this.props.goToPage(page)}>
|
onClick={this.props.goToPage(page)}>
|
||||||
{directionDisplay}
|
{directionDisplay}
|
||||||
|
@ -4,16 +4,16 @@ import React from 'react';
|
|||||||
|
|
||||||
import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget';
|
import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget';
|
||||||
import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget';
|
import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget';
|
||||||
|
import SearchBar from '../search_bar';
|
||||||
|
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
import Input from 'react-bootstrap/lib/Input';
|
|
||||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
|
||||||
|
|
||||||
let PieceListToolbar = React.createClass({
|
let PieceListToolbar = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
className: React.PropTypes.string,
|
className: React.PropTypes.string,
|
||||||
searchFor: React.PropTypes.func,
|
searchFor: React.PropTypes.func,
|
||||||
|
searchQuery: React.PropTypes.string,
|
||||||
filterParams: React.PropTypes.arrayOf(
|
filterParams: React.PropTypes.arrayOf(
|
||||||
React.PropTypes.shape({
|
React.PropTypes.shape({
|
||||||
label: React.PropTypes.string,
|
label: React.PropTypes.string,
|
||||||
@ -39,11 +39,6 @@ let PieceListToolbar = React.createClass({
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
searchFor() {
|
|
||||||
let searchTerm = this.refs.search.getInputDOMNode().value;
|
|
||||||
this.props.searchFor(searchTerm);
|
|
||||||
},
|
|
||||||
|
|
||||||
getFilterWidget(){
|
getFilterWidget(){
|
||||||
if (this.props.filterParams){
|
if (this.props.filterParams){
|
||||||
return (
|
return (
|
||||||
@ -55,6 +50,7 @@ let PieceListToolbar = React.createClass({
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
getOrderWidget(){
|
getOrderWidget(){
|
||||||
if (this.props.orderParams){
|
if (this.props.orderParams){
|
||||||
return (
|
return (
|
||||||
@ -68,29 +64,25 @@ let PieceListToolbar = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let searchIcon = <span className="ascribe-icon icon-ascribe-search"/>;
|
const { className, children, searchFor, searchQuery } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className}>
|
<div className={className}>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div 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">
|
<div 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">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<span className="pull-left">
|
<span className="pull-left">
|
||||||
{this.props.children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
<span className="pull-right">
|
<span className="pull-right">
|
||||||
{this.getOrderWidget()}
|
{this.getOrderWidget()}
|
||||||
{this.getFilterWidget()}
|
{this.getFilterWidget()}
|
||||||
</span>
|
</span>
|
||||||
<span className="pull-right search-bar ascribe-input-glyph">
|
<SearchBar
|
||||||
<Input
|
className="pull-right search-bar ascribe-input-glyph"
|
||||||
type='text'
|
searchFor={searchFor}
|
||||||
ref="search"
|
searchQuery={searchQuery}
|
||||||
placeholder={getLangText('Search%s', '...')}
|
threshold={AppConstants.searchThreshold}/>
|
||||||
onChange={this.searchFor}
|
|
||||||
addonAfter={searchIcon} />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
107
js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js
Normal file
107
js/components/ascribe_routes/proxy_routes/auth_proxy_handler.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { History } from 'react-router';
|
||||||
|
|
||||||
|
import UserStore from '../../../stores/user_store';
|
||||||
|
import UserActions from '../../../actions/user_actions';
|
||||||
|
|
||||||
|
import AppConstants from '../../../constants/application_constants';
|
||||||
|
|
||||||
|
|
||||||
|
const { object } = React.PropTypes;
|
||||||
|
const WHEN_ENUM = ['loggedIn', 'loggedOut'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used in combination with `Route` as an intermediate Handler
|
||||||
|
* between the actual component we want to display dependent on a certain state
|
||||||
|
* that is required to display that component.
|
||||||
|
*
|
||||||
|
* @param {string} options.to Any type of route path that is defined in routes.js
|
||||||
|
* @param {enum/string} options.when ('loggedIn' || 'loggedOut')
|
||||||
|
*/
|
||||||
|
export default function AuthProxyHandler({to, when}) {
|
||||||
|
|
||||||
|
// validate `when`, must be contained in `WHEN_ENUM`.
|
||||||
|
// Throw an error otherwise.
|
||||||
|
if(WHEN_ENUM.indexOf(when) === -1) {
|
||||||
|
let whenValues = WHEN_ENUM.join(', ');
|
||||||
|
throw new Error(`"when" must be one of: [${whenValues}] got "${when}" instead`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Component) => {
|
||||||
|
return React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: object
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [History],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return UserStore.getState();
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
UserStore.listen(this.onChange);
|
||||||
|
UserActions.fetchCurrentUser();
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.redirectConditionally();
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
UserStore.unlisten(this.onChange);
|
||||||
|
},
|
||||||
|
|
||||||
|
redirectConditionally() {
|
||||||
|
const { query } = this.props.location;
|
||||||
|
const { redirectAuthenticated, redirect } = query;
|
||||||
|
|
||||||
|
// The user of this handler specifies with `when`, what kind of status
|
||||||
|
// needs to be checked to conditionally do - if that state is `true` -
|
||||||
|
// a redirect.
|
||||||
|
//
|
||||||
|
// So if when === 'loggedIn', we're checking if the user is logged in (and
|
||||||
|
// vice versa)
|
||||||
|
let exprToValidate = when === 'loggedIn' ?
|
||||||
|
this.state.currentUser && this.state.currentUser.email :
|
||||||
|
this.state.currentUser && !this.state.currentUser.email;
|
||||||
|
|
||||||
|
// and redirect if `true`.
|
||||||
|
if(exprToValidate) {
|
||||||
|
window.setTimeout(() => this.history.replaceState(null, to, query));
|
||||||
|
|
||||||
|
// Otherwise there can also be the case that the backend
|
||||||
|
// wants to redirect the user to a specific route when the user is logged out already
|
||||||
|
} else if(!exprToValidate && when === 'loggedIn' && redirect) {
|
||||||
|
|
||||||
|
delete query.redirect;
|
||||||
|
window.setTimeout(() => this.history.replaceState(null, '/' + redirect, query));
|
||||||
|
|
||||||
|
} else if(!exprToValidate && when === 'loggedOut' && redirectAuthenticated) {
|
||||||
|
/*
|
||||||
|
* redirectAuthenticated contains an arbirary path
|
||||||
|
* eg pieces/<id>, editions/<bitcoin_id>, collection, settings, ...
|
||||||
|
* hence transitionTo cannot be used directly.
|
||||||
|
*
|
||||||
|
* While we're getting rid of `query.redirect` explicitly in the
|
||||||
|
* above `else if` statement, here it's sufficient to just call
|
||||||
|
* `baseUrl` + `redirectAuthenticated`, as it gets rid of queries as well.
|
||||||
|
*/
|
||||||
|
window.location = AppConstants.baseUrl + redirectAuthenticated;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onChange(state) {
|
||||||
|
this.setState(state);
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Component {...this.props}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
@ -27,6 +27,10 @@ import { mergeOptions, truncateTextAtCharIndex } from '../../utils/general_utils
|
|||||||
|
|
||||||
|
|
||||||
let ContractSettings = React.createClass({
|
let ContractSettings = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState(){
|
getInitialState(){
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
ContractListStore.getState(),
|
ContractListStore.getState(),
|
||||||
@ -89,7 +93,8 @@ let ContractSettings = React.createClass({
|
|||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
singular: 'new contract',
|
singular: 'new contract',
|
||||||
plural: 'new contracts'
|
plural: 'new contracts'
|
||||||
}}/>
|
}}
|
||||||
|
location={this.props.location}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +119,9 @@ let ContractSettings = React.createClass({
|
|||||||
<AclProxy
|
<AclProxy
|
||||||
aclObject={this.state.whitelabel}
|
aclObject={this.state.whitelabel}
|
||||||
aclName="acl_update_public_contract">
|
aclName="acl_update_public_contract">
|
||||||
<ContractSettingsUpdateButton contract={contract}/>
|
<ContractSettingsUpdateButton
|
||||||
|
contract={contract}
|
||||||
|
location={this.props.location}/>
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
<a
|
<a
|
||||||
className="btn btn-default btn-sm margin-left-2px"
|
className="btn btn-default btn-sm margin-left-2px"
|
||||||
@ -144,7 +151,8 @@ let ContractSettings = React.createClass({
|
|||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
singular: getLangText('new contract'),
|
singular: getLangText('new contract'),
|
||||||
plural: getLangText('new contracts')
|
plural: getLangText('new contracts')
|
||||||
}}/>
|
}}
|
||||||
|
location={this.props.location}/>
|
||||||
{privateContracts.map((contract, i) => {
|
{privateContracts.map((contract, i) => {
|
||||||
return (
|
return (
|
||||||
<ActionPanel
|
<ActionPanel
|
||||||
@ -156,7 +164,9 @@ let ContractSettings = React.createClass({
|
|||||||
<AclProxy
|
<AclProxy
|
||||||
aclObject={this.state.whitelabel}
|
aclObject={this.state.whitelabel}
|
||||||
aclName="acl_update_private_contract">
|
aclName="acl_update_private_contract">
|
||||||
<ContractSettingsUpdateButton contract={contract}/>
|
<ContractSettingsUpdateButton
|
||||||
|
contract={contract}
|
||||||
|
location={this.props.location}/>
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
<a
|
<a
|
||||||
className="btn btn-default btn-sm margin-left-2px"
|
className="btn btn-default btn-sm margin-left-2px"
|
||||||
|
@ -20,7 +20,8 @@ import { getLangText } from '../../utils/lang_utils';
|
|||||||
|
|
||||||
let ContractSettingsUpdateButton = React.createClass({
|
let ContractSettingsUpdateButton = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
contract: React.PropTypes.object
|
contract: React.PropTypes.object,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
submitFile(file) {
|
submitFile(file) {
|
||||||
@ -90,7 +91,7 @@ let ContractSettingsUpdateButton = React.createClass({
|
|||||||
}}
|
}}
|
||||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||||
submitFile={this.submitFile}
|
submitFile={this.submitFile}
|
||||||
/>
|
location={this.props.location}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import UserStore from '../../stores/user_store';
|
import UserStore from '../../stores/user_store';
|
||||||
import UserActions from '../../actions/user_actions';
|
import UserActions from '../../actions/user_actions';
|
||||||
@ -25,8 +24,6 @@ let SettingsContainer = React.createClass({
|
|||||||
React.PropTypes.element])
|
React.PropTypes.element])
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
UserStore.getState(),
|
UserStore.getState(),
|
||||||
|
@ -1,96 +1,40 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react/addons';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
import ReactAddons from 'react/addons';
|
|
||||||
|
|
||||||
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
|
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
|
||||||
|
|
||||||
let State = Router.State;
|
|
||||||
let Navigation = Router.Navigation;
|
|
||||||
|
|
||||||
|
const { arrayOf, element, bool, shape, string, object } = React.PropTypes;
|
||||||
|
|
||||||
let SlidesContainer = React.createClass({
|
const SlidesContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
children: React.PropTypes.arrayOf(React.PropTypes.element),
|
children: arrayOf(element),
|
||||||
forwardProcess: React.PropTypes.bool.isRequired,
|
forwardProcess: bool.isRequired,
|
||||||
|
|
||||||
glyphiconClassNames: React.PropTypes.shape({
|
glyphiconClassNames: shape({
|
||||||
pending: React.PropTypes.string,
|
pending: string,
|
||||||
complete: React.PropTypes.string
|
complete: string
|
||||||
})
|
}),
|
||||||
|
location: object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [State, Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
// handle queryParameters
|
|
||||||
let queryParams = this.getQuery();
|
|
||||||
let slideNum = -1;
|
|
||||||
let startFrom = -1;
|
|
||||||
|
|
||||||
// We can actually need to check if slide_num is present as a key in queryParams.
|
|
||||||
// We do not really care about its value though...
|
|
||||||
if(queryParams && 'slide_num' in queryParams) {
|
|
||||||
slideNum = parseInt(queryParams.slide_num, 10);
|
|
||||||
}
|
|
||||||
// if slide_num is not set, this will be done in componentDidMount
|
|
||||||
|
|
||||||
// the query param 'start_from' removes all slide children before the respective number
|
|
||||||
// Also, we use the 'in' keyword for the same reason as above in 'slide_num'
|
|
||||||
if(queryParams && 'start_from' in queryParams) {
|
|
||||||
startFrom = parseInt(queryParams.start_from, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
slideNum,
|
containerWidth: 0
|
||||||
startFrom,
|
|
||||||
containerWidth: 0,
|
|
||||||
historyLength: window.history.length
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// check if slide_num was defined, and if not then default to 0
|
|
||||||
let queryParams = this.getQuery();
|
|
||||||
|
|
||||||
// We use 'in' to check if the key is present in the user's browser url bar,
|
|
||||||
// we do not really care about its value at this point
|
|
||||||
if(!('slide_num' in queryParams)) {
|
|
||||||
|
|
||||||
// we're first requiring all the other possible queryParams and then set
|
|
||||||
// the specific one we need instead of overwriting them
|
|
||||||
queryParams.slide_num = 0;
|
|
||||||
|
|
||||||
this.replaceWith(this.getPathname(), null, queryParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init container width
|
|
||||||
this.handleContainerResize();
|
|
||||||
|
|
||||||
// we're using an event listener on window here,
|
// we're using an event listener on window here,
|
||||||
// as it was not possible to listen to the resize events of a dom node
|
// as it was not possible to listen to the resize events of a dom node
|
||||||
window.addEventListener('resize', this.handleContainerResize);
|
window.addEventListener('resize', this.handleContainerResize);
|
||||||
},
|
|
||||||
|
|
||||||
componentWillReceiveProps() {
|
// Initially, we need to dispatch 'resize' once to render correctly
|
||||||
let queryParams = this.getQuery();
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
|
||||||
// also check if start_from was updated
|
|
||||||
// This applies for example when the user tries to submit a already existing piece
|
|
||||||
// (starting from slide 1 for example) and then clicking on + NEW WORK
|
|
||||||
if(queryParams && !('start_from' in queryParams)) {
|
|
||||||
this.setState({
|
|
||||||
startFrom: -1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
let queryParams = this.getQuery();
|
|
||||||
|
|
||||||
// check if slide_num was defined, and if not then default to 0
|
|
||||||
this.setSlideNum(queryParams.slide_num);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -105,80 +49,26 @@ let SlidesContainer = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// When the start_from parameter is used, this.setSlideNum can not simply be used anymore.
|
// When the start_from parameter is used, this.setSlideNum can not simply be used anymore.
|
||||||
nextSlide() {
|
nextSlide(additionalQueryParams) {
|
||||||
let nextSlide = this.state.slideNum + 1;
|
const slideNum = parseInt(this.props.location.query.slide_num, 10) || 0;
|
||||||
this.setSlideNum(nextSlide);
|
let nextSlide = slideNum + 1;
|
||||||
|
this.setSlideNum(nextSlide, additionalQueryParams);
|
||||||
},
|
},
|
||||||
|
|
||||||
// We let every one from the outsite set the page number of the slider,
|
setSlideNum(nextSlideNum, additionalQueryParams = {}) {
|
||||||
// though only if the slideNum is actually in the range of our children-list.
|
let queryParams = Object.assign(this.props.location.query, additionalQueryParams);
|
||||||
setSlideNum(slideNum) {
|
queryParams.slide_num = nextSlideNum;
|
||||||
|
this.history.pushState(null, this.props.location.pathname, queryParams);
|
||||||
// we do not want to overwrite other queryParams
|
|
||||||
let queryParams = this.getQuery();
|
|
||||||
|
|
||||||
// slideNum can in some instances be not a number,
|
|
||||||
// therefore we have to parse it to one and make sure that its not NaN
|
|
||||||
slideNum = parseInt(slideNum, 10);
|
|
||||||
|
|
||||||
// if slideNum is not a number (even after we parsed it to one) and there has
|
|
||||||
// never been a transition to another slide (this.state.slideNum ==== -1 indicates that)
|
|
||||||
// then we want to "replace" (in this case append) the current url with ?slide_num=0
|
|
||||||
if(isNaN(slideNum) && this.state.slideNum === -1) {
|
|
||||||
slideNum = 0;
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
|
|
||||||
this.replaceWith(this.getPathname(), null, queryParams);
|
|
||||||
this.setState({slideNum: slideNum});
|
|
||||||
return;
|
|
||||||
|
|
||||||
// slideNum always represents the future state. So if slideNum and
|
|
||||||
// this.state.slideNum are equal, there is no sense in redirecting
|
|
||||||
} else if(slideNum === this.state.slideNum) {
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if slideNum is within the range of slides and none of the previous cases
|
|
||||||
// where matched, we can actually do transitions
|
|
||||||
} else if(slideNum >= 0 || slideNum < this.customChildrenCount()) {
|
|
||||||
|
|
||||||
if(slideNum !== this.state.slideNum - 1) {
|
|
||||||
// Bootstrapping the component, getInitialState is called once to save
|
|
||||||
// the tabs history length.
|
|
||||||
// In order to know if we already pushed a new state on the history stack or not,
|
|
||||||
// we're comparing the old history length with the new one and if it didn't change then
|
|
||||||
// we push a new state on it ONCE (ever).
|
|
||||||
// Otherwise, we're able to use the browsers history.forward() method
|
|
||||||
// to keep the stack clean
|
|
||||||
|
|
||||||
if(this.props.forwardProcess) {
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
this.transitionTo(this.getPathname(), null, queryParams);
|
|
||||||
} else {
|
|
||||||
if(this.state.historyLength === window.history.length) {
|
|
||||||
queryParams.slide_num = slideNum;
|
|
||||||
this.transitionTo(this.getPathname(), null, queryParams);
|
|
||||||
} else {
|
|
||||||
window.history.forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
slideNum: slideNum
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error('You\'re calling a page number that is out of range.');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// breadcrumbs are defined as attributes of the slides.
|
// breadcrumbs are defined as attributes of the slides.
|
||||||
// To extract them we have to read the DOM element's attributes
|
// To extract them we have to read the DOM element's attributes
|
||||||
extractBreadcrumbs() {
|
extractBreadcrumbs() {
|
||||||
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
let breadcrumbs = [];
|
let breadcrumbs = [];
|
||||||
|
|
||||||
ReactAddons.Children.map(this.props.children, (child, i) => {
|
React.Children.map(this.props.children, (child, i) => {
|
||||||
if(child && i >= this.state.startFrom && child.props['data-slide-title']) {
|
if(child && i >= startFrom && child.props['data-slide-title']) {
|
||||||
breadcrumbs.push(child.props['data-slide-title']);
|
breadcrumbs.push(child.props['data-slide-title']);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -191,9 +81,11 @@ let SlidesContainer = React.createClass({
|
|||||||
// Therefore React.Children.count does not work anymore and we
|
// Therefore React.Children.count does not work anymore and we
|
||||||
// need to implement our own method.
|
// need to implement our own method.
|
||||||
customChildrenCount() {
|
customChildrenCount() {
|
||||||
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
React.Children.forEach(this.props.children, (child, i) => {
|
React.Children.forEach(this.props.children, (child, i) => {
|
||||||
if(i >= this.state.startFrom) {
|
if(i >= startFrom) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -212,7 +104,7 @@ let SlidesContainer = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<SlidesContainerBreadcrumbs
|
<SlidesContainerBreadcrumbs
|
||||||
breadcrumbs={breadcrumbs}
|
breadcrumbs={breadcrumbs}
|
||||||
slideNum={this.state.slideNum}
|
slideNum={parseInt(this.props.location.query.slide_num, 10) || 0}
|
||||||
numOfSlides={breadcrumbs.length}
|
numOfSlides={breadcrumbs.length}
|
||||||
containerWidth={this.state.containerWidth}
|
containerWidth={this.state.containerWidth}
|
||||||
glyphiconClassNames={this.props.glyphiconClassNames}/>
|
glyphiconClassNames={this.props.glyphiconClassNames}/>
|
||||||
@ -225,12 +117,13 @@ let SlidesContainer = React.createClass({
|
|||||||
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
|
// Since we need to give the slides a width, we need to call ReactAddons.addons.cloneWithProps
|
||||||
// Also, a key is nice to have!
|
// Also, a key is nice to have!
|
||||||
renderChildren() {
|
renderChildren() {
|
||||||
return ReactAddons.Children.map(this.props.children, (child, i) => {
|
const startFrom = parseInt(this.props.location.query.start_from, 10) || -1;
|
||||||
|
|
||||||
|
return React.Children.map(this.props.children, (child, i) => {
|
||||||
// since the default parameter of startFrom is -1, we do not need to check
|
// since the default parameter of startFrom is -1, we do not need to check
|
||||||
// if its actually present in the url bar, as it will just not match
|
// if its actually present in the url bar, as it will just not match
|
||||||
if(child && i >= this.state.startFrom) {
|
if(child && i >= startFrom) {
|
||||||
return ReactAddons.addons.cloneWithProps(child, {
|
return React.addons.cloneWithProps(child, {
|
||||||
className: 'ascribe-slide',
|
className: 'ascribe-slide',
|
||||||
style: {
|
style: {
|
||||||
width: this.state.containerWidth
|
width: this.state.containerWidth
|
||||||
@ -246,7 +139,7 @@ let SlidesContainer = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let spacing = this.state.containerWidth * this.state.slideNum;
|
let spacing = this.state.containerWidth * parseInt(this.props.location.query.slide_num, 10) || 0;
|
||||||
let translateXValue = 'translateX(' + (-1) * spacing + 'px)';
|
let translateXValue = 'translateX(' + (-1) * spacing + 'px)';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -35,14 +35,7 @@ export class TransitionModel {
|
|||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
toReactRouterLinkProps(queryValue) {
|
toReactRouterLink(queryValue) {
|
||||||
let props = {
|
return '/' + this.to + '/' + queryValue;
|
||||||
to: this.to,
|
|
||||||
params: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
props.params[this.queryKey] = queryValue;
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import { ColumnModel } from './models/table_models';
|
import { ColumnModel } from './models/table_models';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
let TableItemWrapper = React.createClass({
|
let TableItemWrapper = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -15,8 +14,6 @@ let TableItemWrapper = React.createClass({
|
|||||||
onClick: React.PropTypes.func
|
onClick: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<tr onClick={this.props.onClick}>
|
<tr onClick={this.props.onClick}>
|
||||||
@ -35,18 +32,13 @@ let TableItemWrapper = React.createClass({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
let linkProps = column.transition.toReactRouterLinkProps(this.props.columnContent[column.transition.valueKey]);
|
let linkString = column.transition.toReactRouterLink(this.props.columnContent[column.transition.valueKey]);
|
||||||
/**
|
|
||||||
* If a transition is defined in columnContent, then we can use
|
|
||||||
* Router.Navigation.transitionTo to redirect the user
|
|
||||||
* programmatically
|
|
||||||
*/
|
|
||||||
return (
|
return (
|
||||||
<td key={i} className={column.className}>
|
<td key={i} className={column.className}>
|
||||||
<Link
|
<Link
|
||||||
|
to={linkString}
|
||||||
className={'ascribe-table-item-column'}
|
className={'ascribe-table-item-column'}
|
||||||
onClick={column.transition.callback}
|
onClick={column.transition.callback}>
|
||||||
{...linkProps}>
|
|
||||||
<TypeElement {...typeElementProps} />
|
<TypeElement {...typeElementProps} />
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
|
@ -40,7 +40,8 @@ let FileDragAndDrop = React.createClass({
|
|||||||
plural: React.PropTypes.string
|
plural: React.PropTypes.string
|
||||||
}),
|
}),
|
||||||
|
|
||||||
allowedExtensions: React.PropTypes.string
|
allowedExtensions: React.PropTypes.string,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDragOver(event) {
|
handleDragOver(event) {
|
||||||
@ -142,7 +143,8 @@ let FileDragAndDrop = React.createClass({
|
|||||||
fileClassToUpload,
|
fileClassToUpload,
|
||||||
areAssetsDownloadable,
|
areAssetsDownloadable,
|
||||||
areAssetsEditable,
|
areAssetsEditable,
|
||||||
allowedExtensions
|
allowedExtensions,
|
||||||
|
location
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// has files only is true if there are files that do not have the status deleted or canceled
|
// has files only is true if there are files that do not have the status deleted or canceled
|
||||||
@ -179,7 +181,8 @@ let FileDragAndDrop = React.createClass({
|
|||||||
hasFiles={hasFiles}
|
hasFiles={hasFiles}
|
||||||
onClick={this.handleOnClick}
|
onClick={this.handleOnClick}
|
||||||
enableLocalHashing={enableLocalHashing}
|
enableLocalHashing={enableLocalHashing}
|
||||||
fileClassToUpload={fileClassToUpload}/>
|
fileClassToUpload={fileClassToUpload}
|
||||||
|
location={location}/>
|
||||||
<FileDragAndDropPreviewIterator
|
<FileDragAndDropPreviewIterator
|
||||||
files={filesToUpload}
|
files={filesToUpload}
|
||||||
handleDeleteFile={this.handleDeleteFile}
|
handleDeleteFile={this.handleDeleteFile}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import { getLangText } from '../../../utils/lang_utils';
|
import { getLangText } from '../../../utils/lang_utils';
|
||||||
|
import { dragAndDropAvailable } from '../../../utils/feature_detection_utils';
|
||||||
|
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
let FileDragAndDropDialog = React.createClass({
|
let FileDragAndDropDialog = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -19,13 +20,24 @@ let FileDragAndDropDialog = React.createClass({
|
|||||||
fileClassToUpload: React.PropTypes.shape({
|
fileClassToUpload: React.PropTypes.shape({
|
||||||
singular: React.PropTypes.string,
|
singular: React.PropTypes.string,
|
||||||
plural: React.PropTypes.string
|
plural: React.PropTypes.string
|
||||||
})
|
}),
|
||||||
|
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.State],
|
getDragDialog(fileClass) {
|
||||||
|
if(dragAndDropAvailable) {
|
||||||
|
return [
|
||||||
|
<p>{getLangText('Drag %s here', fileClass)}</p>,
|
||||||
|
<p>{getLangText('or')}</p>
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const queryParams = this.getQuery();
|
const queryParams = this.props.location.query;
|
||||||
|
|
||||||
if(this.props.hasFiles) {
|
if(this.props.hasFiles) {
|
||||||
return null;
|
return null;
|
||||||
@ -38,11 +50,13 @@ let FileDragAndDropDialog = React.createClass({
|
|||||||
let queryParamsUpload = Object.assign({}, queryParams);
|
let queryParamsUpload = Object.assign({}, queryParams);
|
||||||
queryParamsUpload.method = 'upload';
|
queryParamsUpload.method = 'upload';
|
||||||
|
|
||||||
|
let { location } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="file-drag-and-drop-dialog present-options">
|
<div className="file-drag-and-drop-dialog present-options">
|
||||||
<p>{getLangText('Would you rather')}</p>
|
<p>{getLangText('Would you rather')}</p>
|
||||||
<Link
|
<Link
|
||||||
to={this.getPath()}
|
to={location.pathname}
|
||||||
query={queryParamsHash}>
|
query={queryParamsHash}>
|
||||||
<span className="btn btn-default btn-sm">
|
<span className="btn btn-default btn-sm">
|
||||||
{getLangText('Hash your work')}
|
{getLangText('Hash your work')}
|
||||||
@ -52,7 +66,7 @@ let FileDragAndDropDialog = React.createClass({
|
|||||||
<span> or </span>
|
<span> or </span>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
to={this.getPath()}
|
to={location.pathname}
|
||||||
query={queryParamsUpload}>
|
query={queryParamsUpload}>
|
||||||
<span className="btn btn-default btn-sm">
|
<span className="btn btn-default btn-sm">
|
||||||
{getLangText('Upload and hash your work')}
|
{getLangText('Upload and hash your work')}
|
||||||
@ -64,8 +78,7 @@ let FileDragAndDropDialog = React.createClass({
|
|||||||
if(this.props.multipleFiles) {
|
if(this.props.multipleFiles) {
|
||||||
return (
|
return (
|
||||||
<span className="file-drag-and-drop-dialog">
|
<span className="file-drag-and-drop-dialog">
|
||||||
<p>{getLangText('Drag %s here', this.props.fileClassToUpload.plural)}</p>
|
{this.getDragDialog(this.props.fileClassToUpload.plural)}
|
||||||
<p>{getLangText('or')}</p>
|
|
||||||
<span
|
<span
|
||||||
className="btn btn-default"
|
className="btn btn-default"
|
||||||
onClick={this.props.onClick}>
|
onClick={this.props.onClick}>
|
||||||
@ -78,8 +91,7 @@ let FileDragAndDropDialog = React.createClass({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="file-drag-and-drop-dialog">
|
<span className="file-drag-and-drop-dialog">
|
||||||
<p>{getLangText('Drag a %s here', this.props.fileClassToUpload.singular)}</p>
|
{this.getDragDialog(this.props.fileClassToUpload.singular)}
|
||||||
<p>{getLangText('or')}</p>
|
|
||||||
<span
|
<span
|
||||||
className="btn btn-default"
|
className="btn btn-default"
|
||||||
onClick={this.props.onClick}>
|
onClick={this.props.onClick}>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import React from 'react/addons';
|
import React from 'react/addons';
|
||||||
import fineUploader from 'fineUploader';
|
import fineUploader from 'fineUploader';
|
||||||
import Router from 'react-router';
|
|
||||||
import Q from 'q';
|
import Q from 'q';
|
||||||
|
|
||||||
import S3Fetcher from '../../fetchers/s3_fetcher';
|
import S3Fetcher from '../../fetchers/s3_fetcher';
|
||||||
@ -127,10 +126,10 @@ let ReactS3FineUploader = React.createClass({
|
|||||||
fileInputElement: React.PropTypes.oneOfType([
|
fileInputElement: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.func,
|
React.PropTypes.func,
|
||||||
React.PropTypes.element
|
React.PropTypes.element
|
||||||
])
|
]),
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [Router.State],
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
@ -649,7 +648,7 @@ let ReactS3FineUploader = React.createClass({
|
|||||||
//
|
//
|
||||||
// In the view this only happens when the user is allowed to do local hashing as well
|
// In the view this only happens when the user is allowed to do local hashing as well
|
||||||
// as when the correct query parameter is present in the url ('hash' and not 'upload')
|
// as when the correct query parameter is present in the url ('hash' and not 'upload')
|
||||||
let queryParams = this.getQuery();
|
let queryParams = this.props.location.query;
|
||||||
if(this.props.enableLocalHashing && queryParams && queryParams.method === 'hash') {
|
if(this.props.enableLocalHashing && queryParams && queryParams.method === 'hash') {
|
||||||
|
|
||||||
let convertedFilePromises = [];
|
let convertedFilePromises = [];
|
||||||
@ -830,7 +829,7 @@ let ReactS3FineUploader = React.createClass({
|
|||||||
|
|
||||||
isDropzoneInactive() {
|
isDropzoneInactive() {
|
||||||
let filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1);
|
let filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1);
|
||||||
let queryParams = this.getQuery();
|
let queryParams = this.props.location.query;
|
||||||
|
|
||||||
if((this.props.enableLocalHashing && !queryParams.method) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) {
|
if((this.props.enableLocalHashing && !queryParams.method) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) {
|
||||||
return true;
|
return true;
|
||||||
@ -859,12 +858,20 @@ let ReactS3FineUploader = React.createClass({
|
|||||||
enableLocalHashing,
|
enableLocalHashing,
|
||||||
fileClassToUpload,
|
fileClassToUpload,
|
||||||
validation,
|
validation,
|
||||||
fileInputElement
|
fileInputElement,
|
||||||
|
location
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// Here we initialize the template that has been either provided from the outside
|
// Here we initialize the template that has been either provided from the outside
|
||||||
// or the default input that is FileDragAndDrop.
|
// or the default input that is FileDragAndDrop.
|
||||||
return React.createElement(fileInputElement, {
|
return React.createElement(fileInputElement, {
|
||||||
|
multiple,
|
||||||
|
areAssetsDownloadable,
|
||||||
|
areAssetsEditable,
|
||||||
|
onInactive,
|
||||||
|
enableLocalHashing,
|
||||||
|
fileClassToUpload,
|
||||||
|
location,
|
||||||
onDrop: this.handleUploadFile,
|
onDrop: this.handleUploadFile,
|
||||||
filesToUpload: this.state.filesToUpload,
|
filesToUpload: this.state.filesToUpload,
|
||||||
handleDeleteFile: this.handleDeleteFile,
|
handleDeleteFile: this.handleDeleteFile,
|
||||||
@ -872,14 +879,8 @@ let ReactS3FineUploader = React.createClass({
|
|||||||
handlePauseFile: this.handlePauseFile,
|
handlePauseFile: this.handlePauseFile,
|
||||||
handleResumeFile: this.handleResumeFile,
|
handleResumeFile: this.handleResumeFile,
|
||||||
handleCancelHashing: this.handleCancelHashing,
|
handleCancelHashing: this.handleCancelHashing,
|
||||||
multiple: multiple,
|
|
||||||
areAssetsDownloadable: areAssetsDownloadable,
|
|
||||||
areAssetsEditable: areAssetsEditable,
|
|
||||||
onInactive: onInactive,
|
|
||||||
dropzoneInactive: this.isDropzoneInactive(),
|
dropzoneInactive: this.isDropzoneInactive(),
|
||||||
hashingProgress: this.state.hashingProgress,
|
hashingProgress: this.state.hashingProgress,
|
||||||
enableLocalHashing: enableLocalHashing,
|
|
||||||
fileClassToUpload: fileClassToUpload,
|
|
||||||
allowedExtensions: this.getAllowedExtensions()
|
allowedExtensions: this.getAllowedExtensions()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import GlobalNotificationModel from '../models/global_notification_model';
|
import GlobalNotificationModel from '../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||||
@ -17,8 +16,6 @@ import { getLangText } from '../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let CoaVerifyContainer = React.createClass({
|
let CoaVerifyContainer = React.createClass({
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-login-wrapper">
|
<div className="ascribe-login-wrapper">
|
||||||
@ -47,8 +44,6 @@ let CoaVerifyContainer = React.createClass({
|
|||||||
|
|
||||||
|
|
||||||
let CoaVerifyForm = React.createClass({
|
let CoaVerifyForm = React.createClass({
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
handleSuccess(response){
|
handleSuccess(response){
|
||||||
let notification = null;
|
let notification = null;
|
||||||
if (response.verdict) {
|
if (response.verdict) {
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import Nav from 'react-bootstrap/lib/Nav';
|
import Nav from 'react-bootstrap/lib/Nav';
|
||||||
import Navbar from 'react-bootstrap/lib/Navbar';
|
import Navbar from 'react-bootstrap/lib/Navbar';
|
||||||
import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav';
|
import CollapsibleNav from 'react-bootstrap/lib/CollapsibleNav';
|
||||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||||
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||||
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
|
import NavItem from 'react-bootstrap/lib/NavItem';
|
||||||
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import AclProxy from './acl_proxy';
|
import AclProxy from './acl_proxy';
|
||||||
|
|
||||||
@ -33,11 +33,9 @@ import { getLangText } from '../utils/lang_utils';
|
|||||||
let Header = React.createClass({
|
let Header = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
showAddWork: React.PropTypes.bool,
|
showAddWork: React.PropTypes.bool,
|
||||||
routes: React.PropTypes.element
|
routes: React.PropTypes.arrayOf(React.PropTypes.object)
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.State],
|
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
showAddWork: true
|
showAddWork: true
|
||||||
@ -133,38 +131,61 @@ let Header = React.createClass({
|
|||||||
ref='dropdownbutton'
|
ref='dropdownbutton'
|
||||||
eventKey="1"
|
eventKey="1"
|
||||||
title={this.state.currentUser.username}>
|
title={this.state.currentUser.username}>
|
||||||
<MenuItemLink
|
<LinkContainer
|
||||||
eventKey="2"
|
to="/settings"
|
||||||
to="settings"
|
|
||||||
onClick={this.onMenuItemClick}>
|
onClick={this.onMenuItemClick}>
|
||||||
{getLangText('Account Settings')}
|
<MenuItem
|
||||||
</MenuItemLink>
|
eventKey="2">
|
||||||
|
{getLangText('Account Settings')}
|
||||||
|
</MenuItem>
|
||||||
|
</LinkContainer>
|
||||||
<AclProxy
|
<AclProxy
|
||||||
aclObject={this.state.currentUser.acl}
|
aclObject={this.state.currentUser.acl}
|
||||||
aclName="acl_view_settings_contract">
|
aclName="acl_view_settings_contract">
|
||||||
<MenuItemLink
|
<LinkContainer
|
||||||
to="contract_settings"
|
to="/contract_settings"
|
||||||
onClick={this.onMenuItemClick}>
|
onClick={this.onMenuItemClick}>
|
||||||
{getLangText('Contract Settings')}
|
<MenuItem
|
||||||
</MenuItemLink>
|
eventKey="2">
|
||||||
|
{getLangText('Contract Settings')}
|
||||||
|
</MenuItem>
|
||||||
|
</LinkContainer>
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
<MenuItem divider />
|
<MenuItem divider />
|
||||||
<MenuItemLink eventKey="3" to="logout">{getLangText('Log out')}</MenuItemLink>
|
<LinkContainer
|
||||||
|
to="/logout">
|
||||||
|
<MenuItem
|
||||||
|
eventKey="3">
|
||||||
|
{getLangText('Log out')}
|
||||||
|
</MenuItem>
|
||||||
|
</LinkContainer>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
navRoutesLinks = <NavRoutesLinks routes={this.props.routes} userAcl={this.state.currentUser.acl} navbar right/>;
|
navRoutesLinks = <NavRoutesLinks routes={this.props.routes} userAcl={this.state.currentUser.acl} navbar right/>;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
account = <NavItemLink to="login">{getLangText('LOGIN')}</NavItemLink>;
|
account = (
|
||||||
signup = <NavItemLink to="signup">{getLangText('SIGNUP')}</NavItemLink>;
|
<LinkContainer
|
||||||
|
to="/login">
|
||||||
|
<NavItem>
|
||||||
|
{getLangText('LOGIN')}
|
||||||
|
</NavItem>
|
||||||
|
</LinkContainer>
|
||||||
|
);
|
||||||
|
signup = (
|
||||||
|
<LinkContainer
|
||||||
|
to="/signup">
|
||||||
|
<NavItem>
|
||||||
|
{getLangText('SIGNUP')}
|
||||||
|
</NavItem>
|
||||||
|
</LinkContainer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Navbar
|
<Navbar
|
||||||
brand={
|
brand={this.getLogo()}
|
||||||
this.getLogo()
|
|
||||||
}
|
|
||||||
toggleNavKey={0}
|
toggleNavKey={0}
|
||||||
fixedTop={true}>
|
fixedTop={true}>
|
||||||
<CollapsibleNav eventKey={0}>
|
<CollapsibleNav eventKey={0}>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||||
@ -14,8 +14,6 @@ import NotificationStore from '../stores/notification_store';
|
|||||||
import { mergeOptions } from '../utils/general_utils';
|
import { mergeOptions } from '../utils/general_utils';
|
||||||
import { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
|
|
||||||
let HeaderNotifications = React.createClass({
|
let HeaderNotifications = React.createClass({
|
||||||
|
|
||||||
@ -39,7 +37,7 @@ let HeaderNotifications = React.createClass({
|
|||||||
this.setState(state);
|
this.setState(state);
|
||||||
},
|
},
|
||||||
|
|
||||||
onMenuItemClick(event) {
|
onMenuItemClick() {
|
||||||
/*
|
/*
|
||||||
This is a hack to make the dropdown close after clicking on an item
|
This is a hack to make the dropdown close after clicking on an item
|
||||||
The function just need to be defined
|
The function just need to be defined
|
||||||
@ -158,23 +156,13 @@ let NotificationListItem = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getLinkData() {
|
getLinkData() {
|
||||||
|
let { pieceOrEdition } = this.props;
|
||||||
|
|
||||||
if (this.isPiece()) {
|
if (this.isPiece()) {
|
||||||
return {
|
return `/pieces/${pieceOrEdition.id}`;
|
||||||
to: 'piece',
|
|
||||||
params: {
|
|
||||||
pieceId: this.props.pieceOrEdition.id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
return {
|
return `/editions/${pieceOrEdition.bitcoin_id}`;
|
||||||
to: 'edition',
|
|
||||||
params: {
|
|
||||||
editionId: this.props.pieceOrEdition.bitcoin_id
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick(event){
|
onClick(event){
|
||||||
@ -184,7 +172,7 @@ let NotificationListItem = React.createClass({
|
|||||||
getNotificationText(){
|
getNotificationText(){
|
||||||
let numNotifications = null;
|
let numNotifications = null;
|
||||||
if (this.props.notification.length > 1){
|
if (this.props.notification.length > 1){
|
||||||
numNotifications = <div>+ {this.props.notification.length - 1} more...</div>;
|
numNotifications = <div>+ {this.props.notification.length - 1} {getLangText('more...')}</div>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="notification-action">
|
<div className="notification-action">
|
||||||
@ -196,7 +184,7 @@ let NotificationListItem = React.createClass({
|
|||||||
render() {
|
render() {
|
||||||
if (this.props.pieceOrEdition) {
|
if (this.props.pieceOrEdition) {
|
||||||
return (
|
return (
|
||||||
<Link {...this.getLinkData()} onClick={this.onClick}>
|
<Link to={this.getLinkData()} onClick={this.onClick}>
|
||||||
<div className="row notification-wrapper">
|
<div className="row notification-wrapper">
|
||||||
<div className="col-xs-4 clear-paddings">
|
<div className="col-xs-4 clear-paddings">
|
||||||
<div className="thumbnail-wrapper">
|
<div className="thumbnail-wrapper">
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import LoginForm from './ascribe_forms/form_login';
|
import LoginForm from './ascribe_forms/form_login';
|
||||||
|
|
||||||
import { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
|
|
||||||
let LoginContainer = React.createClass({
|
let LoginContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
message: React.PropTypes.string,
|
message: React.PropTypes.string,
|
||||||
redirectOnLoggedIn: React.PropTypes.bool,
|
redirectOnLoggedIn: React.PropTypes.bool,
|
||||||
redirectOnLoginSuccess: React.PropTypes.bool,
|
redirectOnLoginSuccess: React.PropTypes.bool,
|
||||||
onLogin: React.PropTypes.func
|
onLogin: React.PropTypes.func,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
@ -33,10 +32,11 @@ let LoginContainer = React.createClass({
|
|||||||
redirectOnLoggedIn={this.props.redirectOnLoggedIn}
|
redirectOnLoggedIn={this.props.redirectOnLoggedIn}
|
||||||
redirectOnLoginSuccess={this.props.redirectOnLoginSuccess}
|
redirectOnLoginSuccess={this.props.redirectOnLoginSuccess}
|
||||||
message={this.props.message}
|
message={this.props.message}
|
||||||
onLogin={this.props.onLogin}/>
|
onLogin={this.props.onLogin}
|
||||||
|
location={this.props.location}/>
|
||||||
<div className="ascribe-login-text">
|
<div className="ascribe-login-text">
|
||||||
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
{getLangText('Not an ascribe user')}? <Link to="/signup">{getLangText('Sign up')}...</Link><br/>
|
||||||
{getLangText('Forgot my password')}? <Link to="password_reset">{getLangText('Rescue me')}...</Link>
|
{getLangText('Forgot my password')}? <Link to="/password_reset">{getLangText('Rescue me')}...</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,38 +1,27 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import AscribeSpinner from './ascribe_spinner';
|
import AscribeSpinner from './ascribe_spinner';
|
||||||
|
|
||||||
import UserActions from '../actions/user_actions';
|
import UserActions from '../actions/user_actions';
|
||||||
import { alt, altWhitelabel, altUser, altThirdParty } from '../alt';
|
import { alt, altWhitelabel, altUser, altThirdParty } from '../alt';
|
||||||
|
|
||||||
import AppConstants from '../constants/application_constants';
|
|
||||||
|
|
||||||
import { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
let baseUrl = AppConstants.baseUrl;
|
|
||||||
|
|
||||||
let LogoutContainer = React.createClass({
|
let LogoutContainer = React.createClass({
|
||||||
|
mixins: [History],
|
||||||
mixins: [Router.Navigation, Router.State],
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
UserActions.logoutCurrentUser()
|
UserActions.logoutCurrentUser();
|
||||||
.then(() => {
|
alt.flush();
|
||||||
alt.flush();
|
altWhitelabel.flush();
|
||||||
altWhitelabel.flush();
|
altUser.flush();
|
||||||
altUser.flush();
|
altThirdParty.flush();
|
||||||
altThirdParty.flush();
|
// kill intercom (with fire)
|
||||||
// kill intercom (with fire)
|
window.Intercom('shutdown');
|
||||||
window.Intercom('shutdown');
|
|
||||||
this.replaceWith(baseUrl);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.logGlobal(err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -45,7 +34,6 @@ let LogoutContainer = React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import { sanitizeList } from '../utils/general_utils';
|
|||||||
|
|
||||||
let NavRoutesLinks = React.createClass({
|
let NavRoutesLinks = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
routes: React.PropTypes.element,
|
routes: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
userAcl: React.PropTypes.object
|
userAcl: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -33,15 +33,15 @@ let NavRoutesLinks = React.createClass({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let links = node.props.children.map((child, j) => {
|
let links = node.childRoutes.map((child, j) => {
|
||||||
let childrenFn = null;
|
let childrenFn = null;
|
||||||
let { aclName, headerTitle, name, children } = child.props;
|
let { aclName, headerTitle, path, childRoutes } = child;
|
||||||
|
|
||||||
// If the node has children that could be rendered, then we want
|
// If the node has children that could be rendered, then we want
|
||||||
// to execute this function again with the child as the root
|
// to execute this function again with the child as the root
|
||||||
//
|
//
|
||||||
// Otherwise we'll just pass childrenFn as false
|
// Otherwise we'll just pass childrenFn as false
|
||||||
if(child.props.children && child.props.children.length > 0) {
|
if(child.childRoutes && child.childRoutes.length > 0) {
|
||||||
childrenFn = this.extractLinksFromRoutes(child, userAcl, i++);
|
childrenFn = this.extractLinksFromRoutes(child, userAcl, i++);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ let NavRoutesLinks = React.createClass({
|
|||||||
aclObject={this.props.userAcl}>
|
aclObject={this.props.userAcl}>
|
||||||
<NavRoutesLinksLink
|
<NavRoutesLinksLink
|
||||||
headerTitle={headerTitle}
|
headerTitle={headerTitle}
|
||||||
routeName={name}
|
routePath={'/' + path}
|
||||||
depth={i}
|
depth={i}
|
||||||
children={childrenFn}/>
|
children={childrenFn}/>
|
||||||
</AclProxy>
|
</AclProxy>
|
||||||
@ -68,7 +68,7 @@ let NavRoutesLinks = React.createClass({
|
|||||||
<NavRoutesLinksLink
|
<NavRoutesLinksLink
|
||||||
key={j}
|
key={j}
|
||||||
headerTitle={headerTitle}
|
headerTitle={headerTitle}
|
||||||
routeName={name}
|
routePath={'/' + path}
|
||||||
depth={i}
|
depth={i}
|
||||||
children={childrenFn}/>
|
children={childrenFn}/>
|
||||||
);
|
);
|
||||||
@ -88,7 +88,7 @@ let NavRoutesLinks = React.createClass({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Nav {...this.props}>
|
<Nav {...this.props}>
|
||||||
{this.extractLinksFromRoutes(routes, userAcl, 0)}
|
{this.extractLinksFromRoutes(routes[0], userAcl, 0)}
|
||||||
</Nav>
|
</Nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
|
||||||
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
|
import MenuItem from 'react-bootstrap/lib/MenuItem';
|
||||||
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
|
import NavItem from 'react-bootstrap/lib/NavItem';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
|
|
||||||
let NavRoutesLinksLink = React.createClass({
|
let NavRoutesLinksLink = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
headerTitle: React.PropTypes.string,
|
headerTitle: React.PropTypes.string,
|
||||||
routeName: React.PropTypes.string,
|
routePath: React.PropTypes.string,
|
||||||
|
|
||||||
children: React.PropTypes.oneOfType([
|
children: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
@ -20,10 +23,10 @@ let NavRoutesLinksLink = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { children, headerTitle, depth, routeName } = this.props;
|
let { children, headerTitle, depth, routePath } = this.props;
|
||||||
|
|
||||||
// if the route has children, we're returning a DropdownButton that will get filled
|
// if the route has children, we're returning a DropdownButton that will get filled
|
||||||
// with MenuItemLinks
|
// with MenuItems
|
||||||
if(children) {
|
if(children) {
|
||||||
return (
|
return (
|
||||||
<DropdownButton title={headerTitle}>
|
<DropdownButton title={headerTitle}>
|
||||||
@ -33,13 +36,17 @@ let NavRoutesLinksLink = React.createClass({
|
|||||||
} else {
|
} else {
|
||||||
if(depth === 1) {
|
if(depth === 1) {
|
||||||
// if the node's child is actually a node of level one (a child of a node), we're
|
// if the node's child is actually a node of level one (a child of a node), we're
|
||||||
// returning a DropdownButton matching MenuItemLink
|
// returning a DropdownButton matching MenuItem
|
||||||
return (
|
return (
|
||||||
<MenuItemLink to={routeName}>{headerTitle}</MenuItemLink>
|
<LinkContainer to={routePath}>
|
||||||
|
<MenuItem>{headerTitle}</MenuItem>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
} else if(depth === 0) {
|
} else if(depth === 0) {
|
||||||
return (
|
return (
|
||||||
<NavItemLink to={routeName}>{headerTitle}</NavItemLink>
|
<LinkContainer to={routePath}>
|
||||||
|
<NavItem>{headerTitle}</NavItem>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import Form from './ascribe_forms/form';
|
import Form from './ascribe_forms/form';
|
||||||
import Property from './ascribe_forms/property';
|
import Property from './ascribe_forms/property';
|
||||||
@ -14,7 +14,9 @@ import { getLangText } from '../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let PasswordResetContainer = React.createClass({
|
let PasswordResetContainer = React.createClass({
|
||||||
mixins: [Router.Navigation],
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {isRequested: false};
|
return {isRequested: false};
|
||||||
@ -25,12 +27,14 @@ let PasswordResetContainer = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.query.email && this.props.query.token) {
|
let { location } = this.props;
|
||||||
|
|
||||||
|
if (location.query.email && location.query.token) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PasswordResetForm
|
<PasswordResetForm
|
||||||
email={this.props.query.email}
|
email={location.query.email}
|
||||||
token={this.props.query.token}/>
|
token={location.query.token}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -113,7 +117,7 @@ let PasswordResetForm = React.createClass({
|
|||||||
token: React.PropTypes.string
|
token: React.PropTypes.string
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getFormData() {
|
getFormData() {
|
||||||
return {
|
return {
|
||||||
@ -123,7 +127,7 @@ let PasswordResetForm = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleSuccess() {
|
handleSuccess() {
|
||||||
this.transitionTo('pieces');
|
this.history.pushState(null, '/collection');
|
||||||
let notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000);
|
let notification = new GlobalNotificationModel(getLangText('password successfully updated'), 'success', 10000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import PieceListStore from '../stores/piece_list_store';
|
import PieceListStore from '../stores/piece_list_store';
|
||||||
import PieceListActions from '../actions/piece_list_actions';
|
import PieceListActions from '../actions/piece_list_actions';
|
||||||
@ -35,10 +35,11 @@ let PieceList = React.createClass({
|
|||||||
customSubmitButton: React.PropTypes.element,
|
customSubmitButton: React.PropTypes.element,
|
||||||
filterParams: React.PropTypes.array,
|
filterParams: React.PropTypes.array,
|
||||||
orderParams: React.PropTypes.array,
|
orderParams: React.PropTypes.array,
|
||||||
orderBy: React.PropTypes.string
|
orderBy: React.PropTypes.string,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
@ -62,7 +63,7 @@ let PieceList = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
let page = this.getQuery().page || 1;
|
let page = this.props.location.query.page || 1;
|
||||||
|
|
||||||
PieceListStore.listen(this.onChange);
|
PieceListStore.listen(this.onChange);
|
||||||
EditionListStore.listen(this.onChange);
|
EditionListStore.listen(this.onChange);
|
||||||
@ -77,7 +78,7 @@ let PieceList = React.createClass({
|
|||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
if (this.props.redirectTo && this.state.unfilteredPieceListCount === 0) {
|
if (this.props.redirectTo && this.state.unfilteredPieceListCount === 0) {
|
||||||
// FIXME: hack to redirect out of the dispatch cycle
|
// FIXME: hack to redirect out of the dispatch cycle
|
||||||
window.setTimeout(() => this.transitionTo(this.props.redirectTo, this.getQuery()));
|
window.setTimeout(() => this.history.pushState(null, this.props.redirectTo, this.props.location.query), 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ let PieceList = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getPagination() {
|
getPagination() {
|
||||||
let currentPage = parseInt(this.getQuery().page, 10) || 1;
|
let currentPage = parseInt(this.props.location.query.page, 10) || 1;
|
||||||
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
|
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
|
||||||
|
|
||||||
if (this.state.pieceListCount > 20) {
|
if (this.state.pieceListCount > 20) {
|
||||||
@ -118,7 +119,7 @@ let PieceList = React.createClass({
|
|||||||
searchFor(searchTerm) {
|
searchFor(searchTerm) {
|
||||||
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy,
|
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy,
|
||||||
this.state.orderAsc, this.state.filterBy);
|
this.state.orderAsc, this.state.filterBy);
|
||||||
this.transitionTo(this.getPathname(), {page: 1});
|
this.history.pushState(null, this.props.location.pathname, {page: 1});
|
||||||
},
|
},
|
||||||
|
|
||||||
applyFilterBy(filterBy){
|
applyFilterBy(filterBy){
|
||||||
@ -142,7 +143,7 @@ let PieceList = React.createClass({
|
|||||||
|
|
||||||
// we have to redirect the user always to page one as it could be that there is no page two
|
// we have to redirect the user always to page one as it could be that there is no page two
|
||||||
// for filtered pieces
|
// for filtered pieces
|
||||||
this.transitionTo(this.getPathname(), {page: 1});
|
this.history.pushState(null, this.props.location.pathname, {page: 1});
|
||||||
},
|
},
|
||||||
|
|
||||||
applyOrderBy(orderBy) {
|
applyOrderBy(orderBy) {
|
||||||
@ -159,6 +160,7 @@ let PieceList = React.createClass({
|
|||||||
<PieceListToolbar
|
<PieceListToolbar
|
||||||
className="ascribe-piece-list-toolbar"
|
className="ascribe-piece-list-toolbar"
|
||||||
searchFor={this.searchFor}
|
searchFor={this.searchFor}
|
||||||
|
searchQuery={this.state.search}
|
||||||
filterParams={this.props.filterParams}
|
filterParams={this.props.filterParams}
|
||||||
orderParams={this.props.orderParams}
|
orderParams={this.props.orderParams}
|
||||||
filterBy={this.state.filterBy}
|
filterBy={this.state.filterBy}
|
||||||
@ -184,6 +186,7 @@ let PieceList = React.createClass({
|
|||||||
orderBy={this.state.orderBy}
|
orderBy={this.state.orderBy}
|
||||||
orderAsc={this.state.orderAsc}
|
orderAsc={this.state.orderAsc}
|
||||||
search={this.state.search}
|
search={this.state.search}
|
||||||
|
searchFor={this.searchFor}
|
||||||
page={this.state.page}
|
page={this.state.page}
|
||||||
pageSize={this.state.pageSize}
|
pageSize={this.state.pageSize}
|
||||||
loadingElement={loadingElement}>
|
loadingElement={loadingElement}>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import Col from 'react-bootstrap/lib/Col';
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
import Row from 'react-bootstrap/lib/Row';
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
@ -20,10 +20,6 @@ import GlobalNotificationActions from '../actions/global_notification_actions';
|
|||||||
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
||||||
import RegisterPieceForm from './ascribe_forms/form_register_piece';
|
import RegisterPieceForm from './ascribe_forms/form_register_piece';
|
||||||
|
|
||||||
import LoginContainer from './login_container';
|
|
||||||
import SlidesContainer from './ascribe_slides_container/slides_container';
|
|
||||||
|
|
||||||
|
|
||||||
import { mergeOptions } from '../utils/general_utils';
|
import { mergeOptions } from '../utils/general_utils';
|
||||||
import { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
@ -37,10 +33,11 @@ let RegisterPiece = React.createClass( {
|
|||||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
React.PropTypes.element,
|
React.PropTypes.element,
|
||||||
React.PropTypes.string
|
React.PropTypes.string
|
||||||
])
|
]),
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
@ -60,10 +57,10 @@ let RegisterPiece = React.createClass( {
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
WhitelabelActions.fetchWhitelabel();
|
|
||||||
PieceListStore.listen(this.onChange);
|
PieceListStore.listen(this.onChange);
|
||||||
UserStore.listen(this.onChange);
|
UserStore.listen(this.onChange);
|
||||||
WhitelabelStore.listen(this.onChange);
|
WhitelabelStore.listen(this.onChange);
|
||||||
|
WhitelabelActions.fetchWhitelabel();
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -98,7 +95,7 @@ let RegisterPiece = React.createClass( {
|
|||||||
this.state.filterBy
|
this.state.filterBy
|
||||||
);
|
);
|
||||||
|
|
||||||
this.transitionTo('piece', {pieceId: response.piece.id});
|
this.history.pushState(null, `/pieces/${response.piece.id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSpecifyEditions() {
|
getSpecifyEditions() {
|
||||||
@ -117,53 +114,20 @@ let RegisterPiece = React.createClass( {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// basically redirects to the second slide (index: 1), when the user is not logged in
|
|
||||||
onLoggedOut() {
|
|
||||||
// only transition to the login store, if user is not logged in
|
|
||||||
// ergo the currentUser object is not properly defined
|
|
||||||
if(this.state.currentUser && !this.state.currentUser.email) {
|
|
||||||
this.refs.slidesContainer.setSlideNum(1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onLogin() {
|
|
||||||
// once the currentUser object from UserStore is defined (eventually the user was transitioned
|
|
||||||
// to the login form via the slider and successfully logged in), we can direct him back to the
|
|
||||||
// register_piece slide
|
|
||||||
if(this.state.currentUser && this.state.currentUser.email) {
|
|
||||||
window.history.back();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SlidesContainer
|
<Row className="no-margin">
|
||||||
ref="slidesContainer"
|
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||||
forwardProcess={false}>
|
<RegisterPieceForm
|
||||||
<div
|
{...this.props}
|
||||||
onClick={this.onLoggedOut}
|
isFineUploaderActive={this.state.isFineUploaderActive}
|
||||||
onFocus={this.onLoggedOut}>
|
handleSuccess={this.handleSuccess}
|
||||||
<Row className="no-margin">
|
location={this.props.location}>
|
||||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
{this.props.children}
|
||||||
<RegisterPieceForm
|
{this.getSpecifyEditions()}
|
||||||
{...this.props}
|
</RegisterPieceForm>
|
||||||
isFineUploaderActive={this.state.isFineUploaderActive}
|
</Col>
|
||||||
handleSuccess={this.handleSuccess}
|
</Row>
|
||||||
onLoggedOut={this.onLoggedOut}>
|
|
||||||
{this.props.children}
|
|
||||||
{this.getSpecifyEditions()}
|
|
||||||
</RegisterPieceForm>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<LoginContainer
|
|
||||||
message={getLangText('Please login before ascribing your work%s', '...')}
|
|
||||||
redirectOnLoggedIn={false}
|
|
||||||
redirectOnLoginSuccess={false}
|
|
||||||
onLogin={this.onLogin}/>
|
|
||||||
</div>
|
|
||||||
</SlidesContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
140
js/components/search_bar.js
Normal file
140
js/components/search_bar.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Input from 'react-bootstrap/lib/Input';
|
||||||
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
|
const { func, string, number } = React.PropTypes;
|
||||||
|
|
||||||
|
const SearchBar = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
// a function that accepts a string as a search query and updates the
|
||||||
|
// propagated `searchQuery` after successfully retrieving the
|
||||||
|
// request from the server
|
||||||
|
searchFor: func.isRequired,
|
||||||
|
searchQuery: string.isRequired,
|
||||||
|
|
||||||
|
className: string,
|
||||||
|
|
||||||
|
// the number of milliseconds the component
|
||||||
|
// should wait before requesting search results from the server
|
||||||
|
threshold: number.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
searchQuery: '',
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const searchQueryProps = this.props.searchQuery;
|
||||||
|
const searchQueryPrevProps = prevProps.searchQuery;
|
||||||
|
const searchQueryState = this.state.searchQuery;
|
||||||
|
const { loading } = this.state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Condition: `loading` must be true, which implies that `evaluateTimer`,
|
||||||
|
* has already been called
|
||||||
|
*
|
||||||
|
* AND
|
||||||
|
*
|
||||||
|
* (
|
||||||
|
* 2. Condition: `searchQueryProps` and `searchQueryState` are true and equal
|
||||||
|
* (which means that the search query has been propagated to the inner
|
||||||
|
* fetch method of `fetchPieceList`, which in turn means that a fetch
|
||||||
|
* has completed)
|
||||||
|
*
|
||||||
|
* OR
|
||||||
|
*
|
||||||
|
* 3. Condition: `searchQueryProps` and `searchQueryState` can be any value (`true` or
|
||||||
|
* `false`, as long as they're equal). This case only occurs when the user
|
||||||
|
* has entered a `searchQuery` and deletes the query in one go, reseting
|
||||||
|
* `searchQueryProps` to empty string ('' === false) again.
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
const firstCondition = !!loading;
|
||||||
|
const secondCondition = searchQueryProps && searchQueryState && searchQueryProps === searchQueryState;
|
||||||
|
const thirdCondition = !searchQueryPrevProps && searchQueryProps === searchQueryState;
|
||||||
|
|
||||||
|
if(firstCondition && (secondCondition || thirdCondition)) {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
/**
|
||||||
|
* This enables the `PieceListStore` to override the state
|
||||||
|
* of that component in case someone is changing the `searchQuery` on
|
||||||
|
* another component.
|
||||||
|
*
|
||||||
|
* Like how it's being done in the 'Clear search' dialog.
|
||||||
|
*/
|
||||||
|
if(this.props.searchQuery !== nextProps.searchQuery || !this.state.searchQuery) {
|
||||||
|
this.setState({ searchQuery: nextProps.searchQuery });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startTimer(searchQuery) {
|
||||||
|
const { timer } = this.state;
|
||||||
|
const { threshold } = this.props;
|
||||||
|
|
||||||
|
// The timer waits for the specified threshold time in milliseconds
|
||||||
|
// and then calls `evaluateTimer`.
|
||||||
|
// If another letter has been called in the mean time (timespan < `threshold`),
|
||||||
|
// the present timer gets cleared and a new one is added to `this.state`.
|
||||||
|
// This means that `evaluateTimer`, will only be called when the threshold has actually
|
||||||
|
// passed,
|
||||||
|
clearTimeout(timer); // apparently `clearTimeout` can be called with null, without throwing errors
|
||||||
|
const newTimer = setTimeout(this.evaluateTimer(searchQuery), threshold);
|
||||||
|
|
||||||
|
this.setState({ timer: newTimer });
|
||||||
|
},
|
||||||
|
|
||||||
|
evaluateTimer(searchQuery) {
|
||||||
|
return () => {
|
||||||
|
this.setState({ timer: null, loading: true }, () => {
|
||||||
|
// search for the query
|
||||||
|
this.props.searchFor(searchQuery);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange({ target: { value }}) {
|
||||||
|
// On each letter entry we're updating the state of the component
|
||||||
|
// and start a timer, which we're also pushing to the state
|
||||||
|
// of the component
|
||||||
|
this.startTimer(value);
|
||||||
|
this.setState({ searchQuery: value });
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let searchIcon = <Glyphicon glyph='search' className="filter-glyph"/>;
|
||||||
|
const { className } = this.props;
|
||||||
|
const { loading, searchQuery } = this.state;
|
||||||
|
|
||||||
|
if(loading) {
|
||||||
|
searchIcon = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={className}>
|
||||||
|
<Input
|
||||||
|
type='text'
|
||||||
|
value={searchQuery}
|
||||||
|
placeholder={getLangText('Search%s', '...')}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
addonAfter={searchIcon} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default SearchBar;
|
@ -1,15 +1,18 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import SignupForm from './ascribe_forms/form_signup';
|
import SignupForm from './ascribe_forms/form_signup';
|
||||||
|
|
||||||
import { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
let SignupContainer = React.createClass({
|
let SignupContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {
|
return {
|
||||||
submitted: false,
|
submitted: false,
|
||||||
@ -37,9 +40,11 @@ let SignupContainer = React.createClass({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-login-wrapper">
|
<div className="ascribe-login-wrapper">
|
||||||
<SignupForm handleSuccess={this.handleSuccess} />
|
<SignupForm
|
||||||
|
handleSuccess={this.handleSuccess}
|
||||||
|
location={this.props.location}/>
|
||||||
<div className="ascribe-login-text">
|
<div className="ascribe-login-text">
|
||||||
{getLangText('Already an ascribe user')}? <Link to="login">{getLangText('Log in')}...</Link><br/>
|
{getLangText('Already an ascribe user')}? <Link to="/login">{getLangText('Log in')}...</Link><br/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import StarRating from 'react-star-rating';
|
import StarRating from 'react-star-rating';
|
||||||
|
|
||||||
import PieceListActions from '../../../../../actions/piece_list_actions';
|
import PieceListActions from '../../../../../actions/piece_list_actions';
|
||||||
@ -21,12 +21,9 @@ import GlobalNotificationActions from '../../../../../actions/global_notificatio
|
|||||||
import AclProxy from '../../../../acl_proxy';
|
import AclProxy from '../../../../acl_proxy';
|
||||||
import SubmitToPrizeButton from './../ascribe_buttons/submit_to_prize_button';
|
import SubmitToPrizeButton from './../ascribe_buttons/submit_to_prize_button';
|
||||||
|
|
||||||
|
|
||||||
import { getLangText } from '../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../utils/lang_utils';
|
||||||
import { mergeOptions } from '../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
|
|
||||||
let AccordionListItemPrize = React.createClass({
|
let AccordionListItemPrize = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
@ -85,7 +82,7 @@ let AccordionListItemPrize = React.createClass({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="list-rating" className="pull-right">
|
<div id="list-rating" className="pull-right">
|
||||||
<Link to='piece' params={{pieceId: this.props.content.id}}>
|
<Link to={`/pieces/${this.props.content.id}`}>
|
||||||
<StarRating
|
<StarRating
|
||||||
ref='rating'
|
ref='rating'
|
||||||
name="prize-rating"
|
name="prize-rating"
|
||||||
@ -108,7 +105,7 @@ let AccordionListItemPrize = React.createClass({
|
|||||||
// jury and no rating yet
|
// jury and no rating yet
|
||||||
return (
|
return (
|
||||||
<div className="react-rating-caption pull-right">
|
<div className="react-rating-caption pull-right">
|
||||||
<Link to='piece' params={{pieceId: this.props.content.id}}>
|
<Link to={`/pieces/${this.props.content.id}`}>
|
||||||
{getLangText('Submit your rating')}
|
{getLangText('Submit your rating')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
|
|
||||||
import StarRating from 'react-star-rating';
|
import StarRating from 'react-star-rating';
|
||||||
@ -41,7 +41,6 @@ import ApiUrls from '../../../../../constants/api_urls';
|
|||||||
import { mergeOptions } from '../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
import { getLangText } from '../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the component that implements resource/data specific functionality
|
* This is the component that implements resource/data specific functionality
|
||||||
@ -169,12 +168,12 @@ let NavigationHeader = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div style={{marginBottom: '1em'}}>
|
<div style={{marginBottom: '1em'}}>
|
||||||
<div className="row no-margin">
|
<div className="row no-margin">
|
||||||
<Link className="disable-select" to='piece' params={{pieceId: nav.prev_index ? nav.prev_index : this.props.piece.id}}>
|
<Link className="disable-select" to={`/pieces/${ nav.prev_index || this.props.piece.id }`}>
|
||||||
<span className="glyphicon glyphicon-chevron-left pull-left link-ascribe" aria-hidden="true">
|
<span className="glyphicon glyphicon-chevron-left pull-left link-ascribe" aria-hidden="true">
|
||||||
{getLangText('Previous')}
|
{getLangText('Previous')}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
<Link className="disable-select" to='piece' params={{pieceId: nav.next_index ? nav.next_index : this.props.piece.id}}>
|
<Link className="disable-select" to={`/pieces/${ nav.next_index || this.props.piece.id }`}>
|
||||||
<span className="pull-right link-ascribe">
|
<span className="pull-right link-ascribe">
|
||||||
{getLangText('Next')}
|
{getLangText('Next')}
|
||||||
<span className="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
|
<span className="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import PrizeActions from '../actions/prize_actions';
|
import PrizeActions from '../actions/prize_actions';
|
||||||
import PrizeStore from '../stores/prize_store';
|
import PrizeStore from '../stores/prize_store';
|
||||||
|
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
|
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import UserStore from '../../../../stores/user_store';
|
import UserStore from '../../../../stores/user_store';
|
||||||
import UserActions from '../../../../actions/user_actions';
|
import UserActions from '../../../../actions/user_actions';
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ import { getLangText } from '../../../../utils/lang_utils';
|
|||||||
|
|
||||||
let Landing = React.createClass({
|
let Landing = React.createClass({
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -44,7 +46,7 @@ let Landing = React.createClass({
|
|||||||
// if user is already logged in, redirect him to piece list
|
// if user is already logged in, redirect him to piece list
|
||||||
if(this.state.currentUser && this.state.currentUser.email) {
|
if(this.state.currentUser && this.state.currentUser.email) {
|
||||||
// FIXME: hack to redirect out of the dispatch cycle
|
// FIXME: hack to redirect out of the dispatch cycle
|
||||||
window.setTimeout(() => this.replaceWith('pieces'), 0);
|
window.setTimeout(() => this.history.replaceState(null, '/collection'), 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -52,16 +54,20 @@ let Landing = React.createClass({
|
|||||||
if (this.state.prize && this.state.prize.active){
|
if (this.state.prize && this.state.prize.active){
|
||||||
return (
|
return (
|
||||||
<ButtonGroup className="enter" bsSize="large" vertical>
|
<ButtonGroup className="enter" bsSize="large" vertical>
|
||||||
<ButtonLink to="signup">
|
<LinkContainer to="/signup">
|
||||||
{getLangText('Sign up to submit')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Sign up to submit')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{getLangText('or, already an ascribe user?')}
|
{getLangText('or, already an ascribe user?')}
|
||||||
</p>
|
</p>
|
||||||
<ButtonLink to="login">
|
<LinkContainer to="/login">
|
||||||
{getLangText('Log in to submit')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Log in to submit')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -74,9 +80,11 @@ let Landing = React.createClass({
|
|||||||
<p>
|
<p>
|
||||||
{getLangText('or, already an ascribe user?')}
|
{getLangText('or, already an ascribe user?')}
|
||||||
</p>
|
</p>
|
||||||
<ButtonLink to="login">
|
<LinkContainer to="/login">
|
||||||
{getLangText('Log in')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Log in')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,29 +1,32 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import LoginForm from '../../../ascribe_forms/form_login';
|
import LoginForm from '../../../ascribe_forms/form_login';
|
||||||
|
|
||||||
import { getLangText } from '../../../../utils/lang_utils';
|
import { getLangText } from '../../../../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
|
||||||
|
|
||||||
|
|
||||||
let LoginContainer = React.createClass({
|
let LoginContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-login-wrapper">
|
<div className="ascribe-login-wrapper">
|
||||||
<LoginForm
|
<LoginForm
|
||||||
headerMessage={getLangText('Log in with ascribe')} />
|
headerMessage={getLangText('Log in with ascribe')}
|
||||||
|
location={this.props.location}/>
|
||||||
<div
|
<div
|
||||||
className="ascribe-login-text">
|
className="ascribe-login-text">
|
||||||
{getLangText('I\'m not a user') + ' '}
|
{getLangText('I\'m not a user') + ' '}
|
||||||
<Link to="signup">{getLangText('Sign up...')}</Link>
|
<Link to="/signup">{getLangText('Sign up...')}</Link>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
{getLangText('I forgot my password') + ' '}
|
{getLangText('I forgot my password') + ' '}
|
||||||
<Link to="password_reset">{getLangText('Rescue me...')}</Link>
|
<Link to="/password_reset">{getLangText('Rescue me...')}</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -9,13 +9,20 @@ import UserStore from '../../../../stores/user_store';
|
|||||||
import PrizeActions from '../actions/prize_actions';
|
import PrizeActions from '../actions/prize_actions';
|
||||||
import PrizeStore from '../stores/prize_store';
|
import PrizeStore from '../stores/prize_store';
|
||||||
|
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize';
|
import AccordionListItemPrize from './ascribe_accordion_list/accordion_list_item_prize';
|
||||||
|
|
||||||
import { mergeOptions } from '../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../utils/general_utils';
|
||||||
import { getLangText } from '../../../../utils/lang_utils';
|
import { getLangText } from '../../../../utils/lang_utils';
|
||||||
|
|
||||||
let PrizePieceList = React.createClass({
|
let PrizePieceList = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
PrizeStore.getState(),
|
PrizeStore.getState(),
|
||||||
@ -42,9 +49,11 @@ let PrizePieceList = React.createClass({
|
|||||||
getButtonSubmit() {
|
getButtonSubmit() {
|
||||||
if (this.state.prize && this.state.prize.active && !this.state.currentUser.is_jury){
|
if (this.state.prize && this.state.prize.active && !this.state.currentUser.is_jury){
|
||||||
return (
|
return (
|
||||||
<ButtonLink to="register_piece">
|
<LinkContainer to="/register_piece">
|
||||||
{getLangText('Submit to prize')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Submit to prize')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (this.state.prize && this.state.currentUser.is_judge){
|
else if (this.state.prize && this.state.currentUser.is_judge){
|
||||||
@ -65,12 +74,13 @@ let PrizePieceList = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<PieceList
|
<PieceList
|
||||||
ref="list"
|
ref="list"
|
||||||
redirectTo="register_piece"
|
redirectTo="/register_piece"
|
||||||
accordionListItemType={AccordionListItemPrize}
|
accordionListItemType={AccordionListItemPrize}
|
||||||
orderParams={orderParams}
|
orderParams={orderParams}
|
||||||
orderBy={this.state.currentUser.is_jury ? 'rating' : null}
|
orderBy={this.state.currentUser.is_jury ? 'rating' : null}
|
||||||
filterParams={[]}
|
filterParams={[]}
|
||||||
customSubmitButton={this.getButtonSubmit()}/>
|
customSubmitButton={this.getButtonSubmit()}
|
||||||
|
location={this.props.location}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@ import SignupForm from '../../../ascribe_forms/form_signup';
|
|||||||
import { getLangText } from '../../../../utils/lang_utils';
|
import { getLangText } from '../../../../utils/lang_utils';
|
||||||
|
|
||||||
let SignupContainer = React.createClass({
|
let SignupContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {
|
return {
|
||||||
submitted: false,
|
submitted: false,
|
||||||
@ -35,7 +39,8 @@ let SignupContainer = React.createClass({
|
|||||||
<SignupForm
|
<SignupForm
|
||||||
headerMessage={getLangText('Create account for submission')}
|
headerMessage={getLangText('Create account for submission')}
|
||||||
submitMessage={getLangText('Sign up')}
|
submitMessage={getLangText('Sign up')}
|
||||||
handleSuccess={this.handleSuccess} />
|
handleSuccess={this.handleSuccess}
|
||||||
|
location={this.props.location}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,44 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
import Hero from './components/prize_hero';
|
import Hero from './components/prize_hero';
|
||||||
import Header from '../../header';
|
import Header from '../../header';
|
||||||
import Footer from '../../footer';
|
import Footer from '../../footer';
|
||||||
import GlobalNotification from '../../global_notification';
|
import GlobalNotification from '../../global_notification';
|
||||||
|
|
||||||
import getRoutes from './prize_routes';
|
|
||||||
|
|
||||||
import { getSubdomain } from '../../../utils/general_utils';
|
import { getSubdomain } from '../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
let RouteHandler = Router.RouteHandler;
|
|
||||||
|
|
||||||
let PrizeApp = React.createClass({
|
let PrizeApp = React.createClass({
|
||||||
mixins: [Router.State],
|
propTypes: {
|
||||||
|
children: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
|
React.PropTypes.element
|
||||||
|
]),
|
||||||
|
history: React.PropTypes.object,
|
||||||
|
routes: React.PropTypes.arrayOf(React.PropTypes.object)
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { history, routes } = this.props;
|
||||||
let header = null;
|
let header = null;
|
||||||
let subdomain = getSubdomain();
|
let subdomain = getSubdomain();
|
||||||
|
|
||||||
let ROUTES = getRoutes(null, subdomain);
|
// The second element of routes is always the active component object, where we can
|
||||||
|
// extract the path.
|
||||||
|
let path = routes[1] ? routes[1].path : null;
|
||||||
|
|
||||||
if (this.isActive('landing') || this.isActive('login') || this.isActive('signup')) {
|
// if the path of the current activeRoute is not defined, then this is the IndexRoute
|
||||||
|
if (!path || history.isActive('/login') || history.isActive('/signup')) {
|
||||||
header = <Hero />;
|
header = <Hero />;
|
||||||
} else {
|
} else {
|
||||||
header = <Header showAddWork={false} routes={ROUTES}/>;
|
header = <Header showAddWork={false} routes={routes}/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'container ascribe-prize-app client--' + subdomain}>
|
<div className={'container ascribe-prize-app client--' + subdomain}>
|
||||||
{header}
|
{header}
|
||||||
<RouteHandler />
|
{this.props.children}
|
||||||
<GlobalNotification />
|
<GlobalNotification />
|
||||||
<div id="modal" className="container"></div>
|
<div id="modal" className="container"></div>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Route, IndexRoute } from 'react-router';
|
||||||
|
|
||||||
import Landing from './components/prize_landing';
|
import Landing from './components/prize_landing';
|
||||||
import LoginContainer from './components/prize_login_container';
|
import LoginContainer from './components/prize_login_container';
|
||||||
@ -17,28 +17,42 @@ import CoaVerifyContainer from '../../../components/coa_verify_container';
|
|||||||
import ErrorNotFoundPage from '../../../components/error_not_found_page';
|
import ErrorNotFoundPage from '../../../components/error_not_found_page';
|
||||||
|
|
||||||
import App from './prize_app';
|
import App from './prize_app';
|
||||||
import AppConstants from '../../../constants/application_constants';
|
|
||||||
|
|
||||||
let Route = Router.Route;
|
import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
|
||||||
let NotFoundRoute = Router.NotFoundRoute;
|
|
||||||
let baseUrl = AppConstants.baseUrl;
|
|
||||||
|
|
||||||
|
|
||||||
function getRoutes() {
|
function getRoutes() {
|
||||||
return (
|
return (
|
||||||
<Route name="app" path={baseUrl} handler={App}>
|
<Route path='/' component={App}>
|
||||||
<Route name="landing" path={baseUrl} handler={Landing} />
|
<IndexRoute component={Landing} />
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
<Route
|
||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
path='login'
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(LoginContainer)} />
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
<Route
|
||||||
<Route name="register_piece" path="register_piece" handler={PrizeRegisterPiece} headerTitle="+ NEW WORK" />
|
path='logout'
|
||||||
<Route name="pieces" path="collection" handler={PrizePieceList} headerTitle="COLLECTION" />
|
component={AuthProxyHandler({to: '/', when: 'loggedOut'})(LogoutContainer)}/>
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={PrizePieceContainer} />
|
<Route
|
||||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
path='signup'
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SignupContainer)} />
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
<Route
|
||||||
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
|
path='password_reset'
|
||||||
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(PasswordResetContainer)} />
|
||||||
|
<Route
|
||||||
|
path='settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SettingsContainer)}/>
|
||||||
|
<Route
|
||||||
|
path='register_piece'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(PrizeRegisterPiece)}
|
||||||
|
headerTitle='+ NEW WORK'/>
|
||||||
|
<Route
|
||||||
|
path='collection'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(PrizePieceList)}
|
||||||
|
headerTitle='COLLECTION'/>
|
||||||
|
|
||||||
|
<Route path='pieces/:pieceId' component={PrizePieceContainer} />
|
||||||
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
|
<Route path='*' component={ErrorNotFoundPage} />
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ import { getLangText } from '../../../../../utils/lang_utils';
|
|||||||
import { mergeOptions } from '../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
|
|
||||||
let CCRegisterPiece = React.createClass({
|
let CCRegisterPiece = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -82,7 +85,8 @@ let CCRegisterPiece = React.createClass({
|
|||||||
<RegisterPiece
|
<RegisterPiece
|
||||||
enableLocalHashing={false}
|
enableLocalHashing={false}
|
||||||
headerMessage={getLangText('Register under a Creative Commons license')}
|
headerMessage={getLangText('Register under a Creative Commons license')}
|
||||||
submitMessage={getLangText('Submit')}>
|
submitMessage={getLangText('Submit')}
|
||||||
|
location={this.props.location}>
|
||||||
{this.getLicenses()}
|
{this.getLicenses()}
|
||||||
</RegisterPiece>
|
</RegisterPiece>
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
|
import WhitelabelActions from '../../../../../../actions/whitelabel_actions';
|
||||||
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
|
import WhitelabelStore from '../../../../../../stores/whitelabel_store';
|
||||||
@ -37,29 +39,21 @@ let CylandSubmitButton = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let piece = this.props.piece;
|
const { piece, className } = this.props;
|
||||||
let startFrom = 1;
|
|
||||||
|
|
||||||
// In the Cyland register page a user has to complete three steps.
|
|
||||||
// Since every one of those steps is atomic a user should always be able to continue
|
|
||||||
// where he left of.
|
|
||||||
// This is why we start the process form slide 1/2 if the user has already finished
|
|
||||||
// it in another session.
|
|
||||||
if(piece && piece.extra_data && Object.keys(piece.extra_data).length > 0) {
|
|
||||||
startFrom = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonLink
|
<LinkContainer
|
||||||
to="register_piece"
|
to="/register_piece"
|
||||||
query={{
|
query={{
|
||||||
'slide_num': 0,
|
'slide_num': 0,
|
||||||
'start_from': startFrom,
|
'start_from': 1,
|
||||||
'piece_id': this.props.piece.id
|
'piece_id': piece.id
|
||||||
}}
|
}}>
|
||||||
className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
|
<Button
|
||||||
{getLangText('Submit to Cyland')}
|
className={classNames('btn', 'btn-default', 'btn-xs', className)}>
|
||||||
</ButtonLink>
|
{getLangText('Submit to Cyland')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -22,6 +22,7 @@ import { mergeOptions } from '../../../../../../utils/general_utils';
|
|||||||
|
|
||||||
let CylandPieceContainer = React.createClass({
|
let CylandPieceContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
location: React.PropTypes.object,
|
||||||
params: React.PropTypes.object
|
params: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -72,7 +73,8 @@ let CylandPieceContainer = React.createClass({
|
|||||||
<CylandAdditionalDataForm
|
<CylandAdditionalDataForm
|
||||||
piece={this.state.piece}
|
piece={this.state.piece}
|
||||||
disabled={!this.state.piece.acl.acl_edit}
|
disabled={!this.state.piece.acl.acl_edit}
|
||||||
isInline={true} />
|
isInline={true}
|
||||||
|
location={this.props.location}/>
|
||||||
</CollapsibleParagraph>
|
</CollapsibleParagraph>
|
||||||
</WalletPieceContainer>
|
</WalletPieceContainer>
|
||||||
);
|
);
|
||||||
|
@ -26,7 +26,8 @@ let CylandAdditionalDataForm = React.createClass({
|
|||||||
handleSuccess: React.PropTypes.func,
|
handleSuccess: React.PropTypes.func,
|
||||||
piece: React.PropTypes.object.isRequired,
|
piece: React.PropTypes.object.isRequired,
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
isInline: React.PropTypes.bool
|
isInline: React.PropTypes.bool,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
@ -142,7 +143,8 @@ let CylandAdditionalDataForm = React.createClass({
|
|||||||
isReadyForFormSubmission={formSubmissionValidation.fileOptional}
|
isReadyForFormSubmission={formSubmissionValidation.fileOptional}
|
||||||
pieceId={piece.id}
|
pieceId={piece.id}
|
||||||
otherData={piece.other_data}
|
otherData={piece.other_data}
|
||||||
multiple={true}/>
|
multiple={true}
|
||||||
|
location={this.props.location}/>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
|
|
||||||
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
|
import WhitelabelActions from '../../../../../actions/whitelabel_actions';
|
||||||
import WhitelabelStore from '../../../../../stores/whitelabel_store';
|
import WhitelabelStore from '../../../../../stores/whitelabel_store';
|
||||||
|
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import UserStore from '../../../../../stores/user_store';
|
import UserStore from '../../../../../stores/user_store';
|
||||||
import UserActions from '../../../../../actions/user_actions';
|
import UserActions from '../../../../../actions/user_actions';
|
||||||
@ -16,7 +19,7 @@ import { getLangText } from '../../../../../utils/lang_utils';
|
|||||||
|
|
||||||
let CylandLanding = React.createClass({
|
let CylandLanding = React.createClass({
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -43,7 +46,7 @@ let CylandLanding = React.createClass({
|
|||||||
// if user is already logged in, redirect him to piece list
|
// if user is already logged in, redirect him to piece list
|
||||||
if(this.state.currentUser && this.state.currentUser.email) {
|
if(this.state.currentUser && this.state.currentUser.email) {
|
||||||
// FIXME: hack to redirect out of the dispatch cycle
|
// FIXME: hack to redirect out of the dispatch cycle
|
||||||
window.setTimeout(() => this.replaceWith('pieces'), 0);
|
window.setTimeout(() => this.history.replaceState(null, '/collection'), 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -67,17 +70,21 @@ let CylandLanding = React.createClass({
|
|||||||
<p>
|
<p>
|
||||||
{getLangText('Existing ascribe user?')}
|
{getLangText('Existing ascribe user?')}
|
||||||
</p>
|
</p>
|
||||||
<ButtonLink to="login">
|
<LinkContainer to="/login">
|
||||||
{getLangText('Log in')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Log in')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6">
|
<div className="col-sm-6">
|
||||||
<p>
|
<p>
|
||||||
{getLangText('Do you need an account?')}
|
{getLangText('Do you need an account?')}
|
||||||
</p>
|
</p>
|
||||||
<ButtonLink to="signup">
|
<LinkContainer to="/signup">
|
||||||
{getLangText('Sign up')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('Sign up')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,10 @@ import { getLangText } from '../../../../../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let CylandPieceList = React.createClass({
|
let CylandPieceList = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
},
|
},
|
||||||
@ -33,7 +37,7 @@ let CylandPieceList = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PieceList
|
<PieceList
|
||||||
redirectTo="register_piece"
|
redirectTo="/register_piece?slide_num=0"
|
||||||
accordionListItemType={CylandAccordionListItem}
|
accordionListItemType={CylandAccordionListItem}
|
||||||
filterParams={[{
|
filterParams={[{
|
||||||
label: getLangText('Show works I have'),
|
label: getLangText('Show works I have'),
|
||||||
@ -42,7 +46,7 @@ let CylandPieceList = React.createClass({
|
|||||||
label: getLangText('loaned to Cyland')
|
label: getLangText('loaned to Cyland')
|
||||||
}]
|
}]
|
||||||
}]}
|
}]}
|
||||||
/>
|
location={this.props.location}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
|
|
||||||
@ -39,8 +39,11 @@ import { getAclFormMessage } from '../../../../../utils/form_utils';
|
|||||||
|
|
||||||
|
|
||||||
let CylandRegisterPiece = React.createClass({
|
let CylandRegisterPiece = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState(){
|
getInitialState(){
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -63,7 +66,7 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
UserActions.fetchCurrentUser();
|
UserActions.fetchCurrentUser();
|
||||||
WhitelabelActions.fetchWhitelabel();
|
WhitelabelActions.fetchWhitelabel();
|
||||||
|
|
||||||
let queryParams = this.getQuery();
|
let queryParams = this.props.location.query;
|
||||||
|
|
||||||
// Since every step of this register process is atomic,
|
// Since every step of this register process is atomic,
|
||||||
// we may need to enter the process at step 1 or 2.
|
// we may need to enter the process at step 1 or 2.
|
||||||
@ -101,12 +104,13 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
|
|
||||||
// also start loading the piece for the next step
|
// also start loading the piece for the next step
|
||||||
if(response && response.piece) {
|
if(response && response.piece) {
|
||||||
|
PieceActions.updatePiece({});
|
||||||
PieceActions.updatePiece(response.piece);
|
PieceActions.updatePiece(response.piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.incrementStep();
|
this.incrementStep();
|
||||||
|
|
||||||
this.refs.slidesContainer.nextSlide();
|
this.refs.slidesContainer.nextSlide({ piece_id: response.piece.id });
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAdditionalDataSuccess() {
|
handleAdditionalDataSuccess() {
|
||||||
@ -130,7 +134,8 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
this.refreshPieceList();
|
this.refreshPieceList();
|
||||||
|
|
||||||
PieceActions.fetchOne(this.state.piece.id);
|
PieceActions.fetchOne(this.state.piece.id);
|
||||||
this.transitionTo('piece', {pieceId: this.state.piece.id});
|
|
||||||
|
this.history.pushState(null, `/pieces/${this.state.piece.id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
// We need to increase the step to lock the forms that are already filled out
|
// We need to increase the step to lock the forms that are already filled out
|
||||||
@ -163,7 +168,7 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
|
|
||||||
// basically redirects to the second slide (index: 1), when the user is not logged in
|
// basically redirects to the second slide (index: 1), when the user is not logged in
|
||||||
onLoggedOut() {
|
onLoggedOut() {
|
||||||
this.transitionTo('login');
|
this.history.pushState(null, '/login');
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -179,7 +184,8 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
glyphiconClassNames={{
|
glyphiconClassNames={{
|
||||||
pending: 'glyphicon glyphicon-chevron-right',
|
pending: 'glyphicon glyphicon-chevron-right',
|
||||||
completed: 'glyphicon glyphicon-lock'
|
completed: 'glyphicon glyphicon-lock'
|
||||||
}}>
|
}}
|
||||||
|
location={this.props.location}>
|
||||||
<div data-slide-title={getLangText('Register work')}>
|
<div data-slide-title={getLangText('Register work')}>
|
||||||
<Row className="no-margin">
|
<Row className="no-margin">
|
||||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||||
@ -190,7 +196,8 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
submitMessage={getLangText('Submit')}
|
submitMessage={getLangText('Submit')}
|
||||||
isFineUploaderActive={this.state.isFineUploaderActive}
|
isFineUploaderActive={this.state.isFineUploaderActive}
|
||||||
handleSuccess={this.handleRegisterSuccess}
|
handleSuccess={this.handleRegisterSuccess}
|
||||||
onLoggedOut={this.onLoggedOut} />
|
onLoggedOut={this.onLoggedOut}
|
||||||
|
location={this.props.location}/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
@ -200,7 +207,8 @@ let CylandRegisterPiece = React.createClass({
|
|||||||
<CylandAdditionalDataForm
|
<CylandAdditionalDataForm
|
||||||
disabled={this.state.step > 1}
|
disabled={this.state.step > 1}
|
||||||
handleSuccess={this.handleAdditionalDataSuccess}
|
handleSuccess={this.handleAdditionalDataSuccess}
|
||||||
piece={this.state.piece}/>
|
piece={this.state.piece}
|
||||||
|
location={this.props.location}/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
|
||||||
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import { getLangText } from '../../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../../utils/lang_utils';
|
||||||
|
|
||||||
@ -32,16 +35,18 @@ let IkonotvSubmitButton = React.createClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonLink
|
<LinkContainer
|
||||||
to="register_piece"
|
to="/register_piece"
|
||||||
query={{
|
query={{
|
||||||
'slide_num': 0,
|
'slide_num': 0,
|
||||||
'start_from': startFrom,
|
'start_from': startFrom,
|
||||||
'piece_id': piece.id
|
'piece_id': piece.id
|
||||||
}}
|
}}>
|
||||||
className={classNames('ascribe-margin-1px', this.props.className)}>
|
<Button
|
||||||
{getLangText('Loan to IkonoTV')}
|
className={classNames('ascribe-margin-1px', this.props.className)}>
|
||||||
</ButtonLink>
|
{getLangText('Loan to IkonoTV')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||||
import Button from 'react-bootstrap/lib/Button';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
@ -29,11 +29,10 @@ import AppConstants from '../../../../../constants/application_constants';
|
|||||||
import { getLangText } from '../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../utils/lang_utils';
|
||||||
import { mergeOptions } from '../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../utils/general_utils';
|
||||||
|
|
||||||
let Navigation = Router.Navigation;
|
|
||||||
|
|
||||||
let IkonotvContractNotifications = React.createClass({
|
let IkonotvContractNotifications = React.createClass({
|
||||||
|
|
||||||
mixins: [Navigation],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -114,7 +113,7 @@ let IkonotvContractNotifications = React.createClass({
|
|||||||
handleConfirmSuccess() {
|
handleConfirmSuccess() {
|
||||||
let notification = new GlobalNotificationModel(getLangText('You have accepted the conditions'), 'success', 5000);
|
let notification = new GlobalNotificationModel(getLangText('You have accepted the conditions'), 'success', 5000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
this.transitionTo('pieces');
|
this.history.pushState(null, '/collection');
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDeny() {
|
handleDeny() {
|
||||||
@ -127,7 +126,7 @@ let IkonotvContractNotifications = React.createClass({
|
|||||||
handleDenySuccess() {
|
handleDenySuccess() {
|
||||||
let notification = new GlobalNotificationModel(getLangText('You have denied the conditions'), 'success', 5000);
|
let notification = new GlobalNotificationModel(getLangText('You have denied the conditions'), 'success', 5000);
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
this.transitionTo('pieces');
|
this.history.pushState(null, '/collection');
|
||||||
},
|
},
|
||||||
|
|
||||||
getCopyrightAssociationForm(){
|
getCopyrightAssociationForm(){
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
|
|
||||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
import Button from 'react-bootstrap/lib/Button';
|
||||||
|
|
||||||
|
import LinkContainer from 'react-router-bootstrap/lib/LinkContainer';
|
||||||
|
|
||||||
import UserStore from '../../../../../stores/user_store';
|
import UserStore from '../../../../../stores/user_store';
|
||||||
import UserActions from '../../../../../actions/user_actions';
|
import UserActions from '../../../../../actions/user_actions';
|
||||||
@ -12,8 +13,9 @@ import { getLangText } from '../../../../../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let IkonotvLanding = React.createClass({
|
let IkonotvLanding = React.createClass({
|
||||||
|
propTypes: {
|
||||||
mixins: [Router.Navigation, Router.State],
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
@ -33,18 +35,21 @@ let IkonotvLanding = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getEnterButton() {
|
getEnterButton() {
|
||||||
let redirect = 'login';
|
let redirect = '/login';
|
||||||
|
|
||||||
if(this.state.currentUser && this.state.currentUser.email) {
|
if(this.state.currentUser && this.state.currentUser.email) {
|
||||||
redirect = 'pieces';
|
redirect = '/collection';
|
||||||
}
|
}
|
||||||
else if (this.getQuery() && this.getQuery().redirect) {
|
else if (this.props.location.query && this.props.location.query.redirect) {
|
||||||
redirect = this.getQuery().redirect;
|
redirect = '/' + this.props.location.query.redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonLink to={redirect} query={this.getQuery()}>
|
<LinkContainer to={redirect} query={this.props.location.query}>
|
||||||
{getLangText('ENTER TO START')}
|
<Button>
|
||||||
</ButtonLink>
|
{getLangText('ENTER TO START')}
|
||||||
|
</Button>
|
||||||
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ import { getLangText } from '../../../../../utils/lang_utils';
|
|||||||
|
|
||||||
|
|
||||||
let IkonotvPieceList = React.createClass({
|
let IkonotvPieceList = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return UserStore.getState();
|
return UserStore.getState();
|
||||||
},
|
},
|
||||||
@ -33,7 +37,7 @@ let IkonotvPieceList = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PieceList
|
<PieceList
|
||||||
redirectTo="register_piece"
|
redirectTo="/register_piece?slide_num=0"
|
||||||
accordionListItemType={IkonotvAccordionListItem}
|
accordionListItemType={IkonotvAccordionListItem}
|
||||||
filterParams={[{
|
filterParams={[{
|
||||||
label: getLangText('Show works I have'),
|
label: getLangText('Show works I have'),
|
||||||
@ -47,7 +51,8 @@ let IkonotvPieceList = React.createClass({
|
|||||||
label: getLangText('loaned')
|
label: getLangText('loaned')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]}/>
|
}]}
|
||||||
|
location={this.props.location}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
import Router from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
import Col from 'react-bootstrap/lib/Col';
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
import Row from 'react-bootstrap/lib/Row';
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
@ -33,13 +33,13 @@ import { mergeOptions } from '../../../../../utils/general_utils';
|
|||||||
import { getLangText } from '../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../utils/lang_utils';
|
||||||
|
|
||||||
let IkonotvRegisterPiece = React.createClass({
|
let IkonotvRegisterPiece = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
handleSuccess: React.PropTypes.func,
|
handleSuccess: React.PropTypes.func,
|
||||||
piece: React.PropTypes.object.isRequired
|
piece: React.PropTypes.object.isRequired,
|
||||||
|
location: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation, Router.State],
|
mixins: [History],
|
||||||
|
|
||||||
getInitialState(){
|
getInitialState(){
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
@ -61,7 +61,7 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
// not want to display to the user.
|
// not want to display to the user.
|
||||||
PieceActions.updatePiece({});
|
PieceActions.updatePiece({});
|
||||||
|
|
||||||
let queryParams = this.getQuery();
|
let queryParams = this.props.location.query;
|
||||||
|
|
||||||
// Since every step of this register process is atomic,
|
// Since every step of this register process is atomic,
|
||||||
// we may need to enter the process at step 1 or 2.
|
// we may need to enter the process at step 1 or 2.
|
||||||
@ -102,7 +102,7 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
PieceActions.updatePiece(response.piece);
|
PieceActions.updatePiece(response.piece);
|
||||||
}
|
}
|
||||||
if (!this.canSubmit()) {
|
if (!this.canSubmit()) {
|
||||||
this.transitionTo('pieces');
|
this.history.pushState(null, '/collection');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.incrementStep();
|
this.incrementStep();
|
||||||
@ -132,7 +132,7 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
this.refreshPieceList();
|
this.refreshPieceList();
|
||||||
|
|
||||||
PieceActions.fetchOne(this.state.piece.id);
|
PieceActions.fetchOne(this.state.piece.id);
|
||||||
this.transitionTo('piece', {pieceId: this.state.piece.id});
|
this.history.pushState(null, `/pieces/${this.state.piece.id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
// We need to increase the step to lock the forms that are already filled out
|
// We need to increase the step to lock the forms that are already filled out
|
||||||
@ -165,7 +165,7 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
|
|
||||||
// basically redirects to the second slide (index: 1), when the user is not logged in
|
// basically redirects to the second slide (index: 1), when the user is not logged in
|
||||||
onLoggedOut() {
|
onLoggedOut() {
|
||||||
this.transitionTo('login');
|
this.history.pushState(null, '/login');
|
||||||
},
|
},
|
||||||
|
|
||||||
canSubmit() {
|
canSubmit() {
|
||||||
@ -245,7 +245,8 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
glyphiconClassNames={{
|
glyphiconClassNames={{
|
||||||
pending: 'glyphicon glyphicon-chevron-right',
|
pending: 'glyphicon glyphicon-chevron-right',
|
||||||
completed: 'glyphicon glyphicon-lock'
|
completed: 'glyphicon glyphicon-lock'
|
||||||
}}>
|
}}
|
||||||
|
location={this.props.location}>
|
||||||
<div data-slide-title={getLangText('Register work')}>
|
<div data-slide-title={getLangText('Register work')}>
|
||||||
<Row className="no-margin">
|
<Row className="no-margin">
|
||||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||||
@ -256,7 +257,8 @@ let IkonotvRegisterPiece = React.createClass({
|
|||||||
submitMessage={getLangText('Register')}
|
submitMessage={getLangText('Register')}
|
||||||
isFineUploaderActive={this.state.isFineUploaderActive}
|
isFineUploaderActive={this.state.isFineUploaderActive}
|
||||||
handleSuccess={this.handleRegisterSuccess}
|
handleSuccess={this.handleRegisterSuccess}
|
||||||
onLoggedOut={this.onLoggedOut} />
|
onLoggedOut={this.onLoggedOut}
|
||||||
|
location={this.props.location}/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import ContractAgreementForm from '../../../../ascribe_forms/form_contract_agreement';
|
|
||||||
|
|
||||||
|
|
||||||
let IkonotvRequestLoan = React.createClass({
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ContractAgreementForm />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default IkonotvRequestLoan;
|
|
@ -1,43 +1,50 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
|
||||||
import Header from '../../header';
|
import Header from '../../header';
|
||||||
import Footer from '../../footer';
|
import Footer from '../../footer';
|
||||||
|
|
||||||
import GlobalNotification from '../../global_notification';
|
import GlobalNotification from '../../global_notification';
|
||||||
|
|
||||||
import getRoutes from './wallet_routes';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { getSubdomain } from '../../../utils/general_utils';
|
import { getSubdomain } from '../../../utils/general_utils';
|
||||||
|
|
||||||
|
|
||||||
let RouteHandler = Router.RouteHandler;
|
|
||||||
|
|
||||||
|
|
||||||
let WalletApp = React.createClass({
|
let WalletApp = React.createClass({
|
||||||
mixins: [Router.State],
|
propTypes: {
|
||||||
|
children: React.PropTypes.oneOfType([
|
||||||
|
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||||
|
React.PropTypes.element
|
||||||
|
]),
|
||||||
|
history: React.PropTypes.object,
|
||||||
|
routes: React.PropTypes.arrayOf(React.PropTypes.object)
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let subdomain = getSubdomain();
|
|
||||||
let ROUTES = getRoutes(null, subdomain);
|
|
||||||
let activeRoutes = this.getRoutes().map(elem => 'route--' + elem.name);
|
|
||||||
|
|
||||||
let header = null;
|
let header = null;
|
||||||
if ((this.isActive('landing') || this.isActive('login') || this.isActive('signup') || this.isActive('contract_notifications'))
|
let subdomain = getSubdomain();
|
||||||
|
const { history, routes, children } = this.props;
|
||||||
|
|
||||||
|
// The second element of routes is always the active component object, where we can
|
||||||
|
// extract the path.
|
||||||
|
let path = routes[1] ? routes[1].path : null;
|
||||||
|
|
||||||
|
// if the path of the current activeRoute is not defined, then this is the IndexRoute
|
||||||
|
if ((!path || history.isActive('/login') || history.isActive('/signup') || history.isActive('/contract_notifications'))
|
||||||
&& (['ikonotv']).indexOf(subdomain) > -1) {
|
&& (['ikonotv']).indexOf(subdomain) > -1) {
|
||||||
header = (
|
header = (<div className="hero"/>);
|
||||||
<div className="hero"/>);
|
|
||||||
} else {
|
} else {
|
||||||
header = <Header showAddWork={true} routes={ROUTES} />;
|
header = <Header showAddWork={true} routes={routes} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In react-router 1.0, Routes have no 'name' property anymore. To keep functionality however,
|
||||||
|
// we split the path by the first occurring slash and take the first splitter.
|
||||||
return (
|
return (
|
||||||
<div className={classNames('ascribe-wallet-app', activeRoutes)}>
|
<div className={classNames('ascribe-wallet-app', 'route--' + (path ? path.split('/')[0] : 'landing'))}>
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
{header}
|
{header}
|
||||||
<RouteHandler />
|
{children}
|
||||||
<GlobalNotification />
|
<GlobalNotification />
|
||||||
<div id="modal" className="container"></div>
|
<div id="modal" className="container"></div>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Route, IndexRoute } from 'react-router';
|
||||||
|
|
||||||
// general components
|
// general components
|
||||||
import CoaVerifyContainer from '../../../components/coa_verify_container';
|
import CoaVerifyContainer from '../../../components/coa_verify_container';
|
||||||
@ -23,74 +23,130 @@ import CylandPieceList from './components/cyland/cyland_piece_list';
|
|||||||
|
|
||||||
import IkonotvLanding from './components/ikonotv/ikonotv_landing';
|
import IkonotvLanding from './components/ikonotv/ikonotv_landing';
|
||||||
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
|
import IkonotvPieceList from './components/ikonotv/ikonotv_piece_list';
|
||||||
import IkonotvRequestLoan from './components/ikonotv/ikonotv_request_loan';
|
import ContractAgreementForm from '../../../components/ascribe_forms/form_contract_agreement';
|
||||||
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
|
import IkonotvRegisterPiece from './components/ikonotv/ikonotv_register_piece';
|
||||||
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
|
import IkonotvPieceContainer from './components/ikonotv/ikonotv_detail/ikonotv_piece_container';
|
||||||
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
|
import IkonotvContractNotifications from './components/ikonotv/ikonotv_contract_notifications';
|
||||||
|
|
||||||
import CCRegisterPiece from './components/cc/cc_register_piece';
|
import CCRegisterPiece from './components/cc/cc_register_piece';
|
||||||
|
|
||||||
import WalletApp from './wallet_app';
|
import AuthProxyHandler from '../../../components/ascribe_routes/proxy_routes/auth_proxy_handler';
|
||||||
import AppConstants from '../../../constants/application_constants';
|
|
||||||
|
|
||||||
let Route = Router.Route;
|
import WalletApp from './wallet_app';
|
||||||
let NotFoundRoute = Router.NotFoundRoute;
|
|
||||||
let Redirect = Router.Redirect;
|
|
||||||
let baseUrl = AppConstants.baseUrl;
|
|
||||||
|
|
||||||
|
|
||||||
let ROUTES = {
|
let ROUTES = {
|
||||||
'cyland': (
|
'cyland': (
|
||||||
<Route name="app" path={baseUrl} handler={WalletApp}>
|
<Route path='/' component={WalletApp}>
|
||||||
<Route name="landing" path={baseUrl} handler={CylandLanding} />
|
<IndexRoute component={CylandLanding} />
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
<Route
|
||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
path='login'
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(LoginContainer)} />
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
<Route
|
||||||
<Route name="register_piece" path="register_piece" handler={CylandRegisterPiece} headerTitle="+ NEW WORK" />
|
path='logout'
|
||||||
<Route name="pieces" path="collection" handler={CylandPieceList} headerTitle="COLLECTION" />
|
component={AuthProxyHandler({to: '/', when: 'loggedOut'})(LogoutContainer)}/>
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={CylandPieceContainer} />
|
<Route
|
||||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
path='signup'
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SignupContainer)} />
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
<Route
|
||||||
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
|
path='password_reset'
|
||||||
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(PasswordResetContainer)} />
|
||||||
|
<Route
|
||||||
|
path='settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SettingsContainer)}/>
|
||||||
|
<Route
|
||||||
|
path='contract_settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
|
||||||
|
<Route
|
||||||
|
path='register_piece'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(CylandRegisterPiece)}
|
||||||
|
headerTitle='+ NEW WORK'/>
|
||||||
|
<Route
|
||||||
|
path='collection'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(CylandPieceList)}
|
||||||
|
headerTitle='COLLECTION'/>
|
||||||
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
|
<Route path='pieces/:pieceId' component={CylandPieceContainer} />
|
||||||
|
<Route path='*' component={ErrorNotFoundPage} />
|
||||||
</Route>
|
</Route>
|
||||||
),
|
),
|
||||||
'cc': (
|
'cc': (
|
||||||
<Route name="app" path={baseUrl} handler={WalletApp}>
|
<Route path='/' component={WalletApp}>
|
||||||
<Redirect from={baseUrl} to="login" />
|
<Route
|
||||||
<Redirect from={baseUrl + '/'} to="login" />
|
path='login'
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(LoginContainer)} />
|
||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
<Route
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
path='logout'
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
component={AuthProxyHandler({to: '/', when: 'loggedOut'})(LogoutContainer)}/>
|
||||||
<Route name="register_piece" path="register_piece" handler={CCRegisterPiece} headerTitle="+ NEW WORK" />
|
<Route
|
||||||
<Route name="pieces" path="collection" handler={PieceList} headerTitle="COLLECTION" />
|
path='signup'
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={PieceContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SignupContainer)} />
|
||||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
<Route
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
path='password_reset'
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(PasswordResetContainer)} />
|
||||||
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
|
<Route
|
||||||
|
path='settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SettingsContainer)}/>
|
||||||
|
<Route
|
||||||
|
path='contract_settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
|
||||||
|
<Route
|
||||||
|
path='register_piece'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(CCRegisterPiece)}
|
||||||
|
headerTitle='+ NEW WORK'/>
|
||||||
|
<Route
|
||||||
|
path='collection'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(PieceList)}
|
||||||
|
headerTitle='COLLECTION'/>
|
||||||
|
<Route path='pieces/:pieceId' component={PieceContainer} />
|
||||||
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
|
<Route path='*' component={ErrorNotFoundPage} />
|
||||||
</Route>
|
</Route>
|
||||||
),
|
),
|
||||||
'ikonotv': (
|
'ikonotv': (
|
||||||
<Route name="app" path={baseUrl} handler={WalletApp}>
|
<Route path='/' component={WalletApp}>
|
||||||
<Route name="landing" path={baseUrl} handler={IkonotvLanding} />
|
<IndexRoute component={IkonotvLanding} />
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
<Route
|
||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
path='login'
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(LoginContainer)} />
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
<Route
|
||||||
<Route name="request_loan" path="request_loan" handler={IkonotvRequestLoan} headerTitle="SEND NEW CONTRACT" aclName="acl_create_contractagreement" />
|
path='logout'
|
||||||
<Route name="register_piece" path="register_piece" handler={IkonotvRegisterPiece} headerTitle="+ NEW WORK" aclName="acl_create_piece"/>
|
component={AuthProxyHandler({to: '/', when: 'loggedOut'})(LogoutContainer)}/>
|
||||||
<Route name="pieces" path="collection" handler={IkonotvPieceList} headerTitle="COLLECTION"/>
|
<Route
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={IkonotvPieceContainer} />
|
path='signup'
|
||||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SignupContainer)} />
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
<Route
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
path='password_reset'
|
||||||
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(PasswordResetContainer)} />
|
||||||
<Route name="contract_notifications" path="contract_notifications" handler={IkonotvContractNotifications} />
|
<Route
|
||||||
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
|
path='settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SettingsContainer)}/>
|
||||||
|
<Route
|
||||||
|
path='contract_settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
|
||||||
|
<Route
|
||||||
|
path='request_loan'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractAgreementForm)}
|
||||||
|
headerTitle='SEND NEW CONTRACT'
|
||||||
|
aclName='acl_create_contractagreement'/>
|
||||||
|
<Route
|
||||||
|
path='register_piece'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(IkonotvRegisterPiece)}
|
||||||
|
headerTitle='+ NEW WORK'
|
||||||
|
aclName='acl_create_piece'/>
|
||||||
|
<Route
|
||||||
|
path='collection'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(IkonotvPieceList)}
|
||||||
|
headerTitle='COLLECTION'/>
|
||||||
|
<Route
|
||||||
|
path='contract_notifications'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(IkonotvContractNotifications)}/>
|
||||||
|
<Route path='pieces/:pieceId' component={IkonotvPieceContainer} />
|
||||||
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
|
<Route path='verify' component={CoaVerifyContainer} />
|
||||||
|
<Route path='*' component={ErrorNotFoundPage} />
|
||||||
</Route>
|
</Route>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -78,7 +78,8 @@ let constants = {
|
|||||||
'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA',
|
'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA',
|
||||||
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
|
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
|
||||||
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV',
|
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV',
|
||||||
'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA']
|
'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'],
|
||||||
|
'searchThreshold': 500
|
||||||
};
|
};
|
||||||
|
|
||||||
export default constants;
|
export default constants;
|
||||||
|
13
js/history.js
Normal file
13
js/history.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import useBasename from 'history/lib/useBasename';
|
||||||
|
import createBrowserHistory from 'history/lib/createBrowserHistory';
|
||||||
|
import AppConstants from './constants/application_constants';
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the trailing slash if present
|
||||||
|
let baseUrl = AppConstants.baseUrl.replace(/\/$/, '');
|
||||||
|
|
||||||
|
export default useBasename(createBrowserHistory)({
|
||||||
|
basename: baseUrl
|
||||||
|
});
|
57
js/routes.js
57
js/routes.js
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import { Route } from 'react-router';
|
||||||
|
|
||||||
import getPrizeRoutes from './components/whitelabel/prize/prize_routes';
|
import getPrizeRoutes from './components/whitelabel/prize/prize_routes';
|
||||||
import getWalletRoutes from './components/whitelabel/wallet/wallet_routes';
|
import getWalletRoutes from './components/whitelabel/wallet/wallet_routes';
|
||||||
@ -25,30 +25,41 @@ import ErrorNotFoundPage from './components/error_not_found_page';
|
|||||||
|
|
||||||
import RegisterPiece from './components/register_piece';
|
import RegisterPiece from './components/register_piece';
|
||||||
|
|
||||||
import AppConstants from './constants/application_constants';
|
import AuthProxyHandler from './components/ascribe_routes/proxy_routes/auth_proxy_handler';
|
||||||
|
|
||||||
let Route = Router.Route;
|
|
||||||
let NotFoundRoute = Router.NotFoundRoute;
|
|
||||||
let Redirect = Router.Redirect;
|
|
||||||
let baseUrl = AppConstants.baseUrl;
|
|
||||||
|
|
||||||
|
|
||||||
const COMMON_ROUTES = (
|
let COMMON_ROUTES = (
|
||||||
<Route name="app" path={baseUrl} handler={App}>
|
<Route path='/' component={App}>
|
||||||
<Redirect from={baseUrl} to="login" />
|
<Route
|
||||||
<Redirect from={baseUrl + '/'} to="login" />
|
path='login'
|
||||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(LoginContainer)} />
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
<Route
|
||||||
<Route name="logout" path="logout" handler={LogoutContainer} />
|
path='register_piece'
|
||||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} headerTitle="+ NEW WORK" />
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(RegisterPiece)}
|
||||||
<Route name="pieces" path="collection" handler={PieceList} headerTitle="COLLECTION" />
|
headerTitle='+ NEW WORK'/>
|
||||||
<Route name="piece" path="pieces/:pieceId" handler={PieceContainer} />
|
<Route
|
||||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
path='collection'
|
||||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(PieceList)}
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
headerTitle='COLLECTION'/>
|
||||||
<Route name="contract_settings" path="contract_settings" handler={ContractSettings} />
|
<Route
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
path='signup'
|
||||||
<NotFoundRoute name="notFound" handler={ErrorNotFoundPage} />
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(SignupContainer)} />
|
||||||
|
<Route
|
||||||
|
path='logout'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(LogoutContainer)}/>
|
||||||
|
<Route path='pieces/:pieceId' component={PieceContainer} />
|
||||||
|
<Route path='editions/:editionId' component={EditionContainer} />
|
||||||
|
<Route
|
||||||
|
path='password_reset'
|
||||||
|
component={AuthProxyHandler({to: '/collection', when: 'loggedIn'})(PasswordResetContainer)} />
|
||||||
|
<Route
|
||||||
|
path='settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(SettingsContainer)}/>
|
||||||
|
<Route
|
||||||
|
path='contract_settings'
|
||||||
|
component={AuthProxyHandler({to: '/login', when: 'loggedOut'})(ContractSettings)}/>
|
||||||
|
<Route path='coa_verify' component={CoaVerifyContainer} />
|
||||||
|
<Route path='*' component={ErrorNotFoundPage} />
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
7
js/third_party/notifications.js
vendored
7
js/third_party/notifications.js
vendored
@ -1,6 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import history from '../history';
|
||||||
import { altThirdParty } from '../alt';
|
import { altThirdParty } from '../alt';
|
||||||
|
|
||||||
|
|
||||||
import EventActions from '../actions/event_actions';
|
import EventActions from '../actions/event_actions';
|
||||||
|
|
||||||
import NotificationActions from '../actions/notification_actions';
|
import NotificationActions from '../actions/notification_actions';
|
||||||
@ -9,7 +12,6 @@ import { getSubdomain } from '../utils/general_utils';
|
|||||||
|
|
||||||
|
|
||||||
class NotificationsHandler {
|
class NotificationsHandler {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.bindActions(EventActions);
|
this.bindActions(EventActions);
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
@ -19,6 +21,7 @@ class NotificationsHandler {
|
|||||||
if (this.loaded) {
|
if (this.loaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let subdomain = getSubdomain();
|
let subdomain = getSubdomain();
|
||||||
if (subdomain === 'ikonotv') {
|
if (subdomain === 'ikonotv') {
|
||||||
NotificationActions.fetchContractAgreementListNotifications().then(
|
NotificationActions.fetchContractAgreementListNotifications().then(
|
||||||
@ -26,7 +29,7 @@ class NotificationsHandler {
|
|||||||
if (res.notifications && res.notifications.length > 0) {
|
if (res.notifications && res.notifications.length > 0) {
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
console.log('Contractagreement notifications loaded');
|
console.log('Contractagreement notifications loaded');
|
||||||
setTimeout(() => window.appRouter.transitionTo('contract_notifications'), 0);
|
history.pushState(null, '/contract_notifications');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -8,8 +8,8 @@ export function getSubdomainSettings(subdomain) {
|
|||||||
if(settings.length === 1) {
|
if(settings.length === 1) {
|
||||||
return settings[0];
|
return settings[0];
|
||||||
} else if(settings.length === 0) {
|
} else if(settings.length === 0) {
|
||||||
|
console.warn('There are no subdomain settings for the subdomain: ' + subdomain);
|
||||||
return appConstants.defaultDomain;
|
return appConstants.defaultDomain;
|
||||||
// throw new Error('There are no subdomain settings for the subdomain: ' + subdomain);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Matched multiple subdomains. Adjust constants file.');
|
throw new Error('Matched multiple subdomains. Adjust constants file.');
|
||||||
}
|
}
|
||||||
|
26
js/utils/feature_detection_utils.js
Normal file
26
js/utils/feature_detection_utils.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLEASE
|
||||||
|
*
|
||||||
|
* postfix your function with '-Available'.
|
||||||
|
*
|
||||||
|
* Like this:
|
||||||
|
*
|
||||||
|
* featureNameAvailable
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Even though it is not recommended to check (and maintain) the used browser,
|
||||||
|
* we're checking the browser's ability to drag and drop with this statement as
|
||||||
|
* there is no other way of detecting it another way.
|
||||||
|
*
|
||||||
|
* See this discussion for clarity:
|
||||||
|
* - https://github.com/Modernizr/Modernizr/issues/57#issuecomment-35831605
|
||||||
|
*
|
||||||
|
* @type {bool} Is drag and drop available on this browser
|
||||||
|
*/
|
||||||
|
export const dragAndDropAvailable = 'draggable' in document.createElement('div') &&
|
||||||
|
!/Mobile|Android|Slick\/|Kindle|BlackBerry|Opera Mini|Opera Mobi/i.test(navigator.userAgent);
|
12
package.json
12
package.json
@ -45,7 +45,7 @@
|
|||||||
"bootstrap-sass": "^3.3.4",
|
"bootstrap-sass": "^3.3.4",
|
||||||
"browser-sync": "^2.7.5",
|
"browser-sync": "^2.7.5",
|
||||||
"browserify": "^9.0.8",
|
"browserify": "^9.0.8",
|
||||||
"browserify-shim": "^3.8.9",
|
"browserify-shim": "^3.8.10",
|
||||||
"classnames": "^1.2.2",
|
"classnames": "^1.2.2",
|
||||||
"compression": "^1.4.4",
|
"compression": "^1.4.4",
|
||||||
"envify": "^3.4.0",
|
"envify": "^3.4.0",
|
||||||
@ -64,6 +64,8 @@
|
|||||||
"gulp-uglify": "^1.2.0",
|
"gulp-uglify": "^1.2.0",
|
||||||
"gulp-util": "^3.0.4",
|
"gulp-util": "^3.0.4",
|
||||||
"harmonize": "^1.4.2",
|
"harmonize": "^1.4.2",
|
||||||
|
"history": "^1.11.1",
|
||||||
|
"invariant": "^2.1.1",
|
||||||
"isomorphic-fetch": "^2.0.2",
|
"isomorphic-fetch": "^2.0.2",
|
||||||
"jest-cli": "^0.4.0",
|
"jest-cli": "^0.4.0",
|
||||||
"lodash": "^3.9.3",
|
"lodash": "^3.9.3",
|
||||||
@ -72,11 +74,11 @@
|
|||||||
"opn": "^3.0.2",
|
"opn": "^3.0.2",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"raven-js": "^1.1.19",
|
"raven-js": "^1.1.19",
|
||||||
"react": "^0.13.2",
|
"react": "0.13.2",
|
||||||
"react-bootstrap": "^0.25.1",
|
"react-bootstrap": "0.25.1",
|
||||||
"react-datepicker": "^0.12.0",
|
"react-datepicker": "^0.12.0",
|
||||||
"react-router": "^0.13.3",
|
"react-router": "^1.0.0-rc1",
|
||||||
"react-router-bootstrap": "~0.16.0",
|
"react-router-bootstrap": "^0.19.0",
|
||||||
"react-star-rating": "~1.3.2",
|
"react-star-rating": "~1.3.2",
|
||||||
"react-textarea-autosize": "^2.5.2",
|
"react-textarea-autosize": "^2.5.2",
|
||||||
"reactify": "^1.1.0",
|
"reactify": "^1.1.0",
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
.notification-contract-pdf, .notification-contract-footer {
|
.notification-contract-pdf, .notification-contract-footer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 750px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
.notification-contract-pdf {
|
.notification-contract-pdf {
|
||||||
@ -29,7 +28,8 @@
|
|||||||
border: 1px solid #cccccc;
|
border: 1px solid #cccccc;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 60vh;
|
height: 60vh;
|
||||||
margin-bottom: 0;
|
margin-top: .5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
.loan-form {
|
.loan-form {
|
||||||
margin-top: .5em;
|
margin-top: .5em;
|
||||||
|
Loading…
Reference in New Issue
Block a user