mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-17 21:53:03 +05:30
#48: add dummy ChooseAccountPanel
This commit is contained in:
parent
907ccb39cd
commit
8fbcf27525
5
src/components/accounts/AccountSwitcher.intl.json
Normal file
5
src/components/accounts/AccountSwitcher.intl.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"addAccount": "Add account",
|
||||||
|
"goToEly": "Go to Ely.by profile",
|
||||||
|
"logout": "Log out"
|
||||||
|
}
|
@ -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>
|
|
||||||
*/
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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') {
|
||||||
|
@ -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
|
||||||
|
@ -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}"
|
||||||
|
}
|
12
src/components/auth/chooseAccount/ChooseAccount.jsx
Normal file
12
src/components/auth/chooseAccount/ChooseAccount.jsx
Normal 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
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
36
src/components/auth/chooseAccount/ChooseAccountBody.jsx
Normal file
36
src/components/auth/chooseAccount/ChooseAccountBody.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
6
src/components/auth/chooseAccount/chooseAccount.scss
Normal file
6
src/components/auth/chooseAccount/chooseAccount.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.accountSwitcherContainer {
|
||||||
|
}
|
||||||
|
|
||||||
|
.appName {
|
||||||
|
color: #fff;
|
||||||
|
}
|
@ -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();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
|
@ -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} />
|
||||||
|
@ -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':
|
||||||
|
Loading…
Reference in New Issue
Block a user