refactor: add new use-query endpoint of upload files (#2533)

* refactor: add new use-query endpoint of upload files

* extend type for payload callbackSuccess

* [autofix.ci] apply automated fixes

* bugfix: drag and drop image on chat not working

* Refactored query function to use Options

* Used dedicated function as queryFn

*  (API): export use-post-upload-file in files index
♻️ (FileInput): refactor file upload mutation to use onSuccess and onError
♻️ (chatInput): refactor file upload mutation to use onSuccess and onError
♻️ (chatView): refactor file upload mutation to use onSuccess and onError

* ♻️ (use-get-download-images.ts): simplify getDownloadImagesFn function
♻️ (use-get-transactions.ts): simplify getTransactionsFn function
 (use-handle-file-change.tsx): add hook to handle file input changes
 (use-upload.tsx): add hook to handle file paste events

* Added type on Request Processor

---------

Co-authored-by: anovazzi1 <otavio2204@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com>
This commit is contained in:
Cristhian Zanforlin Lousa 2024-07-04 17:25:57 -03:00 committed by GitHub
commit bfaac8b4ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 362 additions and 184 deletions

View file

@ -38,7 +38,6 @@ export default function App() {
const dark = useDarkStore((state) => state.dark);
const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders);
useGetVersionQuery(undefined, "updateState");
const [isLoadingHealth, setIsLoadingHealth] = useState(false);
useEffect(() => {

View file

@ -1,3 +1,4 @@
import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file";
import { useEffect, useState } from "react";
import {
CONSOLE_ERROR_MSG,
@ -46,6 +47,8 @@ export default function InputFileComponent({
setMyValue(value);
}, [value]);
const mutation = usePostUploadFile();
const handleButtonClick = (): void => {
// Create a file input element
const input = document.createElement("input");
@ -63,24 +66,27 @@ export default function InputFileComponent({
// Check if the file type is correct
if (file && checkFileType(file.name)) {
// Upload the file
uploadFile(file, currentFlowId)
.then((res) => res.data)
.then((data) => {
// Get the file name from the response
const { file_path } = data;
mutation.mutate(
{ file, id: currentFlowId },
{
onSuccess: (data) => {
// Get the file name from the response
const { file_path } = data;
// sets the value that goes to the backend
onFileChange(file_path);
// Update the state and callback with the name of the file
// sets the value to the user
setMyValue(file.name);
onChange(file.name);
setLoading(false);
})
.catch(() => {
console.error(CONSOLE_ERROR_MSG);
setLoading(false);
});
// sets the value that goes to the backend
onFileChange(file_path);
// Update the state and on with the name of the file
// sets the value to the user
setMyValue(file.name);
onChange(file.name);
setLoading(false);
},
onError: () => {
console.error(CONSOLE_ERROR_MSG);
setLoading(false);
},
},
);
} else {
// Show an error if the file type is not allowed
setErrorData({

View file

@ -3,6 +3,7 @@ import { BASE_URL_API } from "../../../constants/constants";
export const URLs = {
TRANSACTIONS: `monitor/transactions`,
API_KEY: `api_key`,
FILES: `files`,
VERSION: `version`,
} as const;

View file

@ -9,10 +9,9 @@ interface IPostAddApiKey {
}
// add types for error handling and success
export const usePostAddApiKey: useMutationFunctionType<IPostAddApiKey> = ({
callbackSuccess,
callbackError,
}) => {
export const usePostAddApiKey: useMutationFunctionType<IPostAddApiKey> = (
options,
) => {
const { mutate } = UseRequestProcessor();
const postAddApiKeyFn = async (payload: IPostAddApiKey): Promise<any> => {
@ -27,18 +26,7 @@ export const usePostAddApiKey: useMutationFunctionType<IPostAddApiKey> = ({
const res = await postAddApiKeyFn(payload);
return res.data;
},
{
onError: (err) => {
if (callbackError) {
callbackError(err);
}
},
onSuccess: (data) => {
if (callbackSuccess) {
callbackSuccess(data);
}
},
},
options,
);
return mutation;

View file

@ -0,0 +1,3 @@
export * from "./use-get-download-images";
export * from "./use-get-profile-pictures";
export * from "./use-post-upload-file";

View file

@ -0,0 +1,38 @@
import { keepPreviousData } from "@tanstack/react-query";
import { useQueryFunctionType } from "../../../../types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
interface DownloadImagesQueryParams {
flowId: string;
fileName: string;
}
export interface DownloadImagesResponse {
response: string;
}
export const useGetDownloadImagesQuery: useQueryFunctionType<
DownloadImagesQueryParams,
DownloadImagesResponse
> = ({ flowId, fileName }) => {
const { query } = UseRequestProcessor();
const getDownloadImagesFn = async () => {
const response = await api.get<DownloadImagesResponse>(
`${getURL("FILES")}/images/${flowId}/${fileName}`,
);
return response["data"];
};
const queryResult = query(
["useGetDownloadImagesQuery"],
getDownloadImagesFn,
{
placeholderData: keepPreviousData,
},
);
return queryResult;
};

View file

@ -0,0 +1,36 @@
import { keepPreviousData } from "@tanstack/react-query";
import { useQueryFunctionType } from "../../../../types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
interface ProfilePicturesQueryParams {}
export interface ProfilePicturesResponse {
files: string[];
}
export const useGetProfilePicturesQuery: useQueryFunctionType<
ProfilePicturesQueryParams,
ProfilePicturesResponse
> = () => {
const { query } = UseRequestProcessor();
const getProfilePicturesFn = async () => {
const response = await api.get<ProfilePicturesResponse>(
`${getURL("FILES")}/profile_pictures/list`,
);
return response.data;
};
const queryResult = query(
["useGetProfilePicturesQuery"],
getProfilePicturesFn,
{
placeholderData: keepPreviousData,
},
);
return queryResult;
};

View file

@ -0,0 +1,40 @@
import { useMutationFunctionType } from "@/types/api";
import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
interface IPostUploadFile {
file: File;
id: string;
}
export const usePostUploadFile: useMutationFunctionType<IPostUploadFile> = (
options?,
) => {
const { mutate } = UseRequestProcessor();
const postUploadFileFn = async (payload: IPostUploadFile): Promise<any> => {
const formData = new FormData();
formData.append("file", payload.file);
const response = await api.post<any>(
`${getURL("FILES")}/upload/${payload.id}`,
formData,
);
return response.data;
};
const mutation: UseMutationResult<IPostUploadFile, any, IPostUploadFile> =
mutate(
["usePostUploadFile"],
async (payload: IPostUploadFile) => {
const res = await postUploadFileFn(payload);
return res;
},
options,
);
return mutation;
};

View file

@ -39,29 +39,24 @@ export const useGetTransactionsQuery: useQueryFunctionType<
}
};
const getTransactionsFn = async (id: string, params = {}) => {
const getTransactionsFn = async () => {
const config = {};
config["params"] = { flow_id: id };
if (params) {
config["params"] = { ...config["params"], ...params };
}
return await api.get<TransactionsResponse>(
const rows = await api.get<TransactionsResponse>(
`${getURL("TRANSACTIONS")}`,
config,
);
return responseFn(rows);
};
const queryResult = query(
["useGetTransactionsQuery"],
async () => {
const rows = await getTransactionsFn(id, params);
return responseFn(rows);
},
{
placeholderData: keepPreviousData,
},
);
const queryResult = query(["useGetTransactionsQuery"], getTransactionsFn, {
placeholderData: keepPreviousData,
});
return queryResult;
};

View file

@ -1,4 +1,10 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
useMutation,
UseMutationOptions,
useQuery,
useQueryClient,
UseQueryOptions,
} from "@tanstack/react-query";
import { MutationFunctionType, QueryFunctionType } from "../../../types/api";
export function UseRequestProcessor(): {
@ -7,7 +13,11 @@ export function UseRequestProcessor(): {
} {
const queryClient = useQueryClient();
function query(queryKey, queryFn, options = {}) {
function query(
queryKey: UseQueryOptions["queryKey"],
queryFn: UseQueryOptions["queryFn"],
options: Omit<UseQueryOptions, "queryFn" | "queryKey"> = {},
) {
return useQuery({
queryKey,
queryFn,
@ -15,11 +25,18 @@ export function UseRequestProcessor(): {
});
}
function mutate(mutationKey, mutationFn, options = {}) {
function mutate(
mutationKey: UseMutationOptions["mutationKey"],
mutationFn: UseMutationOptions["mutationFn"],
options: Omit<UseMutationOptions, "mutationFn" | "mutationKey"> = {},
) {
return useMutation({
mutationKey,
mutationFn,
onSettled: () => queryClient.invalidateQueries(mutationKey),
onSettled: (data, error, variables, context) => {
queryClient.invalidateQueries({ queryKey: mutationKey });
options.onSettled && options.onSettled(data, error, variables, context);
},
...options,
});
}

View file

@ -1,5 +1,6 @@
import { Button } from "../../../../../../components/ui/button";
import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file";
import { useEffect, useState } from "react";
import IconComponent from "../../../../../../components/genericIconComponent";
import { BASE_URL_API } from "../../../../../../constants/constants";
@ -66,6 +67,8 @@ export default function IOFileInput({ field, updateValue }: IOFileInputProps) {
setIsDragging(false);
};
const mutation = usePostUploadFile();
const upload = async (file) => {
if (file) {
// Check if a file was selected
@ -80,17 +83,18 @@ export default function IOFileInput({ field, updateValue }: IOFileInputProps) {
document.body.appendChild(imgElement); // Add the image to the body or replace this with your desired location
};
fileReader.readAsDataURL(file);
uploadFile(file, currentFlowId)
.then((res) => res.data)
.then((data) => {
// Get the file name from the response
const { file_path, flowId } = data;
setFilePath(file_path);
})
.catch(() => {
console.error("Error occurred while uploading file");
});
mutation.mutate(
{ file, id: currentFlowId },
{
onSuccess: (data) => {
const { file_path } = data;
setFilePath(file_path);
},
onError: () => {
console.error("Error occurred while uploading file");
},
},
);
}
};

View file

@ -4,7 +4,7 @@ import {
FS_ERROR_TEXT,
SN_ERROR_TEXT,
} from "../../../../../../constants/constants";
import useFileUpload from "./use-file-upload";
// import useFileUpload from "./use-file-upload";
const useDragAndDrop = (
setIsDragging: (value: boolean) => void,
@ -31,48 +31,11 @@ const useDragAndDrop = (
setIsDragging(false);
};
const onDrop = (e) => {
e.preventDefault();
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
handleFiles(e.dataTransfer.files, setFiles, currentFlowId, setErrorData);
e.dataTransfer.clearData();
}
setIsDragging(false);
};
return {
dragOver,
dragEnter,
dragLeave,
onDrop,
};
};
const handleFiles = (files, setFiles, currentFlowId, setErrorData) => {
if (files) {
const file = files?.[0];
const fileExtension = file.name.split(".").pop()?.toLowerCase();
if (
!fileExtension ||
!ALLOWED_IMAGE_INPUT_EXTENSIONS.includes(fileExtension)
) {
console.log("Error uploading file");
setErrorData({
title: "Error uploading file",
list: [FS_ERROR_TEXT, SN_ERROR_TEXT],
});
return;
}
const uid = new ShortUniqueId();
const id = uid.randomUUID(3);
const type = files[0].type.split("/")[0];
const blob = files[0];
setFiles((prevFiles) => [
...prevFiles,
{ file: blob, loading: true, error: false, id, type },
]);
useFileUpload(blob, currentFlowId, setFiles, id);
}
};
export default useDragAndDrop;

View file

@ -1,27 +0,0 @@
import { uploadFile } from "../../../../../../controllers/API";
const useFileUpload = (blob, currentFlowId, setFiles, id) => {
uploadFile(blob, currentFlowId)
.then((res) => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].path = res.data.file_path;
return newFiles;
});
})
.catch(() => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].error = true;
return newFiles;
});
});
return null;
};
export default useFileUpload;

View file

@ -5,7 +5,7 @@ import {
SN_ERROR_TEXT,
} from "../../../../../../constants/constants";
import useAlertStore from "../../../../../../stores/alertStore";
import useFileUpload from "./use-file-upload";
import handleFileUpload from "../helpers/handle-file-upload";
export const useHandleFileChange = (setFiles, currentFlowId) => {
const setErrorData = useAlertStore((state) => state.setErrorData);
@ -39,7 +39,7 @@ export const useHandleFileChange = (setFiles, currentFlowId) => {
{ file: blob, loading: true, error: false, id, type },
]);
useFileUpload(blob, currentFlowId, setFiles, id);
handleFileUpload(blob, currentFlowId, setFiles, id);
}
// Clear the file input value to ensure the change event is triggered even for the same file

View file

@ -8,7 +8,6 @@ import {
} from "../../../../../../constants/constants";
import useAlertStore from "../../../../../../stores/alertStore";
import { UploadFileTypeAPI } from "../../../../../../types/api";
import useFileUpload from "./use-file-upload";
const useUpload = (
uploadFile: (
@ -49,7 +48,6 @@ const useUpload = (
...prevFiles,
{ file: blob, loading: true, error: false, id, type },
]);
useFileUpload(blob, currentFlowId, setFiles, id);
}
}
}

View file

@ -1,7 +1,13 @@
import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file";
import useAlertStore from "@/stores/alertStore";
import { useRef, useState } from "react";
import ShortUniqueId from "short-unique-id";
import {
ALLOWED_IMAGE_INPUT_EXTENSIONS,
CHAT_INPUT_PLACEHOLDER,
CHAT_INPUT_PLACEHOLDER_SEND,
FS_ERROR_TEXT,
SN_ERROR_TEXT,
} from "../../../../../constants/constants";
import { uploadFile } from "../../../../../controllers/API";
import useFlowsManagerStore from "../../../../../stores/flowsManagerStore";
@ -16,8 +22,6 @@ import UploadFileButton from "./components/uploadFileButton";
import { getClassNamesFilePreview } from "./helpers/get-class-file-preview";
import useAutoResizeTextArea from "./hooks/use-auto-resize-text-area";
import useFocusOnUnlock from "./hooks/use-focus-unlock";
import useHandleFileChange from "./hooks/use-handle-file-change";
import useUpload from "./hooks/use-upload";
export default function ChatInput({
lockChat,
chatValue,
@ -34,11 +38,72 @@ export default function ChatInput({
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const [inputFocus, setInputFocus] = useState<boolean>(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const setErrorData = useAlertStore((state) => state.setErrorData);
const [id, setId] = useState<string>("");
useFocusOnUnlock(lockChat, inputRef);
useAutoResizeTextArea(chatValue, inputRef);
useUpload(uploadFile, currentFlowId, setFiles, lockChat || saveLoading);
const { handleFileChange } = useHandleFileChange(setFiles, currentFlowId);
const handleFileChange = async (
event: React.ChangeEvent<HTMLInputElement>,
) => {
const fileInput = event.target;
const file = fileInput.files?.[0];
if (file) {
const fileExtension = file.name.split(".").pop()?.toLowerCase();
if (
!fileExtension ||
!ALLOWED_IMAGE_INPUT_EXTENSIONS.includes(fileExtension)
) {
setErrorData({
title: "Error uploading file",
list: [FS_ERROR_TEXT, SN_ERROR_TEXT],
});
return;
}
const uid = new ShortUniqueId();
const id = uid.randomUUID(10);
setId(id);
const type = file.type.split("/")[0];
const blob = file;
setFiles((prevFiles) => [
...prevFiles,
{ file: blob, loading: true, error: false, id, type },
]);
mutation.mutate(
{ file: blob, id: currentFlowId },
{
onSuccess: (data) => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].path = data.file_path;
return newFiles;
});
},
onError: () => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].error = true;
return newFiles;
});
},
},
);
}
fileInput.value = "";
};
const mutation = usePostUploadFile();
const send = () => {
sendMessage({

View file

@ -1,10 +1,14 @@
import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file";
import { useEffect, useRef, useState } from "react";
import ShortUniqueId from "short-unique-id";
import IconComponent from "../../../../components/genericIconComponent";
import { Button } from "../../../../components/ui/button";
import {
ALLOWED_IMAGE_INPUT_EXTENSIONS,
CHAT_FIRST_INITIAL_TEXT,
CHAT_SECOND_INITIAL_TEXT,
EMPTY_INPUT_SEND_MESSAGE,
FS_ERROR_TEXT,
SN_ERROR_TEXT,
} from "../../../../constants/constants";
import { deleteFlowPool } from "../../../../controllers/API";
import useAlertStore from "../../../../stores/alertStore";
@ -34,8 +38,8 @@ export default function ChatView({
const inputTypes = inputs.map((obj) => obj.type);
const inputIds = inputs.map((obj) => obj.id);
const outputIds = outputs.map((obj) => obj.id);
const outputTypes = outputs.map((obj) => obj.type);
const updateFlowPool = useFlowStore((state) => state.updateFlowPool);
const [id, setId] = useState<string>("");
//build chat history
useEffect(() => {
@ -102,11 +106,6 @@ export default function ChatView({
}
}, []);
async function sendAll(data: sendAllProps): Promise<void> {}
useEffect(() => {
if (ref.current) ref.current.scrollIntoView({ behavior: "smooth" });
}, []);
const ref = useRef<HTMLDivElement | null>(null);
useEffect(() => {
@ -150,13 +149,77 @@ export default function ChatView({
const [files, setFiles] = useState<FilePreviewType[]>([]);
const [isDragging, setIsDragging] = useState(false);
const { dragOver, dragEnter, dragLeave, onDrop } = useDragAndDrop(
const { dragOver, dragEnter, dragLeave } = useDragAndDrop(
setIsDragging,
setFiles,
currentFlowId,
setErrorData,
);
const onDrop = (e) => {
e.preventDefault();
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
handleFiles(e.dataTransfer.files, setFiles, currentFlowId, setErrorData);
e.dataTransfer.clearData();
}
setIsDragging(false);
};
const handleFiles = (files, setFiles, currentFlowId, setErrorData) => {
if (files) {
const file = files?.[0];
const fileExtension = file.name.split(".").pop()?.toLowerCase();
if (
!fileExtension ||
!ALLOWED_IMAGE_INPUT_EXTENSIONS.includes(fileExtension)
) {
console.log("Error uploading file");
setErrorData({
title: "Error uploading file",
list: [FS_ERROR_TEXT, SN_ERROR_TEXT],
});
return;
}
const uid = new ShortUniqueId();
const id = uid.randomUUID(3);
setId(id);
const type = files[0].type.split("/")[0];
const blob = files[0];
setFiles((prevFiles) => [
...prevFiles,
{ file: blob, loading: true, error: false, id, type },
]);
mutation.mutate(
{ file: blob, id: currentFlowId },
{
onSuccess: (data) => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].path = data.file_path;
return newFiles;
});
},
onError: () => {
setFiles((prev) => {
const newFiles = [...prev];
const updatedIndex = newFiles.findIndex((file) => file.id === id);
newFiles[updatedIndex].loading = false;
newFiles[updatedIndex].error = true;
return newFiles;
});
},
},
);
}
};
const mutation = usePostUploadFile();
return (
<div
className="eraser-column-arrangement"

View file

@ -1,3 +1,7 @@
import {
ProfilePicturesResponse,
useGetProfilePicturesQuery,
} from "@/controllers/API/queries/files";
import * as Form from "@radix-ui/react-form";
import { useEffect, useState } from "react";
import { Button } from "../../../../../../components/ui/button";
@ -16,7 +20,7 @@ type ProfilePictureFormComponentProps = {
profilePicture: string;
handleInput: (event: any) => void;
handlePatchProfilePicture: (gradient: string) => void;
handleGetProfilePictures: () => Promise<string[] | undefined>;
handleGetProfilePictures: () => ProfilePicturesResponse | undefined;
userData: any;
};
const ProfilePictureFormComponent = ({
@ -29,39 +33,24 @@ const ProfilePictureFormComponent = ({
const [profilePictures, setProfilePictures] = useState<{
[key: string]: string[];
}>({});
const [loading, setLoading] = useState(true);
const { data: response, isFetching } = useGetProfilePicturesQuery({});
useEffect(() => {
const abortController = new AbortController();
handleGetProfilePictures()
.then((data) => {
if (data) {
data.forEach((profile_picture) => {
const [folder, path] = profile_picture.split("/");
setProfilePictures((prev) => {
if (prev[folder]) {
prev[folder].push(path);
} else {
prev[folder] = [path];
}
setLoading(false);
return prev;
});
});
}
})
.catch(() => {
setLoading(false);
if (response?.files) {
response?.files?.forEach((profile_picture) => {
const [folder, path] = profile_picture.split("/");
setProfilePictures((prev) => {
if (prev[folder]) {
prev[folder].push(path);
} else {
prev[folder] = [path];
}
return prev;
});
});
/*
Abort the request as it isn't needed anymore, the component being
unmounted. It helps avoid, among other things, the well-known "can't
perform a React state update on an unmounted component" warning.
*/
return () => abortController.abort();
}, []);
}
}, [response]);
return (
<Form.Root
@ -81,7 +70,7 @@ const ProfilePictureFormComponent = ({
<div className="py-2">
<ProfilePictureChooserComponent
profilePictures={profilePictures}
loading={loading}
loading={isFetching}
value={
profilePicture == ""
? userData?.profile_image ??

View file

@ -1,4 +1,5 @@
import { usePostAddApiKey } from "@/controllers/API/queries/api-keys";
import { useGetProfilePicturesQuery } from "@/controllers/API/queries/files";
import { useContext, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { CONTROL_PATCH_USER_STATE } from "../../../../constants/constants";
@ -52,7 +53,10 @@ export const GeneralPage = () => {
setErrorData,
);
const { handleGetProfilePictures } = useGetProfilePictures(setErrorData);
const handleGetProfilePictures = () => {
const { data } = useGetProfilePicturesQuery({});
return data;
};
const { handlePatchProfilePicture } = usePatchProfilePicture(
setSuccessData,
@ -64,14 +68,14 @@ export const GeneralPage = () => {
useScrollToElement(scrollId, setCurrentFlowId);
const { mutate } = usePostAddApiKey({
callbackSuccess: () => {
onSuccess: () => {
setSuccessData({ title: "API key saved successfully" });
setHasApiKey(true);
setValidApiKey(true);
setLoadingApiKey(false);
handleInput({ target: { name: "apikey", value: "" } });
},
callbackError: (error) => {
onError: (error) => {
setErrorData({
title: "API key save error",
list: [(error as any)?.response?.data?.detail],

View file

@ -249,10 +249,6 @@ export type MutationFunctionType = (
options?: Omit<UseMutationOptions<any, any>, "mutationFn" | "mutationKey">,
) => UseMutationResult<any, any, any, any>;
export type useMutationFunctionType<Variables, Data = any, Error = any> = ({
callbackError,
callbackSuccess,
}: {
callbackSuccess: (data: Data) => void;
callbackError: (err: Error) => void;
}) => UseMutationResult<Data, Error, Variables>;
export type useMutationFunctionType<Variables, Data = any, Error = any> = (
options?: Omit<UseMutationOptions<Data, Error>, "mutationFn" | "mutationKey">,
) => UseMutationResult<Data, Error, Variables>;