import type { FC } from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' import Uploader from './uploader' import ImageLinkInput from './image-link-input' import cn from '@/utils/classnames' import { ImagePlus } from '@/app/components/base/icons/src/vender/line/images' import { TransferMethod } from '@/types/app' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' import { Upload03 } from '@/app/components/base/icons/src/vender/line/general' import type { ImageFile, VisionSettings } from '@/types/app' type UploadOnlyFromLocalProps = { onUpload: (imageFile: ImageFile) => void disabled?: boolean limit?: number } const UploadOnlyFromLocal: FC<UploadOnlyFromLocalProps> = ({ onUpload, disabled, limit, }) => { return ( <Uploader onUpload={onUpload} disabled={disabled} limit={limit}> {hovering => ( <div className={` relative flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer ${hovering && 'bg-gray-100'} `} > <ImagePlus className="w-4 h-4 text-gray-500" /> </div> )} </Uploader> ) } type UploaderButtonProps = { methods: VisionSettings['transfer_methods'] onUpload: (imageFile: ImageFile) => void disabled?: boolean limit?: number } const UploaderButton: FC<UploaderButtonProps> = ({ methods, onUpload, disabled, limit, }) => { const { t } = useTranslation() const [open, setOpen] = useState(false) const hasUploadFromLocal = methods.find( method => method === TransferMethod.local_file, ) const handleUpload = (imageFile: ImageFile) => { onUpload(imageFile) } const closePopover = () => setOpen(false) const handleToggle = () => { if (disabled) return setOpen(v => !v) } return ( <PortalToFollowElem open={open} onOpenChange={setOpen} placement="top-start" > <PortalToFollowElemTrigger onClick={handleToggle}> <button type="button" disabled={disabled} className="relative flex items-center justify-center w-8 h-8 enabled:hover:bg-gray-100 rounded-lg disabled:cursor-not-allowed" > <ImagePlus className="w-4 h-4 text-gray-500" /> </button> </PortalToFollowElemTrigger> <PortalToFollowElemContent className="z-50"> <div className="p-2 w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg"> <ImageLinkInput onUpload={handleUpload} disabled={disabled} /> {hasUploadFromLocal && ( <> <div className="flex items-center mt-2 px-2 text-xs font-medium text-gray-400"> <div className="mr-3 w-[93px] h-[1px] bg-gradient-to-l from-[#F3F4F6]" /> OR <div className="ml-3 w-[93px] h-[1px] bg-gradient-to-r from-[#F3F4F6]" /> </div> <Uploader onUpload={handleUpload} limit={limit} closePopover={closePopover} > {hovering => ( <div className={cn( 'flex items-center justify-center h-8 text-[13px] font-medium text-[#155EEF] rounded-lg cursor-pointer', hovering && 'bg-primary-50', )} > <Upload03 className="mr-1 w-4 h-4" /> {t('common.imageUploader.uploadFromComputer')} </div> )} </Uploader> </> )} </div> </PortalToFollowElemContent> </PortalToFollowElem> ) } type ChatImageUploaderProps = { settings: VisionSettings onUpload: (imageFile: ImageFile) => void disabled?: boolean } const ChatImageUploader: FC<ChatImageUploaderProps> = ({ settings, onUpload, disabled, }) => { const onlyUploadLocal = settings.transfer_methods.length === 1 && settings.transfer_methods[0] === TransferMethod.local_file if (onlyUploadLocal) { return ( <UploadOnlyFromLocal onUpload={onUpload} disabled={disabled} limit={+settings.image_file_size_limit!} /> ) } return ( <UploaderButton methods={settings.transfer_methods} onUpload={onUpload} disabled={disabled} limit={+settings.image_file_size_limit!} /> ) } export default ChatImageUploader