stacker.news/components/upload.js

91 lines
2.3 KiB
JavaScript
Raw Normal View History

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
</>
)
}