refactor: change post/patch folders requests to use UseQuery (#2917)

*  (sidebarComponent): Add usePostFolders hook to handle adding new folders in the sidebar
📝 (folders): Add use-post-folders and use-patch-folders hooks for handling post and patch requests for folders
🔧 (BundleModal): Remove useFolderSubmit hook and directly use usePostFolders hook for adding and updating folders in the modal

*  (sidebarComponent): Add usePatchFolders hook to handle updating folders in the sidebar component
🔧 (use-patch-folders): Refactor IPatchAddFolders interface to IPatchPatchFolders for better naming consistency
🔧 (use-patch-folders): Refactor addFoldersFn to patchFoldersFn for better function naming
🔧 (use-patch-folders): Update patchFoldersFn to send patch request to specific folder endpoint
🔧 (use-patch-folders): Update patchFoldersFn to handle updating folders and return updated data
🔧 (use-patch-folders): Update usePatchFolders hook to use patchFoldersFn for mutation
🔧 (use-post-folders): Remove unnecessary call to getFoldersApi after posting folders
🔧 (BundleModal): Remove BundleModal component and entities as they are no longer needed

🔧 (BundleModal/index.tsx): Remove unused imports and clean up code
🔧 (foldersModal/component/index.tsx): Remove unused imports and clean up code
🔧 (foldersModal/entities/index.ts): Remove unused zod schema and clean up code
🔧 (foldersModal/hooks/submit-folder.tsx): Remove unused imports and clean up code

 (foldersModal/index.tsx): Remove unused FoldersModal component from modalsComponent to optimize code and improve maintainability.

* 📝 (index.tsx): Remove unused openFolderModal and setOpenFolderModal props from ModalsComponent
♻️ (services/index.ts): Remove addFolder, updateFolder, and deleteFolder functions as they are not used in the application
♻️ (foldersStore.tsx): Remove unused import statements for uploadFlowsFromFolders from services and related functions

* 📝 (index.tsx): replace async/await with synchronous function call to refresh folders after successful operation
This commit is contained in:
Cristhian Zanforlin Lousa 2024-07-24 15:57:31 -03:00 committed by GitHub
commit 6c5b487e47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 119 additions and 655 deletions

View file

@ -1,8 +1,11 @@
import { usePostUploadFolders } from "@/controllers/API/queries/folders";
import {
usePatchFolders,
usePostUploadFolders,
} from "@/controllers/API/queries/folders";
import { usePostFolders } from "@/controllers/API/queries/folders/use-post-folders";
import { useEffect, useRef, useState } from "react";
import { useLocation } from "react-router-dom";
import { FolderType } from "../../../../pages/MainPage/entities";
import { addFolder, updateFolder } from "../../../../pages/MainPage/services";
import { handleDownloadFolderFn } from "../../../../pages/MainPage/utils/handle-download-folder";
import useAlertStore from "../../../../stores/alertStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
@ -51,6 +54,7 @@ const SideBarFoldersButtonsComponent = ({
const getFolderById = useFolderStore((state) => state.getFolderById);
const setErrorData = useAlertStore((state) => state.setErrorData);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const handleFolderChange = () => {
getFolderById(folderId);
@ -110,10 +114,22 @@ const SideBarFoldersButtonsComponent = ({
handleDownloadFolderFn(id);
};
const { mutate: mutateAddFolder } = usePostFolders();
const { mutate: mutateUpdateFolder } = usePatchFolders();
function addNewFolder() {
addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => {
refreshFolders();
mutateAddFolder(
{
data: {
name: "New Folder",
parent_id: null,
description: "",
},
},
{
onSuccess: () => {
refreshFolders();
},
},
);
}
@ -151,22 +167,31 @@ const SideBarFoldersButtonsComponent = ({
flows: item.flows?.length > 0 ? item.flows : [],
components: item.components?.length > 0 ? item.components : [],
};
const updatedFolder = await updateFolder(body, item.id!);
const updatedFolderIndex = folders.findIndex(
(f) => f.id === updatedFolder.id,
);
mutateUpdateFolder(
{
data: body,
folderId: item.id!,
},
{
onSuccess: (updatedFolder) => {
const updatedFolderIndex = folders.findIndex(
(f) => f.id === updatedFolder.id,
);
const updateFolders = [...folders];
updateFolders[updatedFolderIndex] = updatedFolder;
const updateFolders = [...folders];
updateFolders[updatedFolderIndex] = updatedFolder;
setFolders(updateFolders);
setFoldersNames({});
setEditFolderName(
folders.map((obj) => ({
name: obj.name,
edit: false,
})),
setFolders(updateFolders);
setFoldersNames({});
setEditFolderName(
folders.map((obj) => ({
name: obj.name,
edit: false,
})),
);
},
},
);
} else {
setFoldersNames((old) => ({

View file

@ -1,2 +1,4 @@
export * from "./use-delete-folders";
export * from "./use-patch-folders";
export * from "./use-post-folders";
export * from "./use-post-upload-folders";

View file

@ -0,0 +1,39 @@
import { AddFolderType } from "@/pages/MainPage/entities";
import { useFolderStore } from "@/stores/foldersStore";
import { useMutationFunctionType } from "@/types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
interface IPatchPatchFolders {
data: AddFolderType;
folderId: string;
}
export const usePatchFolders: useMutationFunctionType<
undefined,
IPatchPatchFolders
> = (options?) => {
const { mutate } = UseRequestProcessor();
const patchFoldersFn = async (
newFolder: IPatchPatchFolders,
): Promise<void> => {
const payload = {
name: newFolder.data.name,
description: newFolder.data.description,
flows_list: newFolder.data.flows ?? [],
components_list: newFolder.data.components ?? [],
};
const res = await api.patch(
`${getURL("FOLDERS")}/${newFolder.folderId}`,
payload,
);
return res.data;
};
const mutation = mutate(["usePatchFolders"], patchFoldersFn, options);
return mutation;
};

View file

@ -0,0 +1,34 @@
import { AddFolderType } from "@/pages/MainPage/entities";
import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { useFolderStore } from "@/stores/foldersStore";
import { Users, useMutationFunctionType } from "@/types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
interface IPostAddFolders {
data: AddFolderType;
}
export const usePostFolders: useMutationFunctionType<
undefined,
IPostAddFolders
> = (options?) => {
const { mutate } = UseRequestProcessor();
const addFoldersFn = async (newFolder: IPostAddFolders): Promise<void> => {
const payload = {
name: newFolder.data.name,
description: newFolder.data.description,
flows_list: newFolder.data.flows ?? [],
components_list: newFolder.data.components ?? [],
};
const res = await api.post(`${getURL("FOLDERS")}/`, payload);
return res.data;
};
const mutation = mutate(["usePostFolders"], addFoldersFn, options);
return mutation;
};

View file

@ -1,136 +0,0 @@
import { useEffect, useState } from "react";
import InputComponent from "../../../components/inputComponent";
import {
FormControl,
FormField,
FormItem,
FormMessage,
} from "../../../components/ui/form";
import { Input } from "../../../components/ui/input";
import { Label } from "../../../components/ui/label";
import { Textarea } from "../../../components/ui/textarea";
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
type FolderFormsProps = {
control: any;
setValue: any;
folderToEdit: any;
};
export const FolderForms = ({
control,
setValue,
folderToEdit,
}: FolderFormsProps): JSX.Element => {
const flows = useFlowsManagerStore((state) => state.flows);
const [selectedComponents, setSelectedComponents] = useState<string[]>([]);
const [selectedFlows, setSelectedFlows] = useState<string[]>([]);
const componentsList = flows
.filter((flow) => flow.is_component && flow.folder_id !== null)
.map((flow) => ({ id: flow.id, name: flow.name }));
const flowsList = flows
.filter((flow) => !flow.is_component && flow.folder_id !== null)
.map((flow) => ({ id: flow.id, name: flow.name }));
useEffect(() => {
setValue("components", selectedComponents);
setValue("flows", selectedFlows);
}, [selectedComponents, selectedFlows]);
useEffect(() => {
if (folderToEdit) {
setValue("name", folderToEdit.name);
setValue("description", folderToEdit.description);
return;
}
setValue("name", "");
setValue("description", "");
setSelectedComponents([]);
setSelectedFlows([]);
}, [folderToEdit]);
return (
<>
<div className="flex h-full w-full flex-col gap-4 align-middle">
<Label>Folder Name</Label>
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
value={field.value}
onChange={field.onChange}
placeholder="Insert a name for the folder..."
></Input>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Label>Description (optional) </Label>
<FormField
control={control}
name="description"
render={({ field }) => (
<FormControl>
<Textarea
value={field.value}
onChange={field.onChange}
placeholder="Insert a description for the folder..."
></Textarea>
</FormControl>
)}
/>
<Label>Add Flows</Label>
<FormField
control={control}
name="flows"
render={() => (
<FormControl>
<InputComponent
isObjectOption
password={false}
objectOptions={flowsList}
placeholder="Choose a flow to add..."
id="input-flow"
setSelectedOptions={(value: any) => setSelectedFlows(value)}
selectedOptions={selectedFlows}
></InputComponent>
</FormControl>
)}
/>
<Label>Add Components</Label>
<FormField
control={control}
name="components"
render={() => (
<FormControl>
<InputComponent
isObjectOption
password={false}
objectOptions={componentsList}
placeholder="Choose a component to add..."
id="input-component"
setSelectedOptions={(value) => setSelectedComponents(value)}
selectedOptions={selectedComponents}
></InputComponent>
</FormControl>
)}
/>
</div>
</>
);
};
export default FolderForms;

View file

@ -1,10 +0,0 @@
import { z } from "zod";
export const FolderFormsSchema = z.object({
name: z.string().min(1, {
message: "Name must be at least 1 characters.",
}),
description: z.string().optional(),
components: z.array(z.string()),
flows: z.array(z.string()),
});

View file

@ -1,57 +0,0 @@
import { FolderType } from "../../../pages/MainPage/entities";
import { addFolder, updateFolder } from "../../../pages/MainPage/services";
import useAlertStore from "../../../stores/alertStore";
import { useFolderStore } from "../../../stores/foldersStore";
const useFolderSubmit = (
setOpen: (a: boolean) => void,
folderToEdit: FolderType | null,
) => {
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const onSubmit = (data) => {
if (folderToEdit) {
updateFolder(data, folderToEdit?.id!).then(
() => {
setSuccessData({
title: "Folder updated successfully.",
});
getFoldersApi(true);
setOpen(false);
},
(reason) => {
if (reason) {
setErrorData({
title: `Error updating folder.`,
});
console.error(reason);
} else {
getFoldersApi(true);
setOpen(false);
}
},
);
} else {
addFolder(data).then(
() => {
setSuccessData({
title: "Folder created successfully.",
});
getFoldersApi(true);
setOpen(false);
},
() => {
setErrorData({
title: `Error creating folder.`,
});
},
);
}
};
return { onSubmit, open, setOpen };
};
export default useFolderSubmit;

View file

@ -1,79 +0,0 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import ForwardedIconComponent from "../../components/genericIconComponent";
import { Button } from "../../components/ui/button";
import { Form } from "../../components/ui/form";
import { useFolderStore } from "../../stores/foldersStore";
import BaseModal from "../baseModal";
import FolderForms from "./component";
import { FolderFormsSchema } from "./entities";
import useFolderSubmit from "./hooks/submit-folder";
type FoldersModalProps = {
open: boolean;
setOpen: (open: boolean) => void;
};
export default function FoldersModal({
open,
setOpen,
}: FoldersModalProps): JSX.Element {
const form = useForm<z.infer<typeof FolderFormsSchema>>({
resolver: zodResolver(FolderFormsSchema),
defaultValues: {
name: "",
description: "",
components: [],
flows: [],
},
mode: "all",
});
const folderToEdit = useFolderStore((state) => state.folderToEdit);
const { onSubmit: onSubmitFolder } = useFolderSubmit(setOpen, folderToEdit);
const onSubmit = (data) => {
onSubmitFolder(data);
};
return (
<>
<BaseModal size="x-small" open={open} setOpen={setOpen}>
<BaseModal.Header
description={`${folderToEdit ? "Edit a folder" : "Add a new folder"}`}
>
<span className="pr-2" data-testid="modal-title">
{folderToEdit ? "Edit" : "New"} Folder
</span>
<ForwardedIconComponent
name="Plus"
className="h-6 w-6 pl-1 text-primary"
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FolderForms
folderToEdit={folderToEdit}
control={form.control}
setValue={form.setValue}
/>
<Button
className="float-right mt-6"
type="submit"
disabled={!form.formState.isValid}
>
{folderToEdit ? "Edit" : "Save"} Folder
</Button>
</form>
</Form>
</div>
</BaseModal.Content>
</BaseModal>
</>
);
}

View file

@ -1,147 +0,0 @@
import { useEffect, useState } from "react";
import {
FormControl,
FormField,
FormItem,
FormMessage,
} from "../../../components/ui/form";
import { Input } from "../../../components/ui/input";
import { Label } from "../../../components/ui/label";
import { Textarea } from "../../../components/ui/textarea";
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
type FolderFormsProps = {
control: any;
setValue: any;
folderToEdit: any;
};
export const FolderForms = ({
control,
setValue,
folderToEdit,
}: FolderFormsProps): JSX.Element => {
const flows = useFlowsManagerStore((state) => state.flows);
const [selectedComponents, setSelectedComponents] = useState<string[]>([]);
const [selectedFlows, setSelectedFlows] = useState<string[]>([]);
const allFlows = useFlowsManagerStore((state) => state.allFlows);
const componentsList = flows
.filter((flow) => flow.is_component && flow.folder_id !== null)
.map((flow) => ({ id: flow.id, name: flow.name }));
const flowsList = flows
.filter((flow) => !flow.is_component && flow.folder_id !== null)
.map((flow) => ({ id: flow.id, name: flow.name }));
const componentsOnFolder = allFlows
.filter((flow) => flow.is_component && flow.folder_id === folderToEdit?.id)
.map((flow) => flow.id);
const flowsOnFolder = allFlows
.filter((flow) => !flow.is_component && flow.folder_id === folderToEdit?.id)
.map((flow) => flow.id);
useEffect(() => {
setValue("components", selectedComponents);
setValue("flows", selectedFlows);
}, [selectedComponents, selectedFlows]);
useEffect(() => {
if (folderToEdit) {
setValue("name", folderToEdit.name);
setValue("description", folderToEdit.description);
setSelectedComponents(componentsOnFolder);
setSelectedFlows(flowsOnFolder);
return;
}
setValue("name", "");
setValue("description", "");
setSelectedComponents([]);
setSelectedFlows([]);
}, [folderToEdit]);
return (
<>
<div className="flex h-full w-full flex-col gap-4 align-middle">
<Label>Folder Name</Label>
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
value={field.value}
onChange={field.onChange}
placeholder="Insert a name for the folder..."
></Input>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Label>Description (optional) </Label>
<FormField
control={control}
name="description"
render={({ field }) => (
<FormControl>
<Textarea
value={field.value}
onChange={field.onChange}
placeholder="Insert a description for the folder..."
></Textarea>
</FormControl>
)}
/>
{/*
<Label>Add Flows</Label>
<FormField
control={control}
name="flows"
render={() => (
<FormControl>
<InputComponent
isObjectOption
password={false}
objectOptions={flowsList}
placeholder="Choose a flow to add..."
id="input-flow"
setSelectedOptions={(value: any) => setSelectedFlows(value)}
selectedOptions={selectedFlows}
></InputComponent>
</FormControl>
)}
/>
<Label>Add Components</Label>
<FormField
control={control}
name="components"
render={() => (
<FormControl>
<InputComponent
isObjectOption
password={false}
objectOptions={componentsList}
placeholder="Choose a component to add..."
id="input-component"
setSelectedOptions={(value) => setSelectedComponents(value)}
selectedOptions={selectedComponents}
></InputComponent>
</FormControl>
)}
/> */}
</div>
</>
);
};
export default FolderForms;

View file

@ -1,10 +0,0 @@
import { z } from "zod";
export const FolderFormsSchema = z.object({
name: z.string().min(1, {
message: "Name must be at least 1 characters.",
}),
description: z.string().optional(),
components: z.array(z.string()),
flows: z.array(z.string()),
});

View file

@ -1,64 +0,0 @@
import { useNavigate } from "react-router-dom";
import { FolderType } from "../../../pages/MainPage/entities";
import { addFolder, updateFolder } from "../../../pages/MainPage/services";
import useAlertStore from "../../../stores/alertStore";
import { useFolderStore } from "../../../stores/foldersStore";
const useFolderSubmit = (
setOpen: (a: boolean) => void,
folderToEdit: FolderType | null,
) => {
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const navigate = useNavigate();
const onSubmit = (data) => {
if (folderToEdit) {
updateFolder(data, folderToEdit?.id!).then(
() => {
setSuccessData({
title: "Folder updated successfully.",
});
getFoldersApi(true);
setOpen(false);
navigate(`all/folder/${folderToEdit.id}`, {
state: { folderId: folderToEdit.id },
});
},
//TODO: LOOK THIS ERRO MORE CAREFULLY
(reason) => {
if (reason) {
setErrorData({
title: `Error updating folder.`,
});
console.error(reason);
} else {
getFoldersApi(true);
setOpen(false);
}
},
);
} else {
addFolder(data).then(
(res) => {
setSuccessData({
title: "Folder created successfully.",
});
getFoldersApi(true);
setOpen(false);
navigate(`all/folder/${res.id}`, { state: { folderId: res.id } });
},
() => {
setErrorData({
title: `Error creating folder.`,
});
},
);
}
};
return { onSubmit, open, setOpen };
};
export default useFolderSubmit;

View file

@ -1,79 +0,0 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import ForwardedIconComponent from "../../components/genericIconComponent";
import { Button } from "../../components/ui/button";
import { Form } from "../../components/ui/form";
import { useFolderStore } from "../../stores/foldersStore";
import BaseModal from "../baseModal";
import FolderForms from "./component";
import { FolderFormsSchema } from "./entities";
import useFolderSubmit from "./hooks/submit-folder";
type FoldersModalProps = {
open: boolean;
setOpen: (open: boolean) => void;
};
export default function FoldersModal({
open,
setOpen,
}: FoldersModalProps): JSX.Element {
const form = useForm<z.infer<typeof FolderFormsSchema>>({
resolver: zodResolver(FolderFormsSchema),
defaultValues: {
name: "",
description: "",
components: [],
flows: [],
},
mode: "all",
});
const folderToEdit = useFolderStore((state) => state.folderToEdit);
const { onSubmit: onSubmitFolder } = useFolderSubmit(setOpen, folderToEdit);
const onSubmit = (data) => {
onSubmitFolder(data);
};
return (
<>
<BaseModal size="x-small" open={open} setOpen={setOpen}>
<BaseModal.Header
description={`${folderToEdit ? "Edit a folder" : "Add a new folder"}`}
>
<span className="pr-2" data-testid="modal-title">
{folderToEdit ? "Edit" : "New"} Folder
</span>
<ForwardedIconComponent
name={folderToEdit ? "Pencil" : "Plus"}
className="h-6 w-6 pl-1 text-primary"
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FolderForms
folderToEdit={folderToEdit}
control={form.control}
setValue={form.setValue}
/>
<Button
className="float-right mt-6"
type="submit"
disabled={!form.formState.isValid}
>
{folderToEdit ? "Edit" : "Save"} Folder
</Button>
</form>
</Form>
</div>
</BaseModal.Content>
</BaseModal>
</>
);
}

View file

@ -2,15 +2,12 @@
import IconComponent from "../../../../components/genericIconComponent";
import { Button } from "../../../../components/ui/button";
import DeleteConfirmationModal from "../../../../modals/deleteConfirmationModal";
import FoldersModal from "../../../../modals/foldersModal";
import NewFlowModal from "../../../../modals/newFlowModal";
import { cn } from "../../../../utils/utils";
interface ModalsProps {
openModal: boolean;
setOpenModal: (value: boolean) => void;
openFolderModal: boolean;
setOpenFolderModal: (value: boolean) => void;
openDeleteFolderModal: boolean;
setOpenDeleteFolderModal: (value: boolean) => void;
handleDeleteFolder: () => void;
@ -19,17 +16,12 @@ interface ModalsProps {
const ModalsComponent = ({
openModal,
setOpenModal,
openFolderModal,
setOpenFolderModal,
openDeleteFolderModal,
setOpenDeleteFolderModal,
handleDeleteFolder,
}: ModalsProps) => (
<>
{openModal && <NewFlowModal open={openModal} setOpen={setOpenModal} />}
{openFolderModal && (
<FoldersModal open={openFolderModal} setOpen={setOpenFolderModal} />
)}
{openDeleteFolderModal && (
<DeleteConfirmationModal
open={openDeleteFolderModal}

View file

@ -115,8 +115,6 @@ export default function HomePage(): JSX.Element {
<ModalsComponent
openModal={openModal}
setOpenModal={setOpenModal}
openFolderModal={openFolderModal}
setOpenFolderModal={setOpenFolderModal}
openDeleteFolderModal={openDeleteFolderModal}
setOpenDeleteFolderModal={setOpenDeleteFolderModal}
handleDeleteFolder={handleDeleteFolder}

View file

@ -12,46 +12,6 @@ export async function getFolders(): Promise<FolderType[]> {
}
}
export async function addFolder(data: AddFolderType): Promise<FolderType> {
const body = {
name: data.name,
description: data.description,
flows_list: data.flows ?? [],
components_list: data.components ?? [],
};
try {
const response = await api.post(`${BASE_URL_API}folders/`, body);
return response?.data;
} catch (error) {
throw error;
}
}
export async function updateFolder(
body: FolderType,
folderId: string,
): Promise<FolderType> {
try {
const response = await api.patch(
`${BASE_URL_API}folders/${folderId}`,
body,
);
return response?.data;
} catch (error) {
throw error;
}
}
export async function deleteFolder(folderId: string) {
try {
const response = await api.delete(`${BASE_URL_API}folders/${folderId}`);
return response?.data;
} catch (error) {
throw error;
}
}
export async function getFolderById(folderId: string): Promise<FolderType> {
try {
const response = await api.get(`${BASE_URL_API}folders/${folderId}`);

View file

@ -1,10 +1,6 @@
import { create } from "zustand";
import { DEFAULT_FOLDER, STARTER_FOLDER_NAME } from "../constants/constants";
import {
getFolderById,
getFolders,
uploadFlowsFromFolders,
} from "../pages/MainPage/services";
import { getFolderById, getFolders } from "../pages/MainPage/services";
import { FoldersStoreType } from "../types/zustand/folders";
import useFlowsManagerStore from "./flowsManagerStore";
import { useTypesStore } from "./typesStore";