import { formatReduxError } from "@/utils/errorUtils"; import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { getOpenPaasUser, updateUserConfigurations, UserConfigurationUpdates, } from "./userAPI"; import { userData, userOrganiser } from "./userDataTypes"; export const getOpenPaasUserDataAsync = createAsyncThunk< Record, void, { rejectValue: { message: string; status?: number } } >("user/getOpenPaasUserData", async (_, { rejectWithValue }) => { try { const user = (await getOpenPaasUser()) as Record; return user; } catch (err: any) { return rejectWithValue({ message: formatReduxError(err), status: err.response?.status, }); } }); export const updateUserConfigurationsAsync = createAsyncThunk< UserConfigurationUpdates, UserConfigurationUpdates, { rejectValue: { message: string; status?: number } } >("user/updateConfigurations", async (updates, { rejectWithValue }) => { try { await updateUserConfigurations(updates); return updates; } catch (err: any) { return rejectWithValue({ message: formatReduxError(err), status: err.response?.status, }); } }); export const userSlice = createSlice({ name: "user", initialState: { userData: null as unknown as userData, organiserData: null as unknown as userOrganiser, tokens: null as unknown as Record, coreConfig: { language: null as string | null, datetime: { timeZone: null as string | null, }, } as Record, alarmEmailsEnabled: null as boolean | null, loading: true, error: null as unknown as string | null, }, reducers: { setUserData: (state, action) => { state.userData = action.payload; if (!state.organiserData) { state.organiserData = {} as userOrganiser; } state.organiserData.cn = action.payload.sub; state.organiserData.cal_address = `mailto:${action.payload.email}`; state.loading = false; }, setTokens: (state, action) => { state.tokens = action.payload; }, setLanguage: (state, action) => { state.coreConfig.language = action.payload; if (state.userData) { state.userData.language = action.payload; } }, setTimezone: (state, action) => { if (!state.coreConfig.datetime) { state.coreConfig.datetime = {}; } state.coreConfig.datetime.timeZone = action.payload; if (state.userData) { state.userData.timezone = action.payload; } }, setAlarmEmails: (state, action) => { state.alarmEmailsEnabled = action.payload; }, setUserError: (state, action) => { state.error = action.payload; }, clearError: (state) => { state.error = null; }, }, extraReducers: (builder) => { builder .addCase(getOpenPaasUserDataAsync.fulfilled, (state, action) => { state.loading = false; state.userData.name = action.payload.firstname; state.userData.family_name = action.payload.lastname; state.userData.openpaasId = action.payload.id; if (!state.organiserData) { state.organiserData = {} as userOrganiser; } if (action.payload.firstname && action.payload.lastname) { state.organiserData.cn = `${action.payload.firstname} ${action.payload.lastname}`; } if (action.payload.preferredEmail) { state.organiserData.cal_address = action.payload.preferredEmail; state.userData.email = action.payload.preferredEmail; } // Extract data from configurations.modules if (action.payload.configurations?.modules) { const coreModule = action.payload.configurations.modules.find( (module: any) => module.name === "core" ); if (coreModule?.configurations) { const newCoreConfig = Object.fromEntries( coreModule.configurations.map( (e: { name: string; value: any }) => [e.name, e.value] ) ); state.coreConfig = { ...state.coreConfig, ...newCoreConfig, }; const languageConfig = coreModule.configurations.find( (config: any) => config.name === "language" ); if (languageConfig?.value) { state.coreConfig.language = languageConfig.value; if (state.userData) state.userData.language = languageConfig.value; } const datetimeConfig = coreModule.configurations.find( (config: any) => config.name === "datetime" ); if (datetimeConfig?.value) { const serverTimeZone = datetimeConfig.value.timeZone; state.coreConfig.datetime = { ...state.coreConfig.datetime, ...datetimeConfig.value, timeZone: serverTimeZone !== undefined ? serverTimeZone : null, }; if (state.userData) { state.userData.timezone = serverTimeZone !== undefined ? serverTimeZone : null; } } else { state.coreConfig.datetime = { ...state.coreConfig.datetime, timeZone: null, }; if (state.userData) { state.userData.timezone = null; } } } // Extract alarmEmails from configurations.modules const calendarModule = action.payload.configurations.modules.find( (module: any) => module.name === "calendar" ); if (calendarModule?.configurations) { const alarmEmailsConfig = calendarModule.configurations.find( (config: any) => config.name === "alarmEmails" ); if (alarmEmailsConfig) { state.alarmEmailsEnabled = alarmEmailsConfig.value === true; } } } }) .addCase(getOpenPaasUserDataAsync.pending, (state) => { state.loading = true; }) .addCase(getOpenPaasUserDataAsync.rejected, (state, action) => { if (action.payload?.status !== 401) { state.loading = false; state.error = action.payload?.message || "Failed to fetch user information"; } }) .addCase(updateUserConfigurationsAsync.fulfilled, (state, action) => { if (action.payload.language !== undefined) { state.coreConfig.language = action.payload.language; if (state.userData) { state.userData.language = action.payload.language; } } if (action.payload.timezone !== undefined) { if (!state.coreConfig.datetime) { state.coreConfig.datetime = {}; } state.coreConfig.datetime.timeZone = action.payload.timezone; if (state.userData) { state.userData.timezone = action.payload.timezone; } } if (action.payload.alarmEmails !== undefined) { state.alarmEmailsEnabled = action.payload.alarmEmails === true; } }) .addCase(updateUserConfigurationsAsync.rejected, (state, action) => { if (action.payload?.status !== 401) { state.error = action.payload?.message || "Failed to update user configurations"; } }); }, }); // Action creators are generated for each case reducer function export const { setUserData, setTokens, setLanguage, setTimezone, setAlarmEmails, setUserError, clearError, } = userSlice.actions; export default userSlice.reducer;