f9a1fcc6a7
- The previous 2MB was a CDN limit (more of a mistake). That has been increased to a far greater number, so we're setting a more reasonable 5MB limit. - The previous code checks/shows the "size exceeded" message after the file has been uploaded ... in the `catch` block. This will not work since the CDN now allows a 5MB file. - Fixed by checking the size before actually uploading.
182 lines
5.4 KiB
JavaScript
182 lines
5.4 KiB
JavaScript
// @flow
|
|
import React from 'react';
|
|
import { THUMBNAIL_CDN_SIZE_LIMIT_BYTES } from 'config';
|
|
import FileSelector from 'component/common/file-selector';
|
|
import { IMG_CDN_PUBLISH_URL } from 'constants/cdn_urls';
|
|
import { FormField, Form } from 'component/common/form';
|
|
import Button from 'component/button';
|
|
import Card from 'component/common/card';
|
|
import usePersistedState from 'effects/use-persisted-state';
|
|
|
|
const accept = '.png, .jpg, .jpeg, .gif';
|
|
const STATUS = { READY: 'READY', UPLOADING: 'UPLOADING' };
|
|
|
|
type Props = {
|
|
assetName: string,
|
|
currentValue: ?string,
|
|
onUpdate: (string, boolean) => void,
|
|
recommended: string,
|
|
title: string,
|
|
onDone?: () => void,
|
|
inline?: boolean,
|
|
};
|
|
|
|
function SelectAsset(props: Props) {
|
|
const { onUpdate, onDone, assetName, currentValue, recommended, title, inline } = props;
|
|
const [pathSelected, setPathSelected] = React.useState('');
|
|
const [fileSelected, setFileSelected] = React.useState<any>(null);
|
|
const [uploadStatus, setUploadStatus] = React.useState(STATUS.READY);
|
|
const [useUrl, setUseUrl] = usePersistedState('thumbnail-upload:mode', false);
|
|
const [url, setUrl] = React.useState(currentValue);
|
|
const [uploadErrorMsg, setUploadErrorMsg] = React.useState();
|
|
|
|
React.useEffect(() => {
|
|
if (useUrl) {
|
|
setUploadErrorMsg('');
|
|
setFileSelected(null);
|
|
setPathSelected('');
|
|
}
|
|
}, [useUrl]);
|
|
|
|
function doUploadAsset() {
|
|
const uploadError = (error = '') => {
|
|
setUploadErrorMsg(error);
|
|
};
|
|
|
|
const onSuccess = (thumbnailUrl) => {
|
|
setUploadStatus(STATUS.READY);
|
|
onUpdate(thumbnailUrl, !useUrl);
|
|
|
|
if (onDone) {
|
|
onDone();
|
|
}
|
|
};
|
|
|
|
setUploadStatus(STATUS.UPLOADING);
|
|
|
|
const data = new FormData();
|
|
data.append('file-input', fileSelected);
|
|
data.append('upload', 'Upload');
|
|
|
|
return fetch(IMG_CDN_PUBLISH_URL, {
|
|
method: 'POST',
|
|
body: data,
|
|
})
|
|
.then((res) => res.text())
|
|
.then((text) => {
|
|
try {
|
|
return text.length ? JSON.parse(text) : {};
|
|
} catch {
|
|
throw new Error(text);
|
|
}
|
|
})
|
|
.then((json) => {
|
|
return json.type === 'success'
|
|
? onSuccess(`${json.message}`)
|
|
: uploadError(
|
|
json.message || __('There was an error in the upload. The format or extension might not be supported.')
|
|
);
|
|
})
|
|
.catch((err) => {
|
|
uploadError(err.message);
|
|
setUploadStatus(STATUS.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 === STATUS.UPLOADING) {
|
|
fileSelectorLabel = __('Uploading...');
|
|
} else {
|
|
// Include the same label/recommendation for both 'URL' and 'UPLOAD'.
|
|
fileSelectorLabel = `${label} ${fileSelected || pathSelected ? __(selectedLabel) : __(selectFileLabel)}`;
|
|
}
|
|
const formBody = (
|
|
<>
|
|
<fieldset-section>
|
|
{uploadErrorMsg && <div className="error__text">{uploadErrorMsg}</div>}
|
|
{useUrl ? (
|
|
<FormField
|
|
autoFocus
|
|
type={'text'}
|
|
name={'thumbnail'}
|
|
label={label}
|
|
placeholder={`https://example.com/image.png`}
|
|
value={url}
|
|
onChange={(e) => {
|
|
setUrl(e.target.value);
|
|
onUpdate(e.target.value, !useUrl);
|
|
}}
|
|
/>
|
|
) : (
|
|
<FileSelector
|
|
autoFocus
|
|
disabled={uploadStatus === STATUS.UPLOADING}
|
|
label={fileSelectorLabel}
|
|
name="assetSelector"
|
|
currentPath={pathSelected}
|
|
onFileChosen={(file) => {
|
|
if (file.name) {
|
|
setFileSelected(file);
|
|
// what why? why not target=WEB this?
|
|
// file.path is undefined in web but available in electron
|
|
setPathSelected(file.name || file.path);
|
|
setUploadErrorMsg('');
|
|
|
|
if (file.size >= THUMBNAIL_CDN_SIZE_LIMIT_BYTES) {
|
|
const maxSizeMB = THUMBNAIL_CDN_SIZE_LIMIT_BYTES / (1024 * 1024);
|
|
setUploadErrorMsg(
|
|
__('Thumbnail size over %max_size%MB, please edit and reupload.', { max_size: maxSizeMB })
|
|
);
|
|
}
|
|
}
|
|
}}
|
|
accept={accept}
|
|
/>
|
|
)}
|
|
</fieldset-section>
|
|
|
|
<div className="section__actions">
|
|
{onDone && (
|
|
<Button
|
|
button="primary"
|
|
type="submit"
|
|
label={useUrl ? __('Done') : __('Upload')}
|
|
disabled={
|
|
!useUrl && (uploadStatus === STATUS.UPLOADING || !pathSelected || !fileSelected || uploadErrorMsg)
|
|
}
|
|
onClick={() => {
|
|
if (!useUrl) {
|
|
doUploadAsset();
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
<FormField
|
|
name="toggle-upload"
|
|
type="checkbox"
|
|
label={__('Use a URL')}
|
|
checked={useUrl}
|
|
onChange={() => setUseUrl(!useUrl)}
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
if (inline) {
|
|
return <fieldset-section>{formBody}</fieldset-section>;
|
|
}
|
|
|
|
return (
|
|
<Card
|
|
title={title || __('Choose %asset%', { asset: __(`${assetName}`) })}
|
|
actions={<Form onSubmit={onDone}>{formBody}</Form>}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default SelectAsset;
|