import FormProvider from 'domains/forms/provider' import { useI18n } from 'domains/i18n/hooks' import { className } from 'lib/css' import { useCallback, useEffect, useMemo, useRef } from 'preact/hooks' import UploadProgress from 'ui/components/widgets/upload-progress' import { useSeamlyEntry } from 'ui/hooks/seamly-entry-hooks' import { useFileUploadMeta, useFileUploads, useGeneratedId, useLiveRegion, useSkiplinkTarget, useSkiplinkTargetFocusing, } from 'ui/hooks/seamly-hooks' import useSingleFileUpload from 'ui/hooks/use-single-file-upload' import { getValidator } from 'ui/utils/form-utils' import { formatBytes } from 'ui/utils/general-utils' import { fileListObjectIsNotEmpty, validateFileSize, } from 'ui/utils/validations' import FileInputForm from './file-upload-form' const formName = 'fileListForm' const fileInputName = 'fileList' const Upload = () => { const { t } = useI18n() const { sendPolite, sendAssertive } = useLiveRegion() const skiplinkTargetId = useSkiplinkTarget() const focusSkiplinkTarget = useSkiplinkTargetFocusing() // This hook should be refactored at some point const { serviceAllowsUploads, allowedMimeTypes, maxSize } = useFileUploadMeta() const cancelButtonRef = useRef(null) const canUpload = useRef(serviceAllowsUploads) const { cancelEntrySelection } = useSeamlyEntry() const { uploadFile, clearUploads, isUploading, isComplete } = useFileUploads() const hasError = false const { uploadHandle, hasServerError, progress } = useSingleFileUpload( formName, fileInputName, ) const notificationId = useGeneratedId() const prevIsComplete = useRef(true) const contentHintText = t('fileUpload.contentHint', { size: formatBytes(maxSize), }) const prevContentHintText = useRef('') const containerRef = useRef(null) useEffect(() => { if ( prevContentHintText.current && containerRef.current?.contains(document.activeElement) && document.activeElement?.tagName === 'INPUT' ) { sendAssertive(contentHintText) } prevContentHintText.current = contentHintText }, [contentHintText, sendAssertive]) // a11y useEffect(() => { if (progress > 0) { switch (progress) { case 1: sendPolite(t('fileUpload.srStartedText')) break default: sendPolite(`${progress}%`) } } }, [progress, sendPolite, t]) // reset form when uploads are complete useEffect(() => { if (!prevIsComplete.current && !isUploading && isComplete) { clearUploads() cancelEntrySelection() focusSkiplinkTarget() // This timeout is set as testing in VoiceOver revealed that 300 ms is needed for // the live region to resolve in this case. setTimeout(() => { sendPolite(t('fileUpload.srCompleteText')) }, 300) } prevIsComplete.current = isComplete }, [ isUploading, isComplete, clearUploads, cancelEntrySelection, focusSkiplinkTarget, sendPolite, t, ]) // Reset form when service no longer allows uploads useEffect(() => { // If we are currently uploading, don't clear the uploads as that // may be confusing to the user. // When the upload completes and the user clicks the submit button, // there will be an error. if (!serviceAllowsUploads && !isUploading) { clearUploads() cancelEntrySelection() focusSkiplinkTarget() } }, [ serviceAllowsUploads, isUploading, clearUploads, cancelEntrySelection, focusSkiplinkTarget, ]) const handleSubmit = useCallback( ({ fileList }) => { uploadFile(fileList[0]) if (!hasError) { focusSkiplinkTarget() } }, [uploadFile, hasError, focusSkiplinkTarget], ) const handleOnClickCancel = useCallback(() => { if (uploadHandle) { uploadHandle.abort() } clearUploads() cancelEntrySelection() focusSkiplinkTarget() }, [uploadHandle, clearUploads, cancelEntrySelection, focusSkiplinkTarget]) const validationSchema = useMemo( () => ({ [fileInputName]: [ // For now this is fine, but this shouldn't be a validation on the field itself getValidator( () => serviceAllowsUploads, t('fileUpload.errors.unavailable'), ), getValidator(fileListObjectIsNotEmpty, t('fileUpload.errors.noFile')), getValidator( validateFileSize, t('fileUpload.errors.tooLarge'), maxSize, ), ], }), [maxSize, serviceAllowsUploads, t], ) return (
{(isUploading || !isComplete) && ( <>
)} {!isUploading && isComplete && ( )} {!canUpload.current && ( <> {t('fileUpload.unavailableText')}
)}
) } export default Upload