#204 Error management (#237)

* added error snackbar for api fails
* improved error page to be shown only for userdata errors and to allow retrying
* fixed test breaking only in local because of timezone and reduced warnings for easier reading of tests results
* added error management for failure inside calendars imports
* added error snackbar for api fails
* improved error page to be shown only for userdata errors and to allow retrying
* added error management for failure inside calendars imports

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
Camille Moussu
2025-10-27 11:23:38 +01:00
committed by GitHub
parent 4774e78543
commit 42f5d8e1a9
17 changed files with 960 additions and 371 deletions
+2 -2
View File
@@ -47,10 +47,10 @@ export function HandleLogin() {
initiateLogin();
}, [userData, dispatch]);
useEffect(() => {
if (!calendars.pending && !userData.loading) {
if (userData.error) {
dispatch(push("/error"));
}
if (!calendars.pending && !userData.loading) {
if (!calendars.pending && !userData.loading && !userData.error) {
dispatch(push("/calendar"));
}
}, [calendars.pending, userData.loading]);
+24 -8
View File
@@ -1,15 +1,23 @@
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { userData, userOrganiser } from "./userDataTypes";
import { getOpenPaasUser } from "./userAPI";
import { formatReduxError } from "../../utils/errorUtils";
export const getOpenPaasUserDataAsync = createAsyncThunk<any>(
"user/getOpenPaasUserData",
async () => {
export const getOpenPaasUserDataAsync = createAsyncThunk<
Record<string, string>,
void,
{ rejectValue: { message: string; status?: number } }
>("user/getOpenPaasUserData", async (_, { rejectWithValue }) => {
try {
const user = (await getOpenPaasUser()) as Record<string, string>;
return user;
} catch (err: any) {
return rejectWithValue({
message: formatReduxError(err),
status: err.response?.status,
});
}
);
});
export const userSlice = createSlice({
name: "user",
@@ -18,6 +26,7 @@ export const userSlice = createSlice({
organiserData: null as unknown as userOrganiser,
tokens: null as unknown as Record<string, string>,
loading: true,
error: null as unknown as string | null,
},
reducers: {
setUserData: (state, action) => {
@@ -32,6 +41,9 @@ export const userSlice = createSlice({
setTokens: (state, action) => {
state.tokens = action.payload;
},
clearError: (state) => {
state.error = null;
},
},
extraReducers: (builder) => {
builder
@@ -54,13 +66,17 @@ export const userSlice = createSlice({
.addCase(getOpenPaasUserDataAsync.pending, (state) => {
state.loading = true;
})
.addCase(getOpenPaasUserDataAsync.rejected, (state) => {
state.loading = false;
.addCase(getOpenPaasUserDataAsync.rejected, (state, action) => {
if (action.payload?.status !== 401) {
state.loading = false;
state.error =
action.payload?.message || "Failed to fetch user information";
}
});
},
});
// Action creators are generated for each case reducer function
export const { setUserData, setTokens } = userSlice.actions;
export const { setUserData, setTokens, clearError } = userSlice.actions;
export default userSlice.reducer;