1
0
This commit is contained in:
2024-05-19 20:29:19 +03:00
parent 9b27b59b69
commit e87b740e29
14 changed files with 68 additions and 44 deletions

View File

@@ -25,6 +25,6 @@ export async function removeUserFromChannel(channelId: number, userId: number) {
return await apiRequest<unknown>(`/channel/${channelId}/user/${userId}`, 'delete'); return await apiRequest<unknown>(`/channel/${channelId}/user/${userId}`, 'delete');
} }
export async function getMessagesByChannelId(channelId: number, before_id: number, limit?: number) { export async function getMessagesByChannelId(channelId: number, beforeId?: number, limit?: number) {
return await apiRequest<Message[]>(`/channel/${channelId}/message`, 'get', { data: { before_id, limit } }); return await apiRequest<Message[]>(`/channel/${channelId}/message${beforeId || limit ? '?' : ''}${beforeId ? `before=${beforeId}` : ''}${limit ? `&limit=${limit}` : ''}`, 'get');
} }

View File

@@ -1,8 +1,9 @@
import { derived, get, writable } from "svelte/store"; import { derived, get } from "svelte/store";
import { isErrorResponse, type User } from "../types"; import { isErrorResponse, type User } from "../types";
import { getByToken } from "$lib/api/user"; 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) => { token.subscribe((token) => {
console.log(`updated token: ${JSON.stringify(token)}`); console.log(`updated token: ${JSON.stringify(token)}`);

View File

@@ -16,7 +16,7 @@ export type Token = {
export type User = { export type User = {
id: number; id: number;
username: string; username: string;
avatar: string | null; avatar?: string;
createdAt: string; createdAt: string;
}; };
@@ -31,6 +31,6 @@ export type Message = {
export type Channel = { export type Channel = {
id: number; id: number;
name: string; name: string;
lastMessageId: number | null; lastMessageId?: number;
createdAt: string; createdAt: string;
}; };

View File

@@ -3,6 +3,9 @@ import type { LayoutServerLoad } from './$types';
import { getByToken } from '$lib/api/user'; import { getByToken } from '$lib/api/user';
import { isErrorResponse } from '$lib/types'; import { isErrorResponse } from '$lib/types';
export const prerender = false;
export const ssr = false;
export const load = (async ({ cookies }) => { export const load = (async ({ cookies }) => {
const token = cookies.get('token'); const token = cookies.get('token');

View File

@@ -5,6 +5,9 @@
export let data: LayoutData; export let data: LayoutData;
console.log(`loading`);
console.log(data);
$token = data.token; $token = data.token;
addUserToCache(data.user); addUserToCache(data.user);
</script> </script>

View File

@@ -1 +0,0 @@
export const ssr = false

View File

@@ -1,15 +1,27 @@
<script lang="ts"> <script lang="ts">
import { createMessage } from '$lib/api/message';
import * as Avatar from '$lib/components/ui/avatar'; import * as Avatar from '$lib/components/ui/avatar';
import { ScrollArea } from '$lib/components/ui/scroll-area'; 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 MessageArea from './message-area.svelte';
import Message from './message.svelte'; import Message from './message.svelte';
import TextField from './text-field.svelte'; import TextField from './text-field.svelte';
export let username: string; export let channel: Channel | null = null;
export let messages: MessageType[] = []; export let messages: MessageType[] = [];
let messageArea: MessageArea; 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> </script>
<div class="flex h-screen w-[95%] flex-col contain-strict"> <div class="flex h-screen w-[95%] flex-col contain-strict">
@@ -18,9 +30,9 @@
<Avatar.Root class="h-12 w-12"> <Avatar.Root class="h-12 w-12">
<Avatar.Image src="/default-avatar.png" /> <Avatar.Image src="/default-avatar.png" />
<Avatar.Fallback>{username[0].toUpperCase()}</Avatar.Fallback> <Avatar.Fallback>{channel?.name[0].toUpperCase() || ''}</Avatar.Fallback>
</Avatar.Root> </Avatar.Root>
<span class="text-xl font-bold">{username}</span> <span class="text-xl font-bold">{channel?.name || ''}</span>
</div> </div>
</div> </div>
@@ -28,17 +40,6 @@
<MessageArea {messages} bind:this={messageArea} /> <MessageArea {messages} bind:this={messageArea} />
</div> </div>
<div class="m-4 mt-1 max-h-[40%] flex-grow"> <div class="m-4 mt-1 max-h-[40%] flex-grow">
<TextField <TextField onSend={sendMessage} />
onSend={(message) => {
messages = [
...messages,
{ content: message, createdAt: new Date(), authorId: 1, id: 1 }
];
setTimeout(() => {
messageArea.scroll('bottom');
}, 100);
}}
/>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@
let scrollArea: ScrollArea; 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') { export function scroll(anchor: 'top' | 'bottom') {
if (scrollArea) { if (scrollArea) {

View File

@@ -34,7 +34,7 @@
{message.content} {message.content}
</span> </span>
<span class={cn('text-md', timestampPosition)} <span class={cn('text-md', timestampPosition)}
>{message.createdAt.toLocaleString()} >{new Date(message.createdAt).toLocaleString()}
</span> </span>
</div> </div>
{#if isSelf} {#if isSelf}

View File

@@ -11,11 +11,12 @@
import type { ComponentType } from 'svelte'; import type { ComponentType } from 'svelte';
import type { MenuItem } from './(components)/sidebar-header.svelte'; import type { MenuItem } from './(components)/sidebar-header.svelte';
import ChannelList from './(components)/channel-list.svelte'; import ChannelList from './(components)/channel-list.svelte';
import { user } from '$lib/stores/user'; import { addChannelToCache } from '$lib/stores/cache/channels';
import { number } from 'zod';
export let data: LayoutData; export let data: LayoutData;
for (const channel of data.channels) addChannelToCache(channel);
let channelList: ChannelList | undefined; let channelList: ChannelList | undefined;
function onKeyUp(event: KeyboardEvent) { function onKeyUp(event: KeyboardEvent) {

View File

@@ -3,7 +3,9 @@ import type { Channel } from '$lib/types';
import type { LayoutLoad } from './$types'; import type { LayoutLoad } from './$types';
export const load = (async () => { export const load = (async ({ parent }) => {
await parent();
const response = await getAllChannels(); const response = await getAllChannels();
const channels = response as Channel[] const channels = response as Channel[]

View File

@@ -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"> <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> <h1 class="text-center text-4xl font-bold">No channel selected</h1>
</div> </div>

View File

@@ -1,13 +1,22 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types'; import type { PageData } from './$types';
import { page } from '$app/stores'; 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; 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> </script>
<div class="flex h-screen w-full items-center justify-center"> <div class="flex h-screen w-full items-center justify-center">
<Channel {username} messages={data.messages} /> <ChannelArea {channel} messages={data.messages} />
</div> </div>

View File

@@ -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 type { PageLoad } from './$types';
import { isErrorResponse } from '$lib/types';
const messages = [ export const ssr = false;
{ 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 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 }; return { messages };
}) satisfies PageLoad; }) satisfies PageLoad;