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:
parent
4f586adf0a
commit
bfaac8b4ba
20 changed files with 362 additions and 184 deletions
|
|
@ -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(() => {
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
3
src/frontend/src/controllers/API/queries/files/index.ts
Normal file
3
src/frontend/src/controllers/API/queries/files/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./use-get-download-images";
|
||||
export * from "./use-get-profile-pictures";
|
||||
export * from "./use-post-upload-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;
|
||||
};
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 ??
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue