enh: manage shared chats
This commit is contained in:
@@ -20,6 +20,9 @@
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import ChevronUp from '../icons/ChevronUp.svelte';
|
||||
import ChevronDown from '../icons/ChevronDown.svelte';
|
||||
import Link from '../icons/Link.svelte';
|
||||
import LinkSlash from '../icons/LinkSlash.svelte';
|
||||
import Clipboard from '../icons/Clipboard.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@@ -46,6 +49,7 @@
|
||||
|
||||
export let loadHandler: null | Function = null;
|
||||
export let unarchiveHandler: null | Function = null;
|
||||
export let unshareHandler: null | Function = null;
|
||||
|
||||
const setSortKey = (key) => {
|
||||
if (orderBy === key) {
|
||||
@@ -286,30 +290,57 @@
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
<Tooltip content={$i18n.t('Delete Chat')}>
|
||||
{#if unshareHandler && chat.share_id}
|
||||
<Tooltip content={$i18n.t('Copy Share Link')}>
|
||||
<button
|
||||
class="self-center w-fit px-1 text-sm rounded-xl"
|
||||
on:click={async (e) => {
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
const shareUrl = `${window.location.origin}/s/${chat.share_id}`;
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
toast.success($i18n.t('Share link copied to clipboard.'));
|
||||
}}
|
||||
>
|
||||
<Clipboard class="size-4" strokeWidth="1.5" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
<Tooltip
|
||||
content={unshareHandler ? $i18n.t('Unshare Chat') : $i18n.t('Delete Chat')}
|
||||
>
|
||||
<button
|
||||
class="self-center w-fit px-1 text-sm rounded-xl"
|
||||
on:click={async (e) => {
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
selectedChatId = chat.id;
|
||||
showDeleteConfirmDialog = true;
|
||||
if (unshareHandler) {
|
||||
unshareHandler(chat.id);
|
||||
} else {
|
||||
selectedChatId = chat.id;
|
||||
showDeleteConfirmDialog = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
{#if unshareHandler}
|
||||
<LinkSlash />
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<script lang="ts">
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { getContext } from 'svelte';
|
||||
import { deleteSharedChatById, getSharedChatList } from '$lib/apis/chats';
|
||||
|
||||
import ChatsModal from './ChatsModal.svelte';
|
||||
|
||||
const i18n: Writable<any> = getContext('i18n');
|
||||
|
||||
export let show = false;
|
||||
export let onUpdate = () => {};
|
||||
|
||||
let chatList: any[] | null = null;
|
||||
let page = 1;
|
||||
|
||||
let query = '';
|
||||
let orderBy = 'updated_at';
|
||||
let direction = 'desc';
|
||||
|
||||
let allChatsLoaded = false;
|
||||
let chatListLoading = false;
|
||||
let searchDebounceTimeout: any;
|
||||
|
||||
let filter: any = {};
|
||||
$: filter = {
|
||||
...(query ? { query } : {}),
|
||||
...(orderBy ? { order_by: orderBy } : {}),
|
||||
...(direction ? { direction } : {})
|
||||
};
|
||||
|
||||
$: if (filter !== null) {
|
||||
searchHandler();
|
||||
}
|
||||
|
||||
const searchHandler = async () => {
|
||||
if (!show) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchDebounceTimeout) {
|
||||
clearTimeout(searchDebounceTimeout);
|
||||
}
|
||||
|
||||
page = 1;
|
||||
chatList = null;
|
||||
|
||||
if (query === '') {
|
||||
chatList = await getSharedChatList(localStorage.token, page, filter);
|
||||
} else {
|
||||
searchDebounceTimeout = setTimeout(async () => {
|
||||
chatList = await getSharedChatList(localStorage.token, page, filter);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
if ((chatList ?? []).length === 0) {
|
||||
allChatsLoaded = true;
|
||||
} else {
|
||||
allChatsLoaded = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreChats = async () => {
|
||||
chatListLoading = true;
|
||||
page += 1;
|
||||
|
||||
let newChatList = [];
|
||||
|
||||
if (query) {
|
||||
newChatList = await getSharedChatList(localStorage.token, page, filter);
|
||||
} else {
|
||||
newChatList = await getSharedChatList(localStorage.token, page, filter);
|
||||
}
|
||||
|
||||
// once the bottom of the list has been reached (no results) there is no need to continue querying
|
||||
allChatsLoaded = newChatList.length === 0;
|
||||
|
||||
if (newChatList.length > 0) {
|
||||
chatList = [...(chatList || []), ...newChatList];
|
||||
}
|
||||
|
||||
chatListLoading = false;
|
||||
};
|
||||
|
||||
const unshareHandler = async (chatId: string) => {
|
||||
const res = await deleteSharedChatById(localStorage.token, chatId).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (res === true) {
|
||||
toast.success($i18n.t('Chat unshared successfully.'));
|
||||
onUpdate();
|
||||
init();
|
||||
} else if (res === false) {
|
||||
toast.error($i18n.t('Failed to unshare chat.'));
|
||||
}
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
chatList = await getSharedChatList(localStorage.token);
|
||||
};
|
||||
|
||||
$: if (show) {
|
||||
init();
|
||||
}
|
||||
</script>
|
||||
|
||||
<ChatsModal
|
||||
bind:show
|
||||
bind:query
|
||||
bind:orderBy
|
||||
bind:direction
|
||||
title={$i18n.t('Shared Chats')}
|
||||
emptyPlaceholder={$i18n.t('You have no shared conversations.')}
|
||||
shareUrl={false}
|
||||
{chatList}
|
||||
{allChatsLoaded}
|
||||
{chatListLoading}
|
||||
onUpdate={() => {
|
||||
onUpdate();
|
||||
init();
|
||||
}}
|
||||
loadHandler={loadMoreChats}
|
||||
{unshareHandler}
|
||||
/>
|
||||
Reference in New Issue
Block a user