// @flow import React from 'react'; import FileSelector from 'component/common/file-selector'; import * as SPEECH_URLS from 'constants/speech_urls'; import { FormField, Form } from 'component/common/form'; import Button from 'component/button'; import Card from 'component/common/card'; import { generateThumbnailName } from 'util/generate-thumbnail-name'; import usePersistedState from 'effects/use-persisted-state'; const accept = '.png, .jpg, .jpeg, .gif'; const SPEECH_READY = 'READY'; const SPEECH_UPLOADING = 'UPLOADING'; type Props = { assetName: string, currentValue: ?string, onUpdate: (string, boolean, ?string) => void, recommended: string, title: string, onDone?: () => void, inline?: boolean, // When uploading pictures, the upload service // can return success but the image isn't ready // to be displayed yet. This is when a local preview // comes in handy. The preview (base 64) will be // passed to the onUpdate function after the // upload service returns success. buildImagePreview?: boolean, // File extension filtering. Files can be filtered // but the "All Files" options always shows up. To // avoid that, you can use the filters property. // For example, to only accept images pass the // following filter: // { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, filters?: Array<{ name: string, extension: string[] }>, type?: string, }; function filePreview(file) { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = () => { resolve(reader.result.toString()); }; reader.onerror = () => { resolve(undefined); }; reader.readAsDataURL(file); }); } function SelectAsset(props: Props) { const { onUpdate, onDone, assetName, currentValue, recommended, title, inline, buildImagePreview, filters, type } = props; const [pathSelected, setPathSelected] = React.useState(''); const [fileSelected, setFileSelected] = React.useState(null); const [uploadStatus, setUploadStatus] = React.useState(SPEECH_READY); const [useUrl, setUseUrl] = usePersistedState('thumbnail-upload:mode', false); const [url, setUrl] = React.useState(currentValue); const [error, setError] = React.useState(); function doUploadAsset() { const uploadError = (error = '') => { setError(error); }; const onSuccess = async (thumbnailUrl) => { let preview; setUploadStatus(SPEECH_READY); if (buildImagePreview) { preview = await filePreview(fileSelected); } onUpdate(thumbnailUrl, !useUrl, preview); if (onDone) { onDone(); } }; setUploadStatus(SPEECH_UPLOADING); const data = new FormData(); const name = generateThumbnailName(); data.append('name', name); data.append('file', fileSelected); return fetch(SPEECH_URLS.SPEECH_PUBLISH, { method: 'POST', body: data, }) .then((response) => response.json()) .then((json) => (json.success ? onSuccess(`${json.data.serveUrl}`) : uploadError(json.message))) .catch((err) => { uploadError(err.message); setUploadStatus(SPEECH_READY); }); } // Note for translators: e.g. "Thumbnail (1:1)" const label = `${__(assetName)} ${__(recommended)}`; const selectFileLabel = __('Select File'); const selectedLabel = pathSelected ? __('URL Selected') : __('File Selected'); let fileSelectorLabel; if (uploadStatus === SPEECH_UPLOADING) { fileSelectorLabel = __('Uploading...'); } else { // Include the same label/recommendation for both 'URL' and 'UPLOAD'. fileSelectorLabel = `${label} ${fileSelected || pathSelected ? __(selectedLabel) : __(selectFileLabel)}`; } const formBody = ( <> {error &&
{error}
} {useUrl ? ( { setUrl(e.target.value); onUpdate(e.target.value, !useUrl); }} /> ) : ( { if (fileWithPath.file.name) { setFileSelected(fileWithPath.file); setPathSelected(fileWithPath.path); } }} accept={accept} /> )}
{onDone && (
); if (inline) { return {formBody}; } return ( {formBody}} /> ); } export default SelectAsset;