forked from ddrilling/asb_cloud_front
93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||
import { UploadFile } from 'antd/lib/upload/interface'
|
||
import { UploadOutlined } from '@ant-design/icons'
|
||
import { RcFile } from 'antd/lib/upload'
|
||
import { Upload, Button } from 'antd'
|
||
|
||
import { isDev } from '@utils'
|
||
|
||
import { notify, upload } from './factory'
|
||
import { ErrorFetch } from './ErrorFetch'
|
||
|
||
export type UploadFormProps = {
|
||
multiple?: boolean
|
||
url: string
|
||
disabled?: boolean
|
||
accept?: string
|
||
mimeTypes?: string | string[]
|
||
style?: CSSStyleSheet
|
||
formData: FormData
|
||
onUploadStart?: () => void
|
||
onUploadSuccess?: () => void
|
||
onUploadComplete?: () => void
|
||
onUploadError?: (error: unknown) => void
|
||
}
|
||
|
||
export const UploadForm = memo<UploadFormProps>(({ url, multiple, disabled, style, formData, mimeTypes, onUploadStart, onUploadSuccess, onUploadComplete, onUploadError }) => {
|
||
const [fileList, setfileList] = useState<UploadFile<any>[]>([])
|
||
|
||
const checkMimeTypes = useCallback((file: RcFile) => {
|
||
const isAccepted = !mimeTypes || mimeTypes.includes(file.type)
|
||
if (isAccepted) return false
|
||
notify(`"${file.name}" является файлом неподходящего типа`, 'error')
|
||
return Upload.LIST_IGNORE
|
||
}, [mimeTypes])
|
||
|
||
const accept = useMemo(() => Array.isArray(mimeTypes) ? mimeTypes.join(',') : mimeTypes, [mimeTypes])
|
||
|
||
const handleFileSend = useCallback(async () => {
|
||
onUploadStart?.()
|
||
try {
|
||
const formDataLocal = new FormData()
|
||
fileList.forEach((val) => formDataLocal.append(multiple ? 'files' : 'file', val.originFileObj as Blob))
|
||
|
||
if(formData)
|
||
for(const propName in formData)
|
||
formDataLocal.append(propName, String(formData.get(propName)))
|
||
|
||
const response = await upload(url, formDataLocal)
|
||
if (!response.ok) {
|
||
const errorText = await response.text()
|
||
const error = new ErrorFetch(response.status, errorText)
|
||
throw error
|
||
} else {
|
||
onUploadSuccess?.()
|
||
}
|
||
} catch(error) {
|
||
if(isDev())
|
||
console.error(error)
|
||
onUploadError?.(error)
|
||
} finally {
|
||
setfileList([])
|
||
onUploadComplete?.()
|
||
}
|
||
}, [fileList, formData, onUploadComplete, onUploadError, onUploadStart, onUploadSuccess, url, multiple])
|
||
|
||
const isSendButtonEnabled = fileList.length > 0
|
||
return(
|
||
<div style={{ display: 'flex', ...style }}>
|
||
<Upload
|
||
name={'file'}
|
||
accept={accept}
|
||
disabled={disabled}
|
||
fileList={fileList}
|
||
onChange={(props) => setfileList(props.fileList)}
|
||
beforeUpload={checkMimeTypes}
|
||
maxCount={multiple ? undefined : 1}
|
||
>
|
||
<Button disabled={disabled} icon={<UploadOutlined/>}>Загрузить файл</Button>
|
||
</Upload>
|
||
<Button
|
||
type={'primary'}
|
||
onClick={handleFileSend}
|
||
disabled={!isSendButtonEnabled}
|
||
style={{ marginLeft: '10px', display: isSendButtonEnabled ? '' : 'none' }}
|
||
>
|
||
Отправить
|
||
</Button>
|
||
</div>
|
||
)
|
||
})
|
||
|
||
export default UploadForm
|