diff --git a/web/src/lib/components/admin-page/delete-confirm-dialoge.svelte b/web/src/lib/components/admin-page/delete-confirm-dialoge.svelte
index 5b1298c26..8f687f3b6 100644
--- a/web/src/lib/components/admin-page/delete-confirm-dialoge.svelte
+++ b/web/src/lib/components/admin-page/delete-confirm-dialoge.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
 	import { api, UserResponseDto } from '@api';
 	import { createEventDispatcher } from 'svelte';
-	import Button from '../elements/buttons/button.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 	import { handleError } from '../../utils/handle-error';
 
 	export let user: UserResponseDto;
@@ -23,25 +23,14 @@
 	};
 </script>
 
-<div
-	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] max-w-[95vw] rounded-3xl py-8 dark:text-immich-dark-fg"
->
-	<div
-		class="flex flex-col place-items-center place-content-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
-	>
-		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
-			Confirm User Deletion
-		</h1>
-	</div>
-	<div>
-		<p class="ml-4 text-md py-5 text-center">
-			{user.firstName}
-			{user.lastName} account and assets along will be marked to delete completely after 7 days. are
-			you sure you want to proceed ?
-		</p>
-
-		<div class="flex w-full px-4 gap-4 mt-8">
-			<Button fullwidth color="red" on:click={deleteUser}>Confirm</Button>
+<ConfirmDialogue title="Delete User" confirmText="Delete" on:confirm={deleteUser} on:cancel>
+	<svelte:fragment slot="prompt">
+		<div class="flex flex-col gap-4">
+			<p>
+				<b>{user.firstName} {user.lastName}</b>'s account and assets will be permanently deleted
+				after 7 days.
+			</p>
+			<p>Are you sure you want to continue?</p>
 		</div>
-	</div>
-</div>
+	</svelte:fragment>
+</ConfirmDialogue>
diff --git a/web/src/lib/components/admin-page/restore-dialoge.svelte b/web/src/lib/components/admin-page/restore-dialoge.svelte
index 6573e04f6..d78006413 100644
--- a/web/src/lib/components/admin-page/restore-dialoge.svelte
+++ b/web/src/lib/components/admin-page/restore-dialoge.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
 	import { api, UserResponseDto } from '@api';
 	import { createEventDispatcher } from 'svelte';
-	import Button from '../elements/buttons/button.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 
 	export let user: UserResponseDto;
 
@@ -14,24 +14,14 @@
 	};
 </script>
 
-<div
-	class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] max-w-[95vw] rounded-3xl py-8 dark:text-immich-dark-fg"
+<ConfirmDialogue
+	title="Restore User"
+	confirmText="Continue"
+	confirmColor="green"
+	on:confirm={restoreUser}
+	on:cancel
 >
-	<div
-		class="flex flex-col place-items-center place-content-center gap-4 px-4 text-immich-primary dark:text-immich-dark-primary"
-	>
-		<h1 class="text-2xl text-immich-primary dark:text-immich-dark-primary font-medium">
-			Restore User
-		</h1>
-	</div>
-	<div>
-		<p class="ml-4 text-md py-5 text-center">
-			{user.firstName}
-			{user.lastName} account will restored
-		</p>
-
-		<div class="flex w-full px-4 gap-4 mt-8">
-			<Button color="green" fullwidth on:click={restoreUser}>Confirm</Button>
-		</div>
-	</div>
-</div>
+	<svelte:fragment slot="prompt">
+		<p><b>{user.firstName} {user.lastName}</b>'s account will be restored.</p>
+	</svelte:fragment>
+</ConfirmDialogue>
diff --git a/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte b/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte
index 1a8d238b4..37f740d43 100644
--- a/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte
+++ b/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte
@@ -4,12 +4,9 @@
 
 <ConfirmDialogue title="Disable Login" on:cancel on:confirm>
 	<svelte:fragment slot="prompt">
-		<div class="flex flex-col gap-4 p-3">
-			<p class="text-md text-center">
-				Are you sure you want to disable all login methods? Login will be completely disabled.
-			</p>
-
-			<p class="text-md text-center">
+		<div class="flex flex-col gap-4">
+			<p>Are you sure you want to disable all login methods? Login will be completely disabled.</p>
+			<p>
 				To re-enable, use a
 				<a
 					href="https://immich.app/docs/administration/server-commands"
diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte
index 9d3933be6..4b0c28cc1 100644
--- a/web/src/lib/components/album-page/album-viewer.svelte
+++ b/web/src/lib/components/album-page/album-viewer.svelte
@@ -43,6 +43,7 @@
 	import ShareInfoModal from './share-info-modal.svelte';
 	import ThumbnailSelection from './thumbnail-selection.svelte';
 	import UserSelectionModal from './user-selection-modal.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 	import { handleError } from '../../utils/handle-error';
 	import { downloadArchive } from '../../utils/asset-utils';
 
@@ -71,6 +72,7 @@
 	let isShowShareInfoModal = false;
 	let isShowAlbumOptions = false;
 	let isShowThumbnailSelection = false;
+	let isShowDeleteConfirmation = false;
 
 	let backUrl = '/albums';
 	let currentAlbumName = '';
@@ -223,21 +225,17 @@
 	};
 
 	const removeAlbum = async () => {
-		if (
-			window.confirm(
-				`Are you sure you want to delete album ${album.albumName}? If the album is shared, other users will not be able to access it.`
-			)
-		) {
-			try {
-				await api.albumApi.deleteAlbum({ id: album.id });
-				goto(backUrl);
-			} catch (e) {
-				console.error('Error [userDeleteMenu] ', e);
-				notificationController.show({
-					type: NotificationType.Error,
-					message: 'Error deleting album, check console for more details'
-				});
-			}
+		try {
+			await api.albumApi.deleteAlbum({ id: album.id });
+			goto(backUrl);
+		} catch (e) {
+			console.error('Error [userDeleteMenu] ', e);
+			notificationController.show({
+				type: NotificationType.Error,
+				message: 'Error deleting album, check console for more details'
+			});
+		} finally {
+			isShowDeleteConfirmation = false;
 		}
 	};
 
@@ -348,7 +346,11 @@
 							on:click={() => (isShowShareUserSelection = true)}
 							logo={ShareVariantOutline}
 						/>
-						<CircleIconButton title="Remove album" on:click={removeAlbum} logo={DeleteOutline} />
+						<CircleIconButton
+							title="Remove album"
+							on:click={() => (isShowDeleteConfirmation = true)}
+							logo={DeleteOutline}
+						/>
 					{/if}
 				{/if}
 
@@ -515,3 +517,17 @@
 		on:thumbnail-selected={setAlbumThumbnailHandler}
 	/>
 {/if}
+
+{#if isShowDeleteConfirmation}
+	<ConfirmDialogue
+		title="Delete Album"
+		confirmText="Delete"
+		on:confirm={removeAlbum}
+		on:cancel={() => (isShowDeleteConfirmation = false)}
+	>
+		<svelte:fragment slot="prompt">
+			<p>Are you sure you want to delete the album <b>{album.albumName}</b>?</p>
+			<p>If this album is shared, other users will not be able to access it anymore.</p>
+		</svelte:fragment>
+	</ConfirmDialogue>
+{/if}
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte
index 0a073f63f..358572001 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte
@@ -21,6 +21,7 @@
 	import DetailPanel from './detail-panel.svelte';
 	import PhotoViewer from './photo-viewer.svelte';
 	import VideoViewer from './video-viewer.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 
 	import { assetStore } from '$lib/stores/assets.store';
 	import { isShowDetail } from '$lib/stores/preferences.store';
@@ -37,6 +38,7 @@
 	let halfRightHover = false;
 	let appearsInAlbums: AlbumResponseDto[] = [];
 	let isShowAlbumPicker = false;
+	let isShowDeleteConfirmation = false;
 	let addToSharedAlbum = true;
 	let shouldPlayMotionPhoto = false;
 	let shouldShowDownloadButton = sharedLink ? sharedLink.allowDownload : true;
@@ -77,7 +79,7 @@
 				closeViewer();
 				return;
 			case 'Delete':
-				deleteAsset();
+				isShowDeleteConfirmation = true;
 				return;
 			case 'i':
 				$isShowDetail = !$isShowDetail;
@@ -116,23 +118,17 @@
 
 	const deleteAsset = async () => {
 		try {
-			if (
-				window.confirm(
-					`Caution! Are you sure you want to delete this asset? This step also deletes this asset in the album(s) to which it belongs. You can not undo this action!`
-				)
-			) {
-				const { data: deletedAssets } = await api.assetApi.deleteAsset({
-					deleteAssetDto: {
-						ids: [asset.id]
-					}
-				});
+			const { data: deletedAssets } = await api.assetApi.deleteAsset({
+				deleteAssetDto: {
+					ids: [asset.id]
+				}
+			});
 
-				navigateAssetForward();
+			navigateAssetForward();
 
-				for (const asset of deletedAssets) {
-					if (asset.status == 'SUCCESS') {
-						assetStore.removeAsset(asset.id);
-					}
+			for (const asset of deletedAssets) {
+				if (asset.status == 'SUCCESS') {
+					assetStore.removeAsset(asset.id);
 				}
 			}
 		} catch (e) {
@@ -140,7 +136,9 @@
 				type: NotificationType.Error,
 				message: 'Error deleting this asset, check console for more details'
 			});
-			console.error('Error deleteSelectedAssetHandler', e);
+			console.error('Error deleteAsset', e);
+		} finally {
+			isShowDeleteConfirmation = false;
 		}
 	};
 
@@ -227,6 +225,17 @@
 			});
 		}
 	};
+
+	const getAssetType = () => {
+		switch (asset.type) {
+			case 'IMAGE':
+				return 'Photo';
+			case 'VIDEO':
+				return 'Video';
+			default:
+				return 'Asset';
+		}
+	};
 </script>
 
 <section
@@ -244,7 +253,7 @@
 			on:goBack={closeViewer}
 			on:showDetail={showDetailInfoHandler}
 			on:download={() => downloadFile(asset, publicSharedKey)}
-			on:delete={deleteAsset}
+			on:delete={() => (isShowDeleteConfirmation = true)}
 			on:favorite={toggleFavorite}
 			on:addToAlbum={() => openAlbumPicker(false)}
 			on:addToSharedAlbum={() => openAlbumPicker(true)}
@@ -358,6 +367,23 @@
 			on:close={() => (isShowAlbumPicker = false)}
 		/>
 	{/if}
+
+	{#if isShowDeleteConfirmation}
+		<ConfirmDialogue
+			title="Delete {getAssetType()}"
+			confirmText="Delete"
+			on:confirm={deleteAsset}
+			on:cancel={() => (isShowDeleteConfirmation = false)}
+		>
+			<svelte:fragment slot="prompt">
+				<p>
+					Are you sure you want to delete this {getAssetType().toLowerCase()}? This will also remove
+					it from its album(s).
+				</p>
+				<p><b>You cannot undo this action!</b></p>
+			</svelte:fragment>
+		</ConfirmDialogue>
+	{/if}
 </section>
 
 <style>
diff --git a/web/src/lib/components/forms/edit-user-form.svelte b/web/src/lib/components/forms/edit-user-form.svelte
index 3aedf0f28..6160901b7 100644
--- a/web/src/lib/components/forms/edit-user-form.svelte
+++ b/web/src/lib/components/forms/edit-user-form.svelte
@@ -7,6 +7,7 @@
 		NotificationType
 	} from '../shared-components/notification/notification';
 	import Button from '../elements/buttons/button.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 	import { handleError } from '../../utils/handle-error';
 
 	export let user: UserResponseDto;
@@ -15,6 +16,8 @@
 	let error: string;
 	let success: string;
 
+	let isShowResetPasswordConfirmation = false;
+
 	const dispatch = createEventDispatcher();
 
 	const editUser = async () => {
@@ -41,20 +44,18 @@
 
 	const resetPassword = async () => {
 		try {
-			if (window.confirm('Do you want to reset the user password?')) {
-				const defaultPassword = 'password';
+			const defaultPassword = 'password';
 
-				const { status } = await api.userApi.updateUser({
-					updateUserDto: {
-						id: user.id,
-						password: defaultPassword,
-						shouldChangePassword: true
-					}
-				});
-
-				if (status == 200) {
-					dispatch('reset-password-success');
+			const { status } = await api.userApi.updateUser({
+				updateUserDto: {
+					id: user.id,
+					password: defaultPassword,
+					shouldChangePassword: true
 				}
+			});
+
+			if (status == 200) {
+				dispatch('reset-password-success');
 			}
 		} catch (e) {
 			console.error('Error reseting user password', e);
@@ -62,6 +63,8 @@
 				message: 'Error reseting user password, check console for more details',
 				type: NotificationType.Error
 			});
+		} finally {
+			isShowResetPasswordConfirmation = false;
 		}
 	};
 </script>
@@ -125,9 +128,9 @@
 			/>
 
 			<p>
-				Note: To apply the Storage Label to previously uploaded assets, run the <a
-					href="/admin/jobs-status"
-					class="text-immich-primary dark:text-immich-dark-primary">Storage Migration Job</a
+				Note: To apply the Storage Label to previously uploaded assets, run the
+				<a href="/admin/jobs-status" class="text-immich-primary dark:text-immich-dark-primary">
+					Storage Migration Job</a
 				>
 			</p>
 		</div>
@@ -157,9 +160,28 @@
 		{/if}
 		<div class="flex w-full px-4 gap-4 mt-8">
 			{#if canResetPassword}
-				<Button color="light-red" fullwidth on:click={resetPassword}>Reset password</Button>
+				<Button
+					color="light-red"
+					fullwidth
+					on:click={() => (isShowResetPasswordConfirmation = true)}>Reset password</Button
+				>
 			{/if}
 			<Button type="submit" fullwidth>Confirm</Button>
 		</div>
 	</form>
 </div>
+
+{#if isShowResetPasswordConfirmation}
+	<ConfirmDialogue
+		title="Reset Password"
+		confirmText="Reset"
+		on:confirm={resetPassword}
+		on:cancel={() => (isShowResetPasswordConfirmation = false)}
+	>
+		<svelte:fragment slot="prompt">
+			<p>
+				Are you sure you want to reset <b>{user.firstName} {user.lastName}</b>'s password?
+			</p>
+		</svelte:fragment>
+	</ConfirmDialogue>
+{/if}
diff --git a/web/src/lib/components/photos-page/actions/delete-assets.svelte b/web/src/lib/components/photos-page/actions/delete-assets.svelte
index ce030b544..f22a84231 100644
--- a/web/src/lib/components/photos-page/actions/delete-assets.svelte
+++ b/web/src/lib/components/photos-page/actions/delete-assets.svelte
@@ -13,7 +13,7 @@
 	export let onAssetDelete: OnAssetDelete;
 	const { getAssets, clearSelect } = getAssetControlContext();
 
-	let confirm = false;
+	let isShowConfirmation = false;
 
 	const handleDelete = async () => {
 		try {
@@ -32,24 +32,43 @@
 				}
 			}
 
-			notificationController.show({ message: `Deleted ${count}`, type: NotificationType.Info });
+			notificationController.show({
+				message: `Deleted ${count}`,
+				type: NotificationType.Info
+			});
 
 			clearSelect();
 		} catch (e) {
 			handleError(e, 'Error deleting assets');
+		} finally {
+			isShowConfirmation = false;
 		}
 	};
 </script>
 
-<CircleIconButton title="Delete" logo={DeleteOutline} on:click={() => (confirm = true)} />
+<CircleIconButton
+	title="Delete"
+	logo={DeleteOutline}
+	on:click={() => (isShowConfirmation = true)}
+/>
 
-{#if confirm}
+{#if isShowConfirmation}
 	<ConfirmDialogue
-		prompt="Are you sure you want to delete {getAssets()
-			.size} assets? This step also deletes assets in the album(s) to which they belong. You can not undo this action!"
-		title="Delete assets?"
+		title="Delete Asset{getAssets().size > 1 ? 's' : ''}"
 		confirmText="Delete"
 		on:confirm={handleDelete}
-		on:cancel={() => (confirm = false)}
-	/>
+		on:cancel={() => (isShowConfirmation = false)}
+	>
+		<svelte:fragment slot="prompt">
+			<p>
+				Are you sure you want to delete
+				{#if getAssets().size > 1}
+					these <b>{getAssets().size}</b> assets? This will also remove them from their album(s).
+				{:else}
+					this asset? This will also remove it from its album(s).
+				{/if}
+			</p>
+			<p><b>You cannot undo this action!</b></p>
+		</svelte:fragment>
+	</ConfirmDialogue>
 {/if}
diff --git a/web/src/lib/components/photos-page/actions/remove-from-album.svelte b/web/src/lib/components/photos-page/actions/remove-from-album.svelte
index ffcd3d434..33a3d011b 100644
--- a/web/src/lib/components/photos-page/actions/remove-from-album.svelte
+++ b/web/src/lib/components/photos-page/actions/remove-from-album.svelte
@@ -7,32 +7,60 @@
 	import { AlbumResponseDto, api } from '@api';
 	import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
 	import { getAssetControlContext } from '../asset-select-control-bar.svelte';
+	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
 
 	export let album: AlbumResponseDto;
 
 	const { getAssets, clearSelect } = getAssetControlContext();
 
-	const handleRemoveFromAlbum = async () => {
-		if (window.confirm('Do you want to remove selected assets from the album?')) {
-			try {
-				const { data } = await api.albumApi.removeAssetFromAlbum({
-					id: album.id,
-					removeAssetsDto: {
-						assetIds: Array.from(getAssets()).map((a) => a.id)
-					}
-				});
+	let isShowConfirmation = false;
 
-				album = data;
-				clearSelect();
-			} catch (e) {
-				console.error('Error [album-viewer] [removeAssetFromAlbum]', e);
-				notificationController.show({
-					type: NotificationType.Error,
-					message: 'Error removing assets from album, check console for more details'
-				});
-			}
+	const removeFromAlbum = async () => {
+		try {
+			const { data } = await api.albumApi.removeAssetFromAlbum({
+				id: album.id,
+				removeAssetsDto: {
+					assetIds: Array.from(getAssets()).map((a) => a.id)
+				}
+			});
+
+			album = data;
+			clearSelect();
+		} catch (e) {
+			console.error('Error [album-viewer] [removeAssetFromAlbum]', e);
+			notificationController.show({
+				type: NotificationType.Error,
+				message: 'Error removing assets from album, check console for more details'
+			});
+		} finally {
+			isShowConfirmation = false;
 		}
 	};
 </script>
 
-<CircleIconButton title="Remove from album" on:click={handleRemoveFromAlbum} logo={DeleteOutline} />
+<CircleIconButton
+	title="Remove from album"
+	on:click={() => (isShowConfirmation = true)}
+	logo={DeleteOutline}
+/>
+
+{#if isShowConfirmation}
+	<ConfirmDialogue
+		title="Remove Asset{getAssets().size > 1 ? 's' : ''}"
+		confirmText="Remove"
+		on:confirm={removeFromAlbum}
+		on:cancel={() => (isShowConfirmation = false)}
+	>
+		<svelte:fragment slot="prompt">
+			<p>
+				Are you sure you want to remove
+				{#if getAssets().size > 1}
+					these <b>{getAssets().size}</b> assets
+				{:else}
+					this asset
+				{/if}
+				from the album?
+			</p>
+		</svelte:fragment>
+	</ConfirmDialogue>
+{/if}
diff --git a/web/src/lib/components/shared-components/confirm-dialogue.svelte b/web/src/lib/components/shared-components/confirm-dialogue.svelte
index 76fb0e160..5f6551920 100644
--- a/web/src/lib/components/shared-components/confirm-dialogue.svelte
+++ b/web/src/lib/components/shared-components/confirm-dialogue.svelte
@@ -2,18 +2,29 @@
 	import { createEventDispatcher } from 'svelte';
 	import FullScreenModal from './full-screen-modal.svelte';
 	import Button from '../elements/buttons/button.svelte';
+	import type { Color } from '$lib/components/elements/buttons/button.svelte';
 
 	export let title = 'Confirm';
 	export let prompt = 'Are you sure you want to do this?';
 	export let confirmText = 'Confirm';
+	export let confirmColor: Color = 'red';
 	export let cancelText = 'Cancel';
+	export let cancelColor: Color = 'primary';
+	export let hideCancelButton = false;
 
 	const dispatch = createEventDispatcher();
+
+	let isConfirmButtonDisabled = false;
+
 	const handleCancel = () => dispatch('cancel');
-	const handleConfirm = () => dispatch('confirm');
+
+	const handleConfirm = () => {
+		isConfirmButtonDisabled = true;
+		dispatch('confirm');
+	};
 </script>
 
-<FullScreenModal on:clickOutside={() => handleCancel()}>
+<FullScreenModal on:clickOutside={handleCancel}>
 	<div
 		class="border bg-immich-bg dark:bg-immich-dark-gray dark:border-immich-dark-gray p-4 shadow-sm w-[500px] max-w-[95vw] rounded-3xl py-8 dark:text-immich-dark-fg"
 	>
@@ -25,13 +36,26 @@
 			</h1>
 		</div>
 		<div>
-			<slot name="prompt">
-				<p class="ml-4 text-md py-5 text-center">{prompt}</p>
-			</slot>
+			<div class="px-4 py-5 text-md text-center">
+				<slot name="prompt">
+					<p>{prompt}</p>
+				</slot>
+			</div>
 
 			<div class="flex w-full px-4 gap-4 mt-4">
-				<Button fullwidth on:click={() => handleCancel()}>{cancelText}</Button>
-				<Button color="red" fullwidth on:click={() => handleConfirm()}>{confirmText}</Button>
+				{#if !hideCancelButton}
+					<Button color={cancelColor} fullwidth on:click={handleCancel}>
+						{cancelText}
+					</Button>
+				{/if}
+				<Button
+					color={confirmColor}
+					fullwidth
+					on:click={handleConfirm}
+					disabled={isConfirmButtonDisabled}
+				>
+					{confirmText}
+				</Button>
 			</div>
 		</div>
 	</div>
diff --git a/web/src/routes/(user)/albums/+page.svelte b/web/src/routes/(user)/albums/+page.svelte
index f4902b40e..59f57f613 100644
--- a/web/src/routes/(user)/albums/+page.svelte
+++ b/web/src/routes/(user)/albums/+page.svelte
@@ -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}
diff --git a/web/src/routes/(user)/albums/__tests__/albums.bloc.spec.ts b/web/src/routes/(user)/albums/__tests__/albums.bloc.spec.ts
index 8dad0c966..0ae8afe5c 100644
--- a/web/src/routes/(user)/albums/__tests__/albums.bloc.spec.ts
+++ b/web/src/routes/(user)/albums/__tests__/albums.bloc.spec.ts
@@ -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', () => {
diff --git a/web/src/routes/(user)/albums/albums.bloc.ts b/web/src/routes/(user)/albums/albums.bloc.ts
index 537ce33f1..78cd907d5 100644
--- a/web/src/routes/(user)/albums/albums.bloc.ts
+++ b/web/src/routes/(user)/albums/albums.bloc.ts
@@ -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
 	};
 };
diff --git a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
index aee6a9863..6cd7e2e51 100644
--- a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
+++ b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
@@ -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)}
diff --git a/web/src/routes/admin/user-management/+page.svelte b/web/src/routes/admin/user-management/+page.svelte
index 5dc4b8260..aae793d47 100644
--- a/web/src/routes/admin/user-management/+page.svelte
+++ b/web/src/routes/admin/user-management/+page.svelte
@@ -126,23 +126,21 @@
 	{/if}
 
 	{#if shouldShowDeleteConfirmDialog}
-		<FullScreenModal on:clickOutside={() => (shouldShowDeleteConfirmDialog = false)}>
-			<DeleteConfirmDialog
-				user={selectedUser}
-				on:user-delete-success={onUserDeleteSuccess}
-				on:user-delete-fail={onUserDeleteFail}
-			/>
-		</FullScreenModal>
+		<DeleteConfirmDialog
+			user={selectedUser}
+			on:user-delete-success={onUserDeleteSuccess}
+			on:user-delete-fail={onUserDeleteFail}
+			on:cancel={() => (shouldShowDeleteConfirmDialog = false)}
+		/>
 	{/if}
 
 	{#if shouldShowRestoreDialog}
-		<FullScreenModal on:clickOutside={() => (shouldShowRestoreDialog = false)}>
-			<RestoreDialogue
-				user={selectedUser}
-				on:user-restore-success={onUserRestoreSuccess}
-				on:user-restore-fail={onUserRestoreFail}
-			/>
-		</FullScreenModal>
+		<RestoreDialogue
+			user={selectedUser}
+			on:user-restore-success={onUserRestoreSuccess}
+			on:user-restore-fail={onUserRestoreFail}
+			on:cancel={() => (shouldShowRestoreDialog = false)}
+		/>
 	{/if}
 
 	{#if shouldShowInfoPanel}