Edit typing... indicator, loading older message.
This commit is contained in:
@@ -86,6 +86,8 @@ const HIDE_CMD_PREFIX = '__MENTO_HIDE__:';
|
||||
/** Realtime pin / unpin control messages. */
|
||||
const PIN_CMD_PREFIX = '__MENTO_PIN__:';
|
||||
const UNPIN_CMD = '__MENTO_UNPIN__';
|
||||
/** Typing fallback when WS `typing` event is not relayed by external chat. */
|
||||
const TYPING_CMD_PREFIX = '__MENTO_TYPING__:';
|
||||
|
||||
function isDeletedContent(content: string): boolean {
|
||||
const t = content.trim();
|
||||
@@ -95,7 +97,8 @@ function isDeletedContent(content: string): boolean {
|
||||
t === HARD_DELETE_MARKER ||
|
||||
t.startsWith(HIDE_CMD_PREFIX) ||
|
||||
t.startsWith(PIN_CMD_PREFIX) ||
|
||||
t === UNPIN_CMD
|
||||
t === UNPIN_CMD ||
|
||||
t.startsWith(TYPING_CMD_PREFIX)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -237,9 +240,9 @@ function startTypingSweep() {
|
||||
}
|
||||
|
||||
function applyTypingEvent(roomId: string, userId: string) {
|
||||
const rid = String(roomId || '').trim();
|
||||
const uid = String(userId || '').trim();
|
||||
if (!rid || !uid) return;
|
||||
const rid = String(roomId || activeRoomId.value || '').trim();
|
||||
const uid = String(userId || '').trim() || '__someone__';
|
||||
if (!rid) return;
|
||||
if (sessionCache?.chatUserId && uid === sessionCache.chatUserId) return;
|
||||
startTypingSweep();
|
||||
const list = [...(typingMap.value[rid] || [])].filter((t) => t.userId !== uid);
|
||||
@@ -247,6 +250,12 @@ function applyTypingEvent(roomId: string, userId: string) {
|
||||
typingMap.value = { ...typingMap.value, [rid]: list };
|
||||
}
|
||||
|
||||
function parseTypingCommand(content: string): string | null {
|
||||
const t = content.trim();
|
||||
if (!t.startsWith(TYPING_CMD_PREFIX)) return null;
|
||||
return t.slice(TYPING_CMD_PREFIX.length).trim() || '__someone__';
|
||||
}
|
||||
|
||||
function clearTypingForRoom(roomId: string) {
|
||||
if (!typingMap.value[roomId]) return;
|
||||
const next = { ...typingMap.value };
|
||||
@@ -254,6 +263,17 @@ function clearTypingForRoom(roomId: string) {
|
||||
typingMap.value = next;
|
||||
}
|
||||
|
||||
function clearTypingUser(roomId: string, userId: string) {
|
||||
const rid = String(roomId || '').trim();
|
||||
const uid = String(userId || '').trim();
|
||||
if (!rid || !uid || !typingMap.value[rid]) return;
|
||||
const kept = typingMap.value[rid].filter((t) => t.userId !== uid);
|
||||
const next = { ...typingMap.value };
|
||||
if (kept.length) next[rid] = kept;
|
||||
else delete next[rid];
|
||||
typingMap.value = next;
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 40;
|
||||
|
||||
function messageTs(item: ChatMessage): number {
|
||||
@@ -686,6 +706,8 @@ function handleIncomingMessage(msg: ChatMessage) {
|
||||
const myId = sessionCache?.chatUserId ?? '';
|
||||
const fromSelf = Boolean(myId && msg.senderId === myId);
|
||||
|
||||
if (msg.senderId) clearTypingUser(msg.roomId, msg.senderId);
|
||||
|
||||
if (msg.roomId === activeRoomId.value) {
|
||||
messages.value = mergeMessages(
|
||||
{
|
||||
@@ -784,6 +806,7 @@ function onSocketMessage(event: MessageEvent) {
|
||||
parsed.sender_id ??
|
||||
parsed.from_user_id ??
|
||||
parsed.userId ??
|
||||
((parsed.message as Record<string, unknown> | undefined)?.sender_id as string) ??
|
||||
'',
|
||||
);
|
||||
applyTypingEvent(roomId, userId);
|
||||
@@ -830,6 +853,35 @@ function onSocketMessage(event: MessageEvent) {
|
||||
void persistHiddenOnServer(roomId, ids, true);
|
||||
return;
|
||||
}
|
||||
const typingFromCmd = parseTypingCommand(purgeContent);
|
||||
if (typingFromCmd) {
|
||||
const nested =
|
||||
parsed.message && typeof parsed.message === 'object'
|
||||
? (parsed.message as Record<string, unknown>)
|
||||
: undefined;
|
||||
const roomId = String(
|
||||
(parsed.room_id as string) ||
|
||||
(parsed.roomId as string) ||
|
||||
(nested?.room_id as string) ||
|
||||
activeRoomId.value,
|
||||
);
|
||||
const sender =
|
||||
typingFromCmd !== '__someone__'
|
||||
? typingFromCmd
|
||||
: String(
|
||||
(parsed as { sender_id?: string }).sender_id ||
|
||||
(parsed as { user_id?: string }).user_id ||
|
||||
(nested?.sender_id as string) ||
|
||||
(nested?.user_id as string) ||
|
||||
'',
|
||||
);
|
||||
if (purgeId) {
|
||||
rememberHidden(roomId, [purgeId]);
|
||||
void persistHiddenOnServer(roomId, [purgeId], true);
|
||||
}
|
||||
applyTypingEvent(roomId, sender);
|
||||
return;
|
||||
}
|
||||
const pinTarget = parsePinCommand(purgeContent);
|
||||
if (pinTarget !== null) {
|
||||
const roomId = String(
|
||||
@@ -1116,12 +1168,33 @@ export function useOrgChat() {
|
||||
const rid = String(roomId || '').trim();
|
||||
if (!rid) return;
|
||||
const now = Date.now();
|
||||
if (now - lastTypingSentAt < 1800) return;
|
||||
if (now - lastTypingSentAt < 1200) return;
|
||||
lastTypingSentAt = now;
|
||||
try {
|
||||
await connectSocket();
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) return;
|
||||
socket.send(JSON.stringify({ type: 'typing', room_id: rid }));
|
||||
const session = await ensureSession();
|
||||
// Native typing event (if server relays it)
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
type: 'typing',
|
||||
room_id: rid,
|
||||
user_id: session.chatUserId,
|
||||
sender_id: session.chatUserId,
|
||||
}),
|
||||
);
|
||||
// Fallback control text — external chat reliably delivers text; filtered from UI
|
||||
const controlId = crypto.randomUUID();
|
||||
rememberHidden(rid, [controlId]);
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
id: controlId,
|
||||
type: 'text',
|
||||
room_id: rid,
|
||||
content: `${TYPING_CMD_PREFIX}${session.chatUserId}`,
|
||||
}),
|
||||
);
|
||||
void persistHiddenOnServer(rid, [controlId], true);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
@@ -1523,7 +1596,7 @@ export function useOrgChat() {
|
||||
loadingMessages,
|
||||
hasMoreMessages: computed(() => hasMoreMessages.value),
|
||||
loadingOlderMessages: computed(() => loadingOlderMessages.value),
|
||||
typingMap: computed(() => typingMap.value),
|
||||
typingMap,
|
||||
loadMessages,
|
||||
loadOlderMessages,
|
||||
sendTyping,
|
||||
|
||||
Reference in New Issue
Block a user