111 lines
3.5 KiB
TypeScript
111 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;
|
||
|
|
}
|