From 2641012e8defce787959a3b723b1e560f895bc4b Mon Sep 17 00:00:00 2001 From: Gagan Singh Date: Tue, 26 Nov 2024 09:10:25 +0000 Subject: [PATCH 1/5] CHanges for the File Upload UI --- .../src/components/fileUploader.module.css | 90 +++++++++++++++++++ frontend/src/components/fileUploader.tsx | 59 ++++++++++++ frontend/src/components/input.module.css | 52 ++--------- frontend/src/components/input.tsx | 73 +++++++++++---- .../components/uploadedFileDisplay.module.css | 30 +++++++ .../src/components/uploadedFileDisplay.tsx | 16 ++++ 6 files changed, 258 insertions(+), 62 deletions(-) create mode 100644 frontend/src/components/fileUploader.module.css create mode 100644 frontend/src/components/fileUploader.tsx create mode 100644 frontend/src/components/uploadedFileDisplay.module.css create mode 100644 frontend/src/components/uploadedFileDisplay.tsx diff --git a/frontend/src/components/fileUploader.module.css b/frontend/src/components/fileUploader.module.css new file mode 100644 index 00000000..9c42b1fb --- /dev/null +++ b/frontend/src/components/fileUploader.module.css @@ -0,0 +1,90 @@ +.uploadButton_container { + position: relative; + display: flex; + align-items: flex-start; + justify-content: center; + background-color: transparent; + border-radius: 50%; + height: 36px; + width: 36px; + margin-right: 16px; + margin-left: 10px; + margin-top: 5px; +} + +.uploadButton { + background: transparent; + border: none; + height: 36px; + width: 36px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.uploadButton img { + width: 24px; + height: 24px; +} + +.uploadButton:not(:disabled):hover { + cursor: pointer; +} + +.uploadButton:active { + background-color: var(--grey-400); +} + +.uploadButton_container:has(.uploadButton:disabled) { + color: var(--grey-900); + opacity: 0.5; +} + +.uploadButton_container:has(.uploadButton:not(:disabled)):hover { + background-color: var(--grey-300); +} + +.sendButtonContainer { + display: flex; + align-items: flex-start; + justify-content: center; + height: 100%; +} + +.tooltip { + position: absolute; + bottom: 130%; + left: 50%; + transform: translateX(-50%); + width: 336px; + background-color: #333333; + color: #f2f2f2; + padding: 8px; + border-radius: 8px; + font-family: "Roboto", sans-serif; + font-size: 14px; + line-height: 16px; + text-align: left; + box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); + z-index: 10; +} + +.tooltip p { + margin: 0 0 8px 0; +} + +.tooltip p:last-child { + margin-bottom: 0; +} + +.tooltip::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + border-width: 8px; + border-style: solid; + border-color: #333333 transparent transparent transparent; +} \ No newline at end of file diff --git a/frontend/src/components/fileUploader.tsx b/frontend/src/components/fileUploader.tsx new file mode 100644 index 00000000..f0546446 --- /dev/null +++ b/frontend/src/components/fileUploader.tsx @@ -0,0 +1,59 @@ +import React, { ChangeEvent, useState } from 'react'; +import styles from './fileUploader.module.css'; +import UploadIcon from '../icons/upload.svg'; +import UploadInProgressIcon from '../icons/upload-in-progress.svg'; +import CheckCircleIcon from '../icons/check-circle.svg'; + +interface FileUploaderProps { + onFileUpload: (file: File) => Promise; + isUploading: boolean; + isUploaded: boolean; + disabled: boolean; +} + +export const FileUploader = ({ onFileUpload, isUploading, isUploaded, disabled }: FileUploaderProps) => { + const [showTooltip, setShowTooltip] = useState(false); + + const handleFileChange = (event: ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + onFileUpload(file); + } + }; + + const tooltipContent = disabled + ? ( + <> +

You already uploaded one file.

+

You can upload a different file by starting a new chat.

+

Starting a new chat will reset your existing conversation history.

+ + ) + :

You can only upload one .csv, .pdf or .txt file to this chat.

; + + return ( +
setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + + {showTooltip &&
{tooltipContent}
} +
+ ); +}; diff --git a/frontend/src/components/input.module.css b/frontend/src/components/input.module.css index bca3bd42..3e2b0f9b 100644 --- a/frontend/src/components/input.module.css +++ b/frontend/src/components/input.module.css @@ -77,52 +77,7 @@ textarea::placeholder { font-family: 'Roboto', sans-serif; } -.uploadButton_container { - display: flex; - align-items: flex-start; - justify-content: center; - background-color: transparent; - border-radius: 50%; - height: 36px; - width: 36px; - margin-right: 16px; - margin-left: 10px; - margin-top: 5px; -} - -.uploadButton { - background: transparent; - color: var(--grey-900); - border: none; - height: 100%; - width: 100%; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; -} -.uploadButton img { - width: 24px; - height: 24px; -} - -.uploadButton:not(:disabled):hover { - cursor: pointer; -} - -.uploadButton:active { - background-color: var(--grey-400); -} - -.uploadButton_container:has(.uploadButton:disabled) { - color: var(--grey-900); - opacity: 0.5; -} - -.uploadButton_container:has(.uploadButton:not(:disabled)):hover { - background-color: var(--grey-300); -} .sendButtonContainer { display: flex; @@ -130,3 +85,10 @@ textarea::placeholder { justify-content: center; height: 100%; } + +.inputRow { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} diff --git a/frontend/src/components/input.tsx b/frontend/src/components/input.tsx index 9e657c2b..b9c52b9b 100644 --- a/frontend/src/components/input.tsx +++ b/frontend/src/components/input.tsx @@ -8,7 +8,8 @@ import React, { } from 'react'; import styles from './input.module.css'; import RightArrowIcon from '../icons/send.svg'; -import UploadIcon from '../icons/upload.svg'; +import { FileUploader } from './fileUploader'; +import { UploadedFileDisplay } from './uploadedFileDisplay'; import { Suggestions } from './suggestions'; import { Button } from './button'; @@ -20,6 +21,10 @@ export interface InputProps { export const Input = ({ sendMessage, waiting, suggestions }: InputProps) => { const [userInput, setUserInput] = useState(''); + const [uploadedFile, setUploadedFile] = useState(null); + const [isUploading, setIsUploading] = useState(false); + const [isUploaded, setIsUploaded] = useState(false); + const [fileId, setFileId] = useState(''); const textareaRef = useRef(null); const onChange = useCallback((event: ChangeEvent) => { @@ -52,27 +57,61 @@ export const Input = ({ sendMessage, waiting, suggestions }: InputProps) => { [sendMessage, userInput, waiting], ); + const uploadFile = async (file: File) => { + setIsUploading(true); + setIsUploaded(false); + + try { + const formData = new FormData(); + formData.append('file', file); + const response = await fetch(`${process.env.BACKEND_URL}/uploadfile`, { + method: 'POST', + body: formData, + credentials: 'include', + }); + if (!response.ok) throw new Error(`Upload failed with status ${response.status}`); + + const { filename, id } = await response.json(); + console.log(`File uploaded successfully: ${filename} with id ${id}`); + setFileId(id); + setUploadedFile(file); + setIsUploading(false); + setIsUploaded(true); + } catch (error) { + setIsUploading(false); + console.error(error); + } + }; + + return ( <> + {uploadedFile && }
-
-