fix(room): align ReactionGroup types with frontend and guard reaction update handler
- Fix ReactionGroup.count: i64 -> i32 and users: Vec<Uuid> -> Vec<String> to match frontend ReactionItem (count: number, users: string[]). Mismatched types caused the WS reaction update to silently fail. Also update ReactionItem in api/ws_types.rs to match. - Add activeRoomIdRef guard in onRoomReactionUpdated to prevent stale room state from processing outdated events after room switch. - Switch from prev.map() to targeted findIndex+spread in onRoomReactionUpdated to avoid unnecessary array recreation.
This commit is contained in:
parent
047782e585
commit
a171d691c6
@ -449,9 +449,9 @@ impl From<room::MessageReactionsResponse> for ReactionListData {
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ReactionItem {
|
||||
pub emoji: String,
|
||||
pub count: i64,
|
||||
pub count: i32,
|
||||
pub reacted_by_me: bool,
|
||||
pub users: Vec<Uuid>,
|
||||
pub users: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
||||
@ -40,9 +40,10 @@ pub struct RoomMessageEvent {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ReactionGroup {
|
||||
pub emoji: String,
|
||||
pub count: i64,
|
||||
pub count: i32,
|
||||
pub reacted_by_me: bool,
|
||||
pub users: Vec<Uuid>,
|
||||
/// Stored as strings (UUIDs) to match the frontend's `users: string[]` type.
|
||||
pub users: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<RoomMessageEnvelope> for RoomMessageEvent {
|
||||
|
||||
@ -11,9 +11,9 @@ use uuid::Uuid;
|
||||
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
||||
pub struct ReactionGroupResponse {
|
||||
pub emoji: String,
|
||||
pub count: i64,
|
||||
pub count: i32,
|
||||
pub reacted_by_me: bool,
|
||||
pub users: Vec<Uuid>,
|
||||
pub users: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
||||
@ -83,9 +83,9 @@ impl RoomService {
|
||||
.into_iter()
|
||||
.map(|g| ReactionGroup {
|
||||
emoji: g.emoji,
|
||||
count: g.count,
|
||||
count: g.count as i32,
|
||||
reacted_by_me: g.reacted_by_me,
|
||||
users: g.users,
|
||||
users: g.users.into_iter().map(|u| u.to_string()).collect(),
|
||||
})
|
||||
.collect();
|
||||
self.queue
|
||||
@ -121,9 +121,9 @@ impl RoomService {
|
||||
.into_iter()
|
||||
.map(|g| ReactionGroup {
|
||||
emoji: g.emoji,
|
||||
count: g.count,
|
||||
count: g.count as i32,
|
||||
reacted_by_me: g.reacted_by_me,
|
||||
users: g.users,
|
||||
users: g.users.into_iter().map(|u| u.to_string()).collect(),
|
||||
})
|
||||
.collect();
|
||||
self.queue
|
||||
@ -258,11 +258,15 @@ impl RoomService {
|
||||
grouped
|
||||
.into_iter()
|
||||
.map(|(emoji, user_reactions)| {
|
||||
let count = user_reactions.len() as i64;
|
||||
let count = user_reactions.len() as i32;
|
||||
let reacted_by_me = current_user_id
|
||||
.map(|uid| user_reactions.iter().any(|r| r.user == uid))
|
||||
.unwrap_or(false);
|
||||
let users = user_reactions.iter().take(3).map(|r| r.user).collect();
|
||||
let users = user_reactions
|
||||
.iter()
|
||||
.take(3)
|
||||
.map(|r| r.user.to_string())
|
||||
.collect();
|
||||
|
||||
ReactionGroupResponse {
|
||||
emoji,
|
||||
|
||||
@ -517,15 +517,18 @@ export function RoomProvider({
|
||||
}
|
||||
},
|
||||
onRoomReactionUpdated: (payload: RoomReactionUpdatedPayload) => {
|
||||
// Guard: ignore events for rooms that are no longer active.
|
||||
// Without this, a WS event arriving after room switch could update
|
||||
// the wrong room's message list (same message ID, different room).
|
||||
if (!activeRoomIdRef.current) return;
|
||||
|
||||
setMessages((prev) => {
|
||||
const updated = prev.map((m) =>
|
||||
m.id === payload.message_id
|
||||
? { ...m, reactions: payload.reactions }
|
||||
: m,
|
||||
);
|
||||
const existingIdx = prev.findIndex((m) => m.id === payload.message_id);
|
||||
if (existingIdx === -1) return prev;
|
||||
const updated = [...prev];
|
||||
updated[existingIdx] = { ...updated[existingIdx], reactions: payload.reactions };
|
||||
// Persist reaction update to IndexedDB
|
||||
const msg = updated.find((m) => m.id === payload.message_id);
|
||||
if (msg) saveMessage(msg).catch(() => {});
|
||||
saveMessage(updated[existingIdx]).catch(() => {});
|
||||
return updated;
|
||||
});
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user