#48: add dummy ChooseAccountPanel

This commit is contained in:
SleepWalker 2016-11-05 22:23:56 +02:00
parent 907ccb39cd
commit 8fbcf27525
13 changed files with 163 additions and 57 deletions

View File

@ -0,0 +1,5 @@
{
"addAccount": "Add account",
"goToEly": "Go to Ely.by profile",
"logout": "Log out"
}

View File

@ -1,6 +1,12 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';
import { FormattedMessage as Message } from 'react-intl';
import { skins, SKIN_DARK } from 'components/ui';
import styles from './accountSwitcher.scss'; import styles from './accountSwitcher.scss';
import messages from './AccountSwitcher.intl.json';
const accounts = { const accounts = {
active: {id: 7, username: 'SleepWalker', email: 'danilenkos@auroraglobal.com'}, active: {id: 7, username: 'SleepWalker', email: 'danilenkos@auroraglobal.com'},
@ -13,9 +19,46 @@ const accounts = {
}; };
export default class AccountSwitcher extends Component { export default class AccountSwitcher extends Component {
static displayName = 'AccountSwitcher';
static propTypes = {
accounts: PropTypes.shape({ // TODO: accounts shape
active: PropTypes.shape({
id: PropTypes.number
}),
available: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number
}))
}),
skin: PropTypes.oneOf(skins),
hightLightActiveAccount: PropTypes.bool, // whether active account should be expanded and shown on the top
allowLogout: PropTypes.bool, // whether to show logout icon near each account
allowAdd: PropTypes.bool // whether to show add account button
};
static defaultProps = {
skin: SKIN_DARK,
highlightActiveAccount: true,
allowLogout: true,
allowAdd: true,
accounts
};
render() { render() {
const { accounts, skin, allowAdd, allowLogout, highlightActiveAccount } = this.props;
let {available} = accounts;
if (highlightActiveAccount) {
available = available.filter((account) => account.id !== accounts.active.id);
}
return ( return (
<div className={styles.accountSwitcher}> <div className={classNames(
styles.accountSwitcher,
styles[`${skin}AccountSwitcher`],
)}>
{highlightActiveAccount ? (
<div> <div>
<div className="account-icon"></div> <div className="account-icon"></div>
<div> <div>
@ -26,14 +69,15 @@ export default class AccountSwitcher extends Component {
{accounts.active.email} {accounts.active.email}
</div> </div>
<a href=""> <a href="">
Перейти в профиль Ely.by <Message {...messages.goToEly} />
</a> </a>
<a href=""> <a href="">
Выйти <Message {...messages.logout} />
</a> </a>
</div> </div>
</div> </div>
{accounts.available.map((account) => ( ) : null}
{available.map((account) => (
<div key={account.id}> <div key={account.id}>
<div className="account-icon"></div> <div className="account-icon"></div>
<div> <div>
@ -44,34 +88,23 @@ export default class AccountSwitcher extends Component {
{account.email} {account.email}
</div> </div>
</div> </div>
{allowLogout ? (
<div className={styles.logoutIcon}></div> <div className={styles.logoutIcon}></div>
) : (
<div className={styles.nextIcon}></div>
)}
</div> </div>
))} ))}
{allowAdd ? (
<div> <div>
<div> <div>
<span>+</span> <span className={styles.addAccount}>+</span>
Добавить аккаунт <Message {...messages.addAccount} />
</div> </div>
</div> </div>
) : null}
</div> </div>
); );
} }
} }
/*
import { intlShape } from 'react-intl';
import messages from './LoggedInPanel.intl.json';
static contextTypes = {
intl: intlShape.isRequired
};
<button
onClick={this.onLogout}
className={classNames(buttons.green, buttonGroups.item)}
title={this.context.intl.formatMessage(messages.logout)}
>
<span className={styles.logoutIcon} />
</button>
*/

View File

@ -1,6 +1,17 @@
@import '~components/ui/colors.scss';
.accountSwitcher { .accountSwitcher {
background: #fff; background: #fff;
color: #444; color: #444;
text-align: left;
}
.lightAccountSwitcher {
background: #fff;
}
.darkAccountSwitcher {
background: $black;
} }
.logoutIcon { .logoutIcon {
@ -8,3 +19,9 @@
color: #cdcdcd; color: #cdcdcd;
} }
.nextIcon {
composes: arrowRight from 'components/ui/icons.scss';
color: #cdcdcd;
}

View File

@ -33,7 +33,7 @@ const contexts = [
['login', 'password', 'forgotPassword', 'recoverPassword'], ['login', 'password', 'forgotPassword', 'recoverPassword'],
['register', 'activation', 'resendActivation'], ['register', 'activation', 'resendActivation'],
['acceptRules'], ['acceptRules'],
['permissions'] ['chooseAccount', 'permissions']
]; ];
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {

View File

@ -2,12 +2,12 @@
To add new panel you need to: To add new panel you need to:
* add new state to `services/authFlow` and coresponding test to `tests/services/authFlow`
* connect state to `authFlow`. Update `services/authFlow/AuthFlow.test` and `services/authFlow/AuthFlow.functional.test` (the last one for some complex flow)
* add new actions to `components/auth/actions` and api endpoints to `services/api`
* create panel component at `components/auth/[panelId]` * create panel component at `components/auth/[panelId]`
* add new context in `components/auth/PanelTransition` * add new context in `components/auth/PanelTransition`
* connect component to `routes` * connect component to `routes`
* add new state to `services/authFlow` and coresponding test to `tests/services/authFlow`
* connect state to `authFlow`. Update `services/authFlow/AuthFlow.test` and `services/authFlow/AuthFlow.functional.test` (the last one for some complex flow)
* add new actions to `components/auth/actions` and api endpoints to `services/api`
* whatever else you need * whatever else you need
Commit id with example: f4d315c Commit id with example: f4d315c

View File

@ -0,0 +1,5 @@
{
"chooseAccountTitle": "Choose an account",
"addAccount": "Log into another account",
"description": "You have logged in into multiple accounts. Please choose the one, you want to use to authorize {appName}"
}

View File

@ -0,0 +1,12 @@
import factory from 'components/auth/factory';
import messages from './ChooseAccount.intl.json';
import Body from './ChooseAccountBody';
export default factory({
title: messages.chooseAccountTitle,
body: Body,
footer: {
label: messages.addAccount
}
});

View File

@ -0,0 +1,36 @@
import React from 'react';
import { FormattedMessage as Message } from 'react-intl';
import BaseAuthBody from 'components/auth/BaseAuthBody';
import { AccountSwitcher } from 'components/accounts';
import styles from './chooseAccount.scss';
import messages from './ChooseAccount.intl.json';
export default class ChooseAccountBody extends BaseAuthBody {
static displayName = 'ChooseAccountBody';
static panelId = 'chooseAccount';
render() {
const {user} = this.context;
this.context.auth.client = {name: 'foo'}; // TODO: remove me
const {client} = this.context.auth;
return (
<div>
{this.renderErrors()}
<div>
<Message {...messages.description} values={{
appName: <span className={styles.appName}>{client.name}</span>
}} />
</div>
<div className={styles.accountSwitcherContainer}>
<AccountSwitcher allowAdd={false} allowLogout={false} highlightActiveAccount={false} />
</div>
</div>
);
}
}

View File

@ -0,0 +1,6 @@
.accountSwitcherContainer {
}
.appName {
color: #fff;
}

View File

@ -1,4 +1,4 @@
import React, { Component, PropTypes } from 'react'; import React, { Component } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
@ -12,8 +12,7 @@ import { userShape } from 'components/user/User';
export default class LoggedInPanel extends Component { export default class LoggedInPanel extends Component {
static displayName = 'LoggedInPanel'; static displayName = 'LoggedInPanel';
static propTypes = { static propTypes = {
user: userShape, user: userShape
onLogout: PropTypes.func.isRequired
}; };
render() { render() {
@ -28,16 +27,10 @@ export default class LoggedInPanel extends Component {
<span className={styles.expandIcon} /> <span className={styles.expandIcon} />
<div className={classNames(styles.accountSwitcherContainer)}> <div className={classNames(styles.accountSwitcherContainer)}>
<AccountSwitcher /> <AccountSwitcher skin="light" />
</div> </div>
</div> </div>
</div> </div>
); );
} }
onLogout = (event) => {
event.preventDefault();
this.props.onLogout();
};
} }

View File

@ -36,7 +36,6 @@ function RootPage(props) {
</Link> </Link>
<div className={styles.userbar}> <div className={styles.userbar}>
<Userbar {...props} <Userbar {...props}
onLogout={props.logout}
guestAction={isRegisterPage ? 'login' : 'register'} guestAction={isRegisterPage ? 'login' : 'register'}
/> />
</div> </div>
@ -58,16 +57,12 @@ RootPage.propTypes = {
pathname: PropTypes.string pathname: PropTypes.string
}).isRequired, }).isRequired,
children: PropTypes.element, children: PropTypes.element,
logout: PropTypes.func.isRequired,
isPopupActive: PropTypes.bool.isRequired isPopupActive: PropTypes.bool.isRequired
}; };
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { logout } from 'components/user/actions';
export default connect((state) => ({ export default connect((state) => ({
user: state.user, user: state.user,
isPopupActive: state.popup.popups.length > 0 isPopupActive: state.popup.popups.length > 0
}), { }))(RootPage);
logout
})(RootPage);

View File

@ -17,6 +17,7 @@ import OAuthInit from 'components/auth/OAuthInit';
import Register from 'components/auth/register/Register'; import Register from 'components/auth/register/Register';
import Login from 'components/auth/login/Login'; import Login from 'components/auth/login/Login';
import Permissions from 'components/auth/permissions/Permissions'; import Permissions from 'components/auth/permissions/Permissions';
import ChooseAccount from 'components/auth/chooseAccount/ChooseAccount';
import Activation from 'components/auth/activation/Activation'; import Activation from 'components/auth/activation/Activation';
import ResendActivation from 'components/auth/resendActivation/ResendActivation'; import ResendActivation from 'components/auth/resendActivation/ResendActivation';
import Password from 'components/auth/password/Password'; import Password from 'components/auth/password/Password';
@ -62,6 +63,7 @@ export default function routesFactory(store) {
<Route path="/activation(/:key)" components={new Activation()} {...startAuthFlow} /> <Route path="/activation(/:key)" components={new Activation()} {...startAuthFlow} />
<Route path="/resend-activation" components={new ResendActivation()} {...startAuthFlow} /> <Route path="/resend-activation" components={new ResendActivation()} {...startAuthFlow} />
<Route path="/oauth/permissions" components={new Permissions()} {...startAuthFlow} /> <Route path="/oauth/permissions" components={new Permissions()} {...startAuthFlow} />
<Route path="/oauth/choose-account" components={new ChooseAccount()} {...startAuthFlow} />
<Route path="/oauth/finish" component={Finish} {...startAuthFlow} /> <Route path="/oauth/finish" component={Finish} {...startAuthFlow} />
<Route path="/accept-rules" components={new AcceptRules()} {...startAuthFlow} /> <Route path="/accept-rules" components={new AcceptRules()} {...startAuthFlow} />
<Route path="/forgot-password" components={new ForgotPassword()} {...startAuthFlow} /> <Route path="/forgot-password" components={new ForgotPassword()} {...startAuthFlow} />

View File

@ -152,6 +152,8 @@ export default class AuthFlow {
this.setState(new ResendActivationState()); this.setState(new ResendActivationState());
break; break;
case '/oauth/choose-account':
break;
case '/': case '/':
case '/login': case '/login':
case '/password': case '/password':