@triare/auth-redux v0.3.1
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-reduxTo 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
signInClearList of action creators
signIn(({
email: 'email@gmail.com',
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
OTPGenerateClearList 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
confirmClearList 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
userMeClearList of action creators
userMe(); // does not have parametersSign-up
// Sign-up. There are many entry options.
signUp
signUpStart
signUpSuccess
signUpError
signUpErrorClear
signUpClearList 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
signOutClearList of action creators
signOut(); // does not have parametersForgot password
// Instructions with a link will be sent by email.
forgotPassword
forgotPasswordStart
forgotPasswordSuccess
forgotPasswordError
forgotPasswordErrorClear
forgotPasswordClearList of action creators
forgotPassword({
email: string;
});Reset password
// Follow the link in the email and enter a new password.
resetPassword
resetPasswordStart
resetPasswordSuccess
resetPasswordError
resetPasswordErrorClear
resetPasswordClearList 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),
});11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago