mirror of
https://github.com/penxio/penx.git
synced 2026-01-12 23:18:09 -05:00
134 lines
3.4 KiB
TypeScript
134 lines
3.4 KiB
TypeScript
import * as React from 'react'
|
|
import { generateReactHelpers } from '@uploadthing/react'
|
|
import { toast } from 'sonner'
|
|
import type {
|
|
ClientUploadedFileData,
|
|
UploadFilesOptions,
|
|
} from 'uploadthing/types'
|
|
import { z } from 'zod'
|
|
import { uploadFile } from '@penx/services/uploadFile'
|
|
import type { OurFileRouter } from '../app/api/uploadthing/route'
|
|
import { getUrl } from './utils'
|
|
|
|
export interface UploadedFile<T = unknown> extends ClientUploadedFileData<T> {}
|
|
|
|
interface UseUploadFileProps
|
|
extends Pick<
|
|
UploadFilesOptions<OurFileRouter, keyof OurFileRouter>,
|
|
'headers' | 'onUploadBegin' | 'onUploadProgress' | 'skipPolling'
|
|
> {
|
|
onUploadComplete?: (file: UploadedFile) => void
|
|
onUploadError?: (error: unknown) => void
|
|
}
|
|
|
|
export function useUploadFile({
|
|
onUploadComplete,
|
|
onUploadError,
|
|
...props
|
|
}: UseUploadFileProps = {}) {
|
|
const [uploadedFile, setUploadedFile] = React.useState<UploadedFile>()
|
|
const [uploadingFile, setUploadingFile] = React.useState<File>()
|
|
const [progress, setProgress] = React.useState<number>(0)
|
|
const [isUploading, setIsUploading] = React.useState(false)
|
|
|
|
async function uploadThing(file: File) {
|
|
setIsUploading(true)
|
|
setUploadingFile(file)
|
|
|
|
try {
|
|
const data = await uploadFile(file)
|
|
|
|
const uploadedFile = {
|
|
key: data.hash,
|
|
appUrl: getUrl(data.url),
|
|
name: file.name,
|
|
size: file.size,
|
|
type: file.type,
|
|
// url: URL.createObjectURL(file),
|
|
url: getUrl(data.url),
|
|
} as UploadedFile
|
|
|
|
setUploadedFile(uploadedFile)
|
|
onUploadComplete?.(uploadedFile)
|
|
|
|
return uploadedFile
|
|
} catch (error) {
|
|
const errorMessage = getErrorMessage(error)
|
|
|
|
const message =
|
|
errorMessage.length > 0
|
|
? errorMessage
|
|
: 'Something went wrong, please try again later.'
|
|
|
|
toast.error(message)
|
|
|
|
onUploadError?.(error)
|
|
|
|
// Mock upload for unauthenticated users
|
|
// toast.info('User not logged in. Mocking upload process.');
|
|
const mockUploadedFile = {
|
|
key: 'mock-key-0',
|
|
appUrl: `https://mock-app-url.com/${file.name}`,
|
|
name: file.name,
|
|
size: file.size,
|
|
type: file.type,
|
|
url: URL.createObjectURL(file),
|
|
} as UploadedFile
|
|
|
|
// Simulate upload progress
|
|
let progress = 0
|
|
|
|
const simulateProgress = async () => {
|
|
while (progress < 100) {
|
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
progress += 2
|
|
setProgress(Math.min(progress, 100))
|
|
}
|
|
}
|
|
|
|
await simulateProgress()
|
|
|
|
setUploadedFile(mockUploadedFile)
|
|
|
|
return mockUploadedFile
|
|
} finally {
|
|
setProgress(0)
|
|
setIsUploading(false)
|
|
setUploadingFile(undefined)
|
|
}
|
|
}
|
|
|
|
return {
|
|
isUploading,
|
|
progress,
|
|
uploadedFile,
|
|
uploadFile: uploadThing,
|
|
uploadingFile,
|
|
}
|
|
}
|
|
|
|
export const { uploadFiles, useUploadThing } =
|
|
generateReactHelpers<OurFileRouter>()
|
|
|
|
export function getErrorMessage(err: unknown) {
|
|
const unknownError = 'Something went wrong, please try again later.'
|
|
|
|
if (err instanceof z.ZodError) {
|
|
const errors = err.issues.map((issue) => {
|
|
return issue.message
|
|
})
|
|
|
|
return errors.join('\n')
|
|
} else if (err instanceof Error) {
|
|
return err.message
|
|
} else {
|
|
return unknownError
|
|
}
|
|
}
|
|
|
|
export function showErrorToast(err: unknown) {
|
|
const errorMessage = getErrorMessage(err)
|
|
|
|
return toast.error(errorMessage)
|
|
}
|