diff --git a/web/src/lib/components/album-page/album-options.svelte b/web/src/lib/components/album-page/album-options.svelte index 53fd355c4b..3ec1842757 100644 --- a/web/src/lib/components/album-page/album-options.svelte +++ b/web/src/lib/components/album-page/album-options.svelte @@ -6,6 +6,8 @@ type AlbumResponseDto, type UserResponseDto, AssetOrder, + AlbumUserRole, + updateAlbumUser, } from '@immich/sdk'; import { mdiArrowDownThin, mdiArrowUpThin, mdiPlus, mdiDotsVertical } from '@mdi/js'; import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; @@ -29,6 +31,7 @@ export let onToggleEnabledActivity: () => void; export let onShowSelectSharedUser: () => void; export let onRemove: (userId: string) => void; + export let onRefreshAlbum: () => void; let selectedRemoveUser: UserResponseDto | null = null; @@ -80,6 +83,21 @@ selectedRemoveUser = null; } }; + + const handleUpdateSharedUserRole = async (user: UserResponseDto, role: AlbumUserRole) => { + try { + await updateAlbumUser({ id: album.id, userId: user.id, updateAlbumUserDto: { role } }); + const message = $t('user_role_set', { + values: { user: user.name, role: role == AlbumUserRole.Viewer ? $t('role_viewer') : $t('role_editor') }, + }); + onRefreshAlbum(); + notificationController.show({ type: NotificationType.Info, message }); + } catch (error) { + handleError(error, $t('errors.unable_to_change_album_user_role')); + } finally { + selectedRemoveUser = null; + } + }; </script> {#if !selectedRemoveUser} @@ -122,15 +140,31 @@ <div>{$t('owner')}</div> </div> - {#each album.albumUsers as { user } (user.id)} + {#each album.albumUsers as { user, role } (user.id)} <div class="flex items-center gap-2 py-2"> <div> <UserAvatar {user} size="md" /> </div> <div class="w-full">{user.name}</div> + {#if role === AlbumUserRole.Viewer} + {$t('role_viewer')} + {:else} + {$t('role_editor')} + {/if} {#if user.id !== album.ownerId} - <!-- Allow deletion for non-owners --> <ButtonContextMenu icon={mdiDotsVertical} size="20" title={$t('options')}> + {#if role === AlbumUserRole.Viewer} + <MenuOption + onClick={() => handleUpdateSharedUserRole(user, AlbumUserRole.Editor)} + text={$t('allow_edits')} + /> + {:else} + <MenuOption + onClick={() => handleUpdateSharedUserRole(user, AlbumUserRole.Viewer)} + text={$t('disallow_edits')} + /> + {/if} + <!-- Allow deletion for non-owners --> <MenuOption onClick={() => handleMenuRemove(user)} text={$t('remove')} /> </ButtonContextMenu> {/if} diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 9466ba1330..f719c0743f 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -747,6 +747,7 @@ await setModeToView(); }} onRemove={(userId) => handleRemoveUser(userId, ViewMode.OPTIONS)} + onRefreshAlbum={refreshAlbum} onClose={() => (viewMode = ViewMode.VIEW)} onToggleEnabledActivity={handleToggleEnableActivity} onShowSelectSharedUser={() => (viewMode = ViewMode.SELECT_USERS)}