fix(room): revert stale edited_at if messageGet fetch fails

onMessageEdited optimistically set edited_at, then fetched the full
message. If the fetch failed the "Edited" indicator persisted even though
the content was stale. Fix by capturing the original edited_at and
reverting it in the catch block — consistent with editMessage rollback.
This commit is contained in:
ZhenYi 2026-04-16 19:34:59 +08:00
parent beea8854ce
commit 5a59f56319

View File

@ -500,13 +500,16 @@ export function RoomProvider({
const client = wsClientRef.current; const client = wsClientRef.current;
if (!client) return; if (!client) return;
// Optimistic update: set edited_at immediately // Capture original edited_at for rollback if fetch fails
let rollbackEditedAt: string | null = null;
setMessages((prev) => { setMessages((prev) => {
const msg = prev.find((m) => m.id === payload.message_id);
rollbackEditedAt = msg?.edited_at ?? null;
const updated = prev.map((m) => const updated = prev.map((m) =>
m.id === payload.message_id ? { ...m, edited_at: payload.edited_at } : m, m.id === payload.message_id ? { ...m, edited_at: payload.edited_at } : m,
); );
const msg = updated.find((m) => m.id === payload.message_id); const saved = updated.find((m) => m.id === payload.message_id);
if (msg) saveMessage(msg).catch(() => {}); if (saved) saveMessage(saved).catch(() => {});
return updated; return updated;
}); });
@ -526,12 +529,19 @@ export function RoomProvider({
: m, : m,
); );
// Persist to IndexedDB // Persist to IndexedDB
const msg = merged.find((m) => m.id === payload.message_id); const saved = merged.find((m) => m.id === payload.message_id);
if (msg) saveMessage(msg).catch(() => {}); if (saved) saveMessage(saved).catch(() => {});
return merged; return merged;
}); });
} catch { } catch {
// Silently ignore - the optimistic update already applied // Revert edited_at if the fetch failed
if (rollbackEditedAt !== null) {
setMessages((prev) =>
prev.map((m) =>
m.id === payload.message_id ? { ...m, edited_at: rollbackEditedAt! } : m,
),
);
}
} }
}, },
onMessageRevoked: async (payload) => { onMessageRevoked: async (payload) => {