account settings

This commit is contained in:
ddejongh 2015-06-17 17:48:23 +02:00
parent 1eb85786fe
commit fabff2922c
10 changed files with 328 additions and 9 deletions

View File

@ -0,0 +1,25 @@
'use strict';
import alt from '../alt';
import WalletSettingsFetcher from '../fetchers/wallet_settings_fetcher';
class WalletSettingsActions {
constructor() {
this.generateActions(
'updateWalletSettings'
);
}
fetchWalletSettings() {
WalletSettingsFetcher.fetchOne()
.then((res) => {
this.actions.updateWalletSettings(res.wallet_settings);
})
.catch((err) => {
console.log(err);
});
}
}
export default alt.createActions(WalletSettingsActions);

View File

@ -28,7 +28,7 @@ let PieceExtraDataForm = React.createClass({
renderForm() {
let defaultValue = this.props.editions[0].extra_data[this.props.name] || '';
if (defaultValue.length === 0 && ~this.props.editable){
if (defaultValue.length === 0 && !this.props.editable){
return null;
}
return (

View File

@ -91,25 +91,27 @@ let Edition = React.createClass({
<EditionHeader edition={this.props.edition}/>
<EditionSummary
edition={this.props.edition} />
<CollapsibleEditionDetails
title="Personal Note (private)"
show={this.state.currentUser.username && true || false}
iconName="pencil">
show={this.state.currentUser.username && true || false}>
<EditionPersonalNote
currentUser={this.state.currentUser}
handleSuccess={this.props.loadEdition}
edition={this.props.edition}/>
</CollapsibleEditionDetails>
<CollapsibleEditionDetails
title="Edition Note (public)"
show={this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note}
iconName="pencil">
show={this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note}>
<EditionPublicEditionNote
handleSuccess={this.props.loadEdition}
edition={this.props.edition}/>
</CollapsibleEditionDetails>
<CollapsibleEditionDetails
title="Further Details (all editions)">
title="Further Details (all editions)"
show={this.props.edition.acl.indexOf('edit') > -1 || Object.keys(this.props.edition.extra_data).length > 0}>
<EditionFurtherDetails
handleSuccess={this.props.loadEdition}
edition={this.props.edition}/>

View File

@ -15,6 +15,7 @@ import Navbar from 'react-bootstrap/lib/Navbar';
import NavItem from 'react-bootstrap/lib/NavItem';
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
import MenuItem from 'react-bootstrap/lib/MenuItem';
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
import LoginModal from '../components/ascribe_modal/modal_login';
import SignupModal from '../components/ascribe_modal/modal_signup';
@ -57,7 +58,7 @@ let Header = React.createClass({
if (this.state.currentUser.username){
account = (
<DropdownButton eventKey="1" title={this.state.currentUser.username}>
<MenuItem eventKey="1" href="/art/account_settings/">{getLangText('Account Settings')}</MenuItem>
<MenuItemLink to="settings">{getLangText('Account Settings')}</MenuItemLink>
<li className="divider"></li>
<MenuItem eventKey="2" href="/art/faq/">{getLangText('FAQ')}</MenuItem>
<MenuItem eventKey="3" href="/art/terms/">{getLangText('Terms of Service')}</MenuItem>

View File

@ -0,0 +1,257 @@
'use strict';
import React from 'react';
import Router from 'react-router';
import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
import UserActions from '../actions/user_actions';
import UserStore from '../stores/user_store';
import WalletSettingsActions from '../actions/wallet_settings_actions';
import WalletSettingsStore from '../stores/wallet_settings_store';
import GlobalNotificationModel from '../models/global_notification_model';
import GlobalNotificationActions from '../actions/global_notification_actions';
import classNames from 'classnames';
let SettingsContainer = React.createClass({
mixins: [Router.Navigation],
getInitialState() {
return UserStore.getState();
},
componentDidMount() {
UserStore.listen(this.onChange);
UserActions.fetchCurrentUser();
},
componentWillUnmount() {
UserStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
handleSuccess(){
this.transitionTo('pieces');
let notification = new GlobalNotificationModel('password succesfully updated', 'success', 10000);
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
return (
<div>
<CollapsibleParagraph
title="Account"
show={true}
defaultExpanded={true}>
<AccountSettings
currentUser={this.state.currentUser} />
</CollapsibleParagraph>
<CollapsibleParagraph
title="Bitcoin Wallet"
show={true}>
<BitcoinWalletSettings
currentUser={this.state.currentUser} />
</CollapsibleParagraph>
<CollapsibleParagraph
title="Contracts"
show={true}>
<ContractSettings
currentUser={this.state.currentUser} />
</CollapsibleParagraph>
<CollapsibleParagraph
title="API"
show={true}>
<APISettings
currentUser={this.state.currentUser} />
</CollapsibleParagraph>
</div>
);
}
});
const CollapsibleParagraph = React.createClass({
propTypes: {
title: React.PropTypes.string,
children: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
iconName: React.PropTypes.string
},
mixins: [CollapsibleMixin],
getCollapsibleDOMNode(){
return React.findDOMNode(this.refs.panel);
},
getCollapsibleDimensionValue(){
return React.findDOMNode(this.refs.panel).scrollHeight;
},
onHandleToggle(e){
e.preventDefault();
this.setState({expanded: !this.state.expanded});
},
render() {
let styles = this.getCollapsibleClassSet();
let text = this.isExpanded() ? '-' : '+';
return (
<div className="ascribe-detail-header">
<div className="ascribe-edition-collapsible-wrapper">
<div onClick={this.onHandleToggle}>
<span>{text} {this.props.title} </span>
</div>
<div ref='panel' className={classNames(styles) + ' ascribe-edition-collapible-content'}>
{this.props.children}
</div>
</div>
</div>
);
}
});
let SettingsProperty = React.createClass({
propTypes: {
label: React.PropTypes.string,
value: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.element
]),
separator: React.PropTypes.string,
labelClassName: React.PropTypes.string,
valueClassName: React.PropTypes.string
},
getDefaultProps() {
return {
separator: ':',
labelClassName: 'col-xs-3 col-sm-3 col-md-2 col-lg-1',
valueClassName: 'col-xs-9 col-sm-9 col-md-10 col-lg-11'
};
},
//render() {
// return (
// <div className="row ascribe-detail-property">
// <div className="row-same-height">
// <div className={this.props.labelClassName + ' col-xs-height col-bottom'}>
// <pre>{ this.props.label + this.props.separator}</pre>
// </div>
// <div className={this.props.valueClassName + ' col-xs-height col-bottom'}>
// <pre>{ this.props.value }</pre>
// </div>
// </div>
// </div>
// );
//}
render() {
return (
<div className="row ascribe-detail-property">
<div className="row-same-height">
<label>
<span>{ this.props.label + this.props.separator}</span>
<input type="text" disabled>{ this.props.value }</input>
</label>
</div>
</div>
);
}
});
let AccountSettings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object
},
render() {
return (
<div>
<SettingsProperty label="Username" value={this.props.currentUser.username}/>
<SettingsProperty label="Email" value={this.props.currentUser.email}/>
</div>
);
}
});
let BitcoinWalletSettings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object
},
getInitialState() {
return WalletSettingsStore.getState();
},
componentDidMount() {
WalletSettingsStore.listen(this.onChange);
WalletSettingsActions.fetchWalletSettings();
},
componentWillUnmount() {
WalletSettingsStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
render() {
return (
<div>
<SettingsProperty label="Bitcoin public key" value={this.state.walletSettings.btc_public_key}/>
<SettingsProperty label="Root Address" value={this.state.walletSettings.btc_root_address}/>
</div>
);
}
});
let ContractSettings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object
},
render() {
return (
<div>
<div>Username: {this.props.currentUser.username}</div>
<div>Email: {this.props.currentUser.email}</div>
</div>
);
}
});
let APISettings = React.createClass({
propTypes: {
currentUser: React.PropTypes.object
},
render() {
return (
<div>
<div>Username: {this.props.currentUser.username}</div>
<div>Email: {this.props.currentUser.email}</div>
</div>
);
}
});
export default SettingsContainer;

View File

@ -28,7 +28,8 @@ let apiUrls = {
'users_logout': AppConstants.apiEndpoint + 'users/logout/',
'users_password_reset': AppConstants.apiEndpoint + 'users/reset_password/',
'users_password_reset_request': AppConstants.apiEndpoint + 'users/request_reset_password/',
'users_signup': AppConstants.apiEndpoint + 'users/'
'users_signup': AppConstants.apiEndpoint + 'users/',
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/'
};
export default apiUrls;

View File

@ -0,0 +1,12 @@
'use strict';
import requests from '../utils/requests';
let WalletSettingsFetcher = {
fetchOne() {
return requests.get('wallet_settings');
}
};
export default WalletSettingsFetcher;

View File

@ -7,6 +7,7 @@ import AscribeApp from './components/ascribe_app';
import PieceList from './components/piece_list';
import EditionContainer from './components/edition_container';
import PasswordResetContainer from './components/password_reset_container';
import SettingsContainer from './components/settings_container';
import AppConstants from './constants/application_constants';
//import LoginModalHandler from './components/login_modal_handler';
@ -20,6 +21,7 @@ let routes = (
<Route name="pieces" path="collection" handler={PieceList} />
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
<Route name="settings" path="settings" handler={SettingsContainer} />
<Redirect from={baseUrl} to="pieces" />
<Redirect from={baseUrl + '/'} to="pieces" />

View File

@ -0,0 +1,18 @@
'use strict';
import alt from '../alt';
import WalletSettingsActions from '../actions/wallet_settings_actions';
class WalletSettingsStore {
constructor() {
this.walletSettings = {};
this.bindActions(WalletSettingsActions);
}
onUpdateWalletSettings(walletSettings) {
this.walletSettings = walletSettings;
}
}
export default alt.createStore(WalletSettingsStore, 'WalletSettingsStore');

View File

@ -60,7 +60,8 @@
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.1.2",
"yargs": "^3.10.0"
"yargs": "^3.10.0",
"react-router-bootstrap": "~0.16.0"
},
"jest": {
"scriptPreprocessor": "node_modules/babel-jest",