Add authentication and assets
This commit is contained in:
169
src/store/slices/Authentication.slice.ts
Normal file
169
src/store/slices/Authentication.slice.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import {createSlice, PayloadAction, createAsyncThunk, createSelector} from '@reduxjs/toolkit';
|
||||
import AuthenticationService from '../../services/Authentication.service';
|
||||
import {PhenixWebSocketStatusType} from 'services/net/websockets/PhenixWebSocketStatus';
|
||||
import {IPhenixWebSocketResponse} from 'services/net/websockets/PhenixWebSocket';
|
||||
|
||||
export interface IAuthenticationState {
|
||||
applicationId: string | null;
|
||||
secret: string | null;
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
status: PhenixWebSocketStatusType;
|
||||
error: string | null;
|
||||
sessionId: string | null;
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
const initialAuthenticationState: IAuthenticationState = {
|
||||
applicationId: null,
|
||||
sessionId: null,
|
||||
isAuthenticated: false,
|
||||
isLoading: false,
|
||||
status: 'Offline',
|
||||
roles: [],
|
||||
error: null,
|
||||
secret: null
|
||||
};
|
||||
|
||||
// Memoized selectors
|
||||
export const selectAuthentication = (state: {authentication: IAuthenticationState}) => state.authentication;
|
||||
|
||||
export const selectIsLoading = createSelector([selectAuthentication], authentication => authentication.isLoading);
|
||||
|
||||
export const selectIsAuthenticated = createSelector([selectAuthentication], authentication => authentication.isAuthenticated);
|
||||
|
||||
export const selectError = createSelector([selectAuthentication], authentication => authentication.error);
|
||||
|
||||
export const selectStatus = createSelector([selectAuthentication], authentication => authentication.status);
|
||||
|
||||
export const selectCredentials = createSelector([selectAuthentication], authentication => ({
|
||||
id: authentication.applicationId,
|
||||
secret: authentication.secret
|
||||
}));
|
||||
|
||||
export const selectSessionInfo = createSelector([selectAuthentication], authentication => ({
|
||||
sessionId: authentication.sessionId,
|
||||
roles: authentication.roles
|
||||
}));
|
||||
|
||||
const authenticateCredentialsThunk = createAsyncThunk<IPhenixWebSocketResponse, {applicationId: string; secret: string}>(
|
||||
'authentication/authenticate',
|
||||
async (credentials, {rejectWithValue}) => {
|
||||
try {
|
||||
const response = await AuthenticationService.authenticate(credentials.applicationId, credentials.secret);
|
||||
|
||||
return response as IPhenixWebSocketResponse;
|
||||
} catch (error) {
|
||||
// Convert error to serializable format
|
||||
const errorMessage = error instanceof Error ? error.message : 'Authentication failed';
|
||||
return rejectWithValue(errorMessage);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const signoutThunk = createAsyncThunk('authentication/signout', async (_, {rejectWithValue}) => {
|
||||
try {
|
||||
return await AuthenticationService.signout();
|
||||
} catch (error) {
|
||||
// Convert error to serializable format
|
||||
const errorMessage = error instanceof Error ? error.message : 'Signout failed';
|
||||
return rejectWithValue(errorMessage);
|
||||
}
|
||||
});
|
||||
|
||||
const authenticationSlice = createSlice({
|
||||
name: 'authentication',
|
||||
initialState: {...initialAuthenticationState},
|
||||
reducers: {
|
||||
setIsLoading: (state, action: PayloadAction<boolean>) => {
|
||||
state.isLoading = action.payload;
|
||||
},
|
||||
setCredentials: (state, action: PayloadAction<{applicationId: string; secret: string}>) => {
|
||||
state.applicationId = action.payload.applicationId;
|
||||
state.secret = action.payload.secret;
|
||||
},
|
||||
clearState: state => {
|
||||
state.applicationId = null;
|
||||
state.sessionId = null;
|
||||
state.isAuthenticated = false;
|
||||
state.isLoading = false;
|
||||
state.error = null;
|
||||
state.secret = null;
|
||||
state.status = 'Offline';
|
||||
state.roles = [];
|
||||
},
|
||||
setSessionId: (state, action: PayloadAction<string>) => {
|
||||
state.sessionId = action.payload;
|
||||
},
|
||||
setIsAuthenticated: (state, action: PayloadAction<boolean>) => {
|
||||
state.isAuthenticated = action.payload;
|
||||
},
|
||||
setRoles: (state, action: PayloadAction<string[]>) => {
|
||||
state.roles = action.payload;
|
||||
},
|
||||
setApplicationId: (state, action: PayloadAction<string>) => {
|
||||
state.applicationId = action.payload;
|
||||
}
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(authenticateCredentialsThunk.pending, state => {
|
||||
state.isLoading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(authenticateCredentialsThunk.fulfilled, (state, action) => {
|
||||
const authenticationResponse = action.payload;
|
||||
|
||||
if (authenticationResponse.status === 'ok') {
|
||||
state.applicationId = authenticationResponse.applicationId ?? null;
|
||||
state.sessionId = authenticationResponse.sessionId ?? null;
|
||||
state.isAuthenticated = true;
|
||||
state.roles = authenticationResponse.roles ?? [];
|
||||
} else {
|
||||
state.applicationId = null;
|
||||
state.sessionId = null;
|
||||
state.isAuthenticated = false;
|
||||
state.secret = null;
|
||||
state.roles = [];
|
||||
}
|
||||
|
||||
state.status = 'Online';
|
||||
state.isLoading = false;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(authenticateCredentialsThunk.rejected, (state, action) => {
|
||||
state.applicationId = null;
|
||||
state.sessionId = null;
|
||||
state.isAuthenticated = false;
|
||||
state.isLoading = false;
|
||||
state.error = (action.payload as string) || 'Authentication failed';
|
||||
state.secret = null;
|
||||
state.status = 'Offline';
|
||||
state.roles = [];
|
||||
})
|
||||
.addCase(signoutThunk.pending, state => {
|
||||
state.isLoading = true;
|
||||
state.error = null;
|
||||
})
|
||||
.addCase(signoutThunk.fulfilled, state => {
|
||||
state.isAuthenticated = false;
|
||||
state.isLoading = false;
|
||||
state.error = null;
|
||||
state.secret = null;
|
||||
state.status = 'Offline';
|
||||
state.roles = [];
|
||||
})
|
||||
.addCase(signoutThunk.rejected, (state, action) => {
|
||||
state.isAuthenticated = false;
|
||||
state.isLoading = false;
|
||||
state.error = (action.payload as string) || 'Signout failed';
|
||||
state.secret = null;
|
||||
state.status = 'Offline';
|
||||
state.roles = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const {setIsLoading, setCredentials, clearState, setSessionId, setIsAuthenticated, setRoles, setApplicationId} = authenticationSlice.actions;
|
||||
export {authenticateCredentialsThunk};
|
||||
export default authenticationSlice.reducer;
|
||||
Reference in New Issue
Block a user