feat: Add drag and drop file upload functionality to chat input

This commit adds the drag and drop file upload functionality to the chat input component in the IOModal. It allows users to drag and drop files into the chat input area for uploading. The files are then processed and added to the chat message.

Files are validated to ensure they have the correct file extensions (png, jpg, jpeg, gif, bmp, webp) before uploading. If an invalid file is dropped, an error message is displayed.

This feature improves the user experience by providing a convenient way to upload files in the chat input.

Fixes #2115
This commit is contained in:
anovazzi1 2024-06-08 13:41:29 -03:00
commit 719c031212
4 changed files with 50 additions and 7 deletions

View file

@ -1,14 +1,25 @@
import IconComponent from "../../../../../../../components/genericIconComponent";
import { Case } from "../../../../../../../shared/components/caseComponent";
import { FilePreviewType } from "../../../../../../../types/components";
import { classNames } from "../../../../../../../utils/utils";
type ButtonSendWrapperProps = {
send: () => void;
lockChat: boolean;
noInput: boolean;
saveLoading: boolean;
chatValue: string;
files: FilePreviewType[];
};
const ButtonSendWrapper = ({
send,
lockChat,
noInput,
saveLoading,
chatValue,
}) => {
files,
}: ButtonSendWrapperProps) => {
return (
<button
className={classNames(
@ -22,7 +33,11 @@ const ButtonSendWrapper = ({
disabled={lockChat || saveLoading}
onClick={(): void => send()}
>
<Case condition={lockChat || saveLoading}>
<Case
condition={
lockChat || saveLoading || files.some((file) => file.loading)
}
>
<IconComponent
name="Lock"
className="form-modal-lock-icon"
@ -38,7 +53,12 @@ const ButtonSendWrapper = ({
/>
</Case>
<Case condition={!(lockChat || saveLoading) && !noInput}>
<Case
condition={
!(lockChat || saveLoading || files.some((file) => file.loading)) &&
!noInput
}
>
<IconComponent
name="LucideSend"
className="form-modal-send-icon "

View file

@ -1,7 +1,17 @@
import ShortUniqueId from "short-unique-id";
import useFileUpload from "./use-file-upload";
import useAlertStore from "../../../../../../stores/alertStore";
const useDragAndDrop = (setIsDragging, setFiles, currentFlowId) => {
const fsErrorText =
"Please ensure your file has one of the following extensions:";
const snErrorTxt = "png, jpg, jpeg, gif, bmp, webp";
const useDragAndDrop = (
setIsDragging,
setFiles,
currentFlowId,
setErrorData,
) => {
const dragOver = (e) => {
e.preventDefault();
if (e.dataTransfer.types.some((type) => type === "Files")) {
@ -24,7 +34,7 @@ const useDragAndDrop = (setIsDragging, setFiles, currentFlowId) => {
const onDrop = (e) => {
e.preventDefault();
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
handleFiles(e.dataTransfer.files, setFiles, currentFlowId);
handleFiles(e.dataTransfer.files, setFiles, currentFlowId, setErrorData);
e.dataTransfer.clearData();
}
setIsDragging(false);
@ -37,8 +47,19 @@ const useDragAndDrop = (setIsDragging, setFiles, currentFlowId) => {
};
};
const handleFiles = (files, setFiles, currentFlowId) => {
const handleFiles = (files, setFiles, currentFlowId, setErrorData) => {
if (files) {
const allowedExtensions = ["png", "jpg", "jpeg", "gif", "bmp", "webp"];
const file = files?.[0];
const fileExtension = file.name.split(".").pop()?.toLowerCase();
if (!fileExtension || !allowedExtensions.includes(fileExtension)) {
console.log("Error uploading file");
setErrorData({
title: "Error uploading file",
list: [fsErrorText, snErrorTxt],
});
return;
}
const uid = new ShortUniqueId({ length: 3 });
const id = uid();
const type = files[0].type.split("/")[0];

View file

@ -89,6 +89,7 @@ export default function ChatInput({
noInput={noInput}
saveLoading={saveLoading}
chatValue={chatValue}
files={files}
/>
</div>

View file

@ -25,7 +25,7 @@ export default function ChatView({
setLockChat,
}: chatViewProps): JSX.Element {
const { flowPool, outputs, inputs, CleanFlowPool } = useFlowStore();
const { setNoticeData } = useAlertStore();
const { setErrorData } = useAlertStore();
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const messagesRef = useRef<HTMLDivElement | null>(null);
const [chatHistory, setChatHistory] = useState<ChatMessageType[]>([]);
@ -161,6 +161,7 @@ export default function ChatView({
setIsDragging,
setFiles,
currentFlowId,
setErrorData,
);
return (