2022-05-16 20:51:22 +00:00
|
|
|
import { useRef } from 'react'
|
2022-05-12 18:44:21 +00:00
|
|
|
import { gql, useMutation } from '@apollo/client'
|
|
|
|
import { UPLOAD_TYPES_ALLOW } from '../lib/constants'
|
|
|
|
|
2022-05-16 20:51:22 +00:00
|
|
|
export default function Upload ({ as: Component, onSelect, onStarted, onError, onSuccess }) {
|
2022-05-12 18:44:21 +00:00
|
|
|
const [getSignedPOST] = useMutation(
|
|
|
|
gql`
|
|
|
|
mutation getSignedPOST($type: String!, $size: Int!, $width: Int!, $height: Int!) {
|
|
|
|
getSignedPOST(type: $type, size: $size, width: $width, height: $height) {
|
|
|
|
url
|
|
|
|
fields
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
const ref = useRef()
|
|
|
|
|
2022-05-16 20:51:22 +00:00
|
|
|
const upload = file => {
|
|
|
|
onStarted && onStarted()
|
|
|
|
|
2023-07-25 14:14:45 +00:00
|
|
|
const img = new window.Image()
|
2022-05-16 20:51:22 +00:00
|
|
|
img.src = window.URL.createObjectURL(file)
|
|
|
|
img.onload = async () => {
|
|
|
|
let data
|
|
|
|
try {
|
|
|
|
({ data } = await getSignedPOST({
|
|
|
|
variables: {
|
|
|
|
type: file.type,
|
|
|
|
size: file.size,
|
|
|
|
width: img.width,
|
|
|
|
height: img.height
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
} catch (e) {
|
|
|
|
onError && onError(e.toString())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const form = new FormData()
|
|
|
|
Object.keys(data.getSignedPOST.fields).forEach(key =>
|
|
|
|
form.append(key, data.getSignedPOST.fields[key]))
|
|
|
|
form.append('Content-Type', file.type)
|
2022-05-18 16:59:59 +00:00
|
|
|
form.append('Cache-Control', 'max-age=31536000')
|
2022-05-16 20:51:22 +00:00
|
|
|
form.append('acl', 'public-read')
|
|
|
|
form.append('file', file)
|
|
|
|
|
|
|
|
const res = await fetch(data.getSignedPOST.url, {
|
|
|
|
method: 'POST',
|
|
|
|
body: form
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
onError && onError(res.statusText)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
onSuccess && onSuccess(data.getSignedPOST.fields.key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 18:44:21 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<input
|
|
|
|
ref={ref}
|
|
|
|
type='file'
|
|
|
|
className='d-none'
|
2022-05-16 20:51:22 +00:00
|
|
|
accept={UPLOAD_TYPES_ALLOW.join(', ')}
|
2022-05-12 18:44:21 +00:00
|
|
|
onChange={(e) => {
|
|
|
|
if (e.target.files.length === 0) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const file = e.target.files[0]
|
2022-05-16 20:51:22 +00:00
|
|
|
|
2022-05-12 18:44:21 +00:00
|
|
|
if (UPLOAD_TYPES_ALLOW.indexOf(file.type) === -1) {
|
|
|
|
onError && onError(`image must be ${UPLOAD_TYPES_ALLOW.map(t => t.replace('image/', '')).join(', ')}`)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-16 20:51:22 +00:00
|
|
|
if (onSelect) {
|
|
|
|
onSelect(file, upload)
|
|
|
|
} else {
|
|
|
|
upload(file)
|
2022-05-12 18:44:21 +00:00
|
|
|
}
|
|
|
|
|
2022-05-16 20:51:22 +00:00
|
|
|
e.target.value = null
|
2022-05-12 18:44:21 +00:00
|
|
|
}}
|
|
|
|
/>
|
2022-05-16 20:51:22 +00:00
|
|
|
<Component onClick={() => ref.current?.click()} />
|
2022-05-12 18:44:21 +00:00
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|