|  | @@ -111,35 +111,27 @@ export const useImageFiles = () => {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type useClipboardUploaderProps = {
 | 
	
		
			
				|  |  | -  files: ImageFile[]
 | 
	
		
			
				|  |  | -  visionConfig?: VisionSettings
 | 
	
		
			
				|  |  | +type useLocalUploaderProps = {
 | 
	
		
			
				|  |  | +  disabled?: boolean
 | 
	
		
			
				|  |  | +  limit?: number
 | 
	
		
			
				|  |  |    onUpload: (imageFile: ImageFile) => void
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -export const useClipboardUploader = ({ visionConfig, onUpload, files }: useClipboardUploaderProps) => {
 | 
	
		
			
				|  |  | +export const useLocalFileUploader = ({ limit, disabled = false, onUpload }: useLocalUploaderProps) => {
 | 
	
		
			
				|  |  |    const { notify } = useToastContext()
 | 
	
		
			
				|  |  |    const params = useParams()
 | 
	
		
			
				|  |  |    const { t } = useTranslation()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  const handleClipboardPaste = useCallback((e: ClipboardEvent<HTMLTextAreaElement>) => {
 | 
	
		
			
				|  |  | -    if (!visionConfig || !visionConfig.enabled)
 | 
	
		
			
				|  |  | -      return
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    const disabled = files.length >= visionConfig.number_limits
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (disabled)
 | 
	
		
			
				|  |  | +  const handleLocalFileUpload = useCallback((file: File) => {
 | 
	
		
			
				|  |  | +    if (disabled) {
 | 
	
		
			
				|  |  |        // TODO: leave some warnings?
 | 
	
		
			
				|  |  |        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    const file = e.clipboardData?.files[0]
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!file || !ALLOW_FILE_EXTENSIONS.includes(file.type.split('/')[1]))
 | 
	
		
			
				|  |  | +    if (!ALLOW_FILE_EXTENSIONS.includes(file.type.split('/')[1]))
 | 
	
		
			
				|  |  |        return
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    const limit = +visionConfig.image_file_size_limit!
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (file.size > limit * 1024 * 1024) {
 | 
	
		
			
				|  |  | +    if (limit && file.size > limit * 1024 * 1024) {
 | 
	
		
			
				|  |  |        notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerLimit', { size: limit }) })
 | 
	
		
			
				|  |  |        return
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -182,9 +174,97 @@ export const useClipboardUploader = ({ visionConfig, onUpload, files }: useClipb
 | 
	
		
			
				|  |  |        false,
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |      reader.readAsDataURL(file)
 | 
	
		
			
				|  |  | -  }, [visionConfig, files.length, notify, t, onUpload, params.token])
 | 
	
		
			
				|  |  | +  }, [disabled, limit, notify, t, onUpload, params.token])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return { disabled, handleLocalFileUpload }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type useClipboardUploaderProps = {
 | 
	
		
			
				|  |  | +  files: ImageFile[]
 | 
	
		
			
				|  |  | +  visionConfig?: VisionSettings
 | 
	
		
			
				|  |  | +  onUpload: (imageFile: ImageFile) => void
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export const useClipboardUploader = ({ visionConfig, onUpload, files }: useClipboardUploaderProps) => {
 | 
	
		
			
				|  |  | +  const allowLocalUpload = visionConfig?.transfer_methods?.includes(TransferMethod.local_file)
 | 
	
		
			
				|  |  | +  const disabled = useMemo(() =>
 | 
	
		
			
				|  |  | +    !visionConfig
 | 
	
		
			
				|  |  | +    || !visionConfig?.enabled
 | 
	
		
			
				|  |  | +    || !allowLocalUpload
 | 
	
		
			
				|  |  | +    || files.length >= visionConfig.number_limits!,
 | 
	
		
			
				|  |  | +  [allowLocalUpload, files.length, visionConfig])
 | 
	
		
			
				|  |  | +  const limit = useMemo(() => visionConfig ? +visionConfig.image_file_size_limit! : 0, [visionConfig])
 | 
	
		
			
				|  |  | +  const { handleLocalFileUpload } = useLocalFileUploader({ limit, onUpload, disabled })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleClipboardPaste = useCallback((e: ClipboardEvent<HTMLTextAreaElement>) => {
 | 
	
		
			
				|  |  | +    e.preventDefault()
 | 
	
		
			
				|  |  | +    const file = e.clipboardData?.files[0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!file)
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    handleLocalFileUpload(file)
 | 
	
		
			
				|  |  | +  }, [handleLocalFileUpload])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return {
 | 
	
		
			
				|  |  |      onPaste: handleClipboardPaste,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type useDraggableUploaderProps = {
 | 
	
		
			
				|  |  | +  files: ImageFile[]
 | 
	
		
			
				|  |  | +  visionConfig?: VisionSettings
 | 
	
		
			
				|  |  | +  onUpload: (imageFile: ImageFile) => void
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export const useDraggableUploader = <T extends HTMLElement>({ visionConfig, onUpload, files }: useDraggableUploaderProps) => {
 | 
	
		
			
				|  |  | +  const allowLocalUpload = visionConfig?.transfer_methods?.includes(TransferMethod.local_file)
 | 
	
		
			
				|  |  | +  const disabled = useMemo(() =>
 | 
	
		
			
				|  |  | +    !visionConfig
 | 
	
		
			
				|  |  | +    || !visionConfig?.enabled
 | 
	
		
			
				|  |  | +    || !allowLocalUpload
 | 
	
		
			
				|  |  | +    || files.length >= visionConfig.number_limits!,
 | 
	
		
			
				|  |  | +  [allowLocalUpload, files.length, visionConfig])
 | 
	
		
			
				|  |  | +  const limit = useMemo(() => visionConfig ? +visionConfig.image_file_size_limit! : 0, [visionConfig])
 | 
	
		
			
				|  |  | +  const { handleLocalFileUpload } = useLocalFileUploader({ disabled, onUpload, limit })
 | 
	
		
			
				|  |  | +  const [isDragActive, setIsDragActive] = useState(false)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleDragEnter = useCallback((e: React.DragEvent<T>) => {
 | 
	
		
			
				|  |  | +    e.preventDefault()
 | 
	
		
			
				|  |  | +    e.stopPropagation()
 | 
	
		
			
				|  |  | +    if (!disabled)
 | 
	
		
			
				|  |  | +      setIsDragActive(true)
 | 
	
		
			
				|  |  | +  }, [disabled])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleDragOver = useCallback((e: React.DragEvent<T>) => {
 | 
	
		
			
				|  |  | +    e.preventDefault()
 | 
	
		
			
				|  |  | +    e.stopPropagation()
 | 
	
		
			
				|  |  | +  }, [])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleDragLeave = useCallback((e: React.DragEvent<T>) => {
 | 
	
		
			
				|  |  | +    e.preventDefault()
 | 
	
		
			
				|  |  | +    e.stopPropagation()
 | 
	
		
			
				|  |  | +    setIsDragActive(false)
 | 
	
		
			
				|  |  | +  }, [])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const handleDrop = useCallback((e: React.DragEvent<T>) => {
 | 
	
		
			
				|  |  | +    e.preventDefault()
 | 
	
		
			
				|  |  | +    e.stopPropagation()
 | 
	
		
			
				|  |  | +    setIsDragActive(false)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const file = e.dataTransfer.files[0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!file)
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    handleLocalFileUpload(file)
 | 
	
		
			
				|  |  | +  }, [handleLocalFileUpload])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return {
 | 
	
		
			
				|  |  | +    onDragEnter: handleDragEnter,
 | 
	
		
			
				|  |  | +    onDragOver: handleDragOver,
 | 
	
		
			
				|  |  | +    onDragLeave: handleDragLeave,
 | 
	
		
			
				|  |  | +    onDrop: handleDrop,
 | 
	
		
			
				|  |  | +    isDragActive,
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 |