mirror of
https://github.com/ascribe/onion.git
synced 2025-02-14 21:10:27 +01:00
Merge branch 'AD-565-add-landing-page-for-sluice'
This commit is contained in:
commit
3b1fdba80f
@ -18,7 +18,7 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main" class="container"></div>
|
||||
<div id="main"></div>
|
||||
<script src="<%= BASE_URL %>static/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -7,7 +7,8 @@ import PieceFetcher from '../fetchers/piece_fetcher';
|
||||
class PieceActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'updatePiece'
|
||||
'updatePiece',
|
||||
'updateProperty'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,21 @@ class PieceListActions {
|
||||
}
|
||||
|
||||
fetchPieceList(page, pageSize, search, orderBy, orderAsc) {
|
||||
// To prevent flickering on a pagination request,
|
||||
// we overwrite the piecelist with an empty list before
|
||||
// pieceListCount === -1 defines the loading state
|
||||
this.actions.updatePieceList({
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
orderBy,
|
||||
orderAsc,
|
||||
'pieceList': [],
|
||||
'pieceListCount': -1
|
||||
});
|
||||
|
||||
// afterwards, we can load the list
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
PieceListFetcher
|
||||
.fetch(page, pageSize, search, orderBy, orderAsc)
|
||||
|
46
js/app.js
46
js/app.js
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
require("babel/polyfill");
|
||||
require('babel/polyfill');
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
@ -8,7 +8,8 @@ import Router from 'react-router';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
|
||||
import ApiUrls from './constants/api_urls';
|
||||
import routes from './routes';
|
||||
import constants from './constants/application_constants';
|
||||
import getRoutes from './routes';
|
||||
import requests from './utils/requests';
|
||||
|
||||
let headers = {
|
||||
@ -28,9 +29,38 @@ requests.defaults({
|
||||
}
|
||||
});
|
||||
|
||||
Router.run(routes, Router.HistoryLocation, (AscribeApp) => {
|
||||
React.render(
|
||||
<AscribeApp />,
|
||||
document.getElementById('main')
|
||||
);
|
||||
});
|
||||
|
||||
class AppGateway {
|
||||
|
||||
start() {
|
||||
console.log('start');
|
||||
let subdomain = window.location.host.split('.')[0];
|
||||
requests.get('whitelabel_settings', {'subdomain': subdomain})
|
||||
.then(this.loadSubdomain.bind(this))
|
||||
.catch(this.loadDefault.bind(this));
|
||||
}
|
||||
|
||||
loadSubdomain(data) {
|
||||
let settings = data.whitelabel;
|
||||
constants.whitelabel = settings;
|
||||
this.load('prize');
|
||||
}
|
||||
|
||||
loadDefault(error) {
|
||||
console.log('Loading default app, error'. error);
|
||||
this.load('default');
|
||||
}
|
||||
|
||||
load(type) {
|
||||
console.log('loading', type);
|
||||
Router.run(getRoutes(type), Router.HistoryLocation, (App) => {
|
||||
React.render(
|
||||
<App />,
|
||||
document.getElementById('main')
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let ag = new AppGateway();
|
||||
ag.start();
|
||||
|
@ -22,7 +22,7 @@ let AccordionList = React.createClass({
|
||||
} else if(this.props.count === 0) {
|
||||
return (
|
||||
<div>
|
||||
<p className="text-center">{getLangText('We could not find any works related to you%s', '...')}</p>
|
||||
<p className="text-center">{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>
|
||||
);
|
||||
|
@ -8,14 +8,11 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||
import Tooltip from 'react-bootstrap/lib/Tooltip';
|
||||
|
||||
import AccordionListItemEditionWidget from './accordion_list_item_edition_widget';
|
||||
import AccordionListItemCreateEditions from './accordion_list_item_create_editions';
|
||||
import CreateEditionsForm from '../ascribe_forms/create_editions_form';
|
||||
|
||||
import PieceListActions from '../../actions/piece_list_actions';
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
@ -35,20 +32,6 @@ let AccordionListItem = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
if(this.props.content.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') {
|
||||
this.startPolling();
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.state.pollingIntervalIndex);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
getGlyphicon(){
|
||||
if (this.props.content.requestAction){
|
||||
return (
|
||||
@ -66,39 +49,32 @@ let AccordionListItem = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
handleEditionCreationSuccess(response) {
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
handleEditionCreationSuccess() {
|
||||
PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0});
|
||||
|
||||
this.toggleCreateEditionsDialog();
|
||||
},
|
||||
|
||||
startPolling() {
|
||||
// start polling until editions are defined
|
||||
let pollingIntervalIndex = setInterval(() => {
|
||||
EditionListActions.fetchEditionList(this.props.content.id)
|
||||
.then((res) => {
|
||||
|
||||
clearInterval(this.state.pollingIntervalIndex);
|
||||
|
||||
PieceListActions.updatePropertyForPiece({
|
||||
pieceId: this.props.content.id,
|
||||
key: 'num_editions',
|
||||
value: res.editions[0].num_editions
|
||||
});
|
||||
|
||||
EditionListActions.toggleEditionList(this.props.content.id);
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
/* Ignore and keep going */
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
this.setState({
|
||||
pollingIntervalIndex
|
||||
onPollingSuccess(pieceId, numEditions) {
|
||||
PieceListActions.updatePropertyForPiece({
|
||||
pieceId,
|
||||
key: 'num_editions',
|
||||
value: numEditions
|
||||
});
|
||||
|
||||
EditionListActions.toggleEditionList(pieceId);
|
||||
},
|
||||
|
||||
getCreateEditionsDialog() {
|
||||
if(this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) {
|
||||
return (
|
||||
<div className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2">
|
||||
<CreateEditionsForm
|
||||
pieceId={this.props.content.id}
|
||||
handleSuccess={this.handleEditionCreationSuccess} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -141,7 +117,8 @@ let AccordionListItem = React.createClass({
|
||||
<AccordionListItemEditionWidget
|
||||
className="pull-right"
|
||||
piece={this.props.content}
|
||||
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}/>
|
||||
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.onPollingSuccess}/>
|
||||
</div>
|
||||
</div>
|
||||
<span style={{'clear': 'both'}}></span>
|
||||
@ -150,8 +127,9 @@ let AccordionListItem = React.createClass({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog ? <AccordionListItemCreateEditions pieceId={this.props.content.id} handleSuccess={this.handleEditionCreationSuccess}/> : null}
|
||||
|
||||
{this.getCreateEditionsDialog()}
|
||||
|
||||
{/* this.props.children is AccordionListItemTableEditions */}
|
||||
{this.props.children}
|
||||
</div>
|
||||
|
@ -1,51 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Form from '../ascribe_forms/form';
|
||||
import Property from '../ascribe_forms/property';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let AccordionListItemCreateEditions = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
pieceId: React.PropTypes.number,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
piece_id: parseInt(this.props.pieceId, 10)
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2">
|
||||
<Form
|
||||
ref='form'
|
||||
url={apiUrls.editions}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
}>
|
||||
<Property
|
||||
name='num_editions'
|
||||
label={getLangText('Number of editions')}>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 32)"
|
||||
min={0}/>
|
||||
</Property>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default AccordionListItemCreateEditions;
|
@ -6,13 +6,16 @@ import classNames from 'classnames';
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
import EditionListStore from '../../stores/edition_list_store';
|
||||
|
||||
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let AccordionListItemEditionWidget = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
piece: React.PropTypes.object.isRequired,
|
||||
toggleCreateEditionsDialog: React.PropTypes.func.isRequired
|
||||
toggleCreateEditionsDialog: React.PropTypes.func.isRequired,
|
||||
onPollingSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -55,16 +58,9 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false;
|
||||
|
||||
if(isEditionListOpen) {
|
||||
if(typeof this.state.editionList[pieceId] === 'undefined') {
|
||||
return (
|
||||
<span className="glyph-ascribe-spool-chunked spin"/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span>
|
||||
@ -76,23 +72,16 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
let piece = this.props.piece;
|
||||
let numEditions = piece.num_editions;
|
||||
|
||||
if(numEditions === -1) {
|
||||
if(numEditions <= 0) {
|
||||
return (
|
||||
<button
|
||||
onClick={this.props.toggleCreateEditionsDialog}
|
||||
className={classNames('btn', 'btn-default', 'btn-xs', 'ascribe-accordion-list-item-edition-widget', this.props.className)}>
|
||||
+ Editions
|
||||
</button>
|
||||
<CreateEditionsButton
|
||||
label={getLangText('Create editions')}
|
||||
className="btn-xs pull-right"
|
||||
piece={piece}
|
||||
toggleCreateEditionsDialog={this.props.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.props.onPollingSuccess}/>
|
||||
);
|
||||
}
|
||||
else if(numEditions === 0) {
|
||||
return (
|
||||
<button disabled className={classNames('btn', 'btn-default', 'btn-xs', this.props.className)}>
|
||||
Creating Editions <span className="glyph-ascribe-spool-chunked spin"/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
else if(numEditions === 1) {
|
||||
} else if(numEditions === 1) {
|
||||
let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : '';
|
||||
|
||||
return (
|
||||
|
@ -6,14 +6,14 @@ import Header from '../components/header';
|
||||
import Footer from '../components/footer';
|
||||
import GlobalNotification from './global_notification';
|
||||
|
||||
let Link = Router.Link;
|
||||
// let Link = Router.Link;
|
||||
let RouteHandler = Router.RouteHandler;
|
||||
|
||||
|
||||
let AscribeApp = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="container ascribe-default-app">
|
||||
<Header />
|
||||
<RouteHandler />
|
||||
<Footer />
|
||||
|
@ -13,25 +13,28 @@ import AppConstants from '../../constants/application_constants';
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
|
||||
let AclButton = React.createClass({
|
||||
propTypes: {
|
||||
action: React.PropTypes.oneOf(AppConstants.aclList).isRequired,
|
||||
availableAcls: React.PropTypes.array.isRequired,
|
||||
editions: React.PropTypes.array.isRequired,
|
||||
pieceOrEditions: React.PropTypes.object.isRequired,
|
||||
currentUser: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func.isRequired,
|
||||
className: React.PropTypes.string
|
||||
},
|
||||
|
||||
isPiece(){
|
||||
return !(this.props.pieceOrEditions.constructor === Array);
|
||||
},
|
||||
actionProperties(){
|
||||
if (this.props.action === 'consign'){
|
||||
return {
|
||||
title: getLangText('Consign artwork'),
|
||||
tooltip: getLangText('Have someone else sell the artwork'),
|
||||
form: <ConsignForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
|
||||
form: <ConsignForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
|
||||
handleSuccess: this.showNotification
|
||||
};
|
||||
}
|
||||
@ -39,14 +42,14 @@ let AclButton = React.createClass({
|
||||
return {
|
||||
title: getLangText('Unconsign artwork'),
|
||||
tooltip: getLangText('Have the owner manage his sales again'),
|
||||
form: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
|
||||
form: <UnConsignForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
|
||||
handleSuccess: this.showNotification
|
||||
};
|
||||
}else if (this.props.action === 'transfer') {
|
||||
return {
|
||||
title: getLangText('Transfer artwork'),
|
||||
tooltip: getLangText('Transfer the ownership of the artwork'),
|
||||
form: <TransferForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
|
||||
form: <TransferForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
|
||||
handleSuccess: this.showNotification
|
||||
};
|
||||
}
|
||||
@ -54,7 +57,7 @@ let AclButton = React.createClass({
|
||||
return {
|
||||
title: getLangText('Loan artwork'),
|
||||
tooltip: getLangText('Loan your artwork for a limited period of time'),
|
||||
form: <LoanForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
|
||||
form: <LoanForm currentUser={ this.props.currentUser } editions={ this.props.pieceOrEditions }/>,
|
||||
handleSuccess: this.showNotification
|
||||
};
|
||||
}
|
||||
@ -62,18 +65,62 @@ let AclButton = React.createClass({
|
||||
return {
|
||||
title: getLangText('Share artwork'),
|
||||
tooltip: getLangText('Share the artwork'),
|
||||
form: <ShareForm currentUser={ this.props.currentUser } editions={ this.props.editions }/>,
|
||||
form: (
|
||||
<ShareForm
|
||||
message={this.getShareMessage()}
|
||||
id={this.getFormDataId()}
|
||||
url={this.isPiece() ? apiUrls.ownership_shares_pieces : apiUrls.ownership_shares_editions }/>
|
||||
),
|
||||
handleSuccess: this.showNotification
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
showNotification(response){
|
||||
this.props.handleSuccess();
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
getTitlesString(){
|
||||
if (this.isPiece()){
|
||||
return '\"' + this.props.pieceOrEditions.title + '\"';
|
||||
}
|
||||
else {
|
||||
return this.props.pieceOrEditions.map(function(edition) {
|
||||
return '- \"' + edition.title + ', ' + getLangText('edition') + ' ' + edition.edition_number + '\"\n';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getFormDataId(){
|
||||
if (this.isPiece()) {
|
||||
return {piece_id: this.props.pieceOrEditions.id};
|
||||
}
|
||||
else {
|
||||
return {bitcoin_id: this.props.pieceOrEditions.map(function(edition){
|
||||
return edition.bitcoin_id;
|
||||
}).join()};
|
||||
}
|
||||
},
|
||||
|
||||
getShareMessage(){
|
||||
return (
|
||||
`
|
||||
${getLangText('Hi')},
|
||||
|
||||
${getLangText('I am sharing')}:
|
||||
${this.getTitlesString()} ${getLangText('with you')}.
|
||||
|
||||
${getLangText('Truly yours')},
|
||||
${this.props.currentUser.username}
|
||||
`
|
||||
);
|
||||
},
|
||||
|
||||
render() {
|
||||
let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1;
|
||||
let shouldDisplay = this.props.availableAcls[this.props.action];
|
||||
let aclProps = this.actionProperties();
|
||||
return (
|
||||
<ModalWrapper
|
||||
|
@ -11,9 +11,16 @@ import DeleteButton from '../ascribe_buttons/delete_button';
|
||||
let AclButtonList = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
editions: React.PropTypes.array,
|
||||
editions: React.PropTypes.oneOfType([
|
||||
React.PropTypes.object,
|
||||
React.PropTypes.array
|
||||
]),
|
||||
availableAcls: React.PropTypes.array,
|
||||
handleSuccess: React.PropTypes.func
|
||||
handleSuccess: React.PropTypes.func,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
React.PropTypes.element
|
||||
])
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -39,34 +46,36 @@ let AclButtonList = React.createClass({
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="transfer"
|
||||
editions={this.props.editions}
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess}/>
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="consign"
|
||||
editions={this.props.editions}
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="unconsign"
|
||||
editions={this.props.editions}
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="loan"
|
||||
editions={this.props.editions}
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<AclButton
|
||||
availableAcls={this.props.availableAcls}
|
||||
action="share"
|
||||
editions={this.props.editions}
|
||||
pieceOrEditions={this.props.editions}
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.handleSuccess} />
|
||||
<DeleteButton editions={this.props.editions}/>
|
||||
<DeleteButton
|
||||
editions={this.props.editions}/>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
95
js/components/ascribe_buttons/create_editions_button.js
Normal file
95
js/components/ascribe_buttons/create_editions_button.js
Normal file
@ -0,0 +1,95 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import EditionListActions from '../../actions/edition_list_actions';
|
||||
import EditionListStore from '../../stores/edition_list_store';
|
||||
|
||||
import { getAvailableAcls } from '../../utils/acl_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
let CreateEditionsButton = React.createClass({
|
||||
propTypes: {
|
||||
label: React.PropTypes.string,
|
||||
className: React.PropTypes.string,
|
||||
piece: React.PropTypes.object.isRequired,
|
||||
toggleCreateEditionsDialog: React.PropTypes.func.isRequired,
|
||||
onPollingSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return EditionListStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
EditionListStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
EditionListStore.unlisten(this.onChange);
|
||||
clearInterval(this.state.pollingIntervalIndex);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
if(this.props.piece.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') {
|
||||
this.startPolling();
|
||||
}
|
||||
},
|
||||
|
||||
startPolling() {
|
||||
// start polling until editions are defined
|
||||
let pollingIntervalIndex = setInterval(() => {
|
||||
EditionListActions.fetchEditionList(this.props.piece.id)
|
||||
.then((res) => {
|
||||
|
||||
clearInterval(this.state.pollingIntervalIndex);
|
||||
this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions);
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
/* Ignore and keep going */
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
this.setState({
|
||||
pollingIntervalIndex
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let piece = this.props.piece;
|
||||
|
||||
let availableAcls = getAvailableAcls(piece);
|
||||
|
||||
if (availableAcls.editions || piece.num_editions > 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(piece.num_editions === 0 && typeof this.state.editionList[piece.id] === 'undefined') {
|
||||
return (
|
||||
<button
|
||||
disabled
|
||||
className={classNames('btn', 'btn-default', this.props.className)}>
|
||||
{getLangText('Creating editions')} <span className="glyph-ascribe-spool-chunked spin"/>
|
||||
</button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<button
|
||||
className={classNames('btn', 'btn-default', this.props.className)}
|
||||
onClick={this.props.toggleCreateEditionsDialog}>
|
||||
{this.props.label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default CreateEditionsButton;
|
||||
|
@ -41,11 +41,11 @@ let DeleteButton = React.createClass({
|
||||
let btnDelete = null;
|
||||
let content = null;
|
||||
|
||||
if (availableAcls.indexOf('delete') > -1) {
|
||||
if (availableAcls.delete) {
|
||||
content = <EditionDeleteForm editions={ this.props.editions }/>;
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('DELETE')}</Button>;
|
||||
}
|
||||
else if (availableAcls.indexOf('del_from_collection') > -1){
|
||||
else if (availableAcls.unshare){
|
||||
content = <EditionRemoveFromCollectionForm editions={ this.props.editions }/>;
|
||||
btnDelete = <Button bsStyle="danger" className="btn-delete" bsSize="small">{getLangText('REMOVE FROM COLLECTION')}</Button>;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import Router from 'react-router';
|
||||
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
|
||||
import UserActions from '../../actions/user_actions';
|
||||
@ -22,7 +21,6 @@ import Property from './../ascribe_forms/property';
|
||||
import EditionDetailProperty from './detail_property';
|
||||
import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable';
|
||||
|
||||
import EditionHeader from './header';
|
||||
import EditionFurtherDetails from './further_details';
|
||||
|
||||
//import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
|
||||
@ -38,7 +36,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
@ -76,14 +73,19 @@ let Edition = React.createClass({
|
||||
content={this.props.edition}/>
|
||||
</Col>
|
||||
<Col md={6} className="ascribe-edition-details">
|
||||
<EditionHeader content={this.props.edition}/>
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label="TITLE" value={<div className="ascribe-detail-title">{this.props.edition.title}</div>} />
|
||||
<EditionDetailProperty label="BY" value={this.props.edition.artist_name} />
|
||||
<EditionDetailProperty label="DATE" value={ this.props.edition.date_created.slice(0, 4) } />
|
||||
<hr/>
|
||||
</div>
|
||||
<EditionSummary
|
||||
currentUser={this.state.currentUser}
|
||||
edition={this.props.edition} />
|
||||
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Certificate of Authenticity')}
|
||||
show={this.props.edition.acl.indexOf('coa') > -1}>
|
||||
show={this.props.edition.acl.acl_coa}>
|
||||
<CoaDetails
|
||||
edition={this.props.edition}/>
|
||||
</CollapsibleParagraph>
|
||||
@ -112,7 +114,7 @@ let Edition = React.createClass({
|
||||
<CollapsibleParagraph
|
||||
title="Notes"
|
||||
show={(this.state.currentUser.username && true || false) ||
|
||||
(this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note)}>
|
||||
(this.props.edition.acl.acl_edit || this.props.edition.public_note)}>
|
||||
<EditionPersonalNote
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.loadEdition}
|
||||
@ -124,11 +126,11 @@ let Edition = React.createClass({
|
||||
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Further Details')}
|
||||
show={this.props.edition.acl.indexOf('edit') > -1
|
||||
show={this.props.edition.acl.acl_edit
|
||||
|| Object.keys(this.props.edition.extra_data).length > 0
|
||||
|| this.props.edition.other_data !== null}>
|
||||
<EditionFurtherDetails
|
||||
editable={this.props.edition.acl.indexOf('edit') > -1}
|
||||
editable={this.props.edition.acl.acl_edit}
|
||||
pieceId={this.props.edition.parent}
|
||||
extraData={this.props.edition.extra_data}
|
||||
otherData={this.props.edition.other_data}
|
||||
@ -168,7 +170,7 @@ let EditionSummary = React.createClass({
|
||||
if (this.props.edition.status.length > 0){
|
||||
let statusStr = this.props.edition.status.join().replace(/_/, ' ');
|
||||
status = <EditionDetailProperty label="STATUS" value={ statusStr }/>;
|
||||
if (this.props.edition.pending_new_owner && this.props.edition.acl.indexOf('withdraw_transfer') > -1){
|
||||
if (this.props.edition.pending_new_owner && this.props.edition.acl.acl_withdraw_transfer){
|
||||
status = (
|
||||
<Form
|
||||
url={apiUrls.ownership_transfers_withdraw}
|
||||
@ -217,7 +219,6 @@ let EditionSummary = React.createClass({
|
||||
<EditionDetailProperty label={getLangText('ID')} value={ this.props.edition.bitcoin_id } />
|
||||
<EditionDetailProperty label={getLangText('OWNER')} value={ this.props.edition.owner } />
|
||||
{this.getStatus()}
|
||||
<br/>
|
||||
{this.getActions()}
|
||||
<hr/>
|
||||
</div>
|
||||
@ -303,8 +304,8 @@ let EditionPublicEditionNote = React.createClass({
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
render() {
|
||||
let isEditable = this.props.edition.acl.indexOf('edit') > -1;
|
||||
if (this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note){
|
||||
let isEditable = this.props.edition.acl.acl_edit;
|
||||
if (isEditable || this.props.edition.public_note){
|
||||
return (
|
||||
<Form
|
||||
url={apiUrls.note_edition}
|
||||
|
@ -1,26 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import EditionDetailProperty from './detail_property';
|
||||
|
||||
|
||||
let Header = React.createClass({
|
||||
propTypes: {
|
||||
content: React.PropTypes.object
|
||||
},
|
||||
|
||||
render() {
|
||||
var titleHtml = <div className="ascribe-detail-title">{this.props.content.title}</div>;
|
||||
return (
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label="TITLE" value={titleHtml} />
|
||||
<EditionDetailProperty label="BY" value={this.props.content.artist_name} />
|
||||
<EditionDetailProperty label="DATE" value={ this.props.content.date_created.slice(0, 4) } />
|
||||
<hr/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Header;
|
@ -7,13 +7,25 @@ import Col from 'react-bootstrap/lib/Col';
|
||||
|
||||
import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
|
||||
|
||||
import DetailProperty from './detail_property';
|
||||
|
||||
import FurtherDetails from './further_details';
|
||||
//import UserActions from '../../actions/user_actions';
|
||||
//import UserStore from '../../stores/user_store';
|
||||
|
||||
import UserActions from '../../actions/user_actions';
|
||||
import UserStore from '../../stores/user_store';
|
||||
|
||||
import PieceActions from '../../actions/piece_actions';
|
||||
|
||||
import MediaContainer from './media_container';
|
||||
|
||||
import Header from './header';
|
||||
import EditionDetailProperty from './detail_property';
|
||||
|
||||
import AclButtonList from './../ascribe_buttons/acl_button_list';
|
||||
import CreateEditionsForm from '../ascribe_forms/create_editions_form';
|
||||
import CreateEditionsButton from '../ascribe_buttons/create_editions_button';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
import { mergeOptions } from '../../utils/general_utils';
|
||||
|
||||
/**
|
||||
* This is the component that implements display-specific functionality
|
||||
@ -24,25 +36,62 @@ let Piece = React.createClass({
|
||||
loadPiece: React.PropTypes.func
|
||||
},
|
||||
|
||||
//getInitialState() {
|
||||
// return UserStore.getState();
|
||||
//},
|
||||
//
|
||||
//componentDidMount() {
|
||||
// UserStore.listen(this.onChange);
|
||||
// UserActions.fetchCurrentUser();
|
||||
//},
|
||||
//
|
||||
//componentWillUnmount() {
|
||||
// UserStore.unlisten(this.onChange);
|
||||
//},
|
||||
//
|
||||
//onChange(state) {
|
||||
// this.setState(state);
|
||||
//},
|
||||
getInitialState() {
|
||||
return mergeOptions(
|
||||
UserStore.getState(),
|
||||
{
|
||||
showCreateEditionsDialog: false
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
UserActions.fetchCurrentUser();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
toggleCreateEditionsDialog() {
|
||||
this.setState({
|
||||
showCreateEditionsDialog: !this.state.showCreateEditionsDialog
|
||||
});
|
||||
},
|
||||
|
||||
handleEditionCreationSuccess() {
|
||||
PieceActions.updateProperty({key: 'num_editions', value: 0});
|
||||
this.toggleCreateEditionsDialog();
|
||||
},
|
||||
|
||||
getCreateEditionsDialog() {
|
||||
if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) {
|
||||
return (
|
||||
<div style={{marginTop: '1em'}}>
|
||||
<CreateEditionsForm
|
||||
pieceId={this.props.piece.id}
|
||||
handleSuccess={this.handleEditionCreationSuccess} />
|
||||
<hr/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (<hr/>);
|
||||
}
|
||||
},
|
||||
|
||||
handlePollingSuccess(pieceId, numEditions) {
|
||||
PieceActions.updateProperty({
|
||||
key: 'num_editions',
|
||||
value: numEditions
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
@ -50,22 +99,44 @@ let Piece = React.createClass({
|
||||
content={this.props.piece}/>
|
||||
</Col>
|
||||
<Col md={6} className="ascribe-edition-details">
|
||||
<Header
|
||||
content={this.props.piece}/>
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label="TITLE" value={<div className="ascribe-detail-title">{this.props.piece.title}</div>} />
|
||||
<EditionDetailProperty label="BY" value={this.props.piece.artist_name} />
|
||||
<EditionDetailProperty label="DATE" value={ this.props.piece.date_created.slice(0, 4) } />
|
||||
{this.props.piece.num_editions > 0 ? <EditionDetailProperty label="NUMBER OF EDITIONS" value={ this.props.piece.num_editions } /> : null}
|
||||
<hr/>
|
||||
</div>
|
||||
<div className="ascribe-detail-header">
|
||||
<DetailProperty label={getLangText('REGISTREE')} value={ this.props.piece.user_registered } />
|
||||
</div>
|
||||
|
||||
<AclButtonList
|
||||
className="text-center ascribe-button-list"
|
||||
availableAcls={this.props.piece.acl}
|
||||
editions={this.props.piece}>
|
||||
<CreateEditionsButton
|
||||
label={getLangText('CREATE EDITIONS')}
|
||||
className="btn-sm"
|
||||
piece={this.props.piece}
|
||||
toggleCreateEditionsDialog={this.toggleCreateEditionsDialog}
|
||||
onPollingSuccess={this.handlePollingSuccess}/>
|
||||
</AclButtonList>
|
||||
|
||||
{this.getCreateEditionsDialog()}
|
||||
|
||||
<CollapsibleParagraph
|
||||
title="Further Details"
|
||||
show={this.props.piece.acl.indexOf('edit') > -1
|
||||
show={this.props.piece.acl.acl_edit
|
||||
|| Object.keys(this.props.piece.extra_data).length > 0
|
||||
|| this.props.piece.other_data !== null}
|
||||
defaultExpanded={true}>
|
||||
<FurtherDetails
|
||||
editable={this.props.piece.acl.indexOf('edit') > -1}
|
||||
editable={this.props.piece.acl.acl_edit}
|
||||
pieceId={this.props.piece.id}
|
||||
extraData={this.props.piece.extra_data}
|
||||
otherData={this.props.piece.other_data}
|
||||
handleSuccess={this.props.loadPiece}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
62
js/components/ascribe_forms/create_editions_form.js
Normal file
62
js/components/ascribe_forms/create_editions_form.js
Normal file
@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Form from '../ascribe_forms/form';
|
||||
import Property from '../ascribe_forms/property';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let CreateEditionsForm = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
handleSuccess: React.PropTypes.func,
|
||||
pieceId: React.PropTypes.number
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
piece_id: parseInt(this.props.pieceId, 10)
|
||||
};
|
||||
},
|
||||
|
||||
handleSuccess(response) {
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
if(this.props.handleSuccess) {
|
||||
this.props.handleSuccess(response);
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form
|
||||
ref='form'
|
||||
url={apiUrls.editions}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.handleSuccess}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
}>
|
||||
<Property
|
||||
name='num_editions'
|
||||
label={getLangText('Number of editions')}>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 32)"
|
||||
min={0}/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default CreateEditionsForm;
|
@ -1,62 +1,130 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import UserStore from '../../stores/user_store';
|
||||
import UserActions from '../../actions/user_actions';
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
import FormPropertyHeader from './form_property_header';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import InputText from './input_text';
|
||||
import ButtonSubmitOrClose from '../ascribe_buttons/button_submit_close';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
import SignupModal from '../ascribe_modal/modal_signup';
|
||||
import PasswordResetRequestModal from '../ascribe_modal/modal_password_request_reset';
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
let LoginForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
|
||||
url() {
|
||||
return apiUrls.users_login;
|
||||
propTypes: {
|
||||
headerMessage: React.PropTypes.string,
|
||||
submitMessage: React.PropTypes.string,
|
||||
redirectOnLoggedIn: React.PropTypes.bool,
|
||||
redirectOnLoginSuccess: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
email: this.refs.email.state.value,
|
||||
password: this.refs.password.state.value
|
||||
headerMessage: 'Enter ascribe',
|
||||
submitMessage: 'Log in',
|
||||
redirectOnLoggedIn: true,
|
||||
redirectOnLoginSuccess: true
|
||||
};
|
||||
},
|
||||
renderForm() {
|
||||
|
||||
getInitialState() {
|
||||
return UserStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(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) {
|
||||
this.transitionTo('pieces');
|
||||
}
|
||||
},
|
||||
|
||||
handleSuccess(){
|
||||
let notification = new GlobalNotificationModel('Login successful', 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
// register_piece is waiting for a login success as login_container and it is wrapped
|
||||
// in a slides_container component.
|
||||
// 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();
|
||||
|
||||
/* 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
|
||||
*/
|
||||
if(this.props.redirectOnLoginSuccess) {
|
||||
window.location = AppConstants.baseUrl + 'collection';
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form id="login_modal_content" role="form" onSubmit={this.submit}>
|
||||
<input className="invisible" type="email" name="fake_consignee"/>
|
||||
<input className="invisible" type="password" name="fake_password"/>
|
||||
<InputText
|
||||
ref="email"
|
||||
placeHolder={getLangText('Email')}
|
||||
required="required"
|
||||
type="email"
|
||||
submitted={this.state.submitted}/>
|
||||
<InputText
|
||||
ref="password"
|
||||
placeHolder={getLangText('Password')}
|
||||
required="required"
|
||||
type="password"
|
||||
submitted={this.state.submitted}/>
|
||||
<div>
|
||||
{getLangText('Forgot your password')}?
|
||||
<PasswordResetRequestModal
|
||||
button={<a className="button" href="#"> {getLangText('Reset password')}</a>}/>
|
||||
</div>
|
||||
<div>
|
||||
{getLangText('Not a member yet')}?
|
||||
<SignupModal
|
||||
button={<a className="button" href="#"> {getLangText('Sign up')}</a>}/>
|
||||
</div>
|
||||
<ButtonSubmitOrClose
|
||||
text={getLangText('LOGIN')}
|
||||
onClose={this.props.onRequestHide}
|
||||
submitted={this.state.submitted} />
|
||||
</form>
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref="loginForm"
|
||||
url={apiUrls.users_login}
|
||||
handleSuccess={this.handleSuccess}
|
||||
buttons={
|
||||
<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login">
|
||||
{getLangText(this.props.submitMessage)}
|
||||
</button>}
|
||||
spinner={
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</span>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{getLangText(this.props.headerMessage)}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
name='email'
|
||||
label={getLangText('Email')}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={getLangText('Enter your email')}
|
||||
autoComplete="on"
|
||||
name="username"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Enter your password')}
|
||||
autoComplete="on"
|
||||
name="password"
|
||||
required/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -1,43 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
|
||||
|
||||
let EditionNoteForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return apiUrls.note_edition;
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return {
|
||||
bitcoin_id: this.getBitcoinIds().join(),
|
||||
note: this.refs.personalNote.state.value
|
||||
};
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
|
||||
return (
|
||||
<form id="personal_note_content" role="form" key="personal_note_content">
|
||||
<InputTextAreaToggable
|
||||
ref="personalNote"
|
||||
className="form-control"
|
||||
defaultValue={this.props.editions[0].public_note}
|
||||
rows={3}
|
||||
editable={this.props.editable}
|
||||
required=""
|
||||
onSubmit={this.submit}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default EditionNoteForm;
|
@ -1,43 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
|
||||
|
||||
let PersonalNoteForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return apiUrls.note_notes;
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return {
|
||||
bitcoin_id: this.getBitcoinIds().join(),
|
||||
note: this.refs.personalNote.state.value
|
||||
};
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
|
||||
return (
|
||||
<form id="personal_note_content" role="form" key="personal_note_content">
|
||||
<InputTextAreaToggable
|
||||
ref="personalNote"
|
||||
className="form-control"
|
||||
defaultValue={this.props.editions[0].note_from_user}
|
||||
rows={3}
|
||||
editable={this.props.editable}
|
||||
required=""
|
||||
onSubmit={this.submit}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PersonalNoteForm;
|
@ -1,51 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import InputText from './input_text';
|
||||
import ButtonSubmit from '../ascribe_buttons/button_submit';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
let PasswordResetForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return apiUrls.users_password_reset;
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return {
|
||||
email: this.props.email,
|
||||
token: this.props.token,
|
||||
password: this.refs.password.state.value,
|
||||
password_confirm: this.refs.password_confirm.state.value
|
||||
};
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
return (
|
||||
<form id="reset_password_modal_content" role="form" onSubmit={this.submit}>
|
||||
<div>Reset the password for {this.props.email}:</div>
|
||||
<InputText
|
||||
ref="password"
|
||||
placeHolder={getLangText('Choose a password')}
|
||||
required="required"
|
||||
type="password"
|
||||
submitted={this.state.submitted}/>
|
||||
<InputText
|
||||
ref="password_confirm"
|
||||
placeHolder={getLangText('Confirm password')}
|
||||
required="required"
|
||||
type="password"
|
||||
submitted={this.state.submitted}/>
|
||||
<ButtonSubmit
|
||||
text={getLangText('RESET PASSWORD')}
|
||||
submitted={this.state.submitted} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PasswordResetForm;
|
@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import InputText from './input_text';
|
||||
import ButtonSubmitOrClose from '../ascribe_buttons/button_submit_close';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
let PasswordResetRequestForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return apiUrls.users_password_reset_request;
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return {
|
||||
email: this.refs.email.state.value
|
||||
};
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
return (
|
||||
<form id="request_reset_password_modal_content" role="form" onSubmit={this.submit}>
|
||||
<InputText
|
||||
ref="email"
|
||||
placeHolder={getLangText('Email')}
|
||||
required="required"
|
||||
type="email"
|
||||
submitted={this.state.submitted}/>
|
||||
<ButtonSubmitOrClose
|
||||
text={getLangText('RESET PASSWORD')}
|
||||
onClose={this.props.onRequestHide}
|
||||
submitted={this.state.submitted} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PasswordResetRequestForm;
|
180
js/components/ascribe_forms/form_register_piece.js
Normal file
180
js/components/ascribe_forms/form_register_piece.js
Normal file
@ -0,0 +1,180 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
import FormPropertyHeader from './form_property_header';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
|
||||
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
|
||||
let RegisterPieceForm = React.createClass({
|
||||
propTypes: {
|
||||
headerMessage: React.PropTypes.string,
|
||||
submitMessage: React.PropTypes.string,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
isFineUploaderEditable: React.PropTypes.bool,
|
||||
children: React.PropTypes.element
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
headerMessage: getLangText('Register your work'),
|
||||
submitMessage: getLangText('Register work')
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState(){
|
||||
return {
|
||||
digitalWorkKey: null,
|
||||
isUploadReady: false
|
||||
};
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
digital_work_key: this.state.digitalWorkKey
|
||||
};
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
this.setState({
|
||||
digitalWorkKey: key
|
||||
});
|
||||
},
|
||||
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
isReadyForFormSubmission(files) {
|
||||
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
||||
if (files.length > 0 && files[0].status === 'upload successful') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref='form'
|
||||
url={apiUrls.pieces_list}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
buttons={<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login"
|
||||
disabled={!this.state.isUploadReady}>
|
||||
{this.props.submitMessage}
|
||||
</button>}
|
||||
spinner={
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</span>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{this.props.headerMessage}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
ignoreFocus={true}>
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||
editable={this.props.isFineUploaderEditable}/>
|
||||
</Property>
|
||||
<Property
|
||||
name='artist_name'
|
||||
label={getLangText('Artist Name')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="(e.g. Andy Warhol)"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='title'
|
||||
label={getLangText('Title')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="(e.g. 32 Campbell's Soup Cans)"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='date_created'
|
||||
label={getLangText('Year Created')}>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 1962)"
|
||||
min={0}
|
||||
required/>
|
||||
</Property>
|
||||
{this.props.children}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
onClick: React.PropTypes.func,
|
||||
// editable is used to lock react fine uploader in case
|
||||
// a user is actually not logged in already to prevent him from droping files
|
||||
// before login in
|
||||
editable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ReactS3FineUploader
|
||||
onClick={this.props.onClick}
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'digitalwork'
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: apiUrls.blob_digitalworks
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '25000000000'
|
||||
}}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
areAssetsDownloadable={false}
|
||||
areAssetsEditable={this.props.editable}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default RegisterPieceForm;
|
@ -24,8 +24,9 @@ let EditionRemoveFromCollectionForm = React.createClass({
|
||||
<p>{getLangText('Are you sure you would like to remove these editions from your collection')}?</p>
|
||||
<p>{getLangText('This is an irrevocable action%s', '.')}</p>
|
||||
<div className="modal-footer">
|
||||
<button type="submit" className="btn btn-ascribe-inv" onClick={this.submit}>{getLangText('YES, REMOVE')}</button>
|
||||
<button className="btn btn-ascribe" onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
<button type="submit" className="btn btn-danger btn-delete btn-sm ascribe-margin-1px" onClick={this.submit}>{getLangText('YES, REMOVE')}</button>
|
||||
<button className="btn btn-default btn-sm ascribe-margin-1px" style={{marginLeft: '0'}}
|
||||
onClick={this.props.onRequestHide}>{getLangText('CLOSE')}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -2,59 +2,76 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ApiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import InputText from './input_text';
|
||||
import InputTextArea from './input_textarea';
|
||||
import ButtonSubmitOrClose from '../ascribe_buttons/button_submit_close';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
import InputTextAreaToggable from './input_textarea_toggable';
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
import { getLangText } from '../../utils/lang_utils.js';
|
||||
|
||||
|
||||
let ShareForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return ApiUrls.ownership_shares;
|
||||
propTypes: {
|
||||
url: React.PropTypes.string,
|
||||
id: React.PropTypes.string,
|
||||
message: React.PropTypes.string,
|
||||
editions: React.PropTypes.array,
|
||||
currentUser: React.PropTypes.object,
|
||||
onRequestHide: React.PropTypes.func,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
return {
|
||||
bitcoin_id: this.getBitcoinIds().join(),
|
||||
share_emails: this.refs.share_emails.state.value,
|
||||
share_message: this.refs.share_message.state.value
|
||||
};
|
||||
getFormData(){
|
||||
return this.props.id;
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
let title = this.getTitlesString().join('');
|
||||
let username = this.props.currentUser.username;
|
||||
let message =
|
||||
`${getLangText('Hi')},
|
||||
|
||||
${getLangText('I am sharing')} :
|
||||
${title}${getLangText('with you')}.
|
||||
|
||||
${getLangText('Truly yours')},
|
||||
${username}`;
|
||||
render() {
|
||||
|
||||
return (
|
||||
<form id="share_modal_content" role="form" key="share_modal_content" onSubmit={this.submit}>
|
||||
<InputText
|
||||
ref="share_emails"
|
||||
placeHolder={getLangText('Comma separated emails')}
|
||||
required="required"
|
||||
type="text"
|
||||
submitted={this.state.submitted}/>
|
||||
<InputTextArea
|
||||
ref="share_message"
|
||||
defaultValue={message}
|
||||
required=""
|
||||
/>
|
||||
<ButtonSubmitOrClose
|
||||
text={getLangText('SHARE')}
|
||||
onClose={this.props.onRequestHide}
|
||||
submitted={this.state.submitted} />
|
||||
</form>
|
||||
<Form
|
||||
ref='form'
|
||||
url={this.props.url}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.props.handleSuccess}
|
||||
buttons={
|
||||
<div className="modal-footer">
|
||||
<p className="pull-right">
|
||||
<Button
|
||||
className="btn btn-default btn-sm ascribe-margin-1px"
|
||||
type="submit">SHARE</Button>
|
||||
<Button
|
||||
className="btn btn-danger btn-delete btn-sm ascribe-margin-1px"
|
||||
style={{marginLeft: '0'}}
|
||||
onClick={this.props.onRequestHide}>CLOSE</Button>
|
||||
</p>
|
||||
</div>}
|
||||
spinner={
|
||||
<div className="modal-footer">
|
||||
<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_small.gif'} />
|
||||
</div>}>
|
||||
<Property
|
||||
name='share_emails'
|
||||
label={getLangText('Emails')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={getLangText('Comma separated emails')}
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='share_message'
|
||||
label='Personal Message'
|
||||
editable={true}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
editable={true}
|
||||
defaultValue={this.props.message}
|
||||
placeholder={getLangText('Enter a message...')}
|
||||
required="required"/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -1,80 +1,137 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
import UserStore from '../../stores/user_store';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import Form from './form';
|
||||
import Property from './property';
|
||||
import FormPropertyHeader from './form_property_header';
|
||||
import InputCheckbox from './input_checkbox';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import FormMixin from '../../mixins/form_mixin';
|
||||
import InputText from './input_text';
|
||||
import InputCheckbox from './input_checkbox';
|
||||
import ButtonSubmitOrClose from '../ascribe_buttons/button_submit_close';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
|
||||
let SignupForm = React.createClass({
|
||||
mixins: [FormMixin],
|
||||
|
||||
url() {
|
||||
return apiUrls.users_signup;
|
||||
propTypes: {
|
||||
headerMessage: React.PropTypes.string,
|
||||
submitMessage: React.PropTypes.string,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
children: React.PropTypes.element
|
||||
},
|
||||
|
||||
getFormData() {
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
email: this.refs.email.state.value,
|
||||
password: this.refs.password.state.value,
|
||||
password_confirm: this.refs.password_confirm.state.value,
|
||||
terms: this.refs.terms.state.value,
|
||||
promo_code: this.refs.promo_code.state.value
|
||||
headerMessage: 'Welcome to ascribe',
|
||||
submitMessage: 'Sign up'
|
||||
};
|
||||
},
|
||||
|
||||
renderForm() {
|
||||
getInitialState() {
|
||||
return UserStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
|
||||
// if user is already logged in, redirect him to piece list
|
||||
if(this.state.currentUser && this.state.currentUser.email) {
|
||||
this.transitionTo('pieces');
|
||||
}
|
||||
},
|
||||
|
||||
handleSuccess(response){
|
||||
|
||||
let notificationText = getLangText('Sign up successful');
|
||||
let notification = new GlobalNotificationModel(notificationText, 'success', 50000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email +
|
||||
', ' + getLangText('please confirm') + '.');
|
||||
|
||||
},
|
||||
getFormData(){
|
||||
return {terms: this.refs.form.refs.terms.refs.input.state.value};
|
||||
},
|
||||
render() {
|
||||
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('Store it in a safe place') + '!';
|
||||
return (
|
||||
<form id="signup_modal_content" role="form" onSubmit={this.submit}>
|
||||
<input className="invisible" type="email" name="fake_consignee"/>
|
||||
<input className="invisible" type="password" name="fake_password"/>
|
||||
<InputText
|
||||
ref="email"
|
||||
placeHolder={getLangText('Email')}
|
||||
required="required"
|
||||
type="email"
|
||||
submitted={this.state.submitted}/>
|
||||
<InputText
|
||||
ref="password"
|
||||
placeHolder={getLangText('Choose a password')}
|
||||
required="required"
|
||||
type="password"
|
||||
submitted={this.state.submitted}/>
|
||||
<InputText
|
||||
ref="password_confirm"
|
||||
placeHolder={getLangText('Confirm password')}
|
||||
required="required"
|
||||
type="password"
|
||||
submitted={this.state.submitted}/>
|
||||
<div>
|
||||
{getLangText('Your password must be at least 10 characters')}.
|
||||
{getLangText('This password is securing your digital property like a bank account')}.
|
||||
{getLangText('Store it in a safe place')}!
|
||||
</div>
|
||||
<InputCheckbox
|
||||
ref="terms"
|
||||
required="required"
|
||||
label={
|
||||
<div>
|
||||
{getLangText('I agree to the')}
|
||||
<a href="/terms" target="_blank"> {getLangText('Terms of Service')}</a>
|
||||
</div>}/>
|
||||
<InputText
|
||||
ref="promo_code"
|
||||
placeHolder={getLangText('Promocode (Optional)')}
|
||||
required=""
|
||||
type="text"
|
||||
submitted={this.state.submitted}/>
|
||||
<ButtonSubmitOrClose
|
||||
text={getLangText('JOIN US')}
|
||||
onClose={this.props.onRequestHide}
|
||||
submitted={this.state.submitted} />
|
||||
</form>
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref='form'
|
||||
url={apiUrls.users_signup}
|
||||
handleSuccess={this.handleSuccess}
|
||||
getFormData={this.getFormData}
|
||||
buttons={
|
||||
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
|
||||
{getLangText(this.props.submitMessage)}
|
||||
</button>}
|
||||
spinner={
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</span>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{getLangText(this.props.headerMessage)}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
name='email'
|
||||
label={getLangText('Email')}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={getLangText('(e.g. andy@warhol.co.uk)')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}
|
||||
tooltip={tooltipPassword}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Use a combination of minimum 10 chars and numbers')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password_confirm'
|
||||
label={getLangText('Confirm Password')}
|
||||
tooltip={tooltipPassword}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Enter your password once again')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
{this.props.children}
|
||||
<Property
|
||||
name="terms"
|
||||
className="ascribe-settings-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputCheckbox/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SignupForm;
|
||||
|
||||
export default SignupForm;
|
||||
|
@ -1,33 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ModalWrapper from './modal_wrapper';
|
||||
import LoginForm from '../ascribe_forms/form_login';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
let LoginModal = React.createClass({
|
||||
handleLoginSuccess(){
|
||||
this.props.handleSuccess();
|
||||
let notificationText = getLangText('Login successful');
|
||||
let notification = new GlobalNotificationModel(notificationText, 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModalWrapper
|
||||
button={this.props.button}
|
||||
title={getLangText('Log in to ascribe')}
|
||||
handleSuccess={this.handleLoginSuccess}
|
||||
tooltip={getLangText('Log in to ascribe')}>
|
||||
<LoginForm />
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default LoginModal;
|
@ -1,32 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ModalWrapper from './modal_wrapper';
|
||||
import SignupForm from '../ascribe_forms/form_signup';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
import { getLangText } from '../../utils/lang_utils.js'
|
||||
|
||||
let SignupModal = React.createClass({
|
||||
handleSignupSuccess(response){
|
||||
let notificationText = getLangText('We sent an email to your address') + ' ' + response.user.email + ', ' + getLangText('please confirm') + '.';
|
||||
let notification = new GlobalNotificationModel(notificationText, 'success', 50000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ModalWrapper
|
||||
button={this.props.button}
|
||||
title={getLangText('Create an account')}
|
||||
handleSuccess={this.handleSignupSuccess}
|
||||
tooltip={getLangText('Sign up to ascribe')}>
|
||||
<SignupForm />
|
||||
</ModalWrapper>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SignupModal;
|
@ -68,9 +68,9 @@ let CoaVerifyForm = React.createClass({
|
||||
{getLangText('Verify your Certificate of Authenticity')}
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
</span>
|
||||
}>
|
||||
<Property
|
||||
name='message'
|
||||
|
@ -3,23 +3,13 @@
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import GlobalNotificationModel from '../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
|
||||
import UserStore from '../stores/user_store';
|
||||
import UserActions from '../actions/user_actions';
|
||||
|
||||
import Form from './ascribe_forms/form';
|
||||
import Property from './ascribe_forms/property';
|
||||
import FormPropertyHeader from './ascribe_forms/form_property_header';
|
||||
|
||||
import apiUrls from '../constants/api_urls';
|
||||
import AppConstants from '../constants/application_constants';
|
||||
import LoginForm from './ascribe_forms/form_login';
|
||||
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
|
||||
|
||||
let LoginContainer = React.createClass({
|
||||
propTypes: {
|
||||
message: React.PropTypes.string,
|
||||
@ -27,8 +17,6 @@ let LoginContainer = React.createClass({
|
||||
redirectOnLoginSuccess: React.PropTypes.bool
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
message: getLangText('Enter') + ' ascribe',
|
||||
@ -37,32 +25,12 @@ let LoginContainer = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return UserStore.getState();
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(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) {
|
||||
this.transitionTo('pieces');
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="ascribe-login-wrapper">
|
||||
<br/>
|
||||
<LoginForm
|
||||
redirectOnLoggedIn={this.props.redirectOnLoggedIn}
|
||||
redirectOnLoginSuccess={this.props.redirectOnLoginSuccess}
|
||||
message={this.props.message} />
|
||||
<div className="ascribe-login-text">
|
||||
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
||||
@ -74,80 +42,5 @@ let LoginContainer = React.createClass({
|
||||
});
|
||||
|
||||
|
||||
let LoginForm = React.createClass({
|
||||
propTypes: {
|
||||
redirectOnLoginSuccess: React.PropTypes.bool,
|
||||
message: React.PropTypes.string
|
||||
},
|
||||
|
||||
handleSuccess(){
|
||||
let notification = new GlobalNotificationModel('Login successful', 'success', 10000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
// register_piece is waiting for a login success as login_container and it is wrapped
|
||||
// in a slides_container component.
|
||||
// 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();
|
||||
|
||||
/* 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
|
||||
*/
|
||||
if(this.props.redirectOnLoginSuccess) {
|
||||
window.location = AppConstants.baseUrl + 'collection';
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref="loginForm"
|
||||
url={apiUrls.users_login}
|
||||
handleSuccess={this.handleSuccess}
|
||||
buttons={
|
||||
<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login">
|
||||
{getLangText('Enter')} ascribe
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{this.props.message}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
name='email'
|
||||
label={getLangText('Email')}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={getLangText('Enter your email')}
|
||||
autoComplete="on"
|
||||
name="username"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Enter your password')}
|
||||
autoComplete="on"
|
||||
name="password"
|
||||
required/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default LoginContainer;
|
||||
|
@ -39,7 +39,7 @@ let PasswordResetContainer = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<div className="ascribe-login-text ascribe-login-header">
|
||||
{getLangText('Reset your ascribe password')}
|
||||
{getLangText('Reset your password')}
|
||||
</div>
|
||||
<PasswordRequestResetForm
|
||||
handleRequestSuccess={this.handleRequestSuccess}/>
|
||||
@ -82,9 +82,9 @@ let PasswordRequestResetForm = React.createClass({
|
||||
{getLangText('Reset your password')}
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
</span>
|
||||
}>
|
||||
<Property
|
||||
name='email'
|
||||
@ -129,9 +129,9 @@ let PasswordResetForm = React.createClass({
|
||||
{getLangText('Reset your password')}
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<span className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
</span>
|
||||
}>
|
||||
<Property
|
||||
name='password'
|
||||
@ -157,4 +157,4 @@ let PasswordResetForm = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
export default PasswordResetContainer;
|
||||
export default PasswordResetContainer;
|
||||
|
@ -20,7 +20,7 @@ import AppConstants from '../constants/application_constants';
|
||||
|
||||
let PieceList = React.createClass({
|
||||
propTypes: {
|
||||
query: React.PropTypes.object
|
||||
redirectTo: React.PropTypes.string
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation, Router.State],
|
||||
@ -30,7 +30,7 @@ let PieceList = React.createClass({
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
let page = this.props.query.page || 1;
|
||||
let page = this.getQuery().page || 1;
|
||||
PieceListStore.listen(this.onChange);
|
||||
if (this.state.pieceList.length === 0){
|
||||
PieceListActions.fetchPieceList(page, this.state.pageSize, this.state.search, this.state.orderBy, this.state.orderAsc)
|
||||
@ -38,6 +38,12 @@ let PieceList = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.props.redirectTo && this.state.pieceListCount === 0) {
|
||||
this.transitionTo(this.props.redirectTo);
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
PieceListStore.unlisten(this.onChange);
|
||||
},
|
||||
@ -56,6 +62,30 @@ let PieceList = React.createClass({
|
||||
this.state.orderAsc);
|
||||
},
|
||||
|
||||
getPieceListToolbar() {
|
||||
if(this.state.pieceListCount > 10) {
|
||||
return (
|
||||
<PieceListToolbar
|
||||
className="ascribe-piece-list-toolbar"
|
||||
searchFor={this.searchFor} />
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getPagination() {
|
||||
let currentPage = parseInt(this.getQuery().page, 10) || 1;
|
||||
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
|
||||
|
||||
if (this.state.pieceListCount > 10) {
|
||||
return (
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
goToPage={this.paginationGoToPage} />
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
searchFor(searchTerm) {
|
||||
PieceListActions.fetchPieceList(1, this.state.pageSize, searchTerm, this.state.orderBy, this.state.orderAsc);
|
||||
this.transitionTo(this.getPathname(), {page: 1});
|
||||
@ -67,15 +97,11 @@ let PieceList = React.createClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
let currentPage = parseInt(this.props.query.page, 10) || 1;
|
||||
let totalPages = Math.ceil(this.state.pieceListCount / this.state.pageSize);
|
||||
let loadingElement = (<img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PieceListToolbar
|
||||
className="ascribe-piece-list-toolbar"
|
||||
searchFor={this.searchFor} />
|
||||
{this.getPieceListToolbar()}
|
||||
<PieceListBulkModal className="ascribe-piece-list-bulk-modal" />
|
||||
<AccordionList
|
||||
className="ascribe-accordion-list"
|
||||
@ -101,10 +127,7 @@ let PieceList = React.createClass({
|
||||
);
|
||||
})}
|
||||
</AccordionList>
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
goToPage={this.paginationGoToPage} />
|
||||
{this.getPagination()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,14 +2,10 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import DatePicker from 'react-datepicker/dist/react-datepicker';
|
||||
|
||||
import Router from 'react-router';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
|
||||
import AppConstants from '../constants/application_constants';
|
||||
|
||||
import LicenseActions from '../actions/license_actions';
|
||||
import LicenseStore from '../stores/license_store';
|
||||
|
||||
@ -21,33 +17,44 @@ import UserStore from '../stores/user_store';
|
||||
import GlobalNotificationModel from '../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
|
||||
import Form from './ascribe_forms/form';
|
||||
import Property from './ascribe_forms/property';
|
||||
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
||||
import FormPropertyHeader from './ascribe_forms/form_property_header';
|
||||
import RegisterPieceForm from './ascribe_forms/form_register_piece';
|
||||
//import FormPropertyHeader from './ascribe_forms/form_property_header';
|
||||
|
||||
import LoginContainer from './login_container';
|
||||
import SlidesContainer from './ascribe_slides_container/slides_container';
|
||||
|
||||
import apiUrls from '../constants/api_urls';
|
||||
|
||||
import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
import { getCookie } from '../utils/fetch_api_utils';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
|
||||
|
||||
let RegisterPiece = React.createClass( {
|
||||
|
||||
propTypes: {
|
||||
headerMessage: React.PropTypes.string,
|
||||
submitMessage: React.PropTypes.string,
|
||||
canSpecifyEditions: React.PropTypes.bool,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.arrayOf(React.PropTypes.element),
|
||||
React.PropTypes.element])
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
canSpecifyEditions: true
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState(){
|
||||
return mergeOptions(
|
||||
LicenseStore.getState(),
|
||||
UserStore.getState(),
|
||||
PieceListStore.getState(),
|
||||
{
|
||||
digitalWorkKey: null,
|
||||
uploadStatus: false,
|
||||
selectedLicense: 0,
|
||||
isFineUploaderEditable: false
|
||||
});
|
||||
@ -97,32 +104,6 @@ let RegisterPiece = React.createClass( {
|
||||
this.transitionTo('piece', {pieceId: response.piece.id});
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
return {
|
||||
digital_work_key: this.state.digitalWorkKey
|
||||
};
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
this.setState({
|
||||
digitalWorkKey: key
|
||||
});
|
||||
},
|
||||
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
isReadyForFormSubmission(files) {
|
||||
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
||||
if (files.length > 0 && files[0].status === 'upload successful') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onLicenseChange(event){
|
||||
//console.log(this.state.licenses[event.target.selectedIndex].url);
|
||||
this.setState({selectedLicense: event.target.selectedIndex});
|
||||
@ -154,6 +135,21 @@ let RegisterPiece = React.createClass( {
|
||||
return null;
|
||||
},
|
||||
|
||||
getSpecifyEditions() {
|
||||
if (this.props.canSpecifyEditions) {
|
||||
return (
|
||||
<PropertyCollapsible
|
||||
checkboxLabel={getLangText('Specify editions')}>
|
||||
<span>{getLangText('Editions')}</span>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 32)"
|
||||
min={0}/>
|
||||
</PropertyCollapsible>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
changeSlide() {
|
||||
// only transition to the login store, if user is not logged in
|
||||
// ergo the currentUser object is not properly defined
|
||||
@ -170,69 +166,14 @@ let RegisterPiece = React.createClass( {
|
||||
onFocus={this.changeSlide}>
|
||||
<Row className="no-margin">
|
||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref='form'
|
||||
url={apiUrls.pieces_list}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.handleSuccess}
|
||||
buttons={<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login"
|
||||
disabled={!this.state.isUploadReady}>
|
||||
{getLangText('Register work')}
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{getLangText('Register your work')}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
ignoreFocus={true}>
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||
editable={this.state.isFineUploaderEditable}/>
|
||||
</Property>
|
||||
<Property
|
||||
name='artist_name'
|
||||
label={getLangText('Artist Name')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="(e.g. Andy Warhol)"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='title'
|
||||
label={getLangText('Title')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="(e.g. 32 Campbell's Soup Cans)"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='date_created'
|
||||
label={getLangText('Year Created')}>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 1962)"
|
||||
min={0}
|
||||
required/>
|
||||
</Property>
|
||||
<PropertyCollapsible
|
||||
checkboxLabel={getLangText('Specify editions')}>
|
||||
<span>{getLangText('Editions')}</span>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="(e.g. 32)"
|
||||
min={0}/>
|
||||
</PropertyCollapsible>
|
||||
<RegisterPieceForm
|
||||
{...this.props}
|
||||
isFineUploaderEditable={this.state.isFineUploaderEditable}
|
||||
handleSuccess={this.handleSuccess}>
|
||||
{this.getSpecifyEditions()}
|
||||
{this.props.children}
|
||||
{this.getLicenses()}
|
||||
</Form>
|
||||
</RegisterPieceForm>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
@ -248,92 +189,4 @@ let RegisterPiece = React.createClass( {
|
||||
});
|
||||
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
onClick: React.PropTypes.func,
|
||||
// editable is used to lock react fine uploader in case
|
||||
// a user is actually not logged in already to prevent him from droping files
|
||||
// before login in
|
||||
editable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ReactS3FineUploader
|
||||
onClick={this.props.onClick}
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'digitalwork'
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: apiUrls.blob_digitalworks
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '25000000000'
|
||||
}}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
areAssetsDownloadable={false}
|
||||
areAssetsEditable={this.props.editable}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let InputDate = React.createClass({
|
||||
propTypes: {
|
||||
placeholderText: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
value: null,
|
||||
value_formatted: null
|
||||
};
|
||||
},
|
||||
|
||||
handleChange(date) {
|
||||
this.setState({
|
||||
value: date,
|
||||
value_formatted: date.format('YYYY')});
|
||||
let event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('click', false, true);
|
||||
document.dispatchEvent(event);
|
||||
event.target.value = date;
|
||||
this.props.onChange(event);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<DatePicker
|
||||
key="example2"
|
||||
dateFormat="YYYY"
|
||||
selected={this.state.value}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.props.onBlur}
|
||||
placeholderText={this.props.placeholderText}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default RegisterPiece;
|
||||
|
25
js/components/routes.js
Normal file
25
js/components/routes.js
Normal file
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import App from './ascribe_app';
|
||||
import AppConstants from '../constants/application_constants';
|
||||
|
||||
let Route = Router.Route;
|
||||
let Redirect = Router.Redirect;
|
||||
let baseUrl = AppConstants.baseUrl;
|
||||
|
||||
|
||||
function getRoutes(commonRoutes) {
|
||||
return (
|
||||
<Route name="app" path={baseUrl} handler={App}>
|
||||
<Redirect from={baseUrl} to="login" />
|
||||
<Redirect from={baseUrl + '/'} to="login" />
|
||||
{commonRoutes}
|
||||
</Route>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default getRoutes;
|
@ -1,50 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
|
||||
import UserStore from '../stores/user_store';
|
||||
|
||||
import GlobalNotificationModel from '../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
|
||||
import Form from './ascribe_forms/form';
|
||||
import SignupForm from './ascribe_forms/form_signup';
|
||||
import Property from './ascribe_forms/property';
|
||||
import FormPropertyHeader from './ascribe_forms/form_property_header';
|
||||
import InputCheckbox from './ascribe_forms/input_checkbox';
|
||||
|
||||
|
||||
import apiUrls from '../constants/api_urls';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
|
||||
|
||||
let SignupContainer = React.createClass({
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
getInitialState() {
|
||||
return mergeOptions({
|
||||
return {
|
||||
submitted: false,
|
||||
message: null
|
||||
}, UserStore.getState());
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.listen(this.onChange);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
|
||||
// if user is already logged in, redirect him to piece list
|
||||
if(this.state.currentUser && this.state.currentUser.email) {
|
||||
this.transitionTo('pieces');
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
handleSuccess(message){
|
||||
@ -60,108 +28,26 @@ let SignupContainer = React.createClass({
|
||||
<div className="ascribe-login-wrapper">
|
||||
<br/>
|
||||
<div className="ascribe-login-text ascribe-login-header">
|
||||
{this.state.message}
|
||||
{this.state.message}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="ascribe-login-wrapper">
|
||||
<br/>
|
||||
<SignupForm handleSuccess={this.handleSuccess}/>
|
||||
<SignupForm handleSuccess={this.handleSuccess}>
|
||||
<Property
|
||||
name='promo_code'
|
||||
label={getLangText('Promocode')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={getLangText('Enter a promocode here (Optional)')}/>
|
||||
</Property>
|
||||
</SignupForm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let SignupForm = React.createClass({
|
||||
propTypes: {
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
mixins: [Router.Navigation],
|
||||
|
||||
handleSuccess(response){
|
||||
|
||||
let notificationText = getLangText('Sign up successful');
|
||||
let notification = new GlobalNotificationModel(notificationText, 'success', 50000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
this.props.handleSuccess(getLangText('We sent an email to your address') + ' ' + response.user.email +
|
||||
', ' + getLangText('please confirm') + '.');
|
||||
|
||||
},
|
||||
getFormData(){
|
||||
return {terms: this.refs.form.refs.terms.refs.input.state.value};
|
||||
},
|
||||
render() {
|
||||
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('Store it in a safe place') + '!';
|
||||
return (
|
||||
<Form
|
||||
className="ascribe-form-bordered"
|
||||
ref='form'
|
||||
url={apiUrls.users_signup}
|
||||
handleSuccess={this.handleSuccess}
|
||||
getFormData={this.getFormData}
|
||||
buttons={
|
||||
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
|
||||
{getLangText('Sign up to ascribe')}
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
</button>
|
||||
}>
|
||||
<FormPropertyHeader>
|
||||
<h3>{getLangText('Welcome to ascribe')}</h3>
|
||||
</FormPropertyHeader>
|
||||
<Property
|
||||
name='email'
|
||||
label={getLangText('Email')}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder={getLangText('(e.g. andy@warhol.co.uk)')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password'
|
||||
label={getLangText('Password')}
|
||||
tooltip={tooltipPassword}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Use a combination of minimum 10 chars and numbers')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='password_confirm'
|
||||
label={getLangText('Confirm Password')}
|
||||
tooltip={tooltipPassword}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder={getLangText('Enter your password once again')}
|
||||
autoComplete="on"
|
||||
required/>
|
||||
</Property>
|
||||
<Property
|
||||
name='promo_code'
|
||||
label={getLangText('Promocode')}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={getLangText('Enter a promocode here (Optional)')}/>
|
||||
</Property>
|
||||
<Property
|
||||
name="terms"
|
||||
className="ascribe-settings-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputCheckbox/>
|
||||
</Property>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SignupContainer;
|
||||
export default SignupContainer;
|
||||
|
34
js/components/whitelabel/prize/app.js
Normal file
34
js/components/whitelabel/prize/app.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
import Hero from './components/hero';
|
||||
import Header from '../../header';
|
||||
// import Footer from '../../footer';
|
||||
import GlobalNotification from '../../global_notification';
|
||||
|
||||
let RouteHandler = Router.RouteHandler;
|
||||
|
||||
|
||||
let PrizeApp = React.createClass({
|
||||
mixins: [Router.State],
|
||||
|
||||
render() {
|
||||
let header = null;
|
||||
if (this.isActive('pieces')) {
|
||||
header = null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="whitelabel-prize">
|
||||
<Hero />
|
||||
{header}
|
||||
<RouteHandler />
|
||||
<GlobalNotification />
|
||||
<div id="modal" className="container"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PrizeApp;
|
18
js/components/whitelabel/prize/components/hero.js
Normal file
18
js/components/whitelabel/prize/components/hero.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import constants from '../../../../constants/application_constants';
|
||||
|
||||
|
||||
let Hero = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div className="hero">
|
||||
<img className="logo" src={constants.whitelabel.logo} alt="Sluice Art Prize" />
|
||||
<h1>Sluice Art Prize 2015</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Hero;
|
29
js/components/whitelabel/prize/components/landing.js
Normal file
29
js/components/whitelabel/prize/components/landing.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import ButtonLink from 'react-router-bootstrap/lib/ButtonLink';
|
||||
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
|
||||
|
||||
let Link = Router.Link;
|
||||
|
||||
let Landing = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="container">
|
||||
<ButtonGroup className="enter" bsSize="large" vertical block>
|
||||
<ButtonLink to="signup">
|
||||
Signup to the prize
|
||||
</ButtonLink>
|
||||
|
||||
Already a user? <Link to="login">log in</Link>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Landing;
|
27
js/components/whitelabel/prize/components/login_container.js
Normal file
27
js/components/whitelabel/prize/components/login_container.js
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import LoginForm from '../../../ascribe_forms/form_login';
|
||||
|
||||
let Link = Router.Link;
|
||||
|
||||
|
||||
let LoginContainer = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div className="ascribe-login-wrapper">
|
||||
<LoginForm headerMessage="Log in" />
|
||||
<div className="ascribe-login-text">
|
||||
I'm not a user <Link to="signup">Sign up...</Link><br/>
|
||||
I forgot my password <Link to="password_reset">Rescue me...</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
export default LoginContainer;
|
15
js/components/whitelabel/prize/components/piece_list.js
Normal file
15
js/components/whitelabel/prize/components/piece_list.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import PieceList from '../../../piece_list';
|
||||
|
||||
|
||||
let PrizePieceList = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<PieceList redirectTo="register_piece" />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PrizePieceList;
|
50
js/components/whitelabel/prize/components/register_piece.js
Normal file
50
js/components/whitelabel/prize/components/register_piece.js
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import RegisterPiece from '../../../register_piece';
|
||||
import Property from '../../../ascribe_forms/property';
|
||||
import InputTextAreaToggable from '../../../ascribe_forms/input_textarea_toggable';
|
||||
import InputCheckbox from '../../../ascribe_forms/input_checkbox';
|
||||
|
||||
import { getLangText } from '../../../../utils/lang_utils';
|
||||
|
||||
|
||||
let PrizeRegisterPiece = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<RegisterPiece
|
||||
headerMessage={getLangText('Submit to the prize')}
|
||||
submitMessage={getLangText('Submit')}
|
||||
canSpecifyEditions={false} >
|
||||
<Property
|
||||
name='artist_statement'
|
||||
label={getLangText('Artist statement')}
|
||||
editable={true}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
editable={true}
|
||||
placeholder={getLangText('Enter your statement')}
|
||||
required="required"/>
|
||||
</Property>
|
||||
<Property
|
||||
name='work_description'
|
||||
label={getLangText('Work description')}
|
||||
editable={true}>
|
||||
<InputTextAreaToggable
|
||||
rows={1}
|
||||
editable={true}
|
||||
placeholder={getLangText('Enter the description for your work')}
|
||||
required="required"/>
|
||||
</Property>
|
||||
<Property
|
||||
name="terms"
|
||||
className="ascribe-settings-property-collapsible-toggle"
|
||||
style={{paddingBottom: 0}}>
|
||||
<InputCheckbox/>
|
||||
</Property>
|
||||
</RegisterPiece>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PrizeRegisterPiece;
|
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import SignupForm from '../../../ascribe_forms/form_signup';
|
||||
|
||||
|
||||
let SignupContainer = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
submitted: false,
|
||||
message: null
|
||||
};
|
||||
},
|
||||
|
||||
handleSuccess(message){
|
||||
this.setState({
|
||||
submitted: true,
|
||||
message: message
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this.state.submitted){
|
||||
return (
|
||||
<div className="ascribe-login-wrapper">
|
||||
<div className="ascribe-login-text ascribe-login-header">
|
||||
{this.state.message}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="ascribe-login-wrapper">
|
||||
<SignupForm
|
||||
headerMessage="Sign up to the prize"
|
||||
submitMessage="Sign up"
|
||||
handleSuccess={this.handleSuccess} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default SignupContainer;
|
38
js/components/whitelabel/prize/routes.js
Normal file
38
js/components/whitelabel/prize/routes.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import Landing from './components/landing';
|
||||
import LoginContainer from './components/login_container';
|
||||
import SignupContainer from './components/signup_container';
|
||||
import PasswordResetContainer from '../../../components/password_reset_container';
|
||||
import PrizeRegisterPiece from './components/register_piece';
|
||||
import PrizePieceList from './components/piece_list';
|
||||
import PieceContainer from '../../ascribe_detail/piece_container';
|
||||
import EditionContainer from '../../ascribe_detail/edition_container';
|
||||
|
||||
import App from './app';
|
||||
import AppConstants from '../../../constants/application_constants';
|
||||
|
||||
let Route = Router.Route;
|
||||
let baseUrl = AppConstants.baseUrl;
|
||||
|
||||
|
||||
function getRoutes(commonRoutes) {
|
||||
return (
|
||||
<Route name="app" path={baseUrl} handler={App}>
|
||||
<Route name="landing" path="/" handler={Landing} />
|
||||
<Route name="login" path="login" handler={LoginContainer} />
|
||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
||||
<Route name="register_piece" path="register_piece" handler={PrizeRegisterPiece} />
|
||||
<Route name="pieces" path="collection" handler={PrizePieceList} />
|
||||
<Route name="piece" path="pieces/:pieceId" handler={PieceContainer} />
|
||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
||||
</Route>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default getRoutes;
|
@ -12,7 +12,7 @@ let apiUrls = {
|
||||
'coa_verify': AppConstants.apiEndpoint + 'coa/verify_coa/',
|
||||
'edition': AppConstants.apiEndpoint + 'editions/${bitcoin_id}/',
|
||||
'edition_delete': AppConstants.apiEndpoint + 'editions/${edition_id}/',
|
||||
'edition_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/${edition_id}/',
|
||||
'edition_remove_from_collection': AppConstants.apiEndpoint + 'ownership/shares/editions/${edition_id}/',
|
||||
'editions': AppConstants.apiEndpoint + 'editions/', // this should be moved to the one below
|
||||
'editions_list': AppConstants.apiEndpoint + 'pieces/${piece_id}/editions/',
|
||||
'licenses': AppConstants.apiEndpoint + 'ownership/licenses/',
|
||||
@ -25,7 +25,8 @@ let apiUrls = {
|
||||
'ownership_loans_confirm': AppConstants.apiEndpoint + 'ownership/loans/confirm/',
|
||||
'ownership_loans_deny': AppConstants.apiEndpoint + 'ownership/loans/deny/',
|
||||
'ownership_loans_contract': AppConstants.apiEndpoint + 'ownership/loans/contract/',
|
||||
'ownership_shares': AppConstants.apiEndpoint + 'ownership/shares/',
|
||||
'ownership_shares_editions': AppConstants.apiEndpoint + 'ownership/shares/editions/',
|
||||
'ownership_shares_pieces': AppConstants.apiEndpoint + 'ownership/shares/pieces/',
|
||||
'ownership_transfers': AppConstants.apiEndpoint + 'ownership/transfers/',
|
||||
'ownership_transfers_withdraw': AppConstants.apiEndpoint + 'ownership/transfers/withdraw/',
|
||||
'ownership_unconsigns': AppConstants.apiEndpoint + 'ownership/unconsigns/',
|
||||
|
@ -10,7 +10,10 @@ let constants = {
|
||||
'serverUrl': window.SERVER_URL,
|
||||
'baseUrl': window.BASE_URL,
|
||||
'aclList': ['edit', 'consign', 'consign_request', 'unconsign', 'unconsign_request', 'transfer',
|
||||
'loan', 'loan_request', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection']
|
||||
'loan', 'loan_request', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'],
|
||||
|
||||
// in case of whitelabel cusomization, we store stuff here
|
||||
'whitelabel': {}
|
||||
};
|
||||
|
||||
export default constants;
|
||||
|
@ -210,6 +210,7 @@ const languages = {
|
||||
'I agree to the Terms of Service': 'I agree to the Terms of Service',
|
||||
'read': 'read',
|
||||
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.',
|
||||
'REGISTREE': 'REGISTREE',
|
||||
},
|
||||
'de': {
|
||||
'ID': 'ID',
|
||||
@ -420,6 +421,7 @@ const languages = {
|
||||
'I agree to the Terms of Service': 'I agree to the Terms of Service',
|
||||
'read': 'read',
|
||||
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.',
|
||||
'REGISTREE': 'REGISTREE',
|
||||
},
|
||||
'fr': {
|
||||
'ID': 'ID',
|
||||
@ -630,6 +632,7 @@ const languages = {
|
||||
'I agree to the Terms of Service': 'I agree to the Terms of Service',
|
||||
'read': 'read',
|
||||
'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'Si votre adresse électronique existe dans notre base de données, vous recevrez un lien de récupération de mot de passe dans quelques minutes.',
|
||||
'REGISTREE': 'REGISTREE',
|
||||
}
|
||||
};
|
||||
|
||||
|
31
js/routes.js
31
js/routes.js
@ -3,7 +3,9 @@
|
||||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
|
||||
import AscribeApp from './components/ascribe_app';
|
||||
import getPrizeRoutes from './components/whitelabel/prize/routes';
|
||||
import getDefaultRoutes from './components/routes';
|
||||
|
||||
import PieceList from './components/piece_list';
|
||||
import PieceContainer from './components/ascribe_detail/piece_container';
|
||||
import EditionContainer from './components/ascribe_detail/edition_container';
|
||||
@ -15,15 +17,13 @@ import PasswordResetContainer from './components/password_reset_container';
|
||||
import SettingsContainer from './components/settings_container';
|
||||
import CoaVerifyContainer from './components/coa_verify_container';
|
||||
|
||||
import AppConstants from './constants/application_constants';
|
||||
import RegisterPiece from './components/register_piece';
|
||||
|
||||
let Route = Router.Route;
|
||||
let Redirect = Router.Redirect;
|
||||
let baseUrl = AppConstants.baseUrl;
|
||||
|
||||
let routes = (
|
||||
<Route name="app" path={baseUrl} handler={AscribeApp}>
|
||||
|
||||
const COMMON_ROUTES = (
|
||||
<Route>
|
||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
||||
<Route name="login" path="login" handler={LoginContainer} />
|
||||
<Route name="pieces" path="collection" handler={PieceList} />
|
||||
@ -33,10 +33,21 @@ let routes = (
|
||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} />
|
||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
||||
|
||||
<Redirect from={baseUrl} to="login" />
|
||||
<Redirect from={baseUrl + '/'} to="login" />
|
||||
</Route>
|
||||
);
|
||||
|
||||
export default routes;
|
||||
|
||||
function getRoutes(type) {
|
||||
let routes = null;
|
||||
console.log(type)
|
||||
if (type === 'prize') {
|
||||
routes = getPrizeRoutes(COMMON_ROUTES);
|
||||
} else {
|
||||
routes = getDefaultRoutes(COMMON_ROUTES);
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
|
||||
export default getRoutes;
|
||||
|
@ -19,6 +19,7 @@ class PieceListStore {
|
||||
* the number of items the resource actually - without pagination - provides.
|
||||
*/
|
||||
this.pieceList = [];
|
||||
// -1 specifies that the store is currently loading
|
||||
this.pieceListCount = -1;
|
||||
this.page = 1;
|
||||
this.pageSize = 10;
|
||||
|
@ -13,6 +13,14 @@ class PieceStore {
|
||||
onUpdatePiece(piece) {
|
||||
this.piece = piece;
|
||||
}
|
||||
|
||||
onUpdateProperty({key, value}) {
|
||||
if(this.piece && key in this.piece) {
|
||||
this.piece[key] = value;
|
||||
} else {
|
||||
throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default alt.createStore(PieceStore, 'PieceStore');
|
||||
|
@ -97,7 +97,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
|
||||
}
|
||||
}
|
||||
border-left: 3px solid rgba(0,0,0,0);
|
||||
border-top: 1px solid rgba(0,0,0,.1);
|
||||
//border-top: 1px solid rgba(0,0,0,.1);
|
||||
border-bottom: 1px solid rgba(0,0,0,.05);
|
||||
}
|
||||
tbody {
|
||||
|
5
sass/ascribe_app.scss
Normal file
5
sass/ascribe_app.scss
Normal file
@ -0,0 +1,5 @@
|
||||
.ascribe-default-app {
|
||||
background-color: #FDFDFD;
|
||||
border-radius: 0;
|
||||
padding-top: 70px;
|
||||
}
|
@ -11,6 +11,7 @@ $BASE_URL: '<%= BASE_URL %>';
|
||||
@import 'ascribe_theme';
|
||||
@import './ascribe-fonts/style';
|
||||
@import './ascribe-fonts/ascribe-fonts';
|
||||
@import 'ascribe_app';
|
||||
@import 'ascribe_login';
|
||||
@import 'ascribe_table';
|
||||
@import 'ascribe_accordion_list';
|
||||
@ -28,10 +29,11 @@ $BASE_URL: '<%= BASE_URL %>';
|
||||
@import 'ascribe_slides_container';
|
||||
@import 'ascribe_form';
|
||||
|
||||
body {
|
||||
background-color: #FDFDFD;
|
||||
border-radius: 0;
|
||||
margin-top: 70px;
|
||||
@import 'whitelabel/index';
|
||||
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
@ -42,6 +44,10 @@ hr {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#main {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
1
sass/whitelabel/index.scss
Normal file
1
sass/whitelabel/index.scss
Normal file
@ -0,0 +1 @@
|
||||
@import 'prize/index';
|
1
sass/whitelabel/prize/index.scss
Normal file
1
sass/whitelabel/prize/index.scss
Normal file
@ -0,0 +1 @@
|
||||
@import 'landing'
|
16
sass/whitelabel/prize/landing.scss
Normal file
16
sass/whitelabel/prize/landing.scss
Normal file
@ -0,0 +1,16 @@
|
||||
.whitelabel-prize {
|
||||
.hero {
|
||||
overflow: hidden;
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
padding-right: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.enter {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user