mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-11-27 01:02:14 +05:30
#48: account switcher for oauth
This commit is contained in:
parent
81a5437be0
commit
b6b8468904
@ -17,6 +17,7 @@ export class AccountSwitcher extends Component {
|
||||
switchAccount: PropTypes.func.isRequired,
|
||||
removeAccount: PropTypes.func.isRequired,
|
||||
onAfterAction: PropTypes.func, // called after each action performed
|
||||
onSwitch: PropTypes.func, // called after switching an account. The active account will be passed as arg
|
||||
accounts: PropTypes.shape({ // TODO: accounts shape
|
||||
active: PropTypes.shape({
|
||||
id: PropTypes.number
|
||||
@ -36,7 +37,8 @@ export class AccountSwitcher extends Component {
|
||||
highlightActiveAccount: true,
|
||||
allowLogout: true,
|
||||
allowAdd: true,
|
||||
onAfterAction() {}
|
||||
onAfterAction() {},
|
||||
onSwitch() {}
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -136,7 +138,8 @@ export class AccountSwitcher extends Component {
|
||||
event.preventDefault();
|
||||
|
||||
this.props.switchAccount(account)
|
||||
.then(() => this.props.onAfterAction());
|
||||
.then(() => this.props.onAfterAction())
|
||||
.then(() => this.props.onSwitch(account));
|
||||
};
|
||||
|
||||
onRemove = (account) => (event) => {
|
||||
|
@ -64,10 +64,7 @@ class PanelTransition extends Component {
|
||||
payload: PropTypes.object
|
||||
})]),
|
||||
isLoading: PropTypes.bool,
|
||||
login: PropTypes.shape({
|
||||
login: PropTypes.string,
|
||||
password: PropTypes.string
|
||||
})
|
||||
login: PropTypes.string
|
||||
}).isRequired,
|
||||
user: userShape.isRequired,
|
||||
setErrors: PropTypes.func.isRequired,
|
||||
@ -89,10 +86,7 @@ class PanelTransition extends Component {
|
||||
type: PropTypes.string,
|
||||
payload: PropTypes.object
|
||||
})]),
|
||||
login: PropTypes.shape({
|
||||
login: PropTypes.string,
|
||||
password: PropTypes.string
|
||||
})
|
||||
login: PropTypes.string
|
||||
}),
|
||||
user: userShape,
|
||||
requestRedraw: PropTypes.func,
|
||||
|
@ -122,6 +122,14 @@ export function setLogin(login) {
|
||||
};
|
||||
}
|
||||
|
||||
export const SET_SWITCHER = 'auth:setAccountSwitcher';
|
||||
export function setAccountSwitcher(isOn) {
|
||||
return {
|
||||
type: SET_SWITCHER,
|
||||
payload: isOn
|
||||
};
|
||||
}
|
||||
|
||||
export const ERROR = 'auth:error';
|
||||
export function setErrors(errors) {
|
||||
return {
|
||||
|
@ -13,8 +13,6 @@ export default class ChooseAccountBody extends BaseAuthBody {
|
||||
static panelId = 'chooseAccount';
|
||||
|
||||
render() {
|
||||
const {user} = this.context;
|
||||
this.context.auth.client = {name: 'foo'}; // TODO: remove me
|
||||
const {client} = this.context.auth;
|
||||
|
||||
return (
|
||||
@ -28,9 +26,18 @@ export default class ChooseAccountBody extends BaseAuthBody {
|
||||
</div>
|
||||
|
||||
<div className={styles.accountSwitcherContainer}>
|
||||
<AccountSwitcher allowAdd={false} allowLogout={false} highlightActiveAccount={false} />
|
||||
<AccountSwitcher
|
||||
allowAdd={false}
|
||||
allowLogout={false}
|
||||
highlightActiveAccount={false}
|
||||
onSwitch={this.onSwitch}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onSwitch = (account) => {
|
||||
this.context.resolve(account);
|
||||
};
|
||||
}
|
||||
|
@ -8,13 +8,15 @@ import {
|
||||
SET_SCOPES,
|
||||
SET_LOADING_STATE,
|
||||
REQUIRE_PERMISSIONS_ACCEPT,
|
||||
SET_LOGIN
|
||||
SET_LOGIN,
|
||||
SET_SWITCHER
|
||||
} from './actions';
|
||||
|
||||
export default combineReducers({
|
||||
login,
|
||||
error,
|
||||
isLoading,
|
||||
isSwitcherEnabled,
|
||||
client,
|
||||
oauth,
|
||||
scopes
|
||||
@ -54,6 +56,22 @@ function login(
|
||||
}
|
||||
}
|
||||
|
||||
function isSwitcherEnabled(
|
||||
state = true,
|
||||
{type, payload = false}
|
||||
) {
|
||||
switch (type) {
|
||||
case SET_SWITCHER:
|
||||
if (typeof payload !== 'boolean') {
|
||||
throw new Error('Expected payload of boolean type');
|
||||
}
|
||||
|
||||
return payload;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function isLoading(
|
||||
state = false,
|
||||
|
@ -152,14 +152,13 @@ export default class AuthFlow {
|
||||
this.setState(new ResendActivationState());
|
||||
break;
|
||||
|
||||
case '/oauth/choose-account':
|
||||
break;
|
||||
case '/':
|
||||
case '/login':
|
||||
case '/password':
|
||||
case '/accept-rules':
|
||||
case '/oauth/permissions':
|
||||
case '/oauth/finish':
|
||||
case '/oauth/choose-account':
|
||||
this.setState(new LoginState());
|
||||
break;
|
||||
|
||||
|
20
src/services/authFlow/ChooseAccountState.js
Normal file
20
src/services/authFlow/ChooseAccountState.js
Normal file
@ -0,0 +1,20 @@
|
||||
import AbstractState from './AbstractState';
|
||||
import LoginState from './LoginState';
|
||||
import CompleteState from './CompleteState';
|
||||
|
||||
export default class ChooseAccountState extends AbstractState {
|
||||
enter(context) {
|
||||
context.navigate('/oauth/choose-account');
|
||||
}
|
||||
|
||||
resolve(context, payload) {
|
||||
context.run('setAccountSwitcher', false);
|
||||
|
||||
if (payload.id) {
|
||||
context.setState(new CompleteState());
|
||||
} else {
|
||||
context.navigate('/login');
|
||||
context.setState(new LoginState());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import AbstractState from './AbstractState';
|
||||
import LoginState from './LoginState';
|
||||
import PermissionsState from './PermissionsState';
|
||||
import ChooseAccountState from './ChooseAccountState';
|
||||
import ActivationState from './ActivationState';
|
||||
import AcceptRulesState from './AcceptRulesState';
|
||||
import FinishState from './FinishState';
|
||||
@ -22,7 +23,9 @@ export default class CompleteState extends AbstractState {
|
||||
} else if (user.shouldAcceptRules) {
|
||||
context.setState(new AcceptRulesState());
|
||||
} else if (auth.oauth && auth.oauth.clientId) {
|
||||
if (auth.oauth.code) {
|
||||
if (auth.isSwitcherEnabled) {
|
||||
context.setState(new ChooseAccountState());
|
||||
} else if (auth.oauth.code) {
|
||||
context.setState(new FinishState());
|
||||
} else {
|
||||
const data = {};
|
||||
|
@ -13,6 +13,8 @@ export default class LoginState extends AbstractState {
|
||||
|| /login|password/.test(context.getRequest().path) // TODO: improve me
|
||||
) {
|
||||
context.navigate('/login');
|
||||
} else {
|
||||
context.setState(new PasswordState());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
import expect from 'unexpected';
|
||||
|
||||
import auth from 'components/auth/reducer';
|
||||
import { setLogin, SET_LOGIN } from 'components/auth/actions';
|
||||
import {
|
||||
setLogin, SET_LOGIN,
|
||||
setAccountSwitcher, SET_SWITCHER
|
||||
} from 'components/auth/actions';
|
||||
|
||||
describe('auth reducer', () => {
|
||||
describe('components/auth/reducer', () => {
|
||||
describe(SET_LOGIN, () => {
|
||||
it('should set login', () => {
|
||||
const expectedLogin = 'foo';
|
||||
@ -13,4 +16,28 @@ describe('auth reducer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(SET_SWITCHER, () => {
|
||||
it('should be enabled by default', () =>
|
||||
expect(auth(undefined, {}), 'to satisfy', {
|
||||
isSwitcherEnabled: true
|
||||
})
|
||||
);
|
||||
|
||||
it('should enable switcher', () => {
|
||||
const expectedValue = true;
|
||||
|
||||
expect(auth(undefined, setAccountSwitcher(expectedValue)), 'to satisfy', {
|
||||
isSwitcherEnabled: expectedValue
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable switcher', () => {
|
||||
const expectedValue = false;
|
||||
|
||||
expect(auth(undefined, setAccountSwitcher(expectedValue)), 'to satisfy', {
|
||||
isSwitcherEnabled: expectedValue
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -267,6 +267,7 @@ describe('AuthFlow', () => {
|
||||
'/password': LoginState,
|
||||
'/accept-rules': LoginState,
|
||||
'/oauth/permissions': LoginState,
|
||||
'/oauth/choose-account': LoginState,
|
||||
'/oauth/finish': LoginState,
|
||||
'/oauth2/v1/foo': OAuthState,
|
||||
'/oauth2/v1': OAuthState,
|
||||
|
Loading…
Reference in New Issue
Block a user