Created
June 20, 2018 11:01
-
-
Save simform-solutions/33efbe2843f21a576ff87d911190acd5 to your computer and use it in GitHub Desktop.
Auth module with Redux and Saga Integration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import { Provider } from 'react-redux' | |
import { PersistGate } from 'redux-persist/integration/react' | |
import { store, persistor } from 'rdx' | |
import App from 'containers/App/App.component' | |
import './index.css' | |
import 'assets/fonts.css' | |
import registerServiceWorker from './registerServiceWorker' | |
ReactDOM.render( | |
<Provider store={store}> | |
<PersistGate loading={'Loading...'} persistor={persistor}> | |
<App /> | |
</PersistGate> | |
</Provider>, | |
document.getElementById('root') | |
) | |
registerServiceWorker() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Fragment } from 'react' | |
import cx from 'classnames' | |
import { connect } from 'react-redux' | |
import { Icon } from 'antd' | |
import { Helmet } from 'react-helmet' | |
import { FormattedMessage } from 'react-intl' | |
import { withRouter } from 'react-router-dom' | |
import { truncatePhoneNumber } from 'config/utils' | |
import { required, phoneConstraints } from 'config/validators' | |
import { actions } from 'rdx/auth' | |
import { actionMethods } from 'rdx/ui' | |
import authService from 'services/auth' | |
import { routes } from 'config/routes' | |
import Button from 'components/Button/Button.component' | |
import Input from 'components/TextBox/TextBox.component' | |
import TelInput from 'components/TelInput/TelInput.component' | |
import styles from './Login.scss' | |
import BackArrowComponent from 'components/BackArrow.component' | |
import Loader from 'components/Loader.component' | |
class Login extends React.Component { | |
state = { | |
showPasswordField: false, | |
password: '', | |
phoneNumber: '+82', | |
countryCode: '' | |
} | |
componentDidMount() { | |
this.props.changeText('') | |
this.props.enableBack(false) | |
} | |
onPhoneNumberChange = (status, value, countryData, number, id) => { | |
const val = truncatePhoneNumber(value, countryData.dialCode.toString()) | |
const regex = /[a-zA-z]+(\s+)?/ | |
if (regex.test(value) || val.length > 10) { | |
return | |
} | |
this.setState({ | |
phoneNumber: value, | |
countryCode: countryData.dialCode.toString() | |
}) | |
} | |
onSubmit = async e => { | |
e.preventDefault() | |
const { phoneNumber, showPasswordField, countryCode, password } = this.state | |
const numberWithoutCode = truncatePhoneNumber(phoneNumber, countryCode) | |
if (!showPasswordField) { | |
const phoneError = phoneConstraints(phoneNumber) | |
if (phoneError) { | |
return this.props.showSnackbar({ message: 'validation.phone' }) | |
} | |
const response = await authService.accountExists(numberWithoutCode) | |
if (response) { | |
const state = { ...this.state } | |
state.showPasswordField = true | |
this.setState(state) | |
} else { | |
this.props.history.push({ | |
pathname: routes.otp.path, | |
state: { | |
phoneNumber: numberWithoutCode, | |
countryCode | |
} | |
}) | |
} | |
} else { | |
if (required(password)) { | |
return this.props.showSnackbar({ message: 'login.passwordRequired' }) | |
} | |
this.props.login({ | |
phoneNumber: numberWithoutCode, | |
countryCode, | |
password | |
}) | |
} | |
} | |
forgotPasswordPage = () => this.props.history.push(routes.forgotPassword.path) | |
render() { | |
const { loading } = this.props | |
const { showPasswordField, password } = this.state | |
return ( | |
<div className={cx(styles.app, 'w-100')}> | |
<Helmet> | |
<title>{routes.login.name}</title> | |
</Helmet> | |
<div | |
className={cx('w-100', 'p-l-r-20', 'p-t-120', 'main-locar-container')} | |
> | |
<div className="w-100 desktop-version-container"> | |
<h3 className={cx(styles.titlelogin, 'border-bottom-desktop')}> | |
<BackArrowComponent path={routes.dashboard.path} /> | |
<FormattedMessage | |
id={ | |
!showPasswordField | |
? 'login.enterNumber' | |
: 'login.enterPassword' | |
} | |
/> | |
</h3> | |
<div className="w-100 cutom-desktop-content-box"> | |
<form onSubmit={this.onSubmit} method="post"> | |
<TelInput | |
onPhoneNumberBlur={() => {}} | |
value={this.state.phoneNumber} | |
onPhoneNumberChange={this.onPhoneNumberChange} | |
/> | |
{showPasswordField && ( | |
<Fragment> | |
<Input | |
placeholder="input.password" | |
type="password" | |
value={password} | |
onChange={e => | |
this.setState({ password: e.target.value }) | |
} | |
className={['m-t-10']} | |
icon={ | |
<Icon | |
type="icon-ico-password" | |
style={{ | |
color: password.length ? '#1d1e28' : '#b3bac0', | |
fontSize: '16px', | |
paddingLeft: '3px' | |
}} | |
/> | |
} | |
/> | |
<p | |
onClick={this.forgotPasswordPage} | |
style={{ cursor: 'pointer' }} | |
className={styles.forgotText} | |
> | |
<FormattedMessage id="login.forgotPassword" /> | |
</p> | |
</Fragment> | |
)} | |
<Button type="submit" className={['m-t-20', 'm-b-20']}> | |
{loading ? ( | |
<Loader size={20} /> | |
) : ( | |
<FormattedMessage id="button.continue" /> | |
)} | |
</Button> | |
</form> | |
</div> | |
</div> | |
</div> | |
</div> | |
) | |
} | |
} | |
const mapStateToProps = state => ({ loading: state.auth.loading }) | |
const mapDispatchToProps = { | |
login: ({ phoneNumber, password, countryCode }) => ({ | |
type: actions.LOGIN, | |
phoneNumber, | |
countryCode, | |
password | |
}), | |
showSnackbar: actionMethods.showSnackBar, | |
changeText: actionMethods.changeNavText, | |
enableBack: actionMethods.toggleBackButton | |
} | |
export default withRouter( | |
connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(Login) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createSelector } from 'reselect' | |
import { defaultLang } from 'config/utils' | |
export const actions = { | |
SIGNUP: '[auth] saga signup', | |
SIGNUP_REQUEST: '[auth] signup requested', | |
SIGNUP_SUCCESS: '[auth] signup successful', | |
SIGNUP_ERROR: '[auth] signup error', | |
UPDATE_PHONE: '[auth] saga update phone number', | |
UPDATE_PHONE_REQUEST: '[auth] update phone number request', | |
UPDATE_PHONE_SUCCESS: '[auth] update phone number success', | |
UPDATE_PHONE_ERROR: '[auth] update phone number error', | |
UPDATE_EMAIL: '[auth] saga update email', | |
UPDATE_EMAIL_REQUEST: '[auth] update email request', | |
UPDATE_EMAIL_SUCCESS: '[auth] update email success', | |
UPDATE_EMAIL_ERROR: '[auth] update email error', | |
UPDATE_COMM_LANG: '[auth] saga update communication language', | |
UPDATE_COMM_LANG_REQUEST: '[auth] update communication language request', | |
UPDATE_COMM_LANG_SUCCESS: '[auth] update communication language success', | |
UPDATE_COMM_LANG_ERROR: '[auth] update communication language error', | |
UPDATE_USER_DETAILS: '[auth] saga update user details', | |
UPDATE_USER_DETAILS_REQUEST: '[auth] update user details request', | |
UPDATE_USER_DETAILS_SUCCESS: '[auth] update user details success', | |
UPDATE_USER_DETAILS_ERROR: '[auth] update user details error', | |
VERIFY_OTP: '[auth] saga verify otp', | |
VERIFY_OTP_REQUEST: '[auth] verify otp request', | |
VERIFY_OTP_SUCCESS: '[auth] verify otp success', | |
VERIFY_OTP_ERROR: '[auth] verify otp error', | |
VERIFY_EMAIL: '[auth] saga verify email', | |
VERIFY_EMAIL_REQUEST: '[auth] verify email request', | |
VERIFY_EMAIL_SUCCESS: '[auth] verify email success', | |
VERIFY_EMAIL_ERROR: '[auth] verify email error', | |
RESEND_OTP: '[auth] saga resend otp', | |
RESEND_OTP_REQUEST: '[auth] resend otp request', | |
RESEND_OTP_SUCCESS: '[auth] resend otp success', | |
RESEND_OTP_ERROR: '[auth] resend otp error', | |
LOGIN_REQUEST: '[auth] login user requested', | |
LOGIN: '[auth] saga login', | |
LOGIN_SUCCESS: '[auth] login success', | |
LOGIN_ERROR: '[auth] login error', | |
LOGOUT: '[auth] client unset token', | |
LANGUAGE_CHANGE: '[user] change language' | |
} | |
const userSelector = state => state.auth.user | |
export const selectors = { | |
isAuthenticated: createSelector( | |
userSelector, | |
user => user.isPhoneVerified && user.isEmailVerified | |
), | |
phoneNumber: createSelector(userSelector, user => user.phoneNumber), | |
name: createSelector(userSelector, user => user.name), | |
avatar: createSelector(userSelector, user => user.avatar), | |
countryCode: createSelector(userSelector, user => user.countryCode), | |
email: createSelector(userSelector, user => user.email), | |
emergencyContact: createSelector( | |
userSelector, | |
user => user.emeregencyContact | |
), | |
isphoneVerified: createSelector(userSelector, user => user.isPhoneVerified), | |
isEmailVerified: createSelector(userSelector, user => user.isEmailVerified), | |
token: createSelector(userSelector, user => user.token), | |
appLanguage: createSelector(userSelector, user => user.appLanguage), | |
communicationLanguage: createSelector( | |
userSelector, | |
user => user.communicationLanguage | |
) | |
} | |
const initialState = Object.freeze({ | |
user: { | |
appLanguage: defaultLang | |
}, | |
loading: false, | |
error: null | |
}) | |
export default (state = initialState, action) => { | |
switch (action.type) { | |
case actions.SIGNUP_REQUEST: | |
case actions.LOGIN_REQUEST: | |
case actions.VERIFY_OTP_REQUEST: | |
case actions.VERIFY_EMAIL_REQUEST: | |
case actions.UPDATE_USER_DETAILS_REQUEST: | |
case actions.UPDATE_EMAIL_REQUEST: | |
case actions.UPDATE_COMM_LANG_REQUEST: | |
case actions.UPDATE_PHONE_REQUEST: | |
case actions.RESEND_OTP_REQUEST: | |
return { | |
...state, | |
loading: true, | |
error: null | |
} | |
case actions.LOGIN_SUCCESS: | |
case actions.SIGNUP_SUCCESS: | |
case actions.VERIFY_OTP_SUCCESS: | |
case actions.UPDATE_USER_DETAILS_SUCCESS: | |
case actions.UPDATE_PHONE_SUCCESS: | |
case actions.UPDATE_EMAIL_SUCCESS: | |
case actions.UPDATE_COMM_LANG_SUCCESS: | |
case actions.VERIFY_EMAIL_SUCCESS: | |
case actions.RESEND_OTP_SUCCESS: | |
return { | |
...state, | |
error: null, | |
loading: false, | |
user: { ...state.user, ...action.userData } | |
} | |
case actions.SIGNUP_ERROR: | |
case actions.LOGIN_ERROR: | |
case actions.UPDATE_PHONE_ERROR: | |
case actions.UPDATE_USER_DETAILS_ERROR: | |
case actions.UPDATE_EMAIL_ERROR: | |
case actions.UPDATE_COMM_LANG_ERROR: | |
case actions.VERIFY_OTP_ERROR: | |
case actions.RESEND_OTP_ERROR: | |
case actions.VERIFY_EMAIL_ERROR: | |
const { error } = action | |
return { | |
...state, | |
loading: false, | |
error | |
} | |
case actions.LANGUAGE_CHANGE: | |
return { | |
...state, | |
user: { ...state.user, appLanguage: action.language } | |
} | |
case actions.LOGOUT: | |
const { appLanguage } = state.user | |
return { | |
...initialState, | |
user: { | |
appLanguage | |
} | |
} | |
default: | |
return state | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
call, | |
put, | |
fork, | |
take, | |
cancel, | |
cancelled, | |
takeLatest | |
} from 'redux-saga/effects' | |
import { get } from 'lodash' | |
import { push } from 'react-router-redux' | |
import { truncatePhoneNumber, createFormData } from 'config/utils' | |
import { routes } from 'config/routes' | |
import { actions } from 'rdx/auth' | |
import authService from 'services/auth' | |
import { actionMethods } from 'rdx/ui' | |
function* signUp({ data }) { | |
try { | |
yield put({ type: actions.SIGNUP_REQUEST }) | |
data.phoneNumber = truncatePhoneNumber(data.phoneNumber, data.countryCode) | |
data.countryCode = parseInt(data.countryCode, 10) | |
const response = yield call(authService.signUp, { | |
...data, | |
loginType: 'local', | |
userType: 'passenger' | |
}) | |
yield put({ type: actions.SIGNUP_SUCCESS, userData: response.data }) | |
yield put(push(routes.verifyEmail.path)) | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'Signup Error!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.SIGNUP_ERROR, error: message }) | |
} | |
} | |
function* login({ phoneNumber, password, countryCode }) { | |
let response | |
try { | |
response = yield call(authService.login, { phoneNumber, password }) | |
const userData = response.data | |
yield put({ type: actions.LOGIN_SUCCESS, userData }) | |
if (!userData.isPhoneVerified) { | |
yield put( | |
push({ | |
pathname: routes.otp.path, | |
state: { phoneNumber, countryCode } | |
}) | |
) | |
} else if (!userData.isEmailVerified) { | |
yield put( | |
push({ | |
pathname: routes.verifyEmail.path, | |
state: { verifyEmail: true } | |
}) | |
) | |
} else { | |
yield put(push(routes.dashboard.path)) | |
} | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'Login Error!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.LOGIN_ERROR, error: message }) | |
} finally { | |
if (yield cancelled()) { | |
yield put(actions.LOGOUT) | |
yield put(push(routes.login.path)) | |
} | |
} | |
} | |
function* updatePhone({ phoneNumber, countryCode, verify }) { | |
try { | |
yield put({ type: actions.UPDATE_PHONE_REQUEST }) | |
const response = yield call(authService.updatePhoneNumber, { | |
phoneNumber, | |
countryCode | |
}) | |
yield put({ type: actions.UPDATE_PHONE_SUCCESS, userData: response.data }) | |
if (verify) { | |
yield put(push(routes.otpProfile.path)) | |
} | |
} catch (e) { | |
const message = get( | |
e, | |
'response.data.message', | |
'Phone number update error!' | |
) | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.UPDATE_PHONE_ERROR, error: message }) | |
} | |
} | |
function* updateEmail({ email, verify, redirect }) { | |
try { | |
yield put({ type: actions.UPDATE_EMAIL_REQUEST }) | |
const response = yield call(authService.updateEmail, { email, redirect }) | |
yield put({ type: actions.UPDATE_EMAIL_SUCCESS, userData: response.data }) | |
if (verify) { | |
yield put(push(routes.verifyEmailProfile.path)) | |
} | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'Email update error!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.UPDATE_EMAIL_ERROR, error: message }) | |
} | |
} | |
function* verifyOTP({ otp, redirect }) { | |
try { | |
yield put({ type: actions.VERIFY_OTP_REQUEST }) | |
const response = yield call(authService.verifyOTP, { otp }) | |
yield put({ type: actions.VERIFY_OTP_SUCCESS, userData: response.data }) | |
if (redirect) { | |
yield put(push(routes.profile.path)) | |
} else { | |
yield put(push(routes.verifyEmail.path)) | |
} | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'OTP does not match!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.VERIFY_OTP_ERROR, error: message }) | |
} | |
} | |
function* verifyEmail({ redirect }) { | |
try { | |
yield put({ type: actions.VERIFY_EMAIL_REQUEST }) | |
const response = yield call(authService.verifyEmail) | |
const userData = response.data | |
if (userData.isEmailVerified) { | |
yield put({ type: actions.VERIFY_EMAIL_SUCCESS, userData }) | |
if (redirect) yield put(push(redirect)) | |
} else { | |
yield put(actionMethods.showSnackBar({ message: 'message.verifyemail' })) | |
} | |
} catch (e) { | |
const message = get( | |
e, | |
'response.data.message', | |
'Email could not be verified!' | |
) | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.VERIFY_EMAIL_ERROR, error: message }) | |
} | |
} | |
function* resendOTP() { | |
try { | |
yield put({ type: actions.RESEND_OTP_REQUEST }) | |
const response = yield call(authService.resendOTP) | |
yield put(actionMethods.showSnackBar({ message: 'message.resendOtp' })) | |
yield put({ type: actions.RESEND_OTP_SUCCESS, userData: response.data }) | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'Could not send OTP!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.RESEND_OTP_ERROR, error: message }) | |
} | |
} | |
function* updateUserDetails({ | |
name = undefined, | |
emeregencyContact = undefined, | |
avatar = undefined, | |
push: pushRoute = true | |
}) { | |
try { | |
yield put({ type: actions.UPDATE_USER_DETAILS_REQUEST }) | |
const data = createFormData({ name, emeregencyContact, avatar }) | |
const response = yield call(authService.updateUserDetails, data) | |
yield put({ | |
type: actions.UPDATE_USER_DETAILS_SUCCESS, | |
userData: response.data | |
}) | |
if (pushRoute === true) { | |
yield put(push(routes.profile.path)) | |
} else if (pushRoute) { | |
yield put(push(pushRoute)) | |
} | |
if (emeregencyContact === null) { | |
yield put( | |
actionMethods.showSnackBar({ | |
message: 'message.emergencyContactDelete' | |
}) | |
) | |
} else { | |
yield put( | |
actionMethods.showSnackBar({ message: 'message.updateSuccessful' }) | |
) | |
} | |
} catch (e) { | |
const message = get(e, 'response.data.message', 'Could not update!') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.UPDATE_USER_DETAILS_ERROR, error: message }) | |
} | |
} | |
function* updateCommunicationLanguage({ language }) { | |
try { | |
yield put({ type: actions.UPDATE_COMM_LANG_REQUEST }) | |
const response = yield call( | |
authService.changeCommunicationLanguage, | |
language | |
) | |
yield put({ | |
type: actions.UPDATE_COMM_LANG_SUCCESS, | |
userData: response.data | |
}) | |
yield put(push(routes.settings.path)) | |
yield put(actionMethods.showSnackBar({ message: 'message.languageUpdate' })) | |
} catch (e) { | |
const message = get(e, 'response.data.message', '') | |
yield put(actionMethods.showSnackBar({ defaultMessage: message })) | |
yield put({ type: actions.UPDATE_COMM_LANG_ERROR, error: message }) | |
} | |
} | |
function* logout() { | |
localStorage.removeItem('token') | |
yield put(push(routes.login.path)) | |
} | |
function* watchSignUp() { | |
yield takeLatest(actions.SIGNUP, signUp) | |
} | |
function* watchLogin() { | |
while (true) { | |
const { phoneNumber, password, countryCode } = yield take( | |
actions.LOGIN, | |
login | |
) | |
yield put({ type: actions.LOGIN_REQUEST }) | |
const loginTask = yield fork(login, { phoneNumber, password, countryCode }) | |
const action = yield take([actions.LOGOUT, actions.LOGIN_ERROR]) | |
if (action.type === actions.LOGOUT) yield cancel(loginTask) | |
yield call(logout) | |
} | |
} | |
function* watchUpdatePhone() { | |
yield takeLatest(actions.UPDATE_PHONE, updatePhone) | |
} | |
function* watchUpdateEmail() { | |
yield takeLatest(actions.UPDATE_EMAIL, updateEmail) | |
} | |
function* watchVerifyOTP() { | |
yield takeLatest(actions.VERIFY_OTP, verifyOTP) | |
} | |
function* watchVerifyEmail() { | |
yield takeLatest(actions.VERIFY_EMAIL, verifyEmail) | |
} | |
function* watchResendOTP() { | |
yield takeLatest(actions.RESEND_OTP, resendOTP) | |
} | |
function* watchUpdateUserDetails() { | |
yield takeLatest(actions.UPDATE_USER_DETAILS, updateUserDetails) | |
} | |
function* watchUpdateCommunicationLanguage() { | |
yield takeLatest(actions.UPDATE_COMM_LANG, updateCommunicationLanguage) | |
} | |
export default [ | |
fork(watchSignUp), | |
fork(watchLogin), | |
fork(watchUpdatePhone), | |
fork(watchUpdateEmail), | |
fork(watchVerifyOTP), | |
fork(watchResendOTP), | |
fork(watchVerifyEmail), | |
fork(watchUpdateUserDetails), | |
fork(watchUpdateCommunicationLanguage) | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createStore, combineReducers, compose, applyMiddleware } from 'redux' | |
import { persistReducer, persistStore } from 'redux-persist' | |
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2' | |
import localforage from 'localforage' | |
import { routerReducer, routerMiddleware } from 'react-router-redux' | |
import { | |
setToken, | |
removeToken, | |
setLanguage, | |
logoutUserOnTokenExpire | |
} from './middleware' | |
import createHistory from 'history/createBrowserHistory' | |
import createSageMiddleware from 'redux-saga' | |
import sagas from 'sagas' | |
import { isProduction } from 'config/utils' | |
import auth from './auth' | |
import ui from './ui' | |
export const history = createHistory() | |
const rootReducer = combineReducers({ | |
auth, | |
ui, | |
router: routerReducer | |
}) | |
const persistedReducer = persistReducer( | |
{ | |
key: 'root', | |
storage: localforage, | |
stateReconciler: autoMergeLevel2, | |
blacklist: ['router'] | |
}, | |
rootReducer | |
) | |
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose | |
const sagaMiddleware = createSageMiddleware() | |
const middleware = [ | |
routerMiddleware(history), | |
sagaMiddleware, | |
setToken, | |
setLanguage, | |
removeToken, | |
logoutUserOnTokenExpire | |
] | |
export const store = createStore( | |
persistedReducer, | |
isProduction() | |
? compose(applyMiddleware(...middleware)) | |
: composeEnhancers(applyMiddleware(...middleware)) | |
) | |
export const persistor = persistStore(store) | |
sagaMiddleware.run(sagas) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from 'services' | |
import { actions } from 'rdx/auth' | |
export const setToken = ({ getState }) => next => async action => { | |
const state = getState() | |
let token = action && action.userData && action.userData.token | |
if (!token) { | |
if (state.auth.user.token) { | |
token = state.auth.user.token | |
} else if (localStorage.getItem('token')) { | |
token = localStorage.getItem('token') | |
} | |
token && localStorage.setItem('token', token) | |
} | |
return next(action) | |
} | |
export const removeToken = () => next => action => { | |
if (action && action.type === actions.LOGOUT) { | |
localStorage.removeItem('token') | |
} | |
return next(action) | |
} | |
export const setLanguage = ({ getState }) => next => action => { | |
if (localStorage.getItem('lang')) { | |
const state = getState() | |
localStorage.setItem('lang', state.auth.user.appLanguage) | |
} | |
if (action && action.type === actions.LANGUAGE_CHANGE) { | |
localStorage.setItem('lang', action.language) | |
} | |
axios.defaults.headers.common['language'] = localStorage.getItem('lang') | |
return next(action) | |
} | |
export const logoutUserOnTokenExpire = () => next => async action => { | |
if (action.error === 'jwt expired') { | |
console.log('log out') | |
return next({ type: actions.LOGOUT }) | |
} | |
next(action) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { all } from 'redux-saga/effects' | |
import authSagas from './auth' | |
export default function* watchAll() { | |
yield all([...authSagas]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment