import { cn } from '@/lib/utils'; import { Popover, PopoverButton, PopoverPanel, Transition, } from '@headlessui/react'; import { CopyPlus, File, LoaderCircle, Plus, Trash } from 'lucide-react'; import { Fragment, useRef, useState } from 'react'; import { File as FileType } from '../ChatWindow'; const Attach = ({ fileIds, setFileIds, showText, files, setFiles, }: { fileIds: string[]; setFileIds: (fileIds: string[]) => void; showText?: boolean; files: FileType[]; setFiles: (files: FileType[]) => void; }) => { const [loading, setLoading] = useState(false); const fileInputRef = useRef<any>(); const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { setLoading(true); const data = new FormData(); for (let i = 0; i < e.target.files!.length; i++) { data.append('files', e.target.files![i]); } const embeddingModelProvider = localStorage.getItem( 'embeddingModelProvider', ); const embeddingModel = localStorage.getItem('embeddingModel'); data.append('embedding_model_provider', embeddingModelProvider!); data.append('embedding_model', embeddingModel!); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/uploads`, { method: 'POST', body: data, }); const resData = await res.json(); setFiles([...files, ...resData.files]); setFileIds([...fileIds, ...resData.files.map((file: any) => file.fileId)]); setLoading(false); }; return loading ? ( <div className="flex flex-row items-center justify-between space-x-1"> <LoaderCircle size={18} className="text-sky-400 animate-spin" /> <p className="text-sky-400 inline whitespace-nowrap text-xs font-medium"> Uploading.. </p> </div> ) : files.length > 0 ? ( <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg"> <PopoverButton type="button" className={cn( 'flex flex-row items-center justify-between space-x-1 p-2 text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary active:scale-95 transition duration-200 hover:text-black dark:hover:text-white', files.length > 0 ? '-ml-2 lg:-ml-3' : '', )} > {files.length > 1 && ( <> <File size={19} className="text-sky-400" /> <p className="text-sky-400 inline whitespace-nowrap text-xs font-medium"> {files.length} files </p> </> )} {files.length === 1 && ( <> <File size={18} className="text-sky-400" /> <p className="text-sky-400 text-xs font-medium"> {files[0].fileName.length > 10 ? files[0].fileName.replace(/\.\w+$/, '').substring(0, 3) + '...' + files[0].fileExtension : files[0].fileName} </p> </> )} </PopoverButton> <Transition as={Fragment} enter="transition ease-out duration-150" enterFrom="opacity-0 translate-y-1" enterTo="opacity-100 translate-y-0" leave="transition ease-in duration-150" leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > <PopoverPanel className="absolute z-10 w-64 md:w-[350px] right-0"> <div className="bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col"> <div className="flex flex-row items-center justify-between px-3 py-2"> <h4 className="text-black dark:text-white font-medium text-sm"> Attached files </h4> <div className="flex flex-row items-center space-x-4"> <button type="button" onClick={() => fileInputRef.current.click()} className="flex flex-row items-center space-x-1 text-white/70 hover:text-white transition duration-200" > <input type="file" onChange={handleChange} ref={fileInputRef} accept=".pdf,.docx,.txt" multiple hidden /> <Plus size={18} /> <p className="text-xs">Add</p> </button> <button onClick={() => { setFiles([]); setFileIds([]); }} className="flex flex-row items-center space-x-1 text-white/70 hover:text-white transition duration-200" > <Trash size={14} /> <p className="text-xs">Clear</p> </button> </div> </div> <div className="h-[0.5px] mx-2 bg-white/10" /> <div className="flex flex-col items-center"> {files.map((file, i) => ( <div key={i} className="flex flex-row items-center justify-start w-full space-x-3 p-3" > <div className="bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md"> <File size={16} className="text-white/70" /> </div> <p className="text-white/70 text-sm"> {file.fileName.length > 25 ? file.fileName.replace(/\.\w+$/, '').substring(0, 25) + '...' + file.fileExtension : file.fileName} </p> </div> ))} </div> </div> </PopoverPanel> </Transition> </Popover> ) : ( <button type="button" onClick={() => fileInputRef.current.click()} className={cn( 'flex flex-row items-center space-x-1 text-black/50 dark:text-white/50 rounded-xl hover:bg-light-secondary dark:hover:bg-dark-secondary transition duration-200 hover:text-black dark:hover:text-white', showText ? '' : 'p-2', )} > <input type="file" onChange={handleChange} ref={fileInputRef} accept=".pdf,.docx,.txt" multiple hidden /> <CopyPlus size={showText ? 18 : undefined} /> {showText && <p className="text-xs font-medium pl-[1px]">Attach</p>} </button> ); }; export default Attach;