249 lines
7.8 KiB
TypeScript
249 lines
7.8 KiB
TypeScript
import { AlbumUserRole, type AlbumResponseDto, type UserResponseDto } from '@immich/sdk';
|
|
import { modalManager, type ActionItem } from '@immich/ui';
|
|
import {
|
|
mdiDownload,
|
|
mdiImageOutline,
|
|
mdiLink,
|
|
mdiPlus,
|
|
mdiPlusBoxOutline,
|
|
mdiRenameOutline,
|
|
mdiShareVariantOutline,
|
|
mdiTrashCanOutline,
|
|
mdiExitToApp,
|
|
mdiUpload,
|
|
mdiCogOutline,
|
|
} from '@mdi/js';
|
|
import { type MessageFormatter } from 'svelte-i18n';
|
|
import { goto } from '$app/navigation';
|
|
import { page } from '$app/state';
|
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
|
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
|
import AddUsersModal from '$lib/modals/AddUsersModal.svelte';
|
|
import AlbumEditModal from '$lib/modals/AlbumEditModal.svelte';
|
|
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
|
import {
|
|
addAssetsToAlbumsMutation,
|
|
addUsersToAlbumMutation,
|
|
deleteAlbumMutation,
|
|
removeUserFromAlbumMutation,
|
|
updateAlbumInfoMutation,
|
|
updateAlbumUserMutation,
|
|
} from '$lib/queries/album.query';
|
|
import { executeMutation } from '$lib/queries/client';
|
|
import { Route } from '$lib/route';
|
|
import { createAlbumAndRedirect } from '$lib/utils/album-utils';
|
|
import { downloadArchive } from '$lib/utils/asset-utils';
|
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
|
import { getFormatter } from '$lib/utils/i18n';
|
|
|
|
export const isAlbumOwner = (album: AlbumResponseDto) => album.albumUsers[0].user.id === authManager.user.id;
|
|
export const isAlbumEditor = (album: AlbumResponseDto) =>
|
|
isAlbumOwner(album) ||
|
|
album.albumUsers.find(({ user: { id } }) => id === authManager.user.id)?.role === AlbumUserRole.Editor;
|
|
|
|
export const getAlbumsActions = ($t: MessageFormatter) => {
|
|
const Create: ActionItem = {
|
|
title: $t('create_album'),
|
|
icon: mdiPlusBoxOutline,
|
|
onAction: () => createAlbumAndRedirect(),
|
|
};
|
|
|
|
return { Create };
|
|
};
|
|
|
|
export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) => {
|
|
const isOwned = isAlbumOwner(album);
|
|
const isEditor = isAlbumEditor(album);
|
|
|
|
const AddUsers: ActionItem = {
|
|
title: $t('add_user'),
|
|
icon: mdiPlus,
|
|
color: 'primary',
|
|
onAction: () =>
|
|
modalManager.show(AddUsersModal, {
|
|
excludedUserIds: album.albumUsers.map(({ user: { id } }) => id),
|
|
// TODO that explicit UserResponseDto[] shouldn't be necessary, but svelte's types seem to be messed up right now and AlbumAddUsersModal has a bad type
|
|
onAddUsers: (users: UserResponseDto[]) => handleAddUsersToAlbum(album, users),
|
|
}),
|
|
};
|
|
|
|
const CreateSharedLink: ActionItem = {
|
|
title: $t('create_link'),
|
|
icon: mdiLink,
|
|
color: 'primary',
|
|
onAction: () => modalManager.show(SharedLinkCreateModal, { albumId: album.id }),
|
|
};
|
|
|
|
const Delete: ActionItem = {
|
|
title: $t('delete_album'),
|
|
icon: mdiTrashCanOutline,
|
|
$if: () => isOwned,
|
|
onAction: () => handleDeleteAlbum(album),
|
|
};
|
|
|
|
const Download: ActionItem = {
|
|
title: $t('download'),
|
|
icon: mdiDownload,
|
|
$if: () => album.assetCount > 0,
|
|
onAction: () => handleDownloadAlbum(album),
|
|
};
|
|
|
|
const Edit: ActionItem = {
|
|
title: $t('edit_album'),
|
|
icon: mdiRenameOutline,
|
|
$if: () => isEditor,
|
|
onAction: () => modalManager.show(AlbumEditModal, { album }),
|
|
};
|
|
|
|
const Leave: ActionItem = {
|
|
title: $t('leave_album'),
|
|
icon: mdiExitToApp,
|
|
$if: () => !isOwned,
|
|
onAction: () => handleLeaveAlbum(album),
|
|
};
|
|
|
|
const Options: ActionItem = {
|
|
title: $t('options'),
|
|
icon: mdiCogOutline,
|
|
$if: () => album.assetCount > 0,
|
|
onAction: () => modalManager.show(AlbumOptionsModal, { album, readOnly: !isOwned }),
|
|
};
|
|
|
|
const Share: ActionItem = {
|
|
title: $t('share'),
|
|
icon: mdiShareVariantOutline,
|
|
$if: () => isOwned,
|
|
onAction: () => modalManager.show(AlbumOptionsModal, { album }),
|
|
};
|
|
|
|
return { AddUsers, CreateSharedLink, Delete, Download, Edit, Leave, Options, Share };
|
|
};
|
|
|
|
export const getAlbumAssetActions = ($t: MessageFormatter, album: AlbumResponseDto, asset: { id: string }) => {
|
|
const SetCover: ActionItem = {
|
|
title: $t('set_as_album_cover'),
|
|
icon: mdiImageOutline,
|
|
onAction: () => handleUpdateThumbnail(album, asset.id),
|
|
};
|
|
|
|
return { SetCover };
|
|
};
|
|
|
|
export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponseDto, assets: TimelineAsset[]) => {
|
|
const AddAssets: ActionItem = {
|
|
title: $t('add_assets'),
|
|
color: 'primary',
|
|
icon: mdiPlusBoxOutline,
|
|
$if: () => assets.length > 0,
|
|
onAction: () =>
|
|
executeMutation(addAssetsToAlbumsMutation, { albumIds: [album.id], assetIds: assets.map(({ id }) => id) }),
|
|
};
|
|
|
|
const Upload: ActionItem = {
|
|
title: $t('select_from_computer'),
|
|
description: $t('album_upload_assets'),
|
|
icon: mdiUpload,
|
|
onAction: () => void openFileUploadDialog({ albumId: album.id }),
|
|
};
|
|
|
|
return { AddAssets, Upload };
|
|
};
|
|
|
|
const leaveAlbumPage = (album: AlbumResponseDto) => {
|
|
if (page.params.albumId === album.id) {
|
|
void goto(Route.albums());
|
|
}
|
|
};
|
|
|
|
export const handleUpdateUserAlbumRole = ({
|
|
albumId,
|
|
userId,
|
|
role,
|
|
}: {
|
|
albumId: string;
|
|
userId: string;
|
|
role: AlbumUserRole;
|
|
}) => executeMutation(updateAlbumUserMutation, [{ id: albumId, userId, updateAlbumUserDto: { role } }]);
|
|
|
|
export const handleAddUsersToAlbum = (album: AlbumResponseDto, users: UserResponseDto[], onSuccess?: () => void) =>
|
|
executeMutation(
|
|
addUsersToAlbumMutation,
|
|
[{ id: album.id, addUsersDto: { albumUsers: users.map(({ id }) => ({ userId: id })) } }],
|
|
{ onSuccess },
|
|
);
|
|
|
|
export const handleRemoveUserFromAlbum = async (album: AlbumResponseDto, albumUser: UserResponseDto) => {
|
|
const $t = await getFormatter();
|
|
|
|
const confirmed = await modalManager.showDialog({
|
|
title: $t('album_remove_user'),
|
|
prompt: $t('album_remove_user_confirmation', { values: { user: albumUser.name } }),
|
|
confirmText: $t('remove_user'),
|
|
});
|
|
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
await executeMutation(removeUserFromAlbumMutation, [{ id: album.id, userId: albumUser.id }]);
|
|
};
|
|
|
|
export const handleLeaveAlbum = async (album: AlbumResponseDto) => {
|
|
const $t = await getFormatter();
|
|
|
|
const confirmed = await modalManager.showDialog({
|
|
title: $t('leave_album'),
|
|
prompt: $t('are_you_sure_to_do_this'),
|
|
confirmText: $t('leave'),
|
|
});
|
|
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
await executeMutation(removeUserFromAlbumMutation, [{ id: album.id, userId: 'me' }], {
|
|
onSuccess: () => leaveAlbumPage(album),
|
|
});
|
|
};
|
|
|
|
const handleUpdateThumbnail = (album: AlbumResponseDto, assetId: string) =>
|
|
executeMutation(
|
|
() =>
|
|
updateAlbumInfoMutation({
|
|
success: { toast: 'album_cover_updated' },
|
|
error: { toast: 'errors.unable_to_update_album_cover' },
|
|
}),
|
|
[{ id: album.id, updateAlbumDto: { albumThumbnailAssetId: assetId } }],
|
|
);
|
|
|
|
export const handleDeleteAlbum = async (album: AlbumResponseDto, options?: { prompt?: boolean; notify?: boolean }) => {
|
|
const $t = await getFormatter();
|
|
const { prompt = true, notify = true } = options ?? {};
|
|
|
|
if (prompt) {
|
|
const confirmation =
|
|
album.albumName.length > 0
|
|
? $t('album_delete_confirmation', { values: { album: album.albumName } })
|
|
: $t('unnamed_album_delete_confirmation');
|
|
const description = $t('album_delete_confirmation_description');
|
|
const success = await modalManager.showDialog({ prompt: `${confirmation} ${description}` });
|
|
if (!success) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
await executeMutation(
|
|
() =>
|
|
deleteAlbumMutation(
|
|
notify ? { success: { toast: true }, error: { toast: 'errors.unable_to_delete_album' } } : {},
|
|
),
|
|
[{ id: album.id }],
|
|
{ onSuccess: () => leaveAlbumPage(album) },
|
|
);
|
|
};
|
|
|
|
export const handleDownloadAlbum = async (album: AlbumResponseDto) => {
|
|
await downloadArchive(album.albumName, { albumId: album.id });
|
|
};
|