{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "uploadthing",
  "dependencies": [
    "uploadthing@7.7.4",
    "@uploadthing/react@7.3.3",
    "sonner",
    "zod"
  ],
  "files": [
    {
      "path": "src/registry/hooks/use-upload-file.ts",
      "content": "import * as React from 'react';\n\nimport type { OurFileRouter } from '@/registry/lib/uploadthing';\nimport type {\n  ClientUploadedFileData,\n  UploadFilesOptions,\n} from 'uploadthing/types';\n\nimport { generateReactHelpers } from '@uploadthing/react';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\n\nexport type UploadedFile<T = unknown> = ClientUploadedFileData<T>;\n\ninterface UseUploadFileProps\n  extends Pick<\n    UploadFilesOptions<OurFileRouter['editorUploader']>,\n    'headers' | 'onUploadBegin' | 'onUploadProgress' | 'skipPolling'\n  > {\n  onUploadComplete?: (file: UploadedFile) => void;\n  onUploadError?: (error: unknown) => void;\n}\n\nexport function useUploadFile({\n  onUploadComplete,\n  onUploadError,\n  ...props\n}: UseUploadFileProps = {}) {\n  const [uploadedFile, setUploadedFile] = React.useState<UploadedFile>();\n  const [uploadingFile, setUploadingFile] = React.useState<File>();\n  const [progress, setProgress] = React.useState<number>(0);\n  const [isUploading, setIsUploading] = React.useState(false);\n\n  async function uploadThing(file: File) {\n    setIsUploading(true);\n    setUploadingFile(file);\n\n    try {\n      const res = await uploadFiles('editorUploader', {\n        ...props,\n        files: [file],\n        onUploadProgress: ({ progress }) => {\n          setProgress(Math.min(progress, 100));\n        },\n      });\n\n      setUploadedFile(res[0]);\n\n      onUploadComplete?.(res[0]);\n\n      return uploadedFile;\n    } catch (error) {\n      const errorMessage = getErrorMessage(error);\n\n      const message =\n        errorMessage.length > 0\n          ? errorMessage\n          : 'Something went wrong, please try again later.';\n\n      toast.error(message);\n\n      onUploadError?.(error);\n\n      // Mock upload for unauthenticated users\n      // toast.info('User not logged in. Mocking upload process.');\n      const mockUploadedFile = {\n        key: 'mock-key-0',\n        appUrl: `https://mock-app-url.com/${file.name}`,\n        name: file.name,\n        size: file.size,\n        type: file.type,\n        url: URL.createObjectURL(file),\n      } as UploadedFile;\n\n      // Simulate upload progress\n      let progress = 0;\n\n      const simulateProgress = async () => {\n        while (progress < 100) {\n          await new Promise((resolve) => setTimeout(resolve, 50));\n          progress += 2;\n          setProgress(Math.min(progress, 100));\n        }\n      };\n\n      await simulateProgress();\n\n      setUploadedFile(mockUploadedFile);\n\n      return mockUploadedFile;\n    } finally {\n      setProgress(0);\n      setIsUploading(false);\n      setUploadingFile(undefined);\n    }\n  }\n\n  return {\n    isUploading,\n    progress,\n    uploadedFile,\n    uploadFile: uploadThing,\n    uploadingFile,\n  };\n}\n\nexport const { uploadFiles, useUploadThing } =\n  generateReactHelpers<OurFileRouter>();\n\nexport function getErrorMessage(err: unknown) {\n  const unknownError = 'Something went wrong, please try again later.';\n\n  if (err instanceof z.ZodError) {\n    const errors = err.issues.map((issue) => issue.message);\n\n    return errors.join('\\n');\n  }\n  if (err instanceof Error) {\n    return err.message;\n  }\n  return unknownError;\n}\n\nexport function showErrorToast(err: unknown) {\n  const errorMessage = getErrorMessage(err);\n\n  return toast.error(errorMessage);\n}\n",
      "type": "registry:hook"
    },
    {
      "path": "src/registry/lib/uploadthing.ts",
      "content": "import type { FileRouter } from 'uploadthing/next';\n\nimport { createUploadthing } from 'uploadthing/next';\n\nconst f = createUploadthing();\n\nexport const ourFileRouter = {\n  editorUploader: f(['image', 'text', 'blob', 'pdf', 'video', 'audio'])\n    .middleware(() => ({}))\n    .onUploadComplete(({ file }) => ({\n      key: file.key,\n      name: file.name,\n      size: file.size,\n      type: file.type,\n      url: file.ufsUrl,\n    })),\n} satisfies FileRouter;\n\nexport type OurFileRouter = typeof ourFileRouter;\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:hook"
}