chore(web): replace window.confirm by ConfirmDialogues and cleanup existing ones (#3039)

* chore(web): replace window.confirm by ConfirmDialogues and cleanup existing ones

* fix(web): linter and svelte-check issues

* fix(web): rephrase some confirm dialogs

* fix(web): run prettier

* fix(web): merge with last version and run prettier again

* fix(web): run prettier
This commit is contained in:
Ethan Margaillan
2023-06-30 21:53:16 +02:00
committed by GitHub
parent 734f8e02b5
commit 5869648f19
14 changed files with 313 additions and 228 deletions

View File

@@ -14,6 +14,12 @@
import { onMount } from 'svelte';
import { flip } from 'svelte/animate';
import Dropdown from '$lib/components/elements/dropdown.svelte';
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
import {
notificationController,
NotificationType
} from '$lib/components/shared-components/notification/notification';
import type { AlbumResponseDto } from '@api';
export let data: PageData;
@@ -23,14 +29,36 @@
albums: unsortedAlbums,
isShowContextMenu,
contextMenuPosition,
contextMenuTargetAlbum,
createAlbum,
deleteAlbum,
deleteSelectedContextAlbum,
showAlbumContextMenu,
closeAlbumContextMenu
} = useAlbums({ albums: data.albums });
let albums = unsortedAlbums;
let albumToDelete: AlbumResponseDto | null;
const setAlbumToDelete = () => {
albumToDelete = $contextMenuTargetAlbum ?? null;
closeAlbumContextMenu();
};
const deleteSelectedAlbum = async () => {
if (!albumToDelete) {
return;
}
try {
await deleteAlbum(albumToDelete);
} catch {
notificationController.show({
message: 'Error deleting album',
type: NotificationType.Error
});
} finally {
albumToDelete = null;
}
};
const sortByDate = (a: string, b: string) => {
const aDate = new Date(a);
@@ -69,7 +97,6 @@
for (const album of $albums) {
if (album.assetCount == 0 && album.albumName == 'Untitled') {
await deleteAlbum(album);
$albums = $albums.filter((a) => a.id !== album.id);
}
}
} catch (error) {
@@ -120,7 +147,7 @@
<!-- Context Menu -->
{#if $isShowContextMenu}
<ContextMenu {...$contextMenuPosition} on:outclick={closeAlbumContextMenu}>
<MenuOption on:click={deleteSelectedContextAlbum}>
<MenuOption on:click={() => setAlbumToDelete()}>
<span class="flex place-items-center place-content-center gap-2">
<DeleteOutline size="18" />
<p>Delete album</p>
@@ -128,3 +155,17 @@
</MenuOption>
</ContextMenu>
{/if}
{#if albumToDelete}
<ConfirmDialogue
title="Delete Album"
confirmText="Delete"
on:confirm={deleteSelectedAlbum}
on:cancel={() => (albumToDelete = null)}
>
<svelte:fragment slot="prompt">
<p>Are you sure you want to delete the album <b>{albumToDelete.albumName}</b>?</p>
<p>If this album is shared, other users will not be able to access it anymore.</p>
</svelte:fragment>
</ConfirmDialogue>
{/if}

View File

@@ -12,10 +12,6 @@ jest.mock('@api');
const apiMock: jest.MockedObject<typeof api> = api as jest.MockedObject<typeof api>;
function mockWindowConfirm(result: boolean) {
jest.spyOn(global, 'confirm').mockReturnValueOnce(result);
}
describe('Albums BLoC', () => {
let sut: ReturnType<typeof useAlbums>;
const _albums = albumFactory.buildList(5);
@@ -115,8 +111,6 @@ describe('Albums BLoC', () => {
statusText: ''
});
mockWindowConfirm(true);
const albumToDelete = get(sut.albums)[2]; // delete third album
const albumToDeleteId = albumToDelete.id;
const contextMenuCoords = { x: 100, y: 150 };
@@ -125,52 +119,15 @@ describe('Albums BLoC', () => {
sut.showAlbumContextMenu(contextMenuCoords, albumToDelete);
expect(get(sut.contextMenuPosition)).toEqual(contextMenuCoords);
expect(get(sut.isShowContextMenu)).toBe(true);
expect(get(sut.contextMenuTargetAlbum)).toEqual(albumToDelete);
await sut.deleteSelectedContextAlbum();
await sut.deleteAlbum(albumToDelete);
const updatedAlbums = get(sut.albums);
expect(apiMock.albumApi.deleteAlbum).toHaveBeenCalledTimes(1);
expect(apiMock.albumApi.deleteAlbum).toHaveBeenCalledWith({ id: albumToDeleteId });
expect(updatedAlbums).toHaveLength(4);
expect(updatedAlbums).not.toContain(albumToDelete);
expect(get(sut.isShowContextMenu)).toBe(false);
});
it('shows error message when it fails deleting an album', async () => {
mockWindowConfirm(true);
const albumToDelete = get(sut.albums)[2]; // delete third album
const contextMenuCoords = { x: 100, y: 150 };
apiMock.albumApi.deleteAlbum.mockRejectedValueOnce({});
sut.showAlbumContextMenu(contextMenuCoords, albumToDelete);
const newAlbum = await sut.deleteSelectedContextAlbum();
const notifications = get(notificationController.notificationList);
expect(apiMock.albumApi.deleteAlbum).toHaveBeenCalledTimes(1);
expect(newAlbum).not.toBeDefined();
expect(notifications).toHaveLength(1);
expect(notifications[0].type).toEqual(NotificationType.Error);
});
it('prevents deleting an album when rejecting confirm dialog', async () => {
const albumToDelete = get(sut.albums)[2]; // delete third album
mockWindowConfirm(false);
sut.showAlbumContextMenu({ x: 100, y: 150 }, albumToDelete);
await sut.deleteSelectedContextAlbum();
expect(apiMock.albumApi.deleteAlbum).not.toHaveBeenCalled();
});
it('prevents deleting an album when not previously selected', async () => {
mockWindowConfirm(true);
await sut.deleteSelectedContextAlbum();
expect(apiMock.albumApi.deleteAlbum).not.toHaveBeenCalled();
});
it('closes album context menu, deselecting album', () => {

View File

@@ -24,8 +24,6 @@ export const useAlbums = (props: AlbumsProps) => {
if (album.albumName === 'Untitled' && album.assetCount === 0) {
setTimeout(async () => {
await deleteAlbum(album);
const _albums = get(albums);
albums.set(_albums.filter((a) => a.id !== album.id));
}, 500);
}
}
@@ -54,8 +52,13 @@ export const useAlbums = (props: AlbumsProps) => {
}
}
async function deleteAlbum(album: AlbumResponseDto): Promise<void> {
await api.albumApi.deleteAlbum({ id: album.id });
async function deleteAlbum(albumToDelete: AlbumResponseDto): Promise<void> {
await api.albumApi.deleteAlbum({ id: albumToDelete.id });
albums.set(
get(albums).filter(({ id }) => {
return id !== albumToDelete.id;
})
);
}
async function showAlbumContextMenu(
@@ -74,40 +77,15 @@ export const useAlbums = (props: AlbumsProps) => {
contextMenuTargetAlbum.set(undefined);
}
async function deleteSelectedContextAlbum(): Promise<void> {
const albumToDelete = get(contextMenuTargetAlbum);
if (!albumToDelete) {
return;
}
if (
window.confirm(
`Are you sure you want to delete album ${albumToDelete.albumName}? If the album is shared, other users will not be able to access it.`
)
) {
try {
await api.albumApi.deleteAlbum({ id: albumToDelete.id });
const _albums = get(albums);
albums.set(_albums.filter((a) => a.id !== albumToDelete.id));
} catch {
notificationController.show({
message: 'Error deleting album',
type: NotificationType.Error
});
}
}
closeAlbumContextMenu();
}
return {
albums,
isShowContextMenu,
contextMenuPosition,
contextMenuTargetAlbum,
loadAlbums,
createAlbum,
deleteAlbum,
showAlbumContextMenu,
closeAlbumContextMenu,
deleteSelectedContextAlbum
closeAlbumContextMenu
};
};

View File

@@ -98,7 +98,7 @@
{#if deleteLinkId}
<ConfirmDialogue
title="Delete Shared Link"
prompt="Are you want to delete this shared link?"
prompt="Are you sure you want to delete this shared link?"
confirmText="Delete"
on:confirm={() => handleDeleteLink()}
on:cancel={() => (deleteLinkId = null)}