mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merge branch 'AD-419-decouple-piece-registration-from-' of bitbucket.org:ascribe/onion into AD-419-decouple-piece-registration-from-
Conflicts: js/components/ascribe_accordion_list/accordion_list_item_create_editions.js
This commit is contained in:
commit
6e1cf55841
@ -18,7 +18,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="main" class="container"></div>
|
<div id="main"></div>
|
||||||
<script src="<%= BASE_URL %>static/js/app.js"></script>
|
<script src="<%= BASE_URL %>static/js/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
37
js/app.js
37
js/app.js
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
require("babel/polyfill");
|
require('babel/polyfill');
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import Router from 'react-router';
|
||||||
@ -8,7 +8,8 @@ import Router from 'react-router';
|
|||||||
import fetch from 'isomorphic-fetch';
|
import fetch from 'isomorphic-fetch';
|
||||||
|
|
||||||
import ApiUrls from './constants/api_urls';
|
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';
|
import requests from './utils/requests';
|
||||||
|
|
||||||
let headers = {
|
let headers = {
|
||||||
@ -28,9 +29,35 @@ requests.defaults({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Router.run(routes, Router.HistoryLocation, (AscribeApp) => {
|
|
||||||
|
class AppGateway {
|
||||||
|
|
||||||
|
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() {
|
||||||
|
this.load('default');
|
||||||
|
}
|
||||||
|
|
||||||
|
load(type) {
|
||||||
|
Router.run(getRoutes(type), Router.HistoryLocation, (App) => {
|
||||||
React.render(
|
React.render(
|
||||||
<AscribeApp />,
|
<App />,
|
||||||
document.getElementById('main')
|
document.getElementById('main')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ag = new AppGateway();
|
||||||
|
ag.start();
|
||||||
|
@ -6,14 +6,14 @@ import Header from '../components/header';
|
|||||||
import Footer from '../components/footer';
|
import Footer from '../components/footer';
|
||||||
import GlobalNotification from './global_notification';
|
import GlobalNotification from './global_notification';
|
||||||
|
|
||||||
let Link = Router.Link;
|
// let Link = Router.Link;
|
||||||
let RouteHandler = Router.RouteHandler;
|
let RouteHandler = Router.RouteHandler;
|
||||||
|
|
||||||
|
|
||||||
let AscribeApp = React.createClass({
|
let AscribeApp = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="container ascribe-default-app">
|
||||||
<Header />
|
<Header />
|
||||||
<RouteHandler />
|
<RouteHandler />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
123
js/components/ascribe_forms/form_login.js
Normal file
123
js/components/ascribe_forms/form_login.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
'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 apiUrls from '../../constants/api_urls';
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
|
let LoginForm = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
redirectOnLoggedIn: React.PropTypes.bool,
|
||||||
|
redirectOnLoginSuccess: React.PropTypes.bool
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [Router.Navigation],
|
||||||
|
|
||||||
|
getDefaultProps() {
|
||||||
|
return {
|
||||||
|
redirectOnLoggedIn: true,
|
||||||
|
redirectOnLoginSuccess: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
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
|
||||||
|
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={
|
||||||
|
<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>
|
||||||
|
}>
|
||||||
|
<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>
|
||||||
|
<hr />
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LoginForm;
|
165
js/components/ascribe_forms/form_register_piece.js
Normal file
165
js/components/ascribe_forms/form_register_piece.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
'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({
|
||||||
|
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}>
|
||||||
|
{getLangText('Register work')}
|
||||||
|
</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('Register your work')}</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;
|
@ -1,78 +1,130 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
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 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({
|
let SignupForm = React.createClass({
|
||||||
mixins: [FormMixin],
|
|
||||||
|
|
||||||
url() {
|
propTypes: {
|
||||||
return apiUrls.users_signup;
|
handleSuccess: React.PropTypes.func
|
||||||
},
|
},
|
||||||
|
|
||||||
getFormData() {
|
mixins: [Router.Navigation],
|
||||||
return {
|
|
||||||
email: this.refs.email.state.value,
|
getInitialState() {
|
||||||
password: this.refs.password.state.value,
|
return UserStore.getState();
|
||||||
password_confirm: this.refs.password_confirm.state.value,
|
|
||||||
terms: this.refs.terms.state.value,
|
|
||||||
promo_code: this.refs.promo_code.state.value
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderForm() {
|
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 (
|
return (
|
||||||
<form id="signup_modal_content" role="form" onSubmit={this.submit}>
|
<Form
|
||||||
<input className="invisible" type="email" name="fake_consignee"/>
|
className="ascribe-form-bordered"
|
||||||
<input className="invisible" type="password" name="fake_password"/>
|
ref='form'
|
||||||
<InputText
|
url={apiUrls.users_signup}
|
||||||
ref="email"
|
handleSuccess={this.handleSuccess}
|
||||||
placeHolder={getLangText('Email')}
|
getFormData={this.getFormData}
|
||||||
required="required"
|
buttons={
|
||||||
|
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
|
||||||
|
{getLangText('Sign up to ascribe')}
|
||||||
|
</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('Welcome to ascribe')}</h3>
|
||||||
|
</FormPropertyHeader>
|
||||||
|
<Property
|
||||||
|
name='email'
|
||||||
|
label={getLangText('Email')}>
|
||||||
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
submitted={this.state.submitted}/>
|
placeholder={getLangText('(e.g. andy@warhol.co.uk)')}
|
||||||
<InputText
|
autoComplete="on"
|
||||||
ref="password"
|
required/>
|
||||||
placeHolder={getLangText('Choose a password')}
|
</Property>
|
||||||
required="required"
|
<Property
|
||||||
|
name='password'
|
||||||
|
label={getLangText('Password')}
|
||||||
|
tooltip={tooltipPassword}>
|
||||||
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
submitted={this.state.submitted}/>
|
placeholder={getLangText('Use a combination of minimum 10 chars and numbers')}
|
||||||
<InputText
|
autoComplete="on"
|
||||||
ref="password_confirm"
|
required/>
|
||||||
placeHolder={getLangText('Confirm password')}
|
</Property>
|
||||||
required="required"
|
<Property
|
||||||
|
name='password_confirm'
|
||||||
|
label={getLangText('Confirm Password')}
|
||||||
|
tooltip={tooltipPassword}>
|
||||||
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
submitted={this.state.submitted}/>
|
placeholder={getLangText('Enter your password once again')}
|
||||||
<div>
|
autoComplete="on"
|
||||||
{getLangText('Your password must be at least 10 characters')}.
|
required/>
|
||||||
{getLangText('This password is securing your digital property like a bank account')}.
|
</Property>
|
||||||
{getLangText('Store it in a safe place')}!
|
<Property
|
||||||
</div>
|
name='promo_code'
|
||||||
<InputCheckbox
|
label={getLangText('Promocode')}>
|
||||||
ref="terms"
|
<input
|
||||||
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"
|
type="text"
|
||||||
submitted={this.state.submitted}/>
|
placeholder={getLangText('Enter a promocode here (Optional)')}/>
|
||||||
<ButtonSubmitOrClose
|
</Property>
|
||||||
text={getLangText('JOIN US')}
|
<Property
|
||||||
onClose={this.props.onRequestHide}
|
name="terms"
|
||||||
submitted={this.state.submitted} />
|
className="ascribe-settings-property-collapsible-toggle"
|
||||||
</form>
|
style={{paddingBottom: 0}}>
|
||||||
|
<InputCheckbox/>
|
||||||
|
</Property>
|
||||||
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -68,9 +68,9 @@ let CoaVerifyForm = React.createClass({
|
|||||||
{getLangText('Verify your Certificate of Authenticity')}
|
{getLangText('Verify your Certificate of Authenticity')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='message'
|
name='message'
|
||||||
|
@ -3,23 +3,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import Router from 'react-router';
|
||||||
|
|
||||||
import GlobalNotificationModel from '../models/global_notification_model';
|
import LoginForm from './ascribe_forms/form_login';
|
||||||
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 { getLangText } from '../utils/lang_utils';
|
import { getLangText } from '../utils/lang_utils';
|
||||||
|
|
||||||
let Link = Router.Link;
|
let Link = Router.Link;
|
||||||
|
|
||||||
|
|
||||||
let LoginContainer = React.createClass({
|
let LoginContainer = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
message: React.PropTypes.string,
|
message: React.PropTypes.string,
|
||||||
@ -27,8 +17,6 @@ let LoginContainer = React.createClass({
|
|||||||
redirectOnLoginSuccess: React.PropTypes.bool
|
redirectOnLoginSuccess: React.PropTypes.bool
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
message: getLangText('Enter') + ' ascribe',
|
message: getLangText('Enter') + ' ascribe',
|
||||||
@ -37,32 +25,13 @@ 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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="ascribe-login-wrapper">
|
<div className="ascribe-login-wrapper">
|
||||||
<br/>
|
<br/>
|
||||||
<LoginForm
|
<LoginForm
|
||||||
|
redirectOnLoggedIn={this.props.redirectOnLoggedIn}
|
||||||
|
redirectOnLoginSuccess={this.props.redirectOnLoginSuccess}
|
||||||
message={this.props.message} />
|
message={this.props.message} />
|
||||||
<div className="ascribe-login-text">
|
<div className="ascribe-login-text">
|
||||||
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
{getLangText('Not an ascribe user')}? <Link to="signup">{getLangText('Sign up')}...</Link><br/>
|
||||||
@ -74,80 +43,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;
|
export default LoginContainer;
|
||||||
|
@ -82,9 +82,9 @@ let PasswordRequestResetForm = React.createClass({
|
|||||||
{getLangText('Reset your password')}
|
{getLangText('Reset your password')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='email'
|
name='email'
|
||||||
@ -129,9 +129,9 @@ let PasswordResetForm = React.createClass({
|
|||||||
{getLangText('Reset your password')}
|
{getLangText('Reset your password')}
|
||||||
</button>}
|
</button>}
|
||||||
spinner={
|
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" />
|
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||||
</button>
|
</span>
|
||||||
}>
|
}>
|
||||||
<Property
|
<Property
|
||||||
name='password'
|
name='password'
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import DatePicker from 'react-datepicker/dist/react-datepicker';
|
|
||||||
|
|
||||||
import Router from 'react-router';
|
import Router from 'react-router';
|
||||||
import Col from 'react-bootstrap/lib/Col';
|
import Col from 'react-bootstrap/lib/Col';
|
||||||
import Row from 'react-bootstrap/lib/Row';
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
|
|
||||||
import AppConstants from '../constants/application_constants';
|
|
||||||
|
|
||||||
import LicenseActions from '../actions/license_actions';
|
import LicenseActions from '../actions/license_actions';
|
||||||
import LicenseStore from '../stores/license_store';
|
import LicenseStore from '../stores/license_store';
|
||||||
|
|
||||||
@ -21,17 +17,14 @@ import UserStore from '../stores/user_store';
|
|||||||
import GlobalNotificationModel from '../models/global_notification_model';
|
import GlobalNotificationModel from '../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||||
|
|
||||||
import Form from './ascribe_forms/form';
|
|
||||||
import Property from './ascribe_forms/property';
|
import Property from './ascribe_forms/property';
|
||||||
import PropertyCollapsible from './ascribe_forms/property_collapsible';
|
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 LoginContainer from './login_container';
|
||||||
import SlidesContainer from './ascribe_slides_container/slides_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 { mergeOptions } from '../utils/general_utils';
|
||||||
import { getCookie } from '../utils/fetch_api_utils';
|
import { getCookie } from '../utils/fetch_api_utils';
|
||||||
@ -46,8 +39,6 @@ let RegisterPiece = React.createClass( {
|
|||||||
UserStore.getState(),
|
UserStore.getState(),
|
||||||
PieceListStore.getState(),
|
PieceListStore.getState(),
|
||||||
{
|
{
|
||||||
digitalWorkKey: null,
|
|
||||||
uploadStatus: false,
|
|
||||||
selectedLicense: 0,
|
selectedLicense: 0,
|
||||||
isFineUploaderEditable: false
|
isFineUploaderEditable: false
|
||||||
});
|
});
|
||||||
@ -97,32 +88,6 @@ let RegisterPiece = React.createClass( {
|
|||||||
this.transitionTo('piece', {pieceId: response.piece.id});
|
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){
|
onLicenseChange(event){
|
||||||
//console.log(this.state.licenses[event.target.selectedIndex].url);
|
//console.log(this.state.licenses[event.target.selectedIndex].url);
|
||||||
this.setState({selectedLicense: event.target.selectedIndex});
|
this.setState({selectedLicense: event.target.selectedIndex});
|
||||||
@ -170,59 +135,9 @@ let RegisterPiece = React.createClass( {
|
|||||||
onFocus={this.changeSlide}>
|
onFocus={this.changeSlide}>
|
||||||
<Row className="no-margin">
|
<Row className="no-margin">
|
||||||
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
|
||||||
<Form
|
<RegisterPieceForm
|
||||||
className="ascribe-form-bordered"
|
isFineUploaderEditable={this.state.isFineUploaderEditable}
|
||||||
ref='form'
|
handleSuccess={this.handleSuccess}>
|
||||||
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
|
<PropertyCollapsible
|
||||||
checkboxLabel={getLangText('Specify editions')}>
|
checkboxLabel={getLangText('Specify editions')}>
|
||||||
<span>{getLangText('Editions')}</span>
|
<span>{getLangText('Editions')}</span>
|
||||||
@ -232,7 +147,7 @@ let RegisterPiece = React.createClass( {
|
|||||||
min={0}/>
|
min={0}/>
|
||||||
</PropertyCollapsible>
|
</PropertyCollapsible>
|
||||||
{this.getLicenses()}
|
{this.getLicenses()}
|
||||||
</Form>
|
</RegisterPieceForm>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
@ -248,92 +163,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;
|
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,16 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
import SignupForm from './ascribe_forms/form_signup';
|
||||||
|
|
||||||
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 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({
|
let SignupContainer = React.createClass({
|
||||||
mixins: [Router.Navigation],
|
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return mergeOptions({
|
return {
|
||||||
submitted: false,
|
submitted: false,
|
||||||
message: null
|
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){
|
handleSuccess(message){
|
||||||
@ -75,93 +41,4 @@ let SignupContainer = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
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;
|
36
js/components/whitelabel/prize/app.js
Normal file
36
js/components/whitelabel/prize/app.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
'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 = (
|
||||||
|
<Header />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
26
js/components/whitelabel/prize/routes.js
Normal file
26
js/components/whitelabel/prize/routes.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import Router from 'react-router';
|
||||||
|
|
||||||
|
import Landing from './components/landing';
|
||||||
|
|
||||||
|
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} />
|
||||||
|
|
||||||
|
{commonRoutes}
|
||||||
|
</Route>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default getRoutes;
|
@ -10,7 +10,10 @@ let constants = {
|
|||||||
'serverUrl': window.SERVER_URL,
|
'serverUrl': window.SERVER_URL,
|
||||||
'baseUrl': window.BASE_URL,
|
'baseUrl': window.BASE_URL,
|
||||||
'aclList': ['edit', 'consign', 'consign_request', 'unconsign', 'unconsign_request', 'transfer',
|
'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;
|
export default constants;
|
||||||
|
30
js/routes.js
30
js/routes.js
@ -3,7 +3,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Router from 'react-router';
|
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 PieceList from './components/piece_list';
|
||||||
import PieceContainer from './components/ascribe_detail/piece_container';
|
import PieceContainer from './components/ascribe_detail/piece_container';
|
||||||
import EditionContainer from './components/ascribe_detail/edition_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 SettingsContainer from './components/settings_container';
|
||||||
import CoaVerifyContainer from './components/coa_verify_container';
|
import CoaVerifyContainer from './components/coa_verify_container';
|
||||||
|
|
||||||
import AppConstants from './constants/application_constants';
|
|
||||||
import RegisterPiece from './components/register_piece';
|
import RegisterPiece from './components/register_piece';
|
||||||
|
|
||||||
let Route = Router.Route;
|
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="signup" path="signup" handler={SignupContainer} />
|
||||||
<Route name="login" path="login" handler={LoginContainer} />
|
<Route name="login" path="login" handler={LoginContainer} />
|
||||||
<Route name="pieces" path="collection" handler={PieceList} />
|
<Route name="pieces" path="collection" handler={PieceList} />
|
||||||
@ -33,10 +33,20 @@ let routes = (
|
|||||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} />
|
<Route name="register_piece" path="register_piece" handler={RegisterPiece} />
|
||||||
<Route name="settings" path="settings" handler={SettingsContainer} />
|
<Route name="settings" path="settings" handler={SettingsContainer} />
|
||||||
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
<Route name="coa_verify" path="verify" handler={CoaVerifyContainer} />
|
||||||
|
|
||||||
<Redirect from={baseUrl} to="login" />
|
|
||||||
<Redirect from={baseUrl + '/'} to="login" />
|
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default routes;
|
|
||||||
|
function getRoutes(type) {
|
||||||
|
let routes = null;
|
||||||
|
if (type === 'prize') {
|
||||||
|
routes = getPrizeRoutes(COMMON_ROUTES);
|
||||||
|
} else {
|
||||||
|
routes = getDefaultRoutes(COMMON_ROUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default getRoutes;
|
||||||
|
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_theme';
|
||||||
@import './ascribe-fonts/style';
|
@import './ascribe-fonts/style';
|
||||||
@import './ascribe-fonts/ascribe-fonts';
|
@import './ascribe-fonts/ascribe-fonts';
|
||||||
|
@import 'ascribe_app';
|
||||||
@import 'ascribe_login';
|
@import 'ascribe_login';
|
||||||
@import 'ascribe_table';
|
@import 'ascribe_table';
|
||||||
@import 'ascribe_accordion_list';
|
@import 'ascribe_accordion_list';
|
||||||
@ -28,10 +29,11 @@ $BASE_URL: '<%= BASE_URL %>';
|
|||||||
@import 'ascribe_slides_container';
|
@import 'ascribe_slides_container';
|
||||||
@import 'ascribe_form';
|
@import 'ascribe_form';
|
||||||
|
|
||||||
body {
|
@import 'whitelabel/index';
|
||||||
background-color: #FDFDFD;
|
|
||||||
border-radius: 0;
|
|
||||||
margin-top: 70px;
|
html, body {
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@ -42,6 +44,10 @@ hr {
|
|||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
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