fix: simplify InputFileComponent to use native file picker (#5692)

* ✨ (index.tsx): Add useRef hook to manage file input element reference for better control over file selection process
🐛 (index.tsx): Fix handleButtonClick function to handle file selection asynchronously and provide fallback option if file selection fails
🐛 (index.tsx): Fix handleNativeInputChange function to correctly handle file selection from native file input element and reset its value after selection

* 📝 (index.tsx): Remove unused createFileUpload function and simplify handleButtonClick function to trigger file input click directly
♻️ (index.tsx): Refactor input element to use Button component for better styling and consistency

* 📝 (inputFileComponent/index.tsx): remove unnecessary comment in handleButtonClick function
This commit is contained in:
Cristhian Zanforlin Lousa 2025-01-15 13:27:12 -03:00 • committed by GitHub
commit 65530e210f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,8 +1,7 @@
import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file"; import { usePostUploadFile } from "@/controllers/API/queries/files/use-post-upload-file";
import { createFileUpload } from "@/helpers/create-file-upload";
import useFileSizeValidator from "@/shared/hooks/use-file-size-validator"; import useFileSizeValidator from "@/shared/hooks/use-file-size-validator";
import { cn } from "@/utils/utils"; import { cn } from "@/utils/utils";
import { useEffect } from "react"; import { useEffect, useRef } from "react";
import { import {
CONSOLE_ERROR_MSG, CONSOLE_ERROR_MSG,
INVALID_FILE_ALERT, INVALID_FILE_ALERT,
@ -24,70 +23,77 @@ export default function InputFileComponent({
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const { validateFileSize } = useFileSizeValidator(setErrorData); const { validateFileSize } = useFileSizeValidator(setErrorData);
const fileInputRef = useRef<HTMLInputElement>(null);
// Clear component state // Clear component state
useEffect(() => { useEffect(() => {
if (disabled && value !== "") { if (disabled && value !== "") {
handleOnNewValue({ value: "", file_path: "" }, { skipSnapshot: true }); handleOnNewValue({ value: "", file_path: "" }, { skipSnapshot: true });
} }
}, [disabled, handleOnNewValue]); }, [disabled, handleOnNewValue, value]);
function checkFileType(fileName: string): boolean { function checkFileType(fileName: string): boolean {
if (fileTypes === undefined) return true; if (!fileTypes?.length) return true;
for (let index = 0; index < fileTypes.length; index++) { return fileTypes.some((type) =>
if (fileName.endsWith(fileTypes[index])) { fileName.toLowerCase().endsWith(type.toLowerCase()),
return true; );
}
}
return false;
} }
const { mutate, isPending } = usePostUploadFile(); const { mutate, isPending } = usePostUploadFile();
const handleButtonClick = (): void => { const handleFileSelection = (file: File | null) => {
createFileUpload({ multiple: false, accept: fileTypes?.join(",") }).then( if (!file) {
(files) => { setErrorData({
const file = files[0]; title: "Error selecting file",
if (file) { list: ["No file was selected"],
if (!validateFileSize(file)) { });
return; return;
} }
if (checkFileType(file.name)) { if (!validateFileSize(file)) {
// Upload the file return;
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 if (!checkFileType(file.name)) {
// Update the state and on with the name of the file setErrorData({
// sets the value to the user title: INVALID_FILE_ALERT,
handleOnNewValue({ value: file.name, file_path }); list: [fileTypes?.join(", ") || ""],
}, });
onError: (error) => { return;
console.error(CONSOLE_ERROR_MSG); }
setErrorData({
title: "Error uploading file", mutate(
list: [error.response?.data?.detail], { file, id: currentFlowId },
}); {
}, onSuccess: (data) => {
}, const { file_path } = data;
); handleOnNewValue({ value: file.name, file_path });
} else { },
// Show an error if the file type is not allowed onError: (error) => {
setErrorData({ console.error(CONSOLE_ERROR_MSG);
title: INVALID_FILE_ALERT, setErrorData({
list: [fileTypes?.join(", ") || ""], title: "Error uploading file",
}); list: [error.response?.data?.detail || "Unknown error occurred"],
} });
} },
}, },
); );
}; };
const handleButtonClick = () => {
fileInputRef.current?.click();
};
const handleNativeInputChange = (
event: React.ChangeEvent<HTMLInputElement>,
) => {
const file = event.target.files?.[0] || null;
handleFileSelection(file);
if (event.target) {
event.target.value = "";
}
};
const isDisabled = disabled || isPending; const isDisabled = disabled || isPending;
return ( return (
@ -96,18 +102,29 @@ export default function InputFileComponent({
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">
<div className="relative flex w-full"> <div className="relative flex w-full">
<div className="w-full"> <div className="w-full">
<input <Button
unstyled
data-testid="input-file-component" data-testid="input-file-component"
type="text"
className={cn( className={cn(
"primary-input h-9 w-full cursor-pointer rounded-r-none text-sm focus:border-border focus:outline-none focus:ring-0", "primary-input h-9 w-full justify-start rounded-r-none text-sm focus:border-border focus:outline-none focus:ring-0",
!value && "text-placeholder-foreground", !value && "text-placeholder-foreground",
editNode && "h-6", editNode && "h-6",
)} )}
value={value || "Upload a file..."}
readOnly
disabled={isDisabled}
onClick={handleButtonClick} onClick={handleButtonClick}
disabled={isDisabled}
variant="outline"
>
<span className={cn(editNode && "relative -top-1.5")}>
{value || "Upload a file..."}
</span>
</Button>
<input
ref={fileInputRef}
type="file"
className="hidden"
accept={fileTypes?.join(",")}
onChange={handleNativeInputChange}
onClick={(e) => e.stopPropagation()}
/> />
</div> </div>
<div> <div>