@triare/auth-redux
v0.3.1
Published
redux auth
Downloads
185
Maintainers
Readme
Beta version
The package is designed for internal use by TRIARE. https://triare.net
The package is free and can be freely distributed
The package is written in conjunction with other company products and is part of a comprehensive solution.
How to use
Run
npm i @triare/auth-redux
yarn add @triare/auth-redux
To use it in a React project you need to create a store directory and create 2 files in it
Create files (store/index.ts and store/auth/index.ts)
Copy
store/index.ts
// example
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import createSagaMiddleware from 'redux-saga';
import { spawn } from 'redux-saga/effects';
import { EnhancedStore } from '@reduxjs/toolkit/src/configureStore';
import { moduleName as authModuleName, reducer as authReducer, saga as authSaga } from './auth';
import { moduleName as userModuleName, reducer as userReducer, saga as userSaga } from './user';
import { moduleName as commonModuleName, reducer as commonReducer, saga as commonSaga } from './common';
export const sagaMiddleware = createSagaMiddleware();
const store: EnhancedStore = configureStore({
reducer: combineReducers({
[authModuleName]: authReducer,
[userModuleName]: userReducer,
[commonModuleName]: commonReducer,
}),
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
thunk: false,
}).concat([sagaMiddleware]),
devTools: process.env.REACT_APP_ENV !== 'production',
});
export type RootState = ReturnType<typeof store.getState>;
sagaMiddleware.run(function* runSaga() {
yield spawn(authSaga, store);
yield spawn(commonSaga, store);
yield spawn(userSaga);
});
export default store;
All parameters are described in the @triare/auth-redux/src/config.ts file
Reading descriptions are recommended before usage
Copy
store/auth/index.ts
// example
/* eslint-disable @typescript-eslint/no-unused-vars, no-param-reassign */
import {
config,
createReducers,
State as AuthState,
setActions,
saga as authSaga,
updateConfig,
getLocalState,
Action,
createUrl,
} from '@triare/auth-redux';
import { createSlice, SliceCaseReducers } from '@reduxjs/toolkit';
import { spawn, takeLatest, put } from 'redux-saga/effects';
import { EnhancedStore } from '@reduxjs/toolkit/src/configureStore';
import { useSelector } from 'react-redux';
import { OTPResponse } from '@triare/auth-redux/dist/saga/auth/OTP';
import { SignInAction } from '@triare/auth-redux/dist/saga/auth/signIn';
import { UrlObject } from '@triare/auth-redux/src/config';
import { PayloadAction } from '@triare/auth-redux/src/saga/auth';
import { AnyObject } from '@triare/auth-redux/src/saga/common';
import { User as AuthUser } from '@triare/auth-redux/dist/saga/auth/useMe';
import { RootState } from '../index';
export * from '@triare/auth-redux';
export default updateConfig({
fetchDelay: parseInt(process.env.REACT_APP_FETCH_DELAY || '0', 10),
api: {
url: process.env.REACT_APP_API || '',
},
signIn: {
...config.signIn,
requestBody: {
byEmail: ({ remember, ...data }: SignInAction) => JSON.stringify(data),
byUsername: ({ remember, ...data }: SignInAction) => JSON.stringify(data),
byPhone: ({ remember, ...data }: SignInAction) => JSON.stringify(data),
byService: ({ method, remember, ...data }: SignInAction) => JSON.stringify(data),
},
fetchMeAfterSuccess: true,
},
OTP: {
...config.OTP,
fetchMeAfterSuccess: false,
},
createUrl: (
url: string | UrlObject,
addToUrl?: string,
payload?: PayloadAction,
data?: AnyObject,
_query?: AnyObject,
) => createUrl(url, addToUrl, payload, data, {
..._query,
lang: 'en',
}),
});
export const moduleName = config.auth.name;
export interface User extends AuthUser {
firstName: string;
lastName: string;
email: string;
phone: string;
settings: {
isEmailVerified: boolean;
isPhoneVerified: boolean;
};
}
export interface State extends AuthState {
user: User | null;
secretKey: string;
}
export function useAuth(): State {
return useSelector((state: RootState) => state[moduleName]);
}
export const auth = createSlice<State, SliceCaseReducers<State>, string, SliceSelectors<State>>({
name: moduleName,
initialState: getLocalState<State>(),
reducers: {
...createReducers(),
signInSuccess: (state, { payload }) => {
Object.assign(state, payload);
state.signIn.loading = false;
state.signIn.response = payload || null;
state.authorized = !!(payload.access && payload.refresh);
if (payload?.remember !== undefined) {
state.remember = payload?.remember;
}
},
},
});
export const { reducer, actions } = auth;
setActions(actions);
export function* saga(store: EnhancedStore) {
yield spawn(authSaga, store);
yield takeLatest(actions.OTPSuccess.toString(), function* trigger({ payload }: Action<OTPResponse>) {
yield put({
type: actions.signInSuccess.toString(),
payload,
});
});
// yield takeLatest(actions.userMeSuccess.toString(), function* trigger() {
// const authData = (yield getState()) as State;
//
// if (authData && authData.user && authData.user.role === UserRoles.GUEST) {
// yield put(signOut());
//
// window.location.href = '/sign-up';
// }
// });
}
The following information describes how the auth process functioning. The general course of actions is similar for other entities.
Redux action
[nameEntity] // Signals that the process has been called.
[nameEntity]Start // With this event, all errors that could remain in the store are deleted and a flag is set to indicate the start of the request.
[nameEntity]Success // Positive response from the server. Everything is fine.
[nameEntity]Error // An error has occurred. We learn about the reason from the error field in the store.
[nameEntity]ErrorClear // Automatically clear errors after a certain period of time. Default is 10 seconds.
[nameEntity]Clear // Automatically clear data after a certain period of time. Default is 4 seconds.
Sign-in
// Sign-in. There are many entry options.
signIn
signInStart
signInSuccess
signInError
signInErrorClear
signInClear
List of action creators
signIn(({
email: '[email protected]',
password: 'string'
});
signInByUsername({
username: 'string',
password: 'string'
});
signInByPhone({
phone: '+380673456789',
password: 'string' // optional
});
signInByService({
// google facebook apple
accessToken: access_token | accessToken | id_token,
method: 'facebook' | 'google' | 'apple' | string
})
signInByServiceError({
message: 'some custom error'
})
OTP
// When registering or logging in using a phone number, we will receive a code of 4 or more digits. The number of digits is not configured here.
OTP
OTPStart
OTPSuccess
OTPError
OTPErrorClear
OTPClear
// Generate new code. Code has a lifetime. After a certain time it becomes invalid.
OTPGenerate
OTPGenerateStart
OTPGenerateSuccess
OTPGenerateError
OTPGenerateErrorClear
OTPGenerateClear
List of action creators
OTP({
secretCode: Object.values(values).join(''),
secretKey: 'string'
});
OTPGenerate({
secretKey: 'string'
});
OTPGenerate({
secretKey: 'string',
// If you set this flag, then the code will be sent to your email.
useEmail: true
});
Confirm
// Confirm email. Instructions with a link will be sent by email.
confirm
confirmStart
confirmSuccess
confirmError
confirmErrorClear
confirmClear
List of action creators
confirmEmail({
secretKey: 'string',
password: 'string' // optional - if you created an account using the fast path you must set the password
});
User-me
// After successful authorization, obtain user data.
userMe
userMeStart
userMeSuccess
userMeError
userMeErrorClear
userMeClear
List of action creators
userMe(); // does not have parameters
Sign-up
// Sign-up. There are many entry options.
signUp
signUpStart
signUpSuccess
signUpError
signUpErrorClear
signUpClear
List of action creators
signUp({
email: 'string',
password: 'string' // optional - easy way.
// In this case, you will receive an email with a link. By clicking on it you will need to create a password.
...any else values
});
signUpByUsername({
username: 'string',
password: 'string'
});
signUpByPhone({
phone: 'string',
password: 'string' // optional
// If you do not create a password, then you will use the confirmation code that will be sent to your phone as a password when logging in.
});
signUpByService({
// google facebook apple
accessToken: access_token | accessToken | id_token,
method: 'facebook' | 'google' | 'apple' | string
});
signUpByServiceError({
message: 'some custom error'
});
Sign-out
// Delete all user data. If you want to redirect to the main page after this, subscribe to the signOutSuccess event.
signOut
signOutStart
signOutSuccess
signOutError
signOutErrorClear
signOutClear
List of action creators
signOut(); // does not have parameters
Forgot password
// Instructions with a link will be sent by email.
forgotPassword
forgotPasswordStart
forgotPasswordSuccess
forgotPasswordError
forgotPasswordErrorClear
forgotPasswordClear
List of action creators
forgotPassword({
email: string;
});
Reset password
// Follow the link in the email and enter a new password.
resetPassword
resetPasswordStart
resetPasswordSuccess
resetPasswordError
resetPasswordErrorClear
resetPasswordClear
List of action creators
resetPassword({
password: string;
secretKey: string;
});
Use the following reference example, in order to send language used by the user in every request
updateConfig({
// override function behavior
createUrl: (
url: string | UrlObject, // full path
addToUrl?: string, // additions can come from where the function is called
payload?: PayloadAction, // payload action creator
data?: AnyObject, // data parameter that is in action
_query?: AnyObject, // additional parameters // the lang parameter is part of the query parameters
) => createUrl(url, addToUrl, payload, data, {
..._query,
lang: 'en', // here use your desired language
}),
// OR if you need to add in the path to the endpoint
createUrl: (
url: string | UrlObject,
addToUrl?: string,
payload?: PayloadAction,
data?: AnyObject,
_query?: AnyObject,
) => createUrl(url, '/en' + addToUrl, payload, data, _query),
});