mirror of
https://github.com/elyby/accounts-frontend.git
synced 2025-05-31 14:11:58 +05:30
#245: add register link to account chooser auth panel
This commit is contained in:
@@ -3,6 +3,7 @@ import { routeActions } from 'react-router-redux';
|
|||||||
import authentication from 'services/api/authentication';
|
import authentication from 'services/api/authentication';
|
||||||
import { updateUser, setGuest } from 'components/user/actions';
|
import { updateUser, setGuest } from 'components/user/actions';
|
||||||
import { setLocale } from 'components/i18n/actions';
|
import { setLocale } from 'components/i18n/actions';
|
||||||
|
import { setAccountSwitcher } from 'components/auth/actions';
|
||||||
import logger from 'services/logger';
|
import logger from 'services/logger';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -32,7 +33,7 @@ export { updateToken };
|
|||||||
* @return {function}
|
* @return {function}
|
||||||
*/
|
*/
|
||||||
export function authenticate({token, refreshToken}) {
|
export function authenticate({token, refreshToken}) {
|
||||||
return (dispatch) =>
|
return (dispatch, getState) =>
|
||||||
authentication.validateToken({token, refreshToken})
|
authentication.validateToken({token, refreshToken})
|
||||||
.catch((resp) => {
|
.catch((resp) => {
|
||||||
logger.warn('Error validating token during auth', {
|
logger.warn('Error validating token during auth', {
|
||||||
@@ -56,6 +57,8 @@ export function authenticate({token, refreshToken}) {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.then(({user, account}) => {
|
.then(({user, account}) => {
|
||||||
|
const {auth} = getState();
|
||||||
|
|
||||||
dispatch(add(account));
|
dispatch(add(account));
|
||||||
dispatch(activate(account));
|
dispatch(activate(account));
|
||||||
dispatch(updateUser(user));
|
dispatch(updateUser(user));
|
||||||
@@ -68,6 +71,14 @@ export function authenticate({token, refreshToken}) {
|
|||||||
sessionStorage.setItem(`stranger${account.id}`, 1);
|
sessionStorage.setItem(`stranger${account.id}`, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auth && auth.oauth && auth.oauth.clientId) {
|
||||||
|
// if we authenticating during oauth, we disable account chooser
|
||||||
|
// because user probably has made his choise now
|
||||||
|
// this may happen, when user registers, logs in or uses account
|
||||||
|
// chooser panel during oauth
|
||||||
|
dispatch(setAccountSwitcher(false));
|
||||||
|
}
|
||||||
|
|
||||||
return dispatch(setLocale(user.lang))
|
return dispatch(setLocale(user.lang))
|
||||||
.then(() => account);
|
.then(() => account);
|
||||||
});
|
});
|
||||||
|
@@ -2,5 +2,6 @@
|
|||||||
"chooseAccountTitle": "Choose an account",
|
"chooseAccountTitle": "Choose an account",
|
||||||
"addAccount": "Log into another account",
|
"addAccount": "Log into another account",
|
||||||
"logoutAll": "Log out from all accounts",
|
"logoutAll": "Log out from all accounts",
|
||||||
|
"createNewAccount": "Create new account",
|
||||||
"description": "You have logged in into multiple accounts. Please choose the one, you want to use to authorize {appName}"
|
"description": "You have logged in into multiple accounts. Please choose the one, you want to use to authorize {appName}"
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,11 @@ export default factory({
|
|||||||
},
|
},
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: messages.logoutAll
|
label: messages.createNewAccount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: messages.logoutAll,
|
||||||
|
payload: {logout: true}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import AbstractState from './AbstractState';
|
import AbstractState from './AbstractState';
|
||||||
import LoginState from './LoginState';
|
import LoginState from './LoginState';
|
||||||
import CompleteState from './CompleteState';
|
import CompleteState from './CompleteState';
|
||||||
|
import RegisterState from './RegisterState';
|
||||||
|
|
||||||
export default class ChooseAccountState extends AbstractState {
|
export default class ChooseAccountState extends AbstractState {
|
||||||
enter(context) {
|
enter(context) {
|
||||||
@@ -8,9 +9,6 @@ export default class ChooseAccountState extends AbstractState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolve(context, payload) {
|
resolve(context, payload) {
|
||||||
// do not ask again after user adds account, or chooses an existed one
|
|
||||||
context.run('setAccountSwitcher', false);
|
|
||||||
|
|
||||||
if (payload.id) {
|
if (payload.id) {
|
||||||
context.setState(new CompleteState());
|
context.setState(new CompleteState());
|
||||||
} else {
|
} else {
|
||||||
@@ -19,7 +17,16 @@ export default class ChooseAccountState extends AbstractState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reject(context) {
|
/**
|
||||||
context.run('logout');
|
* @param {object} context
|
||||||
|
* @param {object} payload
|
||||||
|
* @param {bool} [payload.logout=false]
|
||||||
|
*/
|
||||||
|
reject(context, payload = {}) {
|
||||||
|
if (payload.logout) {
|
||||||
|
context.run('logout');
|
||||||
|
} else {
|
||||||
|
context.setState(new RegisterState());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,11 +24,7 @@ export default class PasswordState extends AbstractState {
|
|||||||
rememberMe,
|
rememberMe,
|
||||||
login
|
login
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => context.setState(new CompleteState()))
|
||||||
context.run('setAccountSwitcher', false);
|
|
||||||
|
|
||||||
context.setState(new CompleteState());
|
|
||||||
})
|
|
||||||
.catch((err = {}) => err.errors || logger.warn(err));
|
.catch((err = {}) => err.errors || logger.warn(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,13 +7,7 @@ import ResendActivationState from './ResendActivationState';
|
|||||||
|
|
||||||
export default class RegisterState extends AbstractState {
|
export default class RegisterState extends AbstractState {
|
||||||
enter(context) {
|
enter(context) {
|
||||||
const {user} = context.getState();
|
context.navigate('/register');
|
||||||
|
|
||||||
if (user.isGuest) {
|
|
||||||
context.navigate('/register');
|
|
||||||
} else {
|
|
||||||
context.setState(new CompleteState());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(context, payload) {
|
resolve(context, payload) {
|
||||||
|
@@ -14,4 +14,4 @@ export default {
|
|||||||
return document.referrer.includes(`${location.protocol}//${location.host}`)
|
return document.referrer.includes(`${location.protocol}//${location.host}`)
|
||||||
|| this.initialLength < window.history.length;
|
|| this.initialLength < window.history.length;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@@ -19,6 +19,7 @@ import {
|
|||||||
import { SET_LOCALE } from 'components/i18n/actions';
|
import { SET_LOCALE } from 'components/i18n/actions';
|
||||||
|
|
||||||
import { updateUser, setUser } from 'components/user/actions';
|
import { updateUser, setUser } from 'components/user/actions';
|
||||||
|
import { setAccountSwitcher } from 'components/auth/actions';
|
||||||
|
|
||||||
const account = {
|
const account = {
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -67,7 +68,7 @@ describe('components/accounts/actions', () => {
|
|||||||
|
|
||||||
describe('#authenticate()', () => {
|
describe('#authenticate()', () => {
|
||||||
it('should request user state using token', () =>
|
it('should request user state using token', () =>
|
||||||
authenticate(account)(dispatch).then(() =>
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
expect(authentication.validateToken, 'to have a call satisfying', [
|
expect(authentication.validateToken, 'to have a call satisfying', [
|
||||||
{token: account.token, refreshToken: account.refreshToken}
|
{token: account.token, refreshToken: account.refreshToken}
|
||||||
])
|
])
|
||||||
@@ -75,7 +76,7 @@ describe('components/accounts/actions', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it(`dispatches ${ADD} action`, () =>
|
it(`dispatches ${ADD} action`, () =>
|
||||||
authenticate(account)(dispatch).then(() =>
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
expect(dispatch, 'to have a call satisfying', [
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
add(account)
|
add(account)
|
||||||
])
|
])
|
||||||
@@ -83,7 +84,7 @@ describe('components/accounts/actions', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it(`dispatches ${ACTIVATE} action`, () =>
|
it(`dispatches ${ACTIVATE} action`, () =>
|
||||||
authenticate(account)(dispatch).then(() =>
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
expect(dispatch, 'to have a call satisfying', [
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
activate(account)
|
activate(account)
|
||||||
])
|
])
|
||||||
@@ -91,7 +92,7 @@ describe('components/accounts/actions', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it(`dispatches ${SET_LOCALE} action`, () =>
|
it(`dispatches ${SET_LOCALE} action`, () =>
|
||||||
authenticate(account)(dispatch).then(() =>
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
expect(dispatch, 'to have a call satisfying', [
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
{type: SET_LOCALE, payload: {locale: 'be'}}
|
{type: SET_LOCALE, payload: {locale: 'be'}}
|
||||||
])
|
])
|
||||||
@@ -99,7 +100,7 @@ describe('components/accounts/actions', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it('should update user state', () =>
|
it('should update user state', () =>
|
||||||
authenticate(account)(dispatch).then(() =>
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
expect(dispatch, 'to have a call satisfying', [
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
updateUser({...user, isGuest: false})
|
updateUser({...user, isGuest: false})
|
||||||
])
|
])
|
||||||
@@ -107,7 +108,7 @@ describe('components/accounts/actions', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it('resolves with account', () =>
|
it('resolves with account', () =>
|
||||||
authenticate(account)(dispatch).then((resp) =>
|
authenticate(account)(dispatch, getState).then((resp) =>
|
||||||
expect(resp, 'to equal', account)
|
expect(resp, 'to equal', account)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -115,7 +116,7 @@ describe('components/accounts/actions', () => {
|
|||||||
it('rejects when bad auth data', () => {
|
it('rejects when bad auth data', () => {
|
||||||
authentication.validateToken.returns(Promise.reject({}));
|
authentication.validateToken.returns(Promise.reject({}));
|
||||||
|
|
||||||
return expect(authenticate(account)(dispatch), 'to be rejected').then(() => {
|
return expect(authenticate(account)(dispatch, getState), 'to be rejected').then(() => {
|
||||||
expect(dispatch, 'to have a call satisfying', [
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
{payload: {isGuest: true}},
|
{payload: {isGuest: true}},
|
||||||
]);
|
]);
|
||||||
@@ -134,11 +135,37 @@ describe('components/accounts/actions', () => {
|
|||||||
|
|
||||||
sessionStorage.removeItem(expectedKey);
|
sessionStorage.removeItem(expectedKey);
|
||||||
|
|
||||||
return authenticate(account)(dispatch).then(() => {
|
return authenticate(account)(dispatch, getState).then(() => {
|
||||||
expect(sessionStorage.getItem(expectedKey), 'not to be null');
|
expect(sessionStorage.getItem(expectedKey), 'not to be null');
|
||||||
sessionStorage.removeItem(expectedKey);
|
sessionStorage.removeItem(expectedKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when user authenticated during oauth', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
getState.returns({
|
||||||
|
accounts: {
|
||||||
|
available: [],
|
||||||
|
active: null
|
||||||
|
},
|
||||||
|
user: {},
|
||||||
|
auth: {
|
||||||
|
oauth: {
|
||||||
|
clientId: 'ely.by',
|
||||||
|
prompt: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch setAccountSwitcher', () =>
|
||||||
|
authenticate(account)(dispatch, getState).then(() =>
|
||||||
|
expect(dispatch, 'to have a call satisfying', [
|
||||||
|
setAccountSwitcher(false)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#revoke()', () => {
|
describe('#revoke()', () => {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import ChooseAccountState from 'services/authFlow/ChooseAccountState';
|
import ChooseAccountState from 'services/authFlow/ChooseAccountState';
|
||||||
import CompleteState from 'services/authFlow/CompleteState';
|
import CompleteState from 'services/authFlow/CompleteState';
|
||||||
import LoginState from 'services/authFlow/LoginState';
|
import LoginState from 'services/authFlow/LoginState';
|
||||||
|
import RegisterState from 'services/authFlow/RegisterState';
|
||||||
|
|
||||||
import { bootstrap, expectState, expectNavigate, expectRun } from './helpers';
|
import { bootstrap, expectState, expectNavigate, expectRun } from './helpers';
|
||||||
|
|
||||||
@@ -31,14 +32,12 @@ describe('ChooseAccountState', () => {
|
|||||||
|
|
||||||
describe('#resolve', () => {
|
describe('#resolve', () => {
|
||||||
it('should transition to complete if existed account was choosen', () => {
|
it('should transition to complete if existed account was choosen', () => {
|
||||||
expectRun(mock, 'setAccountSwitcher', false);
|
|
||||||
expectState(mock, CompleteState);
|
expectState(mock, CompleteState);
|
||||||
|
|
||||||
state.resolve(context, {id: 123});
|
state.resolve(context, {id: 123});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transition to login if user wants to add new account', () => {
|
it('should transition to login if user wants to add new account', () => {
|
||||||
expectRun(mock, 'setAccountSwitcher', false);
|
|
||||||
expectNavigate(mock, '/login');
|
expectNavigate(mock, '/login');
|
||||||
expectState(mock, LoginState);
|
expectState(mock, LoginState);
|
||||||
|
|
||||||
@@ -47,10 +46,16 @@ describe('ChooseAccountState', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#reject', () => {
|
describe('#reject', () => {
|
||||||
it('should logout', () => {
|
it('should transition to register', () => {
|
||||||
expectRun(mock, 'logout');
|
expectState(mock, RegisterState);
|
||||||
|
|
||||||
state.reject(context);
|
state.reject(context);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should logout', () => {
|
||||||
|
expectRun(mock, 'logout');
|
||||||
|
|
||||||
|
state.reject(context, {logout: true});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -61,7 +61,6 @@ describe('PasswordState', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
expectRun(mock, 'setAccountSwitcher', false);
|
|
||||||
expectRun(
|
expectRun(
|
||||||
mock,
|
mock,
|
||||||
'login',
|
'login',
|
||||||
|
@@ -34,16 +34,6 @@ describe('RegisterState', () => {
|
|||||||
|
|
||||||
state.enter(context);
|
state.enter(context);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transition to complete if not guest', () => {
|
|
||||||
context.getState.returns({
|
|
||||||
user: {isGuest: false}
|
|
||||||
});
|
|
||||||
|
|
||||||
expectState(mock, CompleteState);
|
|
||||||
|
|
||||||
state.enter(context);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#resolve', () => {
|
describe('#resolve', () => {
|
||||||
|
Reference in New Issue
Block a user