add UI for adding editors

This commit is contained in:
mgabor
2024-04-24 12:29:56 +02:00
parent 5bb3ddb1f5
commit 5a887069da
3 changed files with 41 additions and 21 deletions

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { groupBy, orderBy } from 'lodash-es';
import { addUsersToAlbum, deleteAlbum, type UserResponseDto, type AlbumResponseDto } from '@immich/sdk';
import { addUsersToAlbum, deleteAlbum, type AddUserDto, type AlbumResponseDto } from '@immich/sdk';
import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
@@ -328,7 +328,7 @@
updateAlbumInfo(album);
};
const handleAddUsers = async (users: UserResponseDto[]) => {
const handleAddUsers = async (users: AddUserDto[]) => {
if (!albumToShare) {
return;
}

View File

@@ -8,20 +8,22 @@
type AlbumResponseDto,
type SharedLinkResponseDto,
type UserResponseDto,
AlbumUserRole, type AddUserDto,
} from '@immich/sdk';
import { mdiCheck, mdiLink, mdiShareCircle } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import Button from '../elements/buttons/button.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import Dropdown from '$lib/components/elements/dropdown.svelte';
export let album: AlbumResponseDto;
export let onClose: () => void;
let users: UserResponseDto[] = [];
let selectedUsers: UserResponseDto[] = [];
let selectedUsers: Record<string, { user: UserResponseDto, role: AlbumUserRole }> = {}
const dispatch = createEventDispatcher<{
select: UserResponseDto[];
select: AddUserDto[];
share: void;
}>();
let sharedLinks: SharedLinkResponseDto[] = [];
@@ -43,26 +45,29 @@
sharedLinks = data.filter((link) => link.album?.id === album.id);
};
const handleSelect = (user: UserResponseDto) => {
selectedUsers = selectedUsers.includes(user)
? selectedUsers.filter((selectedUser) => selectedUser.id !== user.id)
: [...selectedUsers, user];
const handleToggle = (user: UserResponseDto) => {
if (Object.keys(selectedUsers).includes(user.id)) {
delete selectedUsers[user.id];
selectedUsers = selectedUsers
} else {
selectedUsers[user.id] = { user, role: AlbumUserRole.Editor };
}
};
const handleUnselect = (user: UserResponseDto) => {
selectedUsers = selectedUsers.filter((selectedUser) => selectedUser.id !== user.id);
const handleChangeRole = (user: UserResponseDto, role: AlbumUserRole) => {
selectedUsers[user.id].role = role;
};
</script>
<FullScreenModal id="user-selection-modal" title="Invite to album" showLogo {onClose}>
{#if selectedUsers.length > 0}
{#if Object.keys(selectedUsers).length > 0}
<div class="mb-2 flex flex-wrap place-items-center gap-4 overflow-x-auto px-5 py-2 sticky">
<p class="font-medium">To</p>
{#each selectedUsers as user}
{#each Object.values(selectedUsers) as { user }}
{#key user.id}
<button
on:click={() => handleUnselect(user)}
on:click={() => handleToggle(user)}
class="flex place-items-center gap-1 rounded-full border border-gray-500 p-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700"
>
<UserAvatar {user} size="sm" />
@@ -80,10 +85,10 @@
<div class="my-4">
{#each users as user}
<button
on:click={() => handleSelect(user)}
on:click={() => handleToggle(user)}
class="flex w-full place-items-center gap-4 px-5 py-4 transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl"
>
{#if selectedUsers.includes(user)}
{#if Object.keys(selectedUsers).includes(user.id)}
<div
class="flex h-10 w-10 items-center justify-center rounded-full border bg-immich-primary text-3xl text-white dark:border-immich-dark-gray dark:bg-immich-dark-primary dark:text-immich-dark-bg"
>
@@ -93,7 +98,7 @@
<UserAvatar {user} size="md" />
{/if}
<div class="text-left">
<div class="text-left flex-grow">
<p class="text-immich-fg dark:text-immich-dark-fg">
{user.name}
</p>
@@ -101,6 +106,21 @@
{user.email}
</p>
</div>
{#if Object.keys(selectedUsers).includes(user.id)}
<div on:click={(e) => e.stopPropagation()}>
<Dropdown
title="Role"
options={[
{ title: 'Editor', value: AlbumUserRole.Editor },
{ title: 'Viewer', value: AlbumUserRole.Viewer },
]}
selectedOption={{ title: 'Editor', value: AlbumUserRole.Editor }}
render={({ title }) => title}
on:select={({detail: {value}}) => handleChangeRole(user, value)}
/>
</div>
{/if}
</button>
{/each}
</div>
@@ -117,8 +137,8 @@
size="sm"
fullwidth
rounded="full"
disabled={selectedUsers.length === 0}
on:click={() => dispatch('select', selectedUsers)}>Add</Button
disabled={Object.keys(selectedUsers).length === 0}
on:click={() => dispatch('select', Object.values(selectedUsers).map(({user, ...rest}) => ({userId: user.id, ...rest})))}>Add</Button
>
</div>
{/if}

View File

@@ -63,7 +63,7 @@
ReactionLevel,
ReactionType,
updateAlbumInfo,
type UserResponseDto,
type AddUserDto,
} from '@immich/sdk';
import {
mdiArrowLeft,
@@ -316,12 +316,12 @@
viewMode = ViewMode.VIEW;
};
const handleAddUsers = async (users: UserResponseDto[]) => {
const handleAddUsers = async (albumUsers: AddUserDto[]) => {
try {
album = await addUsersToAlbum({
id: album.id,
addUsersDto: {
sharedUserIds: [...users].map(({ id }) => id),
albumUsers,
},
});