import { createAsyncThunk , createSlice , PayloadAction } from '@reduxjs/toolkit' ; import { toast } from 'react-toastify' ; import { RootState } from '../..' ; import { teamActions } from '../team' ; import { uiActions } from '../ui' ; import { sessionActions } from '../session' ; import { storageActions } from '../storage' ; import navigationService from '../../../core/services/navigation.service' ; import { sessionSelectors } from '../session/session.selectors' ; import { AppView , LocalStorageItem } from '../../../core/types' ; import tasksService from '../../../tasks/services/tasks.service' ; import authService from '../../../auth/services/auth.service' ; import { UserSettings } from '../../../auth/types' ; import userService , { InitializeUserResponse } from '../../../auth/services/user.service' ; import { storeTeamsInfo } from '../../../teams/services/teams.service' ; import localStorageService from '../../../core/services/local-storage.service' ; import { referralsActions } from '../referrals' ; interface UserState { isInitializing : boolean ; isAuthenticated : boolean ; isInitialized : boolean ; user ? : UserSettings ; } const initialState = { isInitializing : false , isAuthenticated : false , isInitialized : false , user : undefined , } ; export const initializeUserThunk = createAsyncThunk < void , { redirectToLogin : boolean ; } | undefined , { state : RootState ; } > ( 'user/initialize' , async ( payload = { } , { dispatch , getState } ) => { const defaultPayload = { redirectToLogin : true , } ; const { user , isAuthenticated } = getState ( ) . user ; payload = { ... defaultPayload , ... payload } ; if ( user && isAuthenticated ) { if ( ! user . root_folder_id ) { const initializeUserBody = ( await userService . initializeUser ( user . email , user . mnemonic ) ) as InitializeUserResponse ; dispatch ( userActions . setUser ( { ... user , root_folder_id : initializeUserBody . user . root_folder_id , bucket : initializeUserBody . user . bucket , } ) ) ; } if ( user . teams ) { try { await storeTeamsInfo ( ) ; dispatch ( teamActions . initialize ( ) ) ; } catch ( err ) { localStorageService . removeItem ( 'xTeam' ) ; } } dispatch ( setIsUserInitialized ( true ) ) ; } else if ( payload . redirectToLogin ) { navigationService . push ( AppView . Login ) ; } } ) ; export const refreshUserThunk = createAsyncThunk < void , void , { state : RootState ; } > ( 'user/refresh' , async ( payload , { dispatch } ) => { const { user , token } = await userService . refreshUser ( ) ; dispatch ( userActions . setUser ( user ) ) ; dispatch ( userActions . setToken ( token ) ) ; } ) ; export const logoutThunk = createAsyncThunk < void , void , { state : RootState ; } > ( 'user/logout' , async ( payload , { dispatch } ) => { authService . logOut ( ) ; dispatch ( sessionActions . resetState ( ) ) ; dispatch ( userActions . resetState ( ) ) ; dispatch ( teamActions . resetState ( ) ) ; dispatch ( storageActions . resetState ( ) ) ; dispatch ( uiActions . resetState ( ) ) ; dispatch ( referralsActions . resetState ( ) ) ; tasksService . clearTasks ( ) ; } ) ; export const userSlice = createSlice ( { name : 'user' , initialState , reducers : { initialize : ( state ) => { state . user = localStorageService . getUser ( ) || undefined ; state . isAuthenticated = ! ! state . user ; } , setIsUserInitialized : ( state , action ) => { state . isInitialized = action . payload ; } , setUser : ( state , action ) => { state . isAuthenticated = ! ! action . payload ; state . user = action . payload ; localStorageService . set ( LocalStorageItem . User , JSON . stringify ( action . payload ) ) ; } , setToken : ( state , action ) => { localStorageService . set ( LocalStorageItem . UserToken , action . payload ) ; } , resetState : ( state ) => { Object . assign ( state , initialState ) ; } , } , extraReducers : ( builder ) => { builder . addCase ( initializeUserThunk . pending , ( state ) => { state . isInitializing = true ; } ) . addCase ( initializeUserThunk . fulfilled , ( state ) => { state . isInitializing = false ; } ) . addCase ( initializeUserThunk . rejected , ( state , action ) => { const errorMsg = action . payload ? action . payload : '' ; state . isInitializing = false ; toast . warn ( 'User initialization error ' + errorMsg ) ; navigationService . push ( AppView . Login ) ; } ) ; builder . addCase ( refreshUserThunk . pending , ( ) => undefined ) . addCase ( refreshUserThunk . fulfilled , ( ) => undefined ) . addCase ( refreshUserThunk . rejected , ( ) => undefined ) ; builder . addCase ( logoutThunk . pending , ( ) => undefined ) . addCase ( logoutThunk . fulfilled , ( ) => undefined ) . addCase ( logoutThunk . rejected , ( ) => undefined ) ; } , } ) ; export const userSelectors = { userFullName : ( state ) : string => { const { user } = state . user ; return user ? `${ user ?. name } ${ user ?. lastname }` : '' ; } , nameLetters : ( state ) : string => { const { user } = state . user ; const isTeam = sessionSelectors . isTeam ( state ) ; const nameLetters = isTeam ? 'B' : ( user as UserSettings ) . name [ 0 ] + ( ( user as UserSettings ) . lastname [ 0 ] || '' ) ; return nameLetters . toUpperCase ( ) ; } , isFromAppSumo : ( state ) : boolean => ! ! state . user . user ?. appSumoDetails , hasReferralsProgram : ( state ) : boolean => ! ! state . user . user ?. hasReferralsProgram , } ; export const { initialize , resetState , setIsUserInitialized } = userSlice . actions ; export const userActions = userSlice . actions ; export const userThunks = { initializeUserThunk , refreshUserThunk , logoutThunk , } ; export default userSlice . reducer ;