refactor: extract logic from chat page

This commit is contained in:
Shibo Lyu 2024-09-04 03:01:00 +08:00
parent 20fdc2203d
commit 5954928834
9 changed files with 203 additions and 104 deletions

View file

@ -1,68 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import BgPattern from '$lib/components/BgPattern.svelte';
import { messageFromBlah, type Chat, type Message } from '$lib/types';
import { onDestroy } from 'svelte';
import ChatHeader from './ChatHeader.svelte';
import ChatHistory from './ChatHistory.svelte';
import ChatInput from './ChatInput.svelte';
import { BlahChatServerConnection } from '$lib/blah/connection/chatServer';
import { currentKeyPair } from '$lib/keystore';
import { BlahKeyPair, type EncodedBlahKeyPair } from '$lib/blah/crypto';
import { browser } from '$app/environment';
const roomId = $page.params.chatId;
let chat: Chat = {
id: roomId,
name: '',
type: 'group'
};
let messages: Message[] = [];
let server: BlahChatServerConnection;
let unsubscribe: () => void = () => {};
async function initConnection(encodedKeyPair?: EncodedBlahKeyPair) {
messages = [];
const keyPair = encodedKeyPair ? await BlahKeyPair.fromEncoded(encodedKeyPair) : undefined;
server = new BlahChatServerConnection('https://blah.oxa.li/api', keyPair);
unsubscribe();
unsubscribe = server.subscribeRoom(roomId, (message) => {
messages = [...messages, messageFromBlah(message)];
}).unsubscribe;
return server;
}
async function loadChatInfo(server: BlahChatServerConnection) {
const room = await server.fetchRoomInfo(roomId);
chat = {
id: roomId,
name: room.title,
type: 'group'
};
}
async function loadChatHistory(server: BlahChatServerConnection) {
const history = await server.fetchRoomHistory(roomId);
messages = [
...history.map(messageFromBlah).toSorted((a, b) => a.date.getTime() - b.date.getTime()),
...messages
];
}
async function loadChat(server: BlahChatServerConnection) {
return await Promise.allSettled([loadChatInfo(server), loadChatHistory(server)]);
}
$: if (browser) initConnection($currentKeyPair).then((server) => loadChat(server));
onDestroy(() => unsubscribe());
</script>
<div class="flex h-full w-full flex-col justify-stretch">
<ChatHeader {chat} outsideUnreadCount={263723} />
<BgPattern class="flex-1" pattern="charlieBrown">
<ChatHistory {messages} mySenderId={$currentKeyPair?.id} />
</BgPattern>
<ChatInput {roomId} {server} />
</div>

View file

@ -0,0 +1,45 @@
<script lang="ts">
import { page } from '$app/stores';
import BgPattern from '$lib/components/BgPattern.svelte';
import { messageFromBlah, type Chat, type Message } from '$lib/types';
import { onDestroy } from 'svelte';
import ChatHeader from './ChatHeader.svelte';
import ChatHistory from './ChatHistory.svelte';
import ChatInput from './ChatInput.svelte';
import { BlahChatServerConnection } from '$lib/blah/connection/chatServer';
import { currentKeyPair } from '$lib/keystore';
import { BlahKeyPair, type EncodedBlahKeyPair } from '$lib/blah/crypto';
import { browser } from '$app/environment';
import { chatServerConnectionPool } from '$lib/chatServers';
import ServiceMessage from '$lib/components/ServiceMessage.svelte';
import ChatPage from './ChatPage.svelte';
$: roomId = $page.params.chatId;
let serverEndpoint: string = '';
$: {
const endpointString = decodeURIComponent($page.params.server);
serverEndpoint = endpointString.startsWith('http')
? endpointString
: `https://${endpointString}`;
}
let server: BlahChatServerConnection | null;
$: {
if (browser) {
server = chatServerConnectionPool.getConnection(serverEndpoint);
}
}
</script>
<div class="flex h-full w-full flex-col items-center justify-center">
{#if server}
{@const { info, messages, sendMessage } = server.chat(roomId)}
<ChatPage {info} {messages} on:sendMessage={sendMessage} />
{:else}
<ServiceMessage>
To view this chat, you need to connect to chat server
<span class="font-semibold">{serverEndpoint}</span>.
</ServiceMessage>
{/if}
</div>

View file

@ -4,7 +4,7 @@
import type { Chat } from '$lib/types';
import { AvatarBeam } from 'svelte-boring-avatars';
export let chat: Chat;
export let info: Chat;
export let outsideUnreadCount = 0;
</script>
@ -28,10 +28,10 @@
<span class="sr-only">Back</span>
</Button>
<div class="flex flex-1 flex-col justify-center text-center sm:order-2 sm:text-start">
<h3 class="truncate text-sm font-semibold">{chat.name}</h3>
<h3 class="truncate text-sm font-semibold">{info.name}</h3>
</div>
<div class="sm:order-1">
<AvatarBeam size={30} name={chat.name} />
<AvatarBeam size={30} name={info.id} />
</div>
<a class="absolute inset-y-0 start-0 hidden w-2 cursor-default sm:block" href="/">

View file

@ -1,19 +1,16 @@
<script lang="ts">
import type { BlahChatServerConnection } from '$lib/blah/connection/chatServer';
import { BlahError } from '$lib/blah/connection/error';
import Button from '$lib/components/Button.svelte';
import RichTextInput from '$lib/components/RichTextInput.svelte';
import { deltaToBlahRichText } from '$lib/richText';
import { deltaToBlahRichText, type BlahRichText } from '$lib/richText';
import { createEventDispatcher } from 'svelte';
import type { Delta, Editor } from 'typewriter-editor';
export let roomId: string;
export let server: BlahChatServerConnection | undefined;
let editor: Editor | undefined;
let delta: Delta;
let plainText: string = '';
let form: HTMLFormElement | null = null;
let sendDisabled = false;
const dispatch = createEventDispatcher<{ sendMessage: BlahRichText }>();
function onKeyboardSubmit() {
editor?.select(null);
@ -21,27 +18,13 @@
}
async function submit() {
if (!server || plainText.trim() === '') return;
if (plainText.trim() === '') return;
const brt = deltaToBlahRichText(delta);
sendDisabled = true;
try {
await server.sendMessage(roomId, brt);
} catch (e) {
console.log(e);
if (e instanceof BlahError && e.statusCode === 403) {
// TODO: Actual error handling
await server.joinRoom(roomId);
await server.sendMessage(roomId, brt);
} else {
throw e;
}
}
sendDisabled = false;
dispatch('sendMessage', brt);
plainText = '';
}
$: sendDisabled = !server;
</script>
<form
@ -75,7 +58,7 @@
keyboardSubmitMethod="enter"
on:keyboardSubmit={onKeyboardSubmit}
/>
<Button class="p-1.5" variant="primary" type="submit" disabled={sendDisabled}>
<Button class="p-1.5" variant="primary" type="submit">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"

View file

@ -0,0 +1,25 @@
<script lang="ts">
import type { Readable } from 'svelte/store';
import type { Chat, Message } from '$lib/types';
import BgPattern from '$lib/components/BgPattern.svelte';
import { currentKeyPair } from '$lib/keystore';
import ChatHeader from './ChatHeader.svelte';
import ChatHistory from './ChatHistory.svelte';
import ChatInput from './ChatInput.svelte';
import type { BlahRichText } from '$lib/richText';
export let info: Readable<Chat>;
export let messages: Readable<Message[]>;
type $$Events = {
sendMessage: BlahRichText;
};
</script>
<ChatHeader info={$info} outsideUnreadCount={263723} />
<BgPattern class="flex-1" pattern="charlieBrown">
<ChatHistory messages={$messages} mySenderId={$currentKeyPair?.id} />
</BgPattern>
<ChatInput on:sendMessage />