feat: add media upload progress bar (#479)

This commit is contained in:
Taxil Kathiriya 2025-08-12 02:42:57 +01:00 committed by GitHub
parent e78e2c2078
commit 9969ab2414
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 229 additions and 49 deletions

View file

@ -6,16 +6,25 @@ export default function Uploader({
children,
onUploadSuccess,
onUploadingChange,
onUploadStart,
onUploadEnd,
onProgress,
onProvideCancel,
className,
accept = 'image/*'
}: {
children: React.ReactNode
onUploadSuccess: ({ url, tags }: { url: string; tags: string[][] }) => void
onUploadingChange?: (uploading: boolean) => void
onUploadStart?: (file: File) => void
onUploadEnd?: () => void
onProgress?: (progress: number, file: File) => void
onProvideCancel?: (cancel: () => void) => void
className?: string
accept?: string
}) {
const fileInputRef = useRef<HTMLInputElement>(null)
const abortControllerRef = useRef<AbortController | null>(null)
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
if (!event.target.files) return
@ -23,15 +32,29 @@ export default function Uploader({
onUploadingChange?.(true)
try {
for (const file of event.target.files) {
const result = await mediaUpload.upload(file)
abortControllerRef.current = new AbortController()
const cancel = () => abortControllerRef.current?.abort()
onProvideCancel?.(cancel)
onUploadStart?.(file)
const result = await mediaUpload.upload(file, {
onProgress: (p) => onProgress?.(p, file),
signal: abortControllerRef.current.signal
})
onUploadSuccess(result)
abortControllerRef.current = null
onUploadEnd?.()
}
} catch (error) {
console.error('Error uploading file', error)
toast.error(`Failed to upload file: ${(error as Error).message}`)
const message = (error as Error).message
if (message !== 'Upload aborted') {
toast.error(`Failed to upload file: ${message}`)
}
if (fileInputRef.current) {
fileInputRef.current.value = ''
}
abortControllerRef.current = null
onUploadEnd?.()
} finally {
onUploadingChange?.(false)
}
@ -45,8 +68,8 @@ export default function Uploader({
}
return (
<div onClick={handleUploadClick} className={className}>
{children}
<div className={className}>
<div onClick={handleUploadClick}>{children}</div>
<input
type="file"
ref={fileInputRef}