add UI for adding editors
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { groupBy, orderBy } from 'lodash-es';
|
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 { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
|
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
|
||||||
@@ -328,7 +328,7 @@
|
|||||||
updateAlbumInfo(album);
|
updateAlbumInfo(album);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddUsers = async (users: UserResponseDto[]) => {
|
const handleAddUsers = async (users: AddUserDto[]) => {
|
||||||
if (!albumToShare) {
|
if (!albumToShare) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,22 @@
|
|||||||
type AlbumResponseDto,
|
type AlbumResponseDto,
|
||||||
type SharedLinkResponseDto,
|
type SharedLinkResponseDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
|
AlbumUserRole, type AddUserDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { mdiCheck, mdiLink, mdiShareCircle } from '@mdi/js';
|
import { mdiCheck, mdiLink, mdiShareCircle } from '@mdi/js';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
import UserAvatar from '../shared-components/user-avatar.svelte';
|
import UserAvatar from '../shared-components/user-avatar.svelte';
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.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 album: AlbumResponseDto;
|
||||||
export let onClose: () => void;
|
export let onClose: () => void;
|
||||||
let users: UserResponseDto[] = [];
|
let users: UserResponseDto[] = [];
|
||||||
let selectedUsers: UserResponseDto[] = [];
|
let selectedUsers: Record<string, { user: UserResponseDto, role: AlbumUserRole }> = {}
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
select: UserResponseDto[];
|
select: AddUserDto[];
|
||||||
share: void;
|
share: void;
|
||||||
}>();
|
}>();
|
||||||
let sharedLinks: SharedLinkResponseDto[] = [];
|
let sharedLinks: SharedLinkResponseDto[] = [];
|
||||||
@@ -43,26 +45,29 @@
|
|||||||
sharedLinks = data.filter((link) => link.album?.id === album.id);
|
sharedLinks = data.filter((link) => link.album?.id === album.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelect = (user: UserResponseDto) => {
|
const handleToggle = (user: UserResponseDto) => {
|
||||||
selectedUsers = selectedUsers.includes(user)
|
if (Object.keys(selectedUsers).includes(user.id)) {
|
||||||
? selectedUsers.filter((selectedUser) => selectedUser.id !== user.id)
|
delete selectedUsers[user.id];
|
||||||
: [...selectedUsers, user];
|
selectedUsers = selectedUsers
|
||||||
|
} else {
|
||||||
|
selectedUsers[user.id] = { user, role: AlbumUserRole.Editor };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnselect = (user: UserResponseDto) => {
|
const handleChangeRole = (user: UserResponseDto, role: AlbumUserRole) => {
|
||||||
selectedUsers = selectedUsers.filter((selectedUser) => selectedUser.id !== user.id);
|
selectedUsers[user.id].role = role;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal id="user-selection-modal" title="Invite to album" showLogo {onClose}>
|
<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">
|
<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>
|
<p class="font-medium">To</p>
|
||||||
|
|
||||||
{#each selectedUsers as user}
|
{#each Object.values(selectedUsers) as { user }}
|
||||||
{#key user.id}
|
{#key user.id}
|
||||||
<button
|
<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"
|
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" />
|
<UserAvatar {user} size="sm" />
|
||||||
@@ -80,10 +85,10 @@
|
|||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
{#each users as user}
|
{#each users as user}
|
||||||
<button
|
<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"
|
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
|
<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"
|
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" />
|
<UserAvatar {user} size="md" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="text-left">
|
<div class="text-left flex-grow">
|
||||||
<p class="text-immich-fg dark:text-immich-dark-fg">
|
<p class="text-immich-fg dark:text-immich-dark-fg">
|
||||||
{user.name}
|
{user.name}
|
||||||
</p>
|
</p>
|
||||||
@@ -101,6 +106,21 @@
|
|||||||
{user.email}
|
{user.email}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
@@ -117,8 +137,8 @@
|
|||||||
size="sm"
|
size="sm"
|
||||||
fullwidth
|
fullwidth
|
||||||
rounded="full"
|
rounded="full"
|
||||||
disabled={selectedUsers.length === 0}
|
disabled={Object.keys(selectedUsers).length === 0}
|
||||||
on:click={() => dispatch('select', selectedUsers)}>Add</Button
|
on:click={() => dispatch('select', Object.values(selectedUsers).map(({user, ...rest}) => ({userId: user.id, ...rest})))}>Add</Button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
ReactionLevel,
|
ReactionLevel,
|
||||||
ReactionType,
|
ReactionType,
|
||||||
updateAlbumInfo,
|
updateAlbumInfo,
|
||||||
type UserResponseDto,
|
type AddUserDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import {
|
import {
|
||||||
mdiArrowLeft,
|
mdiArrowLeft,
|
||||||
@@ -316,12 +316,12 @@
|
|||||||
viewMode = ViewMode.VIEW;
|
viewMode = ViewMode.VIEW;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddUsers = async (users: UserResponseDto[]) => {
|
const handleAddUsers = async (albumUsers: AddUserDto[]) => {
|
||||||
try {
|
try {
|
||||||
album = await addUsersToAlbum({
|
album = await addUsersToAlbum({
|
||||||
id: album.id,
|
id: album.id,
|
||||||
addUsersDto: {
|
addUsersDto: {
|
||||||
sharedUserIds: [...users].map(({ id }) => id),
|
albumUsers,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user