Cybersecurity-Projects/PROJECTS/advanced/encrypted-p2p-chat/frontend/src/stores/messages.store.ts

152 lines
4.2 KiB
TypeScript

/**
* Messages store
* Manages message cache per room
*/
import { computed, map } from 'nanostores'
import type { Message, MessageStatus } from '../types'
import { $activeRoomId } from './rooms.store'
export const $messagesByRoom = map<Record<string, Message[]>>({})
export const $pendingMessages = map<Record<string, Message[]>>({})
export const $hasMoreByRoom = map<Record<string, boolean>>({})
export const $oldestMessageIdByRoom = map<Record<string, string | undefined>>({})
export const $activeRoomMessages = computed(
[$messagesByRoom, $activeRoomId],
(messages, roomId) => (roomId ? (messages[roomId] ?? []) : [])
)
export const $activeRoomPendingMessages = computed(
[$pendingMessages, $activeRoomId],
(pending, roomId) => (roomId ? (pending[roomId] ?? []) : [])
)
export function addMessage(roomId: string, message: Message): void {
const messages = $messagesByRoom.get()[roomId] ?? []
const exists = messages.some((m) => m.id === message.id)
if (!exists) {
$messagesByRoom.setKey(roomId, [...messages, message])
}
}
export function prependMessages(roomId: string, newMessages: Message[]): void {
const existing = $messagesByRoom.get()[roomId] ?? []
const existingIds = new Set(existing.map((m) => m.id))
const uniqueNew = newMessages.filter((m) => !existingIds.has(m.id))
if (uniqueNew.length > 0) {
$messagesByRoom.setKey(roomId, [...uniqueNew, ...existing])
if (uniqueNew.length > 0) {
const oldest = uniqueNew.reduce((a, b) =>
new Date(a.created_at) < new Date(b.created_at) ? a : b
)
$oldestMessageIdByRoom.setKey(roomId, oldest.id)
}
}
}
export function updateMessageStatus(
roomId: string,
messageId: string,
status: MessageStatus
): void {
const messages = $messagesByRoom.get()[roomId]
if (messages === undefined) return
const index = messages.findIndex((m) => m.id === messageId)
if (index === -1) return
const updated = [...messages]
updated[index] = { ...updated[index], status }
$messagesByRoom.setKey(roomId, updated)
}
export function updateMessageContent(
roomId: string,
messageId: string,
content: string
): void {
const messages = $messagesByRoom.get()[roomId]
if (messages === undefined) return
const index = messages.findIndex((m) => m.id === messageId)
if (index === -1) return
const updated = [...messages]
updated[index] = { ...updated[index], content }
$messagesByRoom.setKey(roomId, updated)
}
export function addPendingMessage(roomId: string, message: Message): void {
const pending = $pendingMessages.get()[roomId] ?? []
$pendingMessages.setKey(roomId, [...pending, message])
}
export function removePendingMessage(roomId: string, messageId: string): void {
const pending = $pendingMessages.get()[roomId] ?? []
$pendingMessages.setKey(
roomId,
pending.filter((m) => m.id !== messageId)
)
}
export function confirmPendingMessage(
roomId: string,
tempId: string,
confirmedMessage: Message
): void {
removePendingMessage(roomId, tempId)
addMessage(roomId, confirmedMessage)
}
export function setRoomMessages(roomId: string, messages: Message[]): void {
$messagesByRoom.setKey(roomId, messages)
if (messages.length > 0) {
const oldest = messages.reduce((a, b) =>
new Date(a.created_at) < new Date(b.created_at) ? a : b
)
$oldestMessageIdByRoom.setKey(roomId, oldest.id)
}
}
export function setHasMore(roomId: string, hasMore: boolean): void {
$hasMoreByRoom.setKey(roomId, hasMore)
}
export function getHasMore(roomId: string): boolean {
return $hasMoreByRoom.get()[roomId] ?? true
}
export function getOldestMessageId(roomId: string): string | undefined {
return $oldestMessageIdByRoom.get()[roomId]
}
export function clearRoomMessages(roomId: string): void {
$messagesByRoom.setKey(roomId, [])
$pendingMessages.setKey(roomId, [])
$hasMoreByRoom.setKey(roomId, true)
$oldestMessageIdByRoom.setKey(roomId, undefined)
}
export function clearAllMessages(): void {
$messagesByRoom.set({})
$pendingMessages.set({})
$hasMoreByRoom.set({})
$oldestMessageIdByRoom.set({})
}
export function getMessageById(
roomId: string,
messageId: string
): Message | null {
const messages = $messagesByRoom.get()[roomId]
return messages?.find((m) => m.id === messageId) ?? null
}