2025-11-11 09:19:51 +01:00

252 lines
7.3 KiB
TypeScript

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<IUserResponse> },
{ rejectValue: ThunkError }
>("user/editUser", async ({ id, updates }, { rejectWithValue }) => {
try {
const res = await fetch(`/api/dashboard/admin/users/${id}`, {
method: "PUT",
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"
);
}
});
// ---------------- Update User Details ----------------
export const updateUserDetails = createAsyncThunk<
ThunkSuccess<{ user: IUserResponse }>,
{ id: string; updates: Record<string, unknown> },
{ rejectValue: ThunkError }
>("user/updateUserDetails", async ({ id, updates }, { rejectWithValue }) => {
try {
const res = await fetch(`/api/dashboard/admin/users/${id}`, {
method: "PUT",
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 details");
}
return {
message: data.message || "User details 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;
})
// Update User Details
.addCase(updateUserDetails.pending, state => {
state.status = "loading";
state.message = "Updating user details...";
state.editedUser = null;
state.error = null;
})
.addCase(updateUserDetails.fulfilled, (state, action) => {
state.status = "succeeded";
state.message = action.payload.message;
state.editedUser = action.payload.user;
state.error = null;
})
.addCase(updateUserDetails.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;