{"version":3,"sources":["../src/hooks/use-upload.ts"],"names":["useUpload","provider","options","files","setFiles","useState","isUploading","setIsUploading","error","setError","uploadProgress","setUploadProgress","fileProcessor","useMemo","FileProcessor","useEffect","addFiles","useCallback","newFiles","result","prev","errorMessage","removeFile","fileId","f","newProgress","clearAll","uploadFile","uploadOptions","file","finalOptions","uploadAll","pendingFiles","results","progress","r","retryUpload","cancelUpload","getStats","testConnection","uploadingFiles","successFiles","errorFiles","cancelledFiles","totalSize","sum","uploadedSize"],"mappings":"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","file":"chunk-4NMULKNG.cjs","sourcesContent":["import { useState, useCallback, useMemo, useEffect } from \"react\";\r\nimport type { UploadFile, UploadOptions } from \"../types\";\r\nimport type { UploadProvider } from \"../core/provider\";\r\nimport { FileProcessor } from \"../core/file-processor\";\r\n\r\n/**\r\n * Hook for managing file uploads with a specific provider\r\n */\r\nexport function useUpload(\r\n  provider: UploadProvider,\r\n  options: UploadOptions = {}\r\n) {\r\n  const [files, setFiles] = useState<UploadFile[]>([]);\r\n  const [isUploading, setIsUploading] = useState(false);\r\n  const [error, setError] = useState<string | null>(null);\r\n  const [uploadProgress, setUploadProgress] = useState<Record<string, number>>(\r\n    {}\r\n  );\r\n\r\n  // Memoized file processor instance\r\n  const fileProcessor = useMemo(\r\n    () => new FileProcessor(options),\r\n    [options.maxFiles, options.maxFileSize, options.allowedTypes]\r\n  );\r\n\r\n  // Initialize provider on mount\r\n  useEffect(() => {\r\n    const initProvider = async () => {\r\n      try {\r\n        await provider.initialize();\r\n      } catch (error) {\r\n        setError(\r\n          `Failed to initialize ${provider.getName()} provider: ${error instanceof Error ? error.message : \"Unknown error\"}`\r\n        );\r\n      }\r\n    };\r\n\r\n    initProvider();\r\n\r\n    // Cleanup on unmount\r\n    return () => {\r\n      provider.cleanup().catch(console.warn);\r\n    };\r\n  }, [provider]);\r\n\r\n  /**\r\n   * Process and add files to the upload queue\r\n   */\r\n  const addFiles = useCallback(\r\n    async (newFiles: readonly File[]) => {\r\n      try {\r\n        setError(null);\r\n        const result = await fileProcessor.processFiles(newFiles);\r\n\r\n        if (result.success && result.files) {\r\n          setFiles((prev) => [...prev, ...result.files!]);\r\n          return { success: true, files: result.files };\r\n        } else if (result.errors) {\r\n          const errorMessage = result.errors.join(\"; \");\r\n          setError(errorMessage);\r\n          return { success: false, errors: result.errors };\r\n        }\r\n      } catch (error) {\r\n        const errorMessage =\r\n          error instanceof Error ? error.message : \"Failed to process files\";\r\n        setError(errorMessage);\r\n        return { success: false, errors: [errorMessage] };\r\n      }\r\n    },\r\n    [fileProcessor]\r\n  );\r\n\r\n  /**\r\n   * Remove a file from the upload queue\r\n   */\r\n  const removeFile = useCallback((fileId: string) => {\r\n    setFiles((prev) => prev.filter((f) => f.id !== fileId));\r\n    setUploadProgress((prev) => {\r\n      const newProgress = { ...prev };\r\n      delete newProgress[fileId];\r\n      return newProgress;\r\n    });\r\n  }, []);\r\n\r\n  /**\r\n   * Clear all files from the upload queue\r\n   */\r\n  const clearAll = useCallback(() => {\r\n    setFiles([]);\r\n    setUploadProgress({});\r\n    setError(null);\r\n  }, []);\r\n\r\n  /**\r\n   * Upload a single file\r\n   */\r\n  const uploadFile = useCallback(\r\n    async (fileId: string, uploadOptions?: UploadOptions) => {\r\n      const file = files.find((f) => f.id === fileId);\r\n      if (!file || file.status === \"success\") return;\r\n\r\n      try {\r\n        setError(null);\r\n        setUploadProgress((prev) => ({ ...prev, [fileId]: 0 }));\r\n\r\n        // Update file status to uploading\r\n        setFiles((prev) =>\r\n          prev.map((f) =>\r\n            f.id === fileId ? { ...f, status: \"uploading\" as const } : f\r\n          )\r\n        );\r\n\r\n        const finalOptions = { ...options, ...uploadOptions };\r\n        const result = await provider.uploadFile(file.file, finalOptions);\r\n\r\n        // Update file with success status\r\n        setFiles((prev) =>\r\n          prev.map((f) =>\r\n            f.id === fileId\r\n              ? {\r\n                  ...f,\r\n                  status: \"success\" as const,\r\n                  progress: 100,\r\n                  publicId: result.id,\r\n                  url: result.url,\r\n                  uploadedAt: result.createdAt,\r\n                }\r\n              : f\r\n          )\r\n        );\r\n\r\n        setUploadProgress((prev) => ({ ...prev, [fileId]: 100 }));\r\n\r\n        return result;\r\n      } catch (error) {\r\n        const errorMessage =\r\n          error instanceof Error ? error.message : \"Upload failed\";\r\n        setError(errorMessage);\r\n\r\n        // Update file with error status\r\n        setFiles((prev) =>\r\n          prev.map((f) =>\r\n            f.id === fileId\r\n              ? { ...f, status: \"error\" as const, error: errorMessage }\r\n              : f\r\n          )\r\n        );\r\n\r\n        throw error;\r\n      }\r\n    },\r\n    [files, provider, options]\r\n  );\r\n\r\n  /**\r\n   * Upload all pending files\r\n   */\r\n  const uploadAll = useCallback(\r\n    async (uploadOptions?: UploadOptions) => {\r\n      if (files.length === 0 || isUploading) return;\r\n\r\n      const pendingFiles = files.filter((f) => f.status === \"pending\");\r\n      if (pendingFiles.length === 0) return;\r\n\r\n      setIsUploading(true);\r\n      setError(null);\r\n\r\n      try {\r\n        const finalOptions = { ...options, ...uploadOptions };\r\n        const results = await provider.uploadFiles(\r\n          pendingFiles.map((f) => f.file),\r\n          finalOptions,\r\n          (fileId, progress) => {\r\n            setUploadProgress((prev) => ({ ...prev, [fileId]: progress }));\r\n          }\r\n        );\r\n\r\n        // Update all files with success status\r\n        setFiles((prev) =>\r\n          prev.map((f) => {\r\n            const result = results.find((r) => r.filename === f.name);\r\n            if (result && f.status === \"pending\") {\r\n              return {\r\n                ...f,\r\n                status: \"success\" as const,\r\n                progress: 100,\r\n                publicId: result.id,\r\n                url: result.url,\r\n                uploadedAt: result.createdAt,\r\n              };\r\n            }\r\n            return f;\r\n          })\r\n        );\r\n\r\n        return results;\r\n      } catch (error) {\r\n        const errorMessage =\r\n          error instanceof Error ? error.message : \"Upload failed\";\r\n        setError(errorMessage);\r\n\r\n        // Update uploading files with error status\r\n        setFiles((prev) =>\r\n          prev.map((f) =>\r\n            f.status === \"uploading\"\r\n              ? { ...f, status: \"error\" as const, error: errorMessage }\r\n              : f\r\n          )\r\n        );\r\n\r\n        throw error;\r\n      } finally {\r\n        setIsUploading(false);\r\n      }\r\n    },\r\n    [files, isUploading, provider, options]\r\n  );\r\n\r\n  /**\r\n   * Retry upload for a failed file\r\n   */\r\n  const retryUpload = useCallback(\r\n    async (fileId: string, uploadOptions?: UploadOptions) => {\r\n      const file = files.find((f) => f.id === fileId);\r\n      if (!file || file.status !== \"error\") return;\r\n\r\n      try {\r\n        setError(null);\r\n        const result = await uploadFile(fileId, uploadOptions);\r\n        return result;\r\n      } catch (error) {\r\n        // Error is already handled in uploadFile\r\n        throw error;\r\n      }\r\n    },\r\n    [files, uploadFile]\r\n  );\r\n\r\n  /**\r\n   * Cancel upload for a file\r\n   */\r\n  const cancelUpload = useCallback(\r\n    async (fileId: string) => {\r\n      const file = files.find((f) => f.id === fileId);\r\n      if (!file || file.status !== \"uploading\") return;\r\n\r\n      try {\r\n        // Update file status to cancelled\r\n        setFiles((prev) =>\r\n          prev.map((f) =>\r\n            f.id === fileId ? { ...f, status: \"cancelled\" as const } : f\r\n          )\r\n        );\r\n\r\n        setUploadProgress((prev) => {\r\n          const newProgress = { ...prev };\r\n          delete newProgress[fileId];\r\n          return newProgress;\r\n        });\r\n      } catch (error) {\r\n        console.warn(`Failed to cancel upload for ${fileId}:`, error);\r\n      }\r\n    },\r\n    [files]\r\n  );\r\n\r\n  /**\r\n   * Get upload statistics\r\n   */\r\n  const getStats = useCallback(async () => {\r\n    try {\r\n      return await provider.getStats();\r\n    } catch (error) {\r\n      console.warn(\"Failed to get upload stats:\", error);\r\n      return null;\r\n    }\r\n  }, [provider]);\r\n\r\n  /**\r\n   * Test provider connection\r\n   */\r\n  const testConnection = useCallback(async () => {\r\n    try {\r\n      return await provider.testConnection();\r\n    } catch (error) {\r\n      console.warn(\"Failed to test provider connection:\", error);\r\n      return false;\r\n    }\r\n  }, [provider]);\r\n\r\n  // Computed values\r\n  const pendingFiles = useMemo(\r\n    () => files.filter((f) => f.status === \"pending\"),\r\n    [files]\r\n  );\r\n  const uploadingFiles = useMemo(\r\n    () => files.filter((f) => f.status === \"uploading\"),\r\n    [files]\r\n  );\r\n  const successFiles = useMemo(\r\n    () => files.filter((f) => f.status === \"success\"),\r\n    [files]\r\n  );\r\n  const errorFiles = useMemo(\r\n    () => files.filter((f) => f.status === \"error\"),\r\n    [files]\r\n  );\r\n  const cancelledFiles = useMemo(\r\n    () => files.filter((f) => f.status === \"cancelled\"),\r\n    [files]\r\n  );\r\n\r\n  const totalSize = useMemo(\r\n    () => files.reduce((sum, f) => sum + f.size, 0),\r\n    [files]\r\n  );\r\n  const uploadedSize = useMemo(\r\n    () => successFiles.reduce((sum, f) => sum + f.size, 0),\r\n    [successFiles]\r\n  );\r\n\r\n  return {\r\n    // State\r\n    files,\r\n    isUploading,\r\n    error,\r\n    uploadProgress,\r\n\r\n    // Computed values\r\n    pendingFiles,\r\n    uploadingFiles,\r\n    successFiles,\r\n    errorFiles,\r\n    cancelledFiles,\r\n    totalSize,\r\n    uploadedSize,\r\n\r\n    // Actions\r\n    addFiles,\r\n    removeFile,\r\n    clearAll,\r\n    uploadFile,\r\n    uploadAll,\r\n    retryUpload,\r\n    cancelUpload,\r\n    getStats,\r\n    testConnection,\r\n\r\n    // Utilities\r\n    hasFiles: files.length > 0,\r\n    hasPendingFiles: pendingFiles.length > 0,\r\n    hasErrors: errorFiles.length > 0,\r\n    isFullyUploaded:\r\n      files.length > 0 && files.every((f) => f.status === \"success\"),\r\n  };\r\n}\r\n"]}