feat: websockets (comment posting + liking)

This commit is contained in:
Face 2025-05-25 12:06:04 +03:00
parent 251609d7b8
commit 3f137e5c3c
15 changed files with 2200 additions and 5 deletions

View file

@ -11,6 +11,7 @@
import { goto } from '$app/navigation';
import { formatTimeAgo, getPublicUrl } from '$lib/utils';
import SignInConfirmDialog from '$lib/components/self/SignInConfirmDialog.svelte';
import WebSocket, { type WebSocketHandle } from '$lib/components/self/WebSocket.svelte';
const { coinSymbol } = $props<{ coinSymbol: string }>();
import type { Comment } from '$lib/types/comment';
@ -19,6 +20,39 @@
let isSubmitting = $state(false);
let isLoading = $state(true);
let shouldSignIn = $state(false);
let wsManager = $state<WebSocketHandle | undefined>();
function handleWebSocketMessage(message: { type: string; data?: any }) {
switch (message.type) {
case 'new_comment':
// check if comment already exists
const commentExists = comments.some((c) => c.id === message.data.id);
if (!commentExists) {
comments = [message.data, ...comments];
}
break;
case 'comment_liked':
const commentIndex = comments.findIndex((c) => c.id === message.data.commentId);
if (commentIndex !== -1) {
comments[commentIndex] = {
...comments[commentIndex],
likesCount: message.data.likesCount,
isLikedByUser:
message.data.userId === Number($USER_DATA?.id)
? message.data.isLikedByUser
: comments[commentIndex].isLikedByUser
};
}
break;
}
}
function handleWebSocketOpen() {
wsManager?.send({
type: 'set_coin',
coinSymbol
});
}
async function loadComments() {
try {
@ -52,7 +86,11 @@
if (response.ok) {
const result = await response.json();
comments = [result.comment, ...comments];
// check if comment already exists (from ws) before adding
const commentExists = comments.some((c) => c.id === result.comment.id);
if (!commentExists) {
comments = [result.comment, ...comments];
}
newComment = '';
} else {
const error = await response.json();
@ -112,6 +150,13 @@
<SignInConfirmDialog bind:open={shouldSignIn} />
<WebSocket
bind:this={wsManager}
onMessage={handleWebSocketMessage}
onOpen={handleWebSocketOpen}
disableReconnect={true}
/>
<Card.Root>
<Card.Header>
<Card.Title class="flex items-center gap-2">