messages
This commit is contained in:
@@ -25,6 +25,6 @@ export async function removeUserFromChannel(channelId: number, userId: number) {
|
||||
return await apiRequest<unknown>(`/channel/${channelId}/user/${userId}`, 'delete');
|
||||
}
|
||||
|
||||
export async function getMessagesByChannelId(channelId: number, before_id: number, limit?: number) {
|
||||
return await apiRequest<Message[]>(`/channel/${channelId}/message`, 'get', { data: { before_id, limit } });
|
||||
export async function getMessagesByChannelId(channelId: number, beforeId?: number, limit?: number) {
|
||||
return await apiRequest<Message[]>(`/channel/${channelId}/message${beforeId || limit ? '?' : ''}${beforeId ? `before=${beforeId}` : ''}${limit ? `&limit=${limit}` : ''}`, 'get');
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { derived, get, writable } from "svelte/store";
|
||||
import { derived, get } from "svelte/store";
|
||||
import { isErrorResponse, type User } from "../types";
|
||||
import { getByToken } from "$lib/api/user";
|
||||
import { persisted } from "svelte-persisted-store";
|
||||
|
||||
export const token = writable<string | null>(null);
|
||||
export const token = persisted<string | null>('token', null);
|
||||
|
||||
token.subscribe((token) => {
|
||||
console.log(`updated token: ${JSON.stringify(token)}`);
|
||||
|
||||
@@ -16,7 +16,7 @@ export type Token = {
|
||||
export type User = {
|
||||
id: number;
|
||||
username: string;
|
||||
avatar: string | null;
|
||||
avatar?: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,6 @@ export type Message = {
|
||||
export type Channel = {
|
||||
id: number;
|
||||
name: string;
|
||||
lastMessageId: number | null;
|
||||
lastMessageId?: number;
|
||||
createdAt: string;
|
||||
};
|
||||
@@ -3,6 +3,9 @@ import type { LayoutServerLoad } from './$types';
|
||||
import { getByToken } from '$lib/api/user';
|
||||
import { isErrorResponse } from '$lib/types';
|
||||
|
||||
export const prerender = false;
|
||||
export const ssr = false;
|
||||
|
||||
export const load = (async ({ cookies }) => {
|
||||
const token = cookies.get('token');
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
export let data: LayoutData;
|
||||
|
||||
console.log(`loading`);
|
||||
console.log(data);
|
||||
|
||||
$token = data.token;
|
||||
addUserToCache(data.user);
|
||||
</script>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const ssr = false
|
||||
@@ -1,15 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { createMessage } from '$lib/api/message';
|
||||
import * as Avatar from '$lib/components/ui/avatar';
|
||||
import { ScrollArea } from '$lib/components/ui/scroll-area';
|
||||
import type { Message as MessageType } from '$lib/types';
|
||||
import { isErrorResponse, type Channel, type Message as MessageType } from '$lib/types';
|
||||
import MessageArea from './message-area.svelte';
|
||||
import Message from './message.svelte';
|
||||
import TextField from './text-field.svelte';
|
||||
|
||||
export let username: string;
|
||||
export let channel: Channel | null = null;
|
||||
export let messages: MessageType[] = [];
|
||||
|
||||
let messageArea: MessageArea;
|
||||
|
||||
const sendMessage = (message: string) => {
|
||||
if (!channel) return;
|
||||
|
||||
createMessage(channel.id, message).then((message) => {
|
||||
if (!isErrorResponse(message)) {
|
||||
messages = [...messages, message];
|
||||
messageArea.scroll('bottom');
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen w-[95%] flex-col contain-strict">
|
||||
@@ -18,9 +30,9 @@
|
||||
<Avatar.Root class="h-12 w-12">
|
||||
<Avatar.Image src="/default-avatar.png" />
|
||||
|
||||
<Avatar.Fallback>{username[0].toUpperCase()}</Avatar.Fallback>
|
||||
<Avatar.Fallback>{channel?.name[0].toUpperCase() || ''}</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<span class="text-xl font-bold">{username}</span>
|
||||
<span class="text-xl font-bold">{channel?.name || ''}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,17 +40,6 @@
|
||||
<MessageArea {messages} bind:this={messageArea} />
|
||||
</div>
|
||||
<div class="m-4 mt-1 max-h-[40%] flex-grow">
|
||||
<TextField
|
||||
onSend={(message) => {
|
||||
messages = [
|
||||
...messages,
|
||||
{ content: message, createdAt: new Date(), authorId: 1, id: 1 }
|
||||
];
|
||||
|
||||
setTimeout(() => {
|
||||
messageArea.scroll('bottom');
|
||||
}, 100);
|
||||
}}
|
||||
/>
|
||||
<TextField onSend={sendMessage} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
let scrollArea: ScrollArea;
|
||||
|
||||
messages = [...messages].sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
||||
messages = [...messages].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
||||
|
||||
export function scroll(anchor: 'top' | 'bottom') {
|
||||
if (scrollArea) {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{message.content}
|
||||
</span>
|
||||
<span class={cn('text-md', timestampPosition)}
|
||||
>{message.createdAt.toLocaleString()}
|
||||
>{new Date(message.createdAt).toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
{#if isSelf}
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
import type { ComponentType } from 'svelte';
|
||||
import type { MenuItem } from './(components)/sidebar-header.svelte';
|
||||
import ChannelList from './(components)/channel-list.svelte';
|
||||
import { user } from '$lib/stores/user';
|
||||
import { number } from 'zod';
|
||||
import { addChannelToCache } from '$lib/stores/cache/channels';
|
||||
|
||||
export let data: LayoutData;
|
||||
|
||||
for (const channel of data.channels) addChannelToCache(channel);
|
||||
|
||||
let channelList: ChannelList | undefined;
|
||||
|
||||
function onKeyUp(event: KeyboardEvent) {
|
||||
|
||||
@@ -3,7 +3,9 @@ import type { Channel } from '$lib/types';
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
|
||||
export const load = (async () => {
|
||||
export const load = (async ({ parent }) => {
|
||||
await parent();
|
||||
|
||||
const response = await getAllChannels();
|
||||
|
||||
const channels = response as Channel[]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="flex h-full w-full items-center justify-center">
|
||||
<div class="flex h-screen w-full items-center justify-center">
|
||||
<div class="w-[20%] min-w-[300px] space-y-4 rounded-lg bg-secondary p-4">
|
||||
<h1 class="text-center text-4xl font-bold">No channel selected</h1>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { page } from '$app/stores';
|
||||
import Channel from '../(components)/(channel)/channel.svelte';
|
||||
import ChannelArea from '../(components)/(channel)/channel-area.svelte';
|
||||
import { getCachedChannel } from '$lib/stores/cache/channels';
|
||||
import type { Channel } from '$lib/types';
|
||||
import { addMessageToCache } from '$lib/stores/cache/messages';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
$: username = $page.params.username;
|
||||
let channel: Channel | null = null;
|
||||
$: channelId = parseInt($page.params.channel_id);
|
||||
$: getCachedChannel(channelId).then((c) => (channel = c));
|
||||
|
||||
for (const message of data.messages)
|
||||
addMessageToCache(message);
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen w-full items-center justify-center">
|
||||
<Channel {username} messages={data.messages} />
|
||||
<ChannelArea {channel} messages={data.messages} />
|
||||
</div>
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { getMessagesByChannelId } from '$lib/api/channel';
|
||||
import { getCachedChannel } from '$lib/stores/cache/channels';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageLoad } from './$types';
|
||||
import { isErrorResponse } from '$lib/types';
|
||||
|
||||
const messages = [
|
||||
{ content: 'Приветdsfsdfsdfsdf', senderId: 1, createdAt: new Date(Date.now() - 1000 * 60 * 25) },
|
||||
{ content: 'Приветffffffffffdsfsdfsdfffffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsffffffffdsfsdfsdffвеffffffffffdsfsdfsdffвеffветdsfsdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff дела?', senderId: 2, createdAt: new Date(Date.now() - 1000 * 60 * 20) },
|
||||
{ content: 'Хорошо', senderId: 1, createdAt: new Date(Date.now() - 1000 * 60 * 15) },
|
||||
{ content: 'Привет', senderId: 2, createdAt: new Date(Date.now() - 1000 * 60 * 10) },
|
||||
{ content: 'Приветdsfsdfsdfsdf', senderId: 1, createdAt: new Date(Date.now() - 1000 * 60 * 25) },
|
||||
{ content: 'fdsfdsfsdfКак дела?', senderId: 2, createdAt: new Date(Date.now() - 1000 * 60 * 20) },
|
||||
{ content: 'Хорошо', senderId: 1, createdAt: new Date(Date.now() - 1000 * 60 * 15) },
|
||||
{ content: 'Приветffffffffffdsfsdfsdfffffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsffffffffdsfsdfsdffвеffffffffffdsfsdfsdffвеffветdsfsdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', senderId: 2, createdAt: new Date(Date.now() - 1000 * 60 * 10) },
|
||||
{ content: 'Приветffffffffffdsfsdfsdfffffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsfffffffdsfsdfsdffffffffffdsffffffffdsfsdfsdffвеffffffffffdsfsdfsdffвеffветdsfsdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', senderId: 1, createdAt: new Date(Date.now() - 1000 * 60 * 25) },
|
||||
export const ssr = false;
|
||||
|
||||
]
|
||||
export const load = (async ({ params, parent }) => {
|
||||
await parent();
|
||||
|
||||
const channelId = parseInt(params.channel_id)
|
||||
const channel = await getCachedChannel(channelId);
|
||||
if (!channel)
|
||||
return redirect(302, '/channels');
|
||||
|
||||
const messages = await getMessagesByChannelId(channel.id, channel.lastMessageId);
|
||||
|
||||
if (isErrorResponse(messages))
|
||||
return redirect(302, '/channels');
|
||||
|
||||
export const load = (async () => {
|
||||
return { messages };
|
||||
}) satisfies PageLoad;
|
||||
Reference in New Issue
Block a user