From b54a10e5196330fd7899402cb08e6629066825f9 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 9 Jul 2024 19:11:16 -0400 Subject: [PATCH 1/4] Added delete user thunk --- .../TabPanels/Account/ProfilePanel.jsx | 14 ++++- Client/src/Features/Auth/authSlice.js | 57 +++++++++++++++++-- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx index a56b65919..122f1668b 100644 --- a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -12,11 +12,16 @@ import { imageValidation, } from "../../../Validation/validation"; import { useDispatch, useSelector } from "react-redux"; -import { update } from "../../../Features/Auth/authSlice"; +import { + clearAuthState, + deleteUser, + update, +} from "../../../Features/Auth/authSlice"; import ImageField from "../../TextFields/Image"; import ImageIcon from "@mui/icons-material/Image"; import ProgressUpload from "../../ProgressBars"; import { formatBytes } from "../../../Utils/fileUtils"; +import { clearMonitorState } from "../../../Features/Monitors/monitorsSlice"; /** * ProfilePanel component displays a form for editing user profile information @@ -158,7 +163,12 @@ const ProfilePanel = () => { // Initiates the account deletion process const handleDeleteAccount = () => { - //TODO - implement delete account function + dispatch(deleteUser(authToken)).then((action) => { + if (action.payload.success) { + dispatch(clearAuthState()); + dispatch(clearMonitorState()); + } + }); }; // Modal state and control functions diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index bc75e53f7..e50611648 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -70,6 +70,31 @@ export const update = createAsyncThunk( } ); +export const deleteUser = createAsyncThunk( + "auth/delete", + async (data, thunkApi) => { + const user = jwtDecode(data); + + //1.5s delay to show loading spinner + await new Promise((resolve) => setTimeout(resolve, 1500)); + + try { + const res = await axiosInstance.delete(`/auth/user/${user._id}`, { + headers: { + Authorization: `Bearer ${data}`, + "Content-Type": "multipart/form-data", + }, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + return thunkApi.rejectWithValue(error.message); + } + } +); + const handleAuthFulfilled = (state, action) => { state.isLoading = false; state.success = action.payload.success; @@ -97,6 +122,16 @@ const handleUpdateRejected = (state, action) => { ? action.payload.msg : "Failed to update profile data."; }; +const handleDeleteFulfilled = (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; +}; +const handleDeleteRejected = (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload ? action.payload.msg : "Failed to delete account."; +}; const authSlice = createSlice({ name: "auth", @@ -111,25 +146,37 @@ const authSlice = createSlice({ }, }, extraReducers: (builder) => { + // Register thunk builder - // Register thunk .addCase(register.pending, (state) => { state.isLoading = true; }) .addCase(register.fulfilled, handleAuthFulfilled) - .addCase(register.rejected, handleAuthRejected) - // Login thunk + .addCase(register.rejected, handleAuthRejected); + + // Login thunk + builder .addCase(login.pending, (state) => { state.isLoading = true; }) .addCase(login.fulfilled, handleAuthFulfilled) - .addCase(login.rejected, handleAuthRejected) - // Update thunk + .addCase(login.rejected, handleAuthRejected); + + // Update thunk + builder .addCase(update.pending, (state) => { state.isLoading = true; }) .addCase(update.fulfilled, handleUpdateFulfilled) .addCase(update.rejected, handleUpdateRejected); + + // Delete thunk + builder + .addCase(deleteUser.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteUser.fulfilled, handleDeleteFulfilled) + .addCase(deleteUser.rejected, handleDeleteRejected); }, }); From 21483d67d5edb5d89a5b25f8f2cdd01a9d6dda4f Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 9 Jul 2024 19:13:22 -0400 Subject: [PATCH 2/4] Fixed image url error --- Client/src/Features/Auth/authSlice.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index e50611648..c26e7332b 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -49,6 +49,7 @@ export const update = createAsyncThunk( const fd = new FormData(); const imageResult = await axiosInstance.get(form.file, { responseType: "blob", + baseURL: "", }); fd.append("firstname", form.firstname); fd.append("lastname", form.lastname); From bd5ed007eb0bdb0508cc1ee5c766f729f0ce1588 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 9 Jul 2024 20:51:26 -0400 Subject: [PATCH 3/4] Removed content type header from request --- Client/src/Features/Auth/authSlice.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index 781fe2fad..e4ab90f72 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -85,10 +85,7 @@ export const deleteUser = createAsyncThunk( try { const res = await axiosInstance.delete(`/auth/user/${user._id}`, { - headers: { - Authorization: `Bearer ${data}`, - "Content-Type": "multipart/form-data", - }, + headers: { Authorization: `Bearer ${data}` }, }); return res.data; } catch (error) { From 85a2177f1d05f08febf18eb2b06256b22816db4f Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Wed, 10 Jul 2024 10:01:36 -0400 Subject: [PATCH 4/4] Removed unnecessary timeout and replaced Promise.then() --- .../Components/TabPanels/Account/ProfilePanel.jsx | 13 ++++++------- Client/src/Features/Auth/authSlice.js | 3 --- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx index a3a50911e..ab44b34b3 100644 --- a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -183,13 +183,12 @@ const ProfilePanel = () => { }; // Initiates the account deletion process - const handleDeleteAccount = () => { - dispatch(deleteUser(authToken)).then((action) => { - if (action.payload.success) { - dispatch(clearAuthState()); - dispatch(clearMonitorState()); - } - }); + const handleDeleteAccount = async () => { + const action = await dispatch(deleteUser(authToken)); + if (action.payload.success) { + dispatch(clearAuthState()); + dispatch(clearMonitorState()); + } }; // Modal state and control functions diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index e4ab90f72..b5e3faa50 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -80,9 +80,6 @@ export const deleteUser = createAsyncThunk( async (data, thunkApi) => { const user = jwtDecode(data); - //1.5s delay to show loading spinner - await new Promise((resolve) => setTimeout(resolve, 1500)); - try { const res = await axiosInstance.delete(`/auth/user/${user._id}`, { headers: { Authorization: `Bearer ${data}` },