import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import { ThunkSuccess, ThunkError, IUserResponse } from "../types"; import { IEditUserForm } from "../../features/UserRoles/User.interfaces"; import { RootState } from "../store"; interface UserState { status: "idle" | "loading" | "succeeded" | "failed"; error: string | null; message: string; addedUser: IUserResponse | null; editedUser: IUserResponse | null; } const initialState: UserState = { status: "idle", error: null, message: "", addedUser: null, editedUser: null, }; // ---------------- Add User ---------------- export const addUser = createAsyncThunk< ThunkSuccess<{ user: IUserResponse; success: boolean }>, IEditUserForm, { rejectValue: ThunkError; state: RootState } >("user/addUser", async (userData, { rejectWithValue, getState }) => { try { const state = getState(); const currentUserId = state.auth.user?.id; console.log("[DEBUG] [ADD-USER] [currentUserId]: ", currentUserId); const res = await fetch("/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...userData, creator: currentUserId || "" }), }); const data = await res.json(); console.log("[DEBUG] [ADD-USER] [data]: ", data); if (!res.ok) { return rejectWithValue(data.message || "Failed to create user"); } return { success: data.success, message: data.message || "User created successfully", user: data.user, } as ThunkSuccess<{ user: IUserResponse; success: boolean }>; } catch (err: unknown) { return rejectWithValue( (err as Error).message || "Network error during user creation" ); } }); // ---------------- Edit User ---------------- export const editUser = createAsyncThunk< ThunkSuccess<{ user: IUserResponse }>, { id: string; updates: Partial }, { rejectValue: ThunkError } >("user/editUser", async ({ id, updates }, { rejectWithValue }) => { try { const res = await fetch(`/api/dashboard/admin/users/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify(updates), }); const data = await res.json(); if (!res.ok) { return rejectWithValue(data.message || "Failed to update user"); } return { message: data.message || "User updated successfully", user: data.user, }; } catch (err: unknown) { return rejectWithValue( (err as Error).message || "Network error during user update" ); } }); // ---------------- Delete User ---------------- export const deleteUser = createAsyncThunk< ThunkSuccess<{ id: string }>, string, { rejectValue: ThunkError } >("user/deleteUser", async (id, { rejectWithValue }) => { try { const res = await fetch(`/api/dashboard/admin/users/${id}`, { method: "DELETE", headers: { "Content-Type": "application/json", }, }); const data = await res.json(); if (!res.ok) { return rejectWithValue(data.message || "Failed to delete user"); } return { message: data.message || "User deleted successfully", id, }; } catch (err: unknown) { return rejectWithValue( (err as Error).message || "Network error during user deletion" ); } }); // ---------------- Slice ---------------- const userSlice = createSlice({ name: "user", initialState, reducers: { clearMessage: state => { state.message = ""; }, clearAddedUser: state => { state.addedUser = null; }, clearEditedUser: state => { state.editedUser = null; }, clearError: state => { state.error = null; }, }, extraReducers: builder => { builder // Add User .addCase(addUser.pending, state => { state.status = "loading"; state.message = "Creating user..."; state.addedUser = null; state.error = null; }) .addCase(addUser.fulfilled, (state, action) => { state.status = "succeeded"; state.message = action.payload.message; state.addedUser = action.payload.user; state.error = null; }) .addCase(addUser.rejected, (state, action) => { state.status = "failed"; state.error = action.payload as string; state.message = action.payload as string; state.addedUser = null; }) // Edit User .addCase(editUser.pending, state => { state.status = "loading"; state.message = "Updating user..."; state.editedUser = null; state.error = null; }) .addCase(editUser.fulfilled, (state, action) => { state.status = "succeeded"; state.message = action.payload.message; state.editedUser = action.payload.user; state.error = null; }) .addCase(editUser.rejected, (state, action) => { state.status = "failed"; state.error = action.payload as string; state.message = action.payload as string; state.editedUser = null; }) // Delete User .addCase(deleteUser.pending, state => { state.status = "loading"; state.message = "Deleting user..."; state.error = null; }) .addCase(deleteUser.fulfilled, (state, action) => { state.status = "succeeded"; state.message = action.payload.message; state.error = null; }) .addCase(deleteUser.rejected, (state, action) => { state.status = "failed"; state.error = action.payload as string; state.message = action.payload as string; }); }, }); export const { clearMessage, clearAddedUser, clearEditedUser, clearError } = userSlice.actions; export default userSlice.reducer;