CoompanionApp/front/play/chat/utils.ts
2026-02-03 13:48:56 +01:00

110 lines
3.5 KiB
TypeScript

import type { ChatMessage, SessionSnapshot } from "../../../shared/types";
import type { ChatThread } from "./types";
import { tStatic } from "../i18n";
function getLastMessage(messages: ChatMessage[]): ChatMessage | null {
if (messages.length === 0) return null;
return messages.reduce((latest, current) =>
current.createdAt > latest.createdAt ? current : latest,
);
}
export function buildThreads(
session: SessionSnapshot,
meId: string | null,
isBanker: boolean,
): ChatThread[] {
const threads: ChatThread[] = [];
const globalMessages = session.chats.filter((message) => message.groupId === null);
threads.push({
id: "global",
name: tStatic("chat.global"),
kind: "global",
members: [],
lastMessage: getLastMessage(globalMessages),
});
session.groups.forEach((group) => {
if (!isBanker && meId && !group.memberIds.includes(meId)) {
return;
}
const groupMessages = session.chats.filter((message) => message.groupId === group.id);
let name = group.name;
let kind: ChatThread["kind"] = "group";
if (group.memberIds.length === 2) {
const [first, second] = group.memberIds;
if (isBanker || !meId) {
const firstName =
session.players.find((player) => player.id === first)?.name ??
tStatic("common.player");
const secondName =
session.players.find((player) => player.id === second)?.name ??
tStatic("common.player");
name = `${firstName} & ${secondName}`;
kind = "direct";
} else {
const otherId = first === meId ? second : first;
const otherName =
session.players.find((player) => player.id === otherId)?.name ??
tStatic("common.player");
name = otherName;
kind = "direct";
}
}
threads.push({
id: group.id,
name,
kind,
members: group.memberIds,
lastMessage: getLastMessage(groupMessages),
});
});
return threads.sort((a, b) => {
const aTime = a.lastMessage?.createdAt ?? 0;
const bTime = b.lastMessage?.createdAt ?? 0;
return bTime - aTime;
});
}
export function getThreadMessages(session: SessionSnapshot, threadId: string): ChatMessage[] {
if (threadId === "global") {
return session.chats.filter((message) => message.groupId === null).slice().reverse();
}
return session.chats.filter((message) => message.groupId === threadId).slice().reverse();
}
export function getLatestThreadTimestamp(session: SessionSnapshot, threadId: string): number | null {
const messages =
threadId === "global"
? session.chats.filter((message) => message.groupId === null)
: session.chats.filter((message) => message.groupId === threadId);
if (messages.length === 0) return null;
return messages.reduce(
(latest, message) => (message.createdAt > latest ? message.createdAt : latest),
0,
);
}
export function getUnreadThreadIds(
session: SessionSnapshot,
meId: string | null,
isBanker: boolean,
readState: Record<string, number>,
): Set<string> {
const unread = new Set<string>();
if (!meId) return unread;
const allowed = new Set(
buildThreads(session, meId, isBanker).map((thread) => thread.id),
);
session.chats.forEach((message) => {
if (message.fromId === meId) return;
const threadId = message.groupId ?? "global";
if (!allowed.has(threadId)) return;
const lastRead = readState[threadId] ?? 0;
if (message.createdAt > lastRead) {
unread.add(threadId);
}
});
return unread;
}