open-webui/src/lib/components/channel/Messages.svelte

198 lines
5 KiB
Svelte
Raw Normal View History

2024-12-22 11:49:24 +00:00
<script lang="ts">
import { toast } from 'svelte-sonner';
2024-12-23 05:24:09 +00:00
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import isToday from 'dayjs/plugin/isToday';
import isYesterday from 'dayjs/plugin/isYesterday';
dayjs.extend(relativeTime);
dayjs.extend(isToday);
dayjs.extend(isYesterday);
import { tick, getContext, onMount, createEventDispatcher } from 'svelte';
2024-12-31 07:06:34 +00:00
import { settings, user } from '$lib/stores';
2024-12-23 05:37:14 +00:00
2024-12-22 11:49:24 +00:00
import Message from './Messages/Message.svelte';
import Loader from '../common/Loader.svelte';
import Spinner from '../common/Spinner.svelte';
2024-12-31 07:06:34 +00:00
import { addReaction, deleteMessage, removeReaction, updateMessage } from '$lib/apis/channels';
2024-12-22 11:49:24 +00:00
const i18n = getContext('i18n');
2024-12-31 08:51:43 +00:00
export let id = null;
2024-12-23 05:24:09 +00:00
export let channel = null;
2024-12-23 02:40:01 +00:00
export let messages = [];
export let top = false;
2024-12-31 08:51:43 +00:00
export let thread = false;
2024-12-22 11:49:24 +00:00
2024-12-23 02:40:01 +00:00
export let onLoad: Function = () => {};
2024-12-31 07:48:55 +00:00
export let onThread: Function = () => {};
2024-12-22 11:49:24 +00:00
let messagesLoading = false;
const loadMoreMessages = async () => {
// scroll slightly down to disable continuous loading
const element = document.getElementById('messages-container');
element.scrollTop = element.scrollTop + 100;
messagesLoading = true;
2024-12-23 02:40:01 +00:00
await onLoad();
2024-12-22 11:49:24 +00:00
2024-12-23 02:40:01 +00:00
await tick();
2024-12-22 11:49:24 +00:00
messagesLoading = false;
};
</script>
2024-12-23 02:40:01 +00:00
{#if messages}
2024-12-23 04:56:51 +00:00
{@const messageList = messages.slice().reverse()}
<div>
{#if !top}
<Loader
on:visible={(e) => {
console.log('visible');
if (!messagesLoading) {
loadMoreMessages();
}
}}
>
<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
<Spinner className=" size-4" />
<div class=" ">Loading...</div>
</div>
</Loader>
2024-12-31 08:51:43 +00:00
{:else if !thread}
2024-12-23 05:37:14 +00:00
<div
2024-12-23 05:39:44 +00:00
class="px-5
2024-12-23 05:37:14 +00:00
{($settings?.widescreenMode ?? null) ? 'max-w-full' : 'max-w-5xl'} mx-auto"
>
2024-12-23 05:24:09 +00:00
{#if channel}
2024-12-27 20:24:58 +00:00
<div class="flex flex-col gap-1.5 pb-5 pt-10">
2024-12-23 05:37:14 +00:00
<div class="text-2xl font-medium capitalize">{channel.name}</div>
2024-12-23 05:24:09 +00:00
2024-12-23 05:37:14 +00:00
<div class=" text-gray-500">
2025-03-07 11:59:09 +00:00
{$i18n.t(
'This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.',
{
createdAt: dayjs(channel.created_at / 1000000).format('MMMM D, YYYY'),
channelName: channel.name
}
)}
2024-12-23 05:24:09 +00:00
</div>
</div>
{:else}
2024-12-23 06:09:51 +00:00
<div class="flex justify-center text-xs items-center gap-2 py-5">
2024-12-23 05:24:09 +00:00
<div class=" ">Start of the channel</div>
</div>
{/if}
2024-12-23 05:37:14 +00:00
2024-12-23 05:39:44 +00:00
{#if messageList.length > 0}
<hr class=" border-gray-50 dark:border-gray-700/20 py-2.5 w-full" />
{/if}
</div>
2024-12-23 04:56:51 +00:00
{/if}
2024-12-31 08:51:43 +00:00
{#each messageList as message, messageIdx (id ? `${id}-${message.id}` : message.id)}
2024-12-23 04:56:51 +00:00
<Message
{message}
2024-12-31 08:51:43 +00:00
{thread}
2024-12-23 04:56:51 +00:00
showUserProfile={messageIdx === 0 ||
2024-12-23 04:57:32 +00:00
messageList.at(messageIdx - 1)?.user_id !== message.user_id}
2024-12-23 08:12:55 +00:00
onDelete={() => {
2024-12-31 07:12:50 +00:00
messages = messages.filter((m) => m.id !== message.id);
2024-12-23 08:12:55 +00:00
const res = deleteMessage(localStorage.token, message.channel_id, message.id).catch(
(error) => {
2025-01-21 06:41:32 +00:00
toast.error(`${error}`);
2024-12-23 08:12:55 +00:00
return null;
}
);
}}
onEdit={(content) => {
2024-12-31 07:12:50 +00:00
messages = messages.map((m) => {
if (m.id === message.id) {
m.content = content;
}
return m;
});
2024-12-23 08:12:55 +00:00
const res = updateMessage(localStorage.token, message.channel_id, message.id, {
content: content
}).catch((error) => {
2025-01-21 06:41:32 +00:00
toast.error(`${error}`);
2024-12-23 08:12:55 +00:00
return null;
});
}}
2024-12-31 07:48:55 +00:00
onThread={(id) => {
onThread(id);
}}
2024-12-31 07:06:34 +00:00
onReaction={(name) => {
if (
2024-12-31 07:12:50 +00:00
(message?.reactions ?? [])
2024-12-31 07:06:34 +00:00
.find((reaction) => reaction.name === name)
2025-04-01 03:32:12 +00:00
?.user_ids?.includes($user?.id) ??
2024-12-31 07:06:34 +00:00
false
) {
2024-12-31 07:12:50 +00:00
messages = messages.map((m) => {
if (m.id === message.id) {
2024-12-31 07:48:55 +00:00
const reaction = m.reactions.find((reaction) => reaction.name === name);
if (reaction) {
2025-04-01 03:32:12 +00:00
reaction.user_ids = reaction.user_ids.filter((id) => id !== $user?.id);
2024-12-31 07:48:55 +00:00
reaction.count = reaction.user_ids.length;
if (reaction.count === 0) {
m.reactions = m.reactions.filter((r) => r.name !== name);
}
}
2024-12-31 07:12:50 +00:00
}
return m;
});
2024-12-31 07:06:34 +00:00
const res = removeReaction(
localStorage.token,
message.channel_id,
message.id,
name
).catch((error) => {
2025-01-21 06:41:32 +00:00
toast.error(`${error}`);
2024-12-31 07:06:34 +00:00
return null;
});
} else {
2024-12-31 07:12:50 +00:00
messages = messages.map((m) => {
if (m.id === message.id) {
if (m.reactions) {
const reaction = m.reactions.find((reaction) => reaction.name === name);
if (reaction) {
2025-04-01 03:32:12 +00:00
reaction.user_ids.push($user?.id);
2024-12-31 07:12:50 +00:00
reaction.count = reaction.user_ids.length;
} else {
m.reactions.push({
name: name,
2025-04-01 03:32:12 +00:00
user_ids: [$user?.id],
2024-12-31 07:12:50 +00:00
count: 1
});
}
}
}
return m;
});
2024-12-31 07:06:34 +00:00
const res = addReaction(localStorage.token, message.channel_id, message.id, name).catch(
(error) => {
2025-01-21 06:41:32 +00:00
toast.error(`${error}`);
2024-12-31 07:06:34 +00:00
return null;
}
);
}
}}
2024-12-23 04:56:51 +00:00
/>
{/each}
<div class="pb-6" />
2024-12-22 11:49:24 +00:00
</div>
2024-12-23 02:40:01 +00:00
{/if}