mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-04 03:03:20 +00:00
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
|
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||
|
|
import { STORAGE_KEY_TOKEN } from '../../constants';
|
||
|
|
|
||
|
|
interface AuthUser {
|
||
|
|
id: string;
|
||
|
|
email: string;
|
||
|
|
displayName: string;
|
||
|
|
role: 'Dispatcher' | 'Admin' | 'SysAdmin';
|
||
|
|
token: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface AuthState {
|
||
|
|
user: AuthUser | null;
|
||
|
|
isAuthenticated: boolean;
|
||
|
|
loading: boolean;
|
||
|
|
error: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const getUserFromStorage = (): AuthUser | null => {
|
||
|
|
try {
|
||
|
|
const result = window.localStorage.getItem(STORAGE_KEY_TOKEN);
|
||
|
|
return result ? JSON.parse(result) : null;
|
||
|
|
} catch {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const isTokenValid = (token: string): boolean => {
|
||
|
|
if (!token) return false;
|
||
|
|
try {
|
||
|
|
const part = token.split('.')[1];
|
||
|
|
if (!part) return false;
|
||
|
|
const payload = JSON.parse(atob(part));
|
||
|
|
return new Date(payload.exp * 1000) > new Date();
|
||
|
|
} catch {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const storedUser = getUserFromStorage();
|
||
|
|
|
||
|
|
const initialState: AuthState = {
|
||
|
|
user: storedUser,
|
||
|
|
isAuthenticated: storedUser?.token ? isTokenValid(storedUser.token) : false,
|
||
|
|
loading: false,
|
||
|
|
error: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
const authSlice = createSlice({
|
||
|
|
name: 'auth',
|
||
|
|
initialState,
|
||
|
|
reducers: {
|
||
|
|
setUser: (state, action: PayloadAction<AuthUser>) => {
|
||
|
|
state.user = action.payload;
|
||
|
|
state.isAuthenticated = action.payload.token ? isTokenValid(action.payload.token) : false;
|
||
|
|
state.loading = false;
|
||
|
|
state.error = null;
|
||
|
|
window.localStorage.setItem(STORAGE_KEY_TOKEN, JSON.stringify(action.payload));
|
||
|
|
},
|
||
|
|
logout: (state) => {
|
||
|
|
state.user = null;
|
||
|
|
state.isAuthenticated = false;
|
||
|
|
state.error = null;
|
||
|
|
window.localStorage.removeItem(STORAGE_KEY_TOKEN);
|
||
|
|
},
|
||
|
|
setLoading: (state, action: PayloadAction<boolean>) => {
|
||
|
|
state.loading = action.payload;
|
||
|
|
},
|
||
|
|
setError: (state, action: PayloadAction<string>) => {
|
||
|
|
state.error = action.payload;
|
||
|
|
state.loading = false;
|
||
|
|
},
|
||
|
|
clearError: (state) => {
|
||
|
|
state.error = null;
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
export const { setUser, logout, setLoading, setError, clearError } = authSlice.actions;
|
||
|
|
|
||
|
|
export const selectUser = (state: { auth: AuthState }) => state.auth.user;
|
||
|
|
export const selectIsAuthenticated = (state: { auth: AuthState }) => state.auth.isAuthenticated;
|
||
|
|
export const selectAuthLoading = (state: { auth: AuthState }) => state.auth.loading;
|
||
|
|
export const selectAuthError = (state: { auth: AuthState }) => state.auth.error;
|
||
|
|
export const selectToken = (state: { auth: AuthState }) => state.auth.user?.token;
|
||
|
|
|
||
|
|
export default authSlice.reducer;
|