diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index c694cc1ee..2b6667099 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -447,18 +447,6 @@ export async function getLoggedUser(): Promise { return null; } -export async function addUser(user: UserInputType): Promise> { - try { - const res = await api.post(`${BASE_URL_API}users/`, user); - if (res.status !== 201) { - throw new Error(res.data.detail); - } - return res.data; - } catch (error) { - throw error; - } -} - export async function getUsersPage( skip: number, limit: number, @@ -476,42 +464,6 @@ export async function getUsersPage( return []; } -export async function deleteUser(user_id: string) { - try { - const res = await api.delete(`${BASE_URL_API}users/${user_id}`); - if (res.status === 200) { - return res.data; - } - } catch (error) { - throw error; - } -} - -export async function updateUser(user_id: string, user: changeUser) { - try { - const res = await api.patch(`${BASE_URL_API}users/${user_id}`, user); - if (res.status === 200) { - return res.data; - } - } catch (error) { - throw error; - } -} - -export async function resetPassword(user_id: string, user: resetPasswordType) { - try { - const res = await api.patch( - `${BASE_URL_API}users/${user_id}/reset-password`, - user, - ); - if (res.status === 200) { - return res.data; - } - } catch (error) { - throw error; - } -} - export async function getApiKey() { try { const res = await api.get(`${BASE_URL_API}api_key/`); diff --git a/src/frontend/src/controllers/API/queries/auth/use-delete-users.ts b/src/frontend/src/controllers/API/queries/auth/use-delete-users.ts index 68aa10a8c..29ff378cb 100644 --- a/src/frontend/src/controllers/API/queries/auth/use-delete-users.ts +++ b/src/frontend/src/controllers/API/queries/auth/use-delete-users.ts @@ -8,7 +8,7 @@ interface DeleteUserParams { user_id: string; } -export const useDeleteMessages: useMutationFunctionType< +export const useDeleteUsers: useMutationFunctionType< undefined, DeleteUserParams > = (options?) => { @@ -20,7 +20,7 @@ export const useDeleteMessages: useMutationFunctionType< }; const mutation: UseMutationResult = - mutate(["useDeleteMessages"], deleteMessage, options); + mutate(["useDeleteUsers"], deleteMessage, options); return mutation; }; diff --git a/src/frontend/src/pages/AdminPage/index.tsx b/src/frontend/src/pages/AdminPage/index.tsx index 80c36adff..8a7912674 100644 --- a/src/frontend/src/pages/AdminPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/index.tsx @@ -1,3 +1,8 @@ +import { + useAddUser, + useDeleteUsers, + useUpdateUser, +} from "@/controllers/API/queries/auth"; import { cloneDeep } from "lodash"; import { useContext, useEffect, useRef, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; @@ -29,12 +34,7 @@ import { ADMIN_HEADER_TITLE, } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; -import { - addUser, - deleteUser, - getUsersPage, - updateUser, -} from "../../controllers/API"; +import { getUsersPage } from "../../controllers/API"; import ConfirmationModal from "../../modals/confirmationModal"; import UserManagementModal from "../../modals/userManagementModal"; import useAlertStore from "../../stores/alertStore"; @@ -45,7 +45,7 @@ import { UserInputType } from "../../types/components"; export default function AdminPage() { const [inputValue, setInputValue] = useState(""); - const [size, setPageSize] = useState(10); + const [size, setPageSize] = useState(12); const [index, setPageIndex] = useState(1); const [loadingUsers, setLoadingUsers] = useState(true); const setSuccessData = useAlertStore((state) => state.setSuccessData); @@ -56,6 +56,10 @@ export default function AdminPage() { (state) => state.setCurrentFlowId, ); + const { mutate: mutateDeleteUser } = useDeleteUsers(); + const { mutate: mutateUpdateUser } = useUpdateUser(); + const { mutate: mutateAddUser } = useAddUser(); + // set null id useEffect(() => { setCurrentFlowId(""); @@ -121,93 +125,125 @@ export default function AdminPage() { } function handleDeleteUser(user) { - deleteUser(user.id) - .then((res) => { - resetFilter(); - setSuccessData({ - title: USER_DEL_SUCCESS_ALERT, - }); - }) - .catch((error) => { - setErrorData({ - title: USER_DEL_ERROR_ALERT, - list: [error["response"]["data"]["detail"]], - }); - }); + mutateDeleteUser( + { user_id: user.id }, + { + onSuccess: () => { + resetFilter(); + setSuccessData({ + title: USER_DEL_SUCCESS_ALERT, + }); + }, + onError: (error) => { + setErrorData({ + title: USER_DEL_ERROR_ALERT, + list: [error["response"]["data"]["detail"]], + }); + }, + }, + ); } function handleEditUser(userId, user) { - updateUser(userId, user) - .then((res) => { - resetFilter(); - setSuccessData({ - title: USER_EDIT_SUCCESS_ALERT, - }); - }) - .catch((error) => { - setErrorData({ - title: USER_EDIT_ERROR_ALERT, - list: [error["response"]["data"]["detail"]], - }); - }); + mutateUpdateUser( + { user_id: userId, user: user }, + { + onSuccess: () => { + resetFilter(); + setSuccessData({ + title: USER_EDIT_SUCCESS_ALERT, + }); + }, + onError: (error) => { + setErrorData({ + title: USER_EDIT_ERROR_ALERT, + list: [error["response"]["data"]["detail"]], + }); + }, + }, + ); } function handleDisableUser(check, userId, user) { const userEdit = cloneDeep(user); userEdit.is_active = !check; - updateUser(userId, userEdit) - .then((res) => { - resetFilter(); - setSuccessData({ - title: USER_EDIT_SUCCESS_ALERT, - }); - }) - .catch((error) => { - setErrorData({ - title: USER_EDIT_ERROR_ALERT, - list: [error["response"]["data"]["detail"]], - }); - }); + mutateUpdateUser( + { user_id: userId, user: userEdit }, + { + onSuccess: () => { + resetFilter(); + setSuccessData({ + title: USER_EDIT_SUCCESS_ALERT, + }); + }, + onError: (error) => { + setErrorData({ + title: USER_EDIT_ERROR_ALERT, + list: [error["response"]["data"]["detail"]], + }); + }, + }, + ); } function handleSuperUserEdit(check, userId, user) { const userEdit = cloneDeep(user); userEdit.is_superuser = !check; - updateUser(userId, userEdit) - .then((res) => { - resetFilter(); - setSuccessData({ - title: USER_EDIT_SUCCESS_ALERT, - }); - }) - .catch((error) => { - setErrorData({ - title: USER_EDIT_ERROR_ALERT, - list: [error["response"]["data"]["detail"]], - }); - }); + + mutateUpdateUser( + { user_id: userId, user: userEdit }, + { + onSuccess: () => { + resetFilter(); + setSuccessData({ + title: USER_EDIT_SUCCESS_ALERT, + }); + }, + onError: (error) => { + setErrorData({ + title: USER_EDIT_ERROR_ALERT, + list: [error["response"]["data"]["detail"]], + }); + }, + }, + ); } function handleNewUser(user: UserInputType) { - addUser(user) - .then((res) => { - updateUser(res["id"], { - is_active: user.is_active, - is_superuser: user.is_superuser, - }).then((res) => { - resetFilter(); - setSuccessData({ - title: USER_ADD_SUCCESS_ALERT, - }); - }); - }) - .catch((error) => { + mutateAddUser(user, { + onSuccess: (res) => { + mutateUpdateUser( + { + user_id: res["id"], + user: { + is_active: user.is_active, + is_superuser: user.is_superuser, + }, + }, + { + onSuccess: () => { + resetFilter(); + setSuccessData({ + title: USER_ADD_SUCCESS_ALERT, + }); + }, + onError: (error) => { + setErrorData({ + title: USER_ADD_ERROR_ALERT, + list: [error["response"]["data"]["detail"]], + }); + }, + }, + ); + }, + onError: (error) => { setErrorData({ title: USER_ADD_ERROR_ALERT, - list: [error.response.data.detail], + list: [error["response"]["data"]["detail"]], }); - }); + }, + }); } return ( diff --git a/src/frontend/src/pages/ProfileSettingsPage/index.tsx b/src/frontend/src/pages/ProfileSettingsPage/index.tsx index 5cedc5841..5d0135d9f 100644 --- a/src/frontend/src/pages/ProfileSettingsPage/index.tsx +++ b/src/frontend/src/pages/ProfileSettingsPage/index.tsx @@ -1,3 +1,7 @@ +import { + useResetPassword, + useUpdateUser, +} from "@/controllers/API/queries/auth"; import * as Form from "@radix-ui/react-form"; import { cloneDeep } from "lodash"; import { useContext, useEffect, useState } from "react"; @@ -13,7 +17,6 @@ import { } from "../../constants/alerts_constants"; import { CONTROL_PATCH_USER_STATE } from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; -import { resetPassword, updateUser } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { @@ -40,6 +43,9 @@ export default function ProfileSettingsPage(): JSX.Element { const { userData, setUserData } = useContext(AuthContext); const { password, cnfPassword, gradient } = inputState; + const { mutate: mutateResetPassword } = useResetPassword(); + const { mutate: mutatePatchUser } = useUpdateUser(); + async function handlePatchUser() { if (password !== cnfPassword) { setErrorData({ @@ -48,27 +54,44 @@ export default function ProfileSettingsPage(): JSX.Element { }); return; } - try { - if (password !== "") await resetPassword(userData!.id, { password }); - if (gradient !== "") - await updateUser(userData!.id, { profile_image: gradient }); - if (gradient !== "") { - let newUserData = cloneDeep(userData); - newUserData!.profile_image = gradient; - - setUserData(newUserData); - } - handleInput({ target: { name: "password", value: "" } }); - handleInput({ target: { name: "cnfPassword", value: "" } }); - setSuccessData({ title: SAVE_SUCCESS_ALERT }); - } catch (error) { - setErrorData({ - title: SAVE_ERROR_ALERT, - list: [(error as any).response.data.detail], - }); + if (password !== "") { + mutateResetPassword( + { user_id: userData!.id, password: { password } }, + { + onSuccess: successUpdates, + onError: errorUpdates, + }, + ); + } + if (gradient !== "") { + mutatePatchUser( + { user_id: userData!.id, user: { profile_image: gradient } }, + { + onSuccess: successUpdates, + onError: errorUpdates, + }, + ); } } + const errorUpdates = (error) => { + setErrorData({ + title: SAVE_ERROR_ALERT, + list: [(error as any).response.data.detail], + }); + }; + + const successUpdates = () => { + if (gradient !== "") { + let newUserData = cloneDeep(userData); + newUserData!.profile_image = gradient; + setUserData(newUserData); + } + handleInput({ target: { name: "password", value: "" } }); + handleInput({ target: { name: "cnfPassword", value: "" } }); + setSuccessData({ title: SAVE_SUCCESS_ALERT }); + }; + function handleInput({ target: { name, value }, }: inputHandlerEventType): void { diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.tsx index 5e5bb2a77..020972b11 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-preload-images.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { BASE_URL_API } from "../../../../../../../../../constants/constants"; const usePreloadImages = ( - profilePictures: { [key: string]: string[] }, + profilePictures?: { [key: string]: string[] }, setImagesLoaded: (value: boolean) => void, loading: boolean, ) => { diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx index 0788e3053..ed5f2c2c2 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx @@ -8,7 +8,7 @@ import { cn } from "../../../../../../../../utils/utils"; import usePreloadImages from "./hooks/use-preload-images"; type ProfilePictureChooserComponentProps = { - profilePictures: ProfilePicturesQueryResponse | undefined; + profilePictures?: ProfilePicturesQueryResponse; loading: boolean; value: string; onChange: (value: string) => void; @@ -30,7 +30,7 @@ export default function ProfilePictureChooserComponent({ } }, [ref, value]); - usePreloadImages(profilePictures!, setImagesLoaded, loading); + usePreloadImages(profilePictures, setImagesLoaded, loading); return (
diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx index abaf2c0ee..5218edb5d 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx @@ -1,8 +1,19 @@ import FeatureFlags from "@/../feature-config.json"; +import { + EDIT_PASSWORD_ALERT_LIST, + EDIT_PASSWORD_ERROR_ALERT, + SAVE_ERROR_ALERT, + SAVE_SUCCESS_ALERT, +} from "@/constants/alerts_constants"; import { usePostAddApiKey } from "@/controllers/API/queries/api-keys"; +import { + useResetPassword, + useUpdateUser, +} from "@/controllers/API/queries/auth"; import { useGetProfilePicturesQuery } from "@/controllers/API/queries/files"; import useAuthStore from "@/stores/authStore"; -import { useContext, useEffect, useState } from "react"; +import { cloneDeep } from "lodash"; +import { useContext, useState } from "react"; import { useParams } from "react-router-dom"; import { CONTROL_PATCH_USER_STATE } from "../../../../constants/constants"; import { AuthContext } from "../../../../contexts/authContext"; @@ -13,13 +24,10 @@ import { inputHandlerEventType, patchUserInputStateType, } from "../../../../types/components"; -import usePatchPassword from "../hooks/use-patch-password"; -import usePatchProfilePicture from "../hooks/use-patch-profile-picture"; import useScrollToElement from "../hooks/use-scroll-to-element"; import GeneralPageHeaderComponent from "./components/GeneralPageHeader"; import PasswordFormComponent from "./components/PasswordForm"; import ProfilePictureFormComponent from "./components/ProfilePictureForm"; -import useGetProfilePictures from "./components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures"; import StoreApiKeyFormComponent from "./components/StoreApiKeyForm"; export const GeneralPage = () => { @@ -48,20 +56,61 @@ export const GeneralPage = () => { const setValidApiKey = useStoreStore((state) => state.updateValidApiKey); const setLoadingApiKey = useStoreStore((state) => state.updateLoadingApiKey); - const { handlePatchPassword } = usePatchPassword( - userData, - setSuccessData, - setErrorData, - ); + const { mutate: mutateResetPassword } = useResetPassword(); + const { mutate: mutatePatchUser } = useUpdateUser(); + + const handlePatchPassword = () => { + if (password !== cnfPassword) { + setErrorData({ + title: EDIT_PASSWORD_ERROR_ALERT, + list: [EDIT_PASSWORD_ALERT_LIST], + }); + return; + } + + if (password !== "") { + mutateResetPassword( + { user_id: userData!.id, password: { password } }, + { + onSuccess: () => { + handleInput({ target: { name: "password", value: "" } }); + handleInput({ target: { name: "cnfPassword", value: "" } }); + setSuccessData({ title: SAVE_SUCCESS_ALERT }); + }, + onError: (error) => { + setErrorData({ + title: SAVE_ERROR_ALERT, + list: [(error as any)?.response?.data?.detail], + }); + }, + }, + ); + } + }; const handleGetProfilePictures = useGetProfilePicturesQuery(); - const { handlePatchProfilePicture } = usePatchProfilePicture( - setSuccessData, - setErrorData, - userData, - setUserData, - ); + const handlePatchProfilePicture = (profile_picture) => { + if (profile_picture !== "") { + mutatePatchUser( + { user_id: userData!.id, user: { profile_image: profile_picture } }, + { + onSuccess: () => { + let newUserData = cloneDeep(userData); + newUserData!.profile_image = profile_picture; + setUserData(newUserData); + setSuccessData({ title: SAVE_SUCCESS_ALERT }); + }, + onError: (error) => { + setErrorData({ + title: SAVE_ERROR_ALERT, + list: [(error as any)?.response?.data?.detail], + }); + }, + }, + ); + } + }; useScrollToElement(scrollId, setCurrentFlowId); diff --git a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx b/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx deleted file mode 100644 index ea61d4722..000000000 --- a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import cloneDeep from "lodash/cloneDeep"; -import { - SAVE_ERROR_ALERT, - SAVE_SUCCESS_ALERT, -} from "../../../../constants/alerts_constants"; -import { updateUser } from "../../../../controllers/API"; - -const usePatchGradient = ( - setSuccessData, - setErrorData, - currentUserData, - setUserData, -) => { - const handlePatchGradient = async (gradient) => { - try { - if (gradient !== "") { - await updateUser(currentUserData.id, { profile_image: gradient }); - let newUserData = cloneDeep(currentUserData); - newUserData.profile_image = gradient; - setUserData(newUserData); - } - setSuccessData({ title: SAVE_SUCCESS_ALERT }); - } catch (error) { - setErrorData({ - title: SAVE_ERROR_ALERT, - list: [(error as any)?.response?.data?.detail], - }); - } - }; - - return { - currentUserData, - handlePatchGradient, - }; -}; - -export default usePatchGradient; diff --git a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-password.tsx b/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-password.tsx deleted file mode 100644 index 0003fe4a1..000000000 --- a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-password.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { - EDIT_PASSWORD_ALERT_LIST, - EDIT_PASSWORD_ERROR_ALERT, - SAVE_ERROR_ALERT, - SAVE_SUCCESS_ALERT, -} from "../../../../constants/alerts_constants"; -import { resetPassword } from "../../../../controllers/API"; -import { Users } from "../../../../types/api"; - -const usePatchPassword = ( - userData: Users | null, - setSuccessData: (data: { title: string; list?: string[] }) => void, - setErrorData: (data: { title: string; list: string[] }) => void, -) => { - const handlePatchPassword = async (password, cnfPassword, handleInput) => { - if (password !== cnfPassword) { - setErrorData({ - title: EDIT_PASSWORD_ERROR_ALERT, - list: [EDIT_PASSWORD_ALERT_LIST], - }); - return; - } - try { - if (password !== "") await resetPassword(userData!.id, { password }); - handleInput({ target: { name: "password", value: "" } }); - handleInput({ target: { name: "cnfPassword", value: "" } }); - setSuccessData({ title: SAVE_SUCCESS_ALERT }); - } catch (error) { - setErrorData({ - title: SAVE_ERROR_ALERT, - list: [(error as any)?.response?.data?.detail], - }); - } - }; - - return { - handlePatchPassword, - }; -}; - -export default usePatchPassword; diff --git a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx b/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx deleted file mode 100644 index 6ad76f4ff..000000000 --- a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import cloneDeep from "lodash/cloneDeep"; -import { - SAVE_ERROR_ALERT, - SAVE_SUCCESS_ALERT, -} from "../../../../constants/alerts_constants"; -import { updateUser } from "../../../../controllers/API"; -import { Users } from "../../../../types/api"; - -const usePatchProfilePicture = ( - setSuccessData: (data: { title: string; list?: string[] }) => void, - setErrorData: (data: { title: string; list: string[] }) => void, - currentUserData: Users | null, - setUserData: (data: any) => void, -) => { - const handlePatchProfilePicture = async (profile_picture) => { - try { - if (profile_picture !== "") { - await updateUser(currentUserData!.id, { - profile_image: profile_picture, - }); - let newUserData = cloneDeep(currentUserData); - newUserData!.profile_image = profile_picture; - setUserData(newUserData); - } - setSuccessData({ title: SAVE_SUCCESS_ALERT }); - } catch (error) { - setErrorData({ - title: SAVE_ERROR_ALERT, - list: [(error as any)?.response?.data?.detail], - }); - } - }; - - return { - currentUserData, - handlePatchProfilePicture, - }; -}; - -export default usePatchProfilePicture; diff --git a/src/frontend/src/pages/SignUpPage/index.tsx b/src/frontend/src/pages/SignUpPage/index.tsx index 1cdad3d59..6b6eaeae7 100644 --- a/src/frontend/src/pages/SignUpPage/index.tsx +++ b/src/frontend/src/pages/SignUpPage/index.tsx @@ -1,3 +1,4 @@ +import { useAddUser } from "@/controllers/API/queries/auth"; import * as Form from "@radix-ui/react-form"; import { FormEvent, useEffect, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; @@ -9,7 +10,6 @@ import { CONTROL_INPUT_STATE, SIGN_UP_SUCCESS, } from "../../constants/constants"; -import { addUser } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; import { UserInputType, @@ -28,6 +28,8 @@ export default function SignUp(): JSX.Element { const setErrorData = useAlertStore((state) => state.setErrorData); const navigate = useNavigate(); + const { mutate: mutateAddUser } = useAddUser(); + function handleInput({ target: { name, value }, }: inputHandlerEventType): void { @@ -47,14 +49,15 @@ export default function SignUp(): JSX.Element { username: username.trim(), password: password.trim(), }; - addUser(newUser) - .then((user) => { + + mutateAddUser(newUser, { + onSuccess: () => { setSuccessData({ title: SIGN_UP_SUCCESS, }); navigate("/login"); - }) - .catch((error) => { + }, + onError: (error) => { const { response: { data: { detail }, @@ -64,8 +67,8 @@ export default function SignUp(): JSX.Element { title: SIGNUP_ERROR_ALERT, list: [detail], }); - return; - }); + }, + }); } return ( diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 02da4d336..81b408d57 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -451,6 +451,7 @@ export type patchUserInputStateType = { cnfPassword: string; profilePicture: string; apikey: string; + gradient?: any; }; export type UserInputType = {