feat: Message timestamps
This commit is contained in:
parent
08493a24b7
commit
e3c8f7fa3a
2
TODO.md
2
TODO.md
@ -14,7 +14,7 @@ A more complex version of this list is available [here](https://trello.com/b/kJw
|
||||
- [x] Notifications
|
||||
- [x] Make the damn textbox stop unfocusing on every message submit
|
||||
- [ ] Message context menus
|
||||
- [ ] Message Timestamps
|
||||
- [x] Message Timestamps
|
||||
- [x] Markdown Support
|
||||
- [x] More Secure database passwords
|
||||
- [x] Minio
|
||||
|
@ -20,13 +20,15 @@ io.on('connection', async (socket) => {
|
||||
if (msg.content !== '') {
|
||||
console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`);
|
||||
// Store the message in the database
|
||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
||||
const timestamp = new Date();
|
||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4(), timestamp);
|
||||
const sender = authdb.getUser(msg.id);
|
||||
io!.emit('message', {
|
||||
user: sender.username,
|
||||
message: msg.content,
|
||||
imageSrc: sender.image,
|
||||
channel: msg.channel,
|
||||
timestamp: timestamp.getTime(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { type TypeMessage } from '$lib/types';
|
||||
import Prose from '$lib/components/prose.svelte';
|
||||
import renderMarkdown from '$lib/functions/renderMarkdown';
|
||||
const { message, imageSrc, user }: TypeMessage = $props();
|
||||
const { message, imageSrc, user, timestamp }: TypeMessage = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex w-full p-2 hover:bg-zinc-200 dark:hover:bg-stone-900">
|
||||
@ -12,7 +12,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<p class="inline-size-full break-words font-bold">{user}</p>
|
||||
<p class="inline-size-full flex items-center gap-1 break-words">
|
||||
<span class="font-bold">{user}</span>
|
||||
<span>·</span>
|
||||
<span class="text-muted-foreground"
|
||||
>{new Date(timestamp).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour12: true,
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
})}</span
|
||||
>
|
||||
</p>
|
||||
<Prose class="inline-size-full text-wrap break-words font-sans">{@html renderMarkdown(message)}</Prose>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,6 +34,7 @@ class Websocket {
|
||||
message: newMsg.message,
|
||||
imageSrc: newMsg.imageSrc,
|
||||
user: newMsg.user,
|
||||
timestamp: newMsg.timestamp,
|
||||
},
|
||||
...this.messages,
|
||||
];
|
||||
|
@ -28,13 +28,15 @@ export function startupSocketIOServer(httpServer: HttpServer | null) {
|
||||
if (msg.content !== '') {
|
||||
console.log(`\x1b[35m[ws:kit]\x1b[0m message from ${socket.id}: ${msg.content}`);
|
||||
// Store the message in the database
|
||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4());
|
||||
const timestamp = new Date();
|
||||
await db.sendMessage(msg.channel, msg.content, msg.id, uuidv4(), timestamp);
|
||||
const sender = authdb.getUser(msg.id);
|
||||
io!.emit('message', {
|
||||
user: sender.username,
|
||||
message: msg.content,
|
||||
imageSrc: sender.image,
|
||||
channel: msg.channel,
|
||||
timestamp: timestamp.getTime(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -6,6 +6,12 @@ interface Messages {
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
interface CassandraTimestamp {
|
||||
low: number;
|
||||
high: number;
|
||||
unsigned: boolean;
|
||||
}
|
||||
|
||||
function createDelay(ms: number) {
|
||||
return new Promise((res) => setTimeout(res, ms));
|
||||
}
|
||||
@ -69,16 +75,15 @@ class Db {
|
||||
}
|
||||
|
||||
// Send message method
|
||||
async sendMessage(channelName: string, content: string, sender: string, id: string) {
|
||||
async sendMessage(channelName: string, content: string, sender: string, id: string, timestamp: Date) {
|
||||
try {
|
||||
const now = new Date();
|
||||
channelName = sanitizeChannelName(channelName);
|
||||
await this.client.execute(`INSERT INTO channels.${channelName} (id, message_content, channel_name, timestamp, sender) VALUES (?, ?, ?, ?, ?)`, {
|
||||
await this.client.execute(`INSERT INTO channels.${channelName} (id, message_content, channel_name, sender, timestamp) VALUES (?, ?, ?, ?, ?)`, {
|
||||
id,
|
||||
message_content: content,
|
||||
channel_name: channelName,
|
||||
timestamp: now.getTime(),
|
||||
sender,
|
||||
timestamp,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Error storing message: ${e as Error}`);
|
||||
@ -130,6 +135,13 @@ class Db {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Timestamp to Epoch method
|
||||
tsEpoch(ts: CassandraTimestamp) {
|
||||
const low = ts.low >>> 0;
|
||||
const high = ts.high >>> 0;
|
||||
return high * 2 ** 32 + low;
|
||||
}
|
||||
}
|
||||
|
||||
const db = new Db();
|
||||
|
@ -2,6 +2,7 @@ export interface TypeMessage {
|
||||
message: string;
|
||||
imageSrc: string;
|
||||
user: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface TypeFullMessage {
|
||||
@ -9,4 +10,5 @@ export interface TypeFullMessage {
|
||||
message: string;
|
||||
imageSrc: string;
|
||||
user: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ export async function load({ params, request }): Promise<ChannelLoad> {
|
||||
user: sender.username,
|
||||
imageSrc: sender.image,
|
||||
channel: value.channel,
|
||||
timestamp: db.tsEpoch(value.timestamp),
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
@ -71,7 +71,7 @@
|
||||
|
||||
{#snippet message(messages: TypeMessage[])}
|
||||
{#each messages as message}
|
||||
<Message imageSrc={message.imageSrc} user={message.user} message={message.message} />
|
||||
<Message imageSrc={message.imageSrc} user={message.user} message={message.message} timestamp={message.timestamp} />
|
||||
{/each}
|
||||
{/snippet}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user