webapp/src/components/Editor/UploadModalContent/UploadModalContent.tsx

140 lines
4.3 KiB
TypeScript
Raw Normal View History

2024-02-04 11:25:21 +00:00
import { UploadFile, createDropzone, createFileUploader } from '@solid-primitives/upload'
import { clsx } from 'clsx'
2024-02-04 11:25:21 +00:00
import { Show, createSignal } from 'solid-js'
import { Button } from '~/components/_shared/Button'
import { Icon } from '~/components/_shared/Icon'
import { Loading } from '~/components/_shared/Loading'
import { useLocalize } from '~/context/localize'
import { useSession } from '~/context/session'
2024-06-24 17:50:27 +00:00
import { useUI } from '~/context/ui'
2024-07-05 14:08:12 +00:00
import { handleImageUpload } from '~/lib/handleImageUpload'
2024-06-24 17:50:27 +00:00
import { UploadedFile } from '~/types/upload'
import { verifyImg } from '~/utils/verifyImg'
import { InlineForm } from '../InlineForm'
import styles from './UploadModalContent.module.scss'
type Props = {
onClose: (image?: UploadedFile) => void
}
export const UploadModalContent = (props: Props) => {
const { t } = useLocalize()
2024-06-24 17:50:27 +00:00
const { hideModal } = useUI()
const [isUploading, setIsUploading] = createSignal(false)
const [uploadError, setUploadError] = createSignal<string | undefined>()
const [dragActive, setDragActive] = createSignal(false)
const [dragError, setDragError] = createSignal<string | undefined>()
2024-05-06 11:07:19 +00:00
const { session } = useSession()
const { selectFiles } = createFileUploader({ multiple: false, accept: 'image/*' })
const runUpload = async (file: UploadFile) => {
try {
setIsUploading(true)
2024-06-24 17:50:27 +00:00
const result = await handleImageUpload(file, session()?.access_token || '')
props.onClose(result)
2023-05-11 11:43:14 +00:00
setIsUploading(false)
} catch (error) {
setIsUploading(false)
setUploadError(t('Error'))
2023-05-09 04:58:00 +00:00
console.error('[runUpload]', error)
}
}
const handleImageFormSubmit = async (value: string) => {
try {
const data = await fetch(value)
const blob = await data.blob()
2024-06-24 17:50:27 +00:00
const file = new File([blob], 'convertedFromUrl', {
2024-06-26 08:22:05 +00:00
type: data.headers.get('Content-Type') || undefined
2024-06-24 17:50:27 +00:00
})
const fileToUpload: UploadFile = {
source: blob.toString(),
name: file.name,
size: file.size,
2024-06-26 08:22:05 +00:00
file: file
}
await runUpload(fileToUpload)
} catch (error) {
console.error('[handleImageFormSubmit]', error)
}
}
2024-02-05 15:04:23 +00:00
const handleUpload = () => {
selectFiles(async ([uploadFile]) => {
await runUpload(uploadFile)
})
}
const { setRef: dropzoneRef, files: droppedFiles } = createDropzone({
onDrop: async () => {
setDragActive(false)
if (droppedFiles().length > 1) {
setDragError(t('Many files, choose only one'))
} else if (droppedFiles()[0].file.type.startsWith('image/')) {
await runUpload(droppedFiles()[0])
} else {
setDragError(t('Image format not supported'))
}
2024-06-26 08:22:05 +00:00
}
})
const handleDrag = (event: MouseEvent) => {
if (event.type === 'dragenter' || event.type === 'dragover') {
setDragActive(true)
} else if (event.type === 'dragleave') {
setDragActive(false)
}
}
const handleValidate = async (value: string) => {
const validationResult = await verifyImg(value)
if (!validationResult) {
return t('Invalid image URL')
}
return ''
}
return (
<div class={styles.uploadModalContent}>
<Show when={!isUploading()} fallback={<Loading />}>
<>
<div
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
ref={dropzoneRef}
class={clsx(styles.dropZone, { [styles.active]: dragActive() })}
>
<Icon class={styles.icon} name="editor-image-dd" />
<div class={clsx(styles.text, { [styles.error]: dragError() })}>
{dragError() ?? t('Drag the image to this area')}
</div>
</div>
<Button
value={t('Upload')}
variant="bordered"
onClick={handleUpload}
class={styles.uploadButton}
/>
<Show when={uploadError()}>
<div class={styles.error}>{uploadError()}</div>
</Show>
<div class={styles.formHolder}>
<InlineForm
placeholder={t('Or paste a link to an image')}
showInput={true}
onClose={() => {
hideModal()
2023-05-09 11:25:40 +00:00
props.onClose()
}}
validate={handleValidate}
onSubmit={handleImageFormSubmit}
/>
</div>
</>
</Show>
</div>
)
}