fix(ui): race condition with toast closing

Instead of providing a duration to the upload action, we close the toast imperatively in the `imageUploaded` listener using a timeout. 3s after the last upload toast, we close it.

This handles the case when we are uploading multiple images and don't want the toast to close til it's all finished.
This commit is contained in:
psychedelicious
2024-10-16 17:23:39 +10:00
parent 2b000cb006
commit f03b77e882
3 changed files with 18 additions and 21 deletions

View File

@@ -40,6 +40,8 @@ const getUploadedToastDescription = (boardId: string, state: RootState) => {
return t('toast.addedToBoard', { name: board?.board_name ?? boardId });
};
let lastUploadedToastTimeout: number | null = null;
export const addImageUploadedFulfilledListener = (startAppListening: AppStartListening) => {
startAppListening({
matcher: imagesApi.endpoints.uploadImage.matchFulfilled,
@@ -64,12 +66,18 @@ export const addImageUploadedFulfilledListener = (startAppListening: AppStartLis
// default action - just upload and alert user
if (postUploadAction.type === 'TOAST') {
const boardId = imageDTO.board_id ?? 'none';
toast({
if (lastUploadedToastTimeout !== null) {
window.clearTimeout(lastUploadedToastTimeout);
}
const toastApi = toast({
...DEFAULT_UPLOADED_TOAST,
title: postUploadAction.title || DEFAULT_UPLOADED_TOAST.title,
duration: postUploadAction.duration !== undefined ? postUploadAction.duration : undefined,
description: getUploadedToastDescription(boardId, state),
duration: null, // we will close the toast manually
});
lastUploadedToastTimeout = window.setTimeout(() => {
toastApi.close();
}, 3000);
/**
* We only want to change the board and view if this is the first upload of a batch, else we end up hijacking
* the user's gallery board and view selection:

View File

@@ -28,20 +28,13 @@ export const useFullscreenDropzone = () => {
const activeTabName = useAppSelector(selectActiveTab);
const maxImageUploadCount = useAppSelector(selectMaxImageUploadCount);
const getPostUploadAction = useCallback(
(isSingleImage: boolean, isLastImage: boolean): PostUploadAction => {
if (isSingleImage && activeTabName === 'upscaling') {
return { type: 'SET_UPSCALE_INITIAL_IMAGE' };
} else if (isSingleImage || isLastImage) {
// Omit the duration if it's the last image - this allows the toast to auto-close
return { type: 'TOAST' };
} else {
// Set duration to `null` to prevent auto-close on any toast that is not the last image
return { type: 'TOAST', duration: null };
}
},
[activeTabName]
);
const getPostUploadAction = useCallback((): PostUploadAction => {
if (activeTabName === 'upscaling') {
return { type: 'SET_UPSCALE_INITIAL_IMAGE' };
} else {
return { type: 'TOAST' };
}
}, [activeTabName]);
const onDrop = useCallback(
(acceptedFiles: Array<File>, fileRejections: Array<FileRejection>) => {
@@ -67,15 +60,12 @@ export const useFullscreenDropzone = () => {
return;
}
const isSingleImage = acceptedFiles.length === 1;
for (const [i, file] of acceptedFiles.entries()) {
const isLastImage = i === acceptedFiles.length - 1;
uploadImage({
file,
image_category: 'user',
is_intermediate: false,
postUploadAction: getPostUploadAction(isSingleImage, isLastImage),
postUploadAction: getPostUploadAction(),
board_id: autoAddBoardId === 'none' ? undefined : autoAddBoardId,
// The `imageUploaded` listener does some extra logic, like switching to the asset view on upload on the
// first upload of a "batch".

View File

@@ -222,7 +222,6 @@ type UpscaleInitialImageAction = {
type ToastAction = {
type: 'TOAST';
title?: string;
duration?: number | null;
};
type AddToBatchAction = {