Files
frontend/src/routes/chat/ChatRoom.svelte
2023-07-08 13:38:57 -04:00

167 lines
3.5 KiB
Svelte

<script lang="ts">
import { identityStore, selectedServer, messageStore, serverDataStore } from '$lib/stores';
import type { RoomI, MessageI } from 'discreetly-interfaces';
import { io } from 'socket.io-client';
import { onDestroy } from 'svelte';
import { genProof } from '$lib/utils';
import { Identity } from '@semaphore-protocol/identity';
export let room: RoomI;
if (!$messageStore[room.id.toString()]) {
$messageStore[room.id.toString()] = [];
}
let messages = [...$messageStore[room.id.toString()]];
onDestroy(() => {
socket.emit('leavingRoom', room?.id);
socket.disconnect();
});
let inputText = '';
let sendButtonText = 'Send';
const socketURL: string = $serverDataStore[$selectedServer].messageHandlerSocket || '';
const socket = io(socketURL);
let connected: boolean = false;
socket.on('connect', () => {
connected = true;
const engine = socket.io.engine;
engine.once('upgrade', () => {
console.debug('Upgraded connection to', engine.transport.name);
});
engine.on('close', (reason) => {
console.debug('socket-io-transport-closed', reason);
});
socket.emit('joiningRoom', room?.id);
});
socket.on('disconnected', () => {
connected = false;
console.debug('disconnected');
});
socket.on('connect_error', (err) => {
console.debug('chat connection error', err.message);
});
socket.on('connect_timeout', (err) => {
console.debug('chat connection timeout', err.message);
});
socket.on('error', (err) => {
console.debug('chat websocket error', err.message);
});
socket.on('messageBroadcast', (data: MessageI) => {
messages = [data, ...messages];
messages = messages.slice(0, 500);
$messageStore[room.id.toString()] = messages;
});
function sendMessage(message: string) {
const identity = new Identity($identityStore.toString());
genProof(room, message, identity).then((msg) => {
socket.emit('validateMessage', msg);
});
}
</script>
<div class="col chat-room">
<h3 class="d-flex justify-content-between align-content-center">
{room?.name}
<span class="fs-6 fw-light align-self-center" style="color:gray">
{#if connected}
<div aria-label="Connected">🟢</div>
{:else}
<div aria-label="Disconnected">🔴</div>
{/if}
</span>
</h3>
<div id="messages" class="mb-3">
<section>
{#each messages as message}
<div class="msg">
<div class="msg-id">{message.id}</div>
<span class="msg-text">{message.message}</span>
</div>
{/each}
</section>
</div>
<div id="chat-input">
<input
type="text"
placeholder="Type your message here"
bind:value={inputText}
on:keydown={(event) => {
if (event.key === 'Enter') {
sendMessage(inputText);
inputText = '';
}
}}
/>
<div
class="btn btn-primary"
on:click={() => {
sendMessage(inputText);
inputText = '';
}}
>
{sendButtonText}
</div>
</div>
</div>
<style>
#messages {
border: 1px solid var(--steel-dark);
border-radius: 0.5em;
padding: 0.35rem 0.5rem;
background-color: var(--steel-white);
}
#messages section {
overflow-y: scroll;
max-height: 60vh;
display: flex;
flex-direction: column-reverse;
gap: 0.5rem;
}
.msg {
display: flex;
flex-direction: row;
gap: 0.5rem;
}
.msg-id {
font-family: 'Space Mono', monospace;
color: var(--steel-dark);
width: 12ch;
text-overflow: ellipsis;
overflow: hidden;
}
.msg-text::before {
content: ':';
color: var(--steel);
margin-right: 0.5rem;
}
#chat-input {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
}
#chat-input input {
flex-grow: 1;
}
</style>