Skip to content

Commit

Permalink
TASK: adjust handling of selected, uploaded and rejected files in upl…
Browse files Browse the repository at this point in the history
…oad dialogs, improve UX
  • Loading branch information
andrehoffmann30 committed Jun 6, 2023
1 parent 277cc45 commit c98fbd6
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from '@neos-project/react-ui-components';
import { createUseMediaUiStyles, MediaUiTheme, useIntl, useNotify } from '@media-ui/core/src';
import { useUploadDialogState, useUploadFiles } from '@media-ui/feature-asset-upload/src/hooks';
import { useCallback } from 'react';
import { UploadedFile } from '@media-ui/feature-asset-upload/src/interfaces';
import { FilesUploadState, UploadedFile } from '@media-ui/feature-asset-upload/src/interfaces';
import { PreviewSection, UploadSection } from '@media-ui/feature-asset-upload/src/components';

const useStyles = createUseMediaUiStyles((theme: MediaUiTheme) => ({
Expand All @@ -30,32 +30,71 @@ const NewAssetUpload = (props: { onComplete: (result: { object: { __identity: st
const handleUpload = useCallback(() => {
uploadFiles(dialogState.files.selected)
.then(({ data: { uploadFiles } }) => {
setFiles((prev) => {
return {
selected: [],
finished: [
...prev.finished,
...prev.selected.filter((file) =>
uploadFiles.find((result) => {
return result.success && result.filename === file.name
? (file.uploadStateResult = result.result)
: false;
})
),
],
rejected: [
...prev.rejected,
...prev.selected.filter((file) =>
uploadFiles.find((result) => {
return !result.success && result.filename === file.name
? (file.uploadStateResult = result.result)
: false;
})
),
],
} as FilesUploadState;
});
if (!uploadFiles[0].success) {
Notify.warning(
translate('uploadDialog.uploadFinishedWithErrors', 'Some files could not be uploaded'),
translate('uploadDialog.uploadFinishedWithErrors', 'Some files could not be uploaded')
);
} else {
Notify.ok(translate('uploadDialog.uploadFinished', 'Upload finished'));
onComplete({ object: { __identity: uploadFiles[0].assetId } });
}
setUploadPossible(false);
})
.catch((error) => {
Notify.error(translate('fileUpload.error', 'Upload failed'), error);
});
}, [uploadFiles, dialogState.files.selected, Notify, translate, onComplete]);
}, [uploadFiles, dialogState.files.selected, setFiles, setUploadPossible, Notify, translate, onComplete]);

const handleSetFiles = useCallback(
(files: UploadedFile[]) => {
setFiles((prev) => {
return { ...prev, selected: files };
const fileNames = new Set();
for (const file of prev.finished.concat(prev.rejected)) {
fileNames.add(file.name);
}
const newSelectedFiles = files.filter((file) => {
return fileNames.has(file.name) ? false : fileNames.add(file.name);
});
return { ...prev, selected: newSelectedFiles };
});
},
[setFiles]
);

return (
<section className={classes.uploadArea}>
<UploadSection files={dialogState.files.selected} loading={loading} onSetFiles={handleSetFiles} />
<UploadSection
files={dialogState.files.selected}
loading={loading}
onSetFiles={handleSetFiles}
maxFiles={1}
/>
<PreviewSection
files={dialogState.files}
loading={loading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const NewAssetDialog: React.FC = () => {
const classes = useStyles();

const handleUpload = useCallback(() => {
uploadFiles(dialogState.files.selected)
const filesToUpload = dialogState.files.selected.filter((file) => !dialogState.files.finished.includes(file));
uploadFiles(filesToUpload)
.then(({ data: { uploadFiles } }) => {
// FIXME: Mapping the uploadState to the files name is not the best solution as the same filename might be used multiple times
// Move uploaded or failed files into separate lists
Expand All @@ -37,13 +38,21 @@ const NewAssetDialog: React.FC = () => {
finished: [
...prev.finished,
...prev.selected.filter((file) =>
uploadFiles.find((result) => result.success && result.filename === file.name)
uploadFiles.find((result) => {
return result.success && result.filename === file.name
? (file.uploadStateResult = result.result)
: false;
})
),
],
rejected: [
...prev.rejected,
...prev.selected.filter((file) =>
uploadFiles.find((result) => !result.success && result.filename === file.name)
uploadFiles.find((result) => {
return !result.success && result.filename === file.name
? (file.uploadStateResult = result.result)
: false;
})
),
],
} as FilesUploadState;
Expand All @@ -60,16 +69,33 @@ const NewAssetDialog: React.FC = () => {
if (uploadFiles.some((result) => result.success)) {
void refetchAssets();
}
setUploadPossible(false);
})
.catch((error) => {
Notify.error(translate('fileUpload.error', 'Upload failed'), error);
});
}, [uploadFiles, dialogState.files.selected, setFiles, Notify, translate, refetchAssets]);
}, [
setUploadPossible,
dialogState.files.selected,
dialogState.files.finished,
uploadFiles,
setFiles,
Notify,
translate,
refetchAssets,
]);

const handleSetFiles = useCallback(
(files: UploadedFile[]) => {
setFiles((prev) => {
return { ...prev, selected: files };
const fileNames = new Set();
for (const file of prev.finished.concat(prev.rejected)) {
fileNames.add(file.name);
}
const newSelectedFiles = files.filter((file) => {
return fileNames.has(file.name) ? false : fileNames.add(file.name);
});
return { ...prev, selected: newSelectedFiles };
});
},
[setFiles]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,13 @@ const FilePreview: React.FC<FilePreviewProps> = ({
setUploadPossible,
}: FilePreviewProps) => {
const classes = useStyles();
const success = fileState?.success;
const error = fileState && !success;
const success = fileState?.success || dialogState.files.finished.includes(file);
const disabled = success || fileState?.result === 'EXISTS' || dialogState.files.rejected.includes(file);
const error = (fileState && !success) || dialogState.files.rejected.includes(file);
const result =
fileState?.result ||
dialogState.files.rejected[dialogState.files.rejected.indexOf(file)]?.uploadStateResult ||
dialogState.files.finished[dialogState.files.finished.indexOf(file)]?.uploadStateResult;
const { translate } = useIntl();
const { config } = useConfigQuery();
const [copyrightNoticeNotNeededChecked, setCopyrightNoticeNotNeededChecked] = useState(false);
Expand All @@ -153,7 +158,10 @@ const FilePreview: React.FC<FilePreviewProps> = ({

const setUploadProperty = (propertyName: string, propertyValue: UploadProperty) => {
const files: UploadedFile[] = [...dialogState.files.selected];
if (files.length === 0) {
const newFile =
files.length === 0 &&
!(dialogState.files.finished.includes(file) || dialogState.files.rejected.includes(file));
if (newFile) {
file[propertyName] = propertyValue;
files.push(file);
} else {
Expand Down Expand Up @@ -234,15 +242,15 @@ const FilePreview: React.FC<FilePreviewProps> = ({
{loading && <Icon icon="spinner" spin={true} />}
{success && <Icon icon="check" />}
{error && <Icon icon="exclamation-circle" />}
{fileState?.result && <span>{fileState.result}</span>}
{result && <span>{result}</span>}
</div>
</div>
<div className={classes.properties}>
{uploadPropertiesConfig['title'].show ? (
<Property label={translate('inspector.title', 'Title')}>
<TextInput
className={classes.textInput}
disabled={false}
disabled={disabled}
value={file.title || ''}
onChange={setTitle}
/>
Expand All @@ -254,7 +262,7 @@ const FilePreview: React.FC<FilePreviewProps> = ({
<Property label={translate('inspector.caption', 'Caption')}>
<TextArea
className={classes.textArea}
disabled={false}
disabled={disabled}
minRows={2}
expandedRows={4}
value={file.caption || ''}
Expand All @@ -269,7 +277,7 @@ const FilePreview: React.FC<FilePreviewProps> = ({
<Property label={translate('inspector.copyrightNotice', 'Copyright notice')}>
<TextArea
className={classes.textArea}
disabled={false}
disabled={disabled}
minRows={2}
expandedRows={4}
value={file.copyrightNotice || ''}
Expand All @@ -285,7 +293,7 @@ const FilePreview: React.FC<FilePreviewProps> = ({
>
<CheckBox
onChange={setCopyrightNoticeNotNeeded}
disabled={false}
disabled={disabled}
isChecked={copyrightNoticeNotNeededChecked}
/>
</Property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export default interface UploadedFile extends File {
copyrightNoticeNotNeeded?: boolean;
title?: string;
caption?: string;
uploadStateResult?: string;
}
4 changes: 2 additions & 2 deletions Resources/Public/AssetEditor/Plugin.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Resources/Public/AssetEditor/Plugin.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit c98fbd6

Please sign in to comment.