diff --git a/src/lib/components/extra/User.svelte b/src/lib/components/extra/User.svelte index de2f5f5..4eea5d2 100644 --- a/src/lib/components/extra/User.svelte +++ b/src/lib/components/extra/User.svelte @@ -1,22 +1,34 @@ - -
- {user.username} - {#if user.status === Status.OFFLINE} - - {:else if user.status === Status.DND} - - {:else if user.status === Status.ONLINE} - - {/if} -
- {user.username} +
{ + e.preventDefault(); + await navigator.clipboard.writeText(user.id); + }} + href="##" + class="flex items-center gap-2" +> +
+ {user.username} + {#if user.status === Status.OFFLINE} + + {:else if user.status === Status.DND} + + {:else if user.status === Status.ONLINE} + + {/if} +
+ {user.username}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ee33998..634542d 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,6 +4,25 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } +export function formatTimestamp(dateString: string) { + const date = new Date(dateString); + const now = new Date(); + + const isToday = + date.getDate() === now.getDate() && + date.getMonth() === now.getMonth() && + date.getFullYear() === now.getFullYear(); + + const pad = (n: number) => n.toString().padStart(2, '0'); + + if (isToday) { + return `${pad(date.getHours())}:${pad(date.getMinutes())}`; + } else { + return `${pad(date.getDate())}/${pad(date.getMonth() + 1)}/${date.getFullYear()}, ${pad( + date.getHours() + )}:${pad(date.getMinutes())}`; + } +} // eslint-disable-next-line @typescript-eslint/no-explicit-any export type WithoutChild = T extends { child?: any } ? Omit : T; diff --git a/src/routes/api/messages/[[groupOrServerId]]/[[channelId]]/+server.ts b/src/routes/api/messages/[[groupOrServerId]]/[[channelId]]/+server.ts deleted file mode 100644 index bb8d1a2..0000000 --- a/src/routes/api/messages/[[groupOrServerId]]/[[channelId]]/+server.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { json } from '@sveltejs/kit'; -import type { RequestHandler } from './$types'; - -export const GET: RequestHandler = async ({ params }) => { - const { groupOrServerId, channelId } = params; - - const isGroup = !channelId; - - // fake messages - const messages = Array.from({ length: 5 }, (_, i) => ({ - id: crypto.randomUUID(), - authorId: `user_${Math.floor(Math.random() * 10)}`, - content: isGroup ? `Group message #${i + 1}` : `Server message #${i + 1}`, - timestamp: Date.now() - Math.floor(Math.random() * 100000) - })); - - return json({ - type: isGroup ? 'group' : 'server', - groupId: isGroup ? groupOrServerId : null, - serverId: isGroup ? null : groupOrServerId, - channelId: channelId ?? null, - messages - }); -}; diff --git a/src/routes/api/messages/[[grp_srv_dm]]/[[channelId]]/[[channelId]]/+server.ts b/src/routes/api/messages/[[grp_srv_dm]]/[[channelId]]/[[channelId]]/+server.ts new file mode 100644 index 0000000..c379631 --- /dev/null +++ b/src/routes/api/messages/[[grp_srv_dm]]/[[channelId]]/[[channelId]]/+server.ts @@ -0,0 +1,53 @@ +import { fail, json } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; +import { GroupID, ServerID, UserID } from '$lib'; + +export const GET: RequestHandler = async ({ params, locals }) => { + if (!locals.user) { + return new Response('No authentication', { status: 401 }); + } + + const { grp_srv_dm, channelId } = params; + if (!grp_srv_dm) { + return new Response('Missing group, server, or DM ID.', { status: 400 }); + } + let messages = []; + let type = ''; + + if (GroupID.is(grp_srv_dm)) { + type = 'group'; + messages = Array.from({ length: 5 }, (_, i) => ({ + id: crypto.randomUUID(), + authorId: `user_${Math.floor(Math.random() * 10)}`, + content: 'group message ' + (i + 1), + timestamp: Date.now() - Math.floor(Math.random() * 100000) + })); + } else if (ServerID.is(grp_srv_dm)) { + type = 'server'; + + if (!channelId) { + return new Response('Missing channel ID.', { status: 400 }); + } + + messages = Array.from({ length: 5 }, (_, i) => ({ + id: crypto.randomUUID(), + authorId: `user_${Math.floor(Math.random() * 10)}`, + content: 'server message ' + (i + 1), + timestamp: Date.now() - Math.floor(Math.random() * 100000) + })); + } else if (UserID.is(grp_srv_dm)) { + type = 'dms'; + messages = Array.from({ length: 5 }, (_, i) => ({ + id: crypto.randomUUID(), + authorId: Math.random() > 0.5 ? locals.user.id : grp_srv_dm, + content: 'dm message ' + (i + 1), + timestamp: Date.now() - Math.floor(Math.random() * 100000) + })); + } + + return json({ + type, + id: grp_srv_dm, + messages + }); +}; diff --git a/src/routes/api/updates/+server.ts b/src/routes/api/updates/+server.ts index c8ac92c..33b9388 100644 --- a/src/routes/api/updates/+server.ts +++ b/src/routes/api/updates/+server.ts @@ -66,6 +66,16 @@ export async function GET({ locals, request }) { kvStore.set(`user-${userId}-state`, Status.OFFLINE); _sendToSubscribers(userId, { type: 'status', id: userId, status: Status.OFFLINE }); }); + }, + cancel() { + console.log(`SSE Client cancelled. total: ${_clients.size}`); + + if (_isUserConnected(userId)) return; + + if (overwrite === Status.OFFLINE) return; + + kvStore.set(`user-${userId}-state`, Status.OFFLINE); + _sendToSubscribers(userId, { type: 'status', id: userId, status: Status.OFFLINE }); } }); diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte index e6ea282..d3550b2 100644 --- a/src/routes/app/+page.svelte +++ b/src/routes/app/+page.svelte @@ -19,11 +19,14 @@ import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js'; import { onMount } from 'svelte'; import type { ActionData } from './$types'; + import { formatTimestamp } from '$lib/utils'; let errorOpen = $state(true); + let { form, data }: { form: ActionData; data: PageServerData } = $props(); let currentPageID: (UserId | GroupId | ServerId) | null = $state(null); let currentPage: OverviewUser | OverviewGroup | OverviewServer | undefined = $state(); + let messages = $state([]); const overview_data: OverviewData = $state({ friends: [], groups: [], @@ -44,6 +47,20 @@ } }); + $effect(() => { + if (!currentPageID || !currentPage) return; + if (ServerID.is(currentPageID)) return; + + async function getMessages() { + const req = await fetch('/api/messages/' + currentPageID); + const data = await req.json(); + + messages = data.messages; + } + + getMessages(); + }); + onMount(() => { async function run() { overview_data.servers = data.user.servers.map((z) => { @@ -159,6 +176,32 @@ {/if} {/if} -

this is like lowkirkounely the content, i should put messages and shi here

+ + {#each messages as message, i (message.id)} + {#if i === 0 || messages[i - 1].authorId !== message.authorId} +
+ {message.authorId} + +
+
+ {message.authorId} + + {formatTimestamp(message.timestamp)} + +
+ +
{message.content}
+
+
+ {:else} +
+
{message.content}
+
+ {/if} + {/each}