252 lines
7.3 KiB
TypeScript
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;
|