From 1f22d5c41b3441518206a2bd4986f6713715bb59 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 28 Nov 2025 18:41:43 +0100 Subject: [PATCH] Refactor rooms management --- .../src/utils/RoomEventsManager.ts | 5 +- .../widgets/messages/MainMessagesWidget.tsx | 132 ++++++++++++------ .../src/widgets/messages/MatrixWS.tsx | 8 +- .../src/widgets/messages/RoomMessagesList.tsx | 12 +- .../src/widgets/messages/RoomWidget.tsx | 40 +----- 5 files changed, 111 insertions(+), 86 deletions(-) diff --git a/matrixgw_frontend/src/utils/RoomEventsManager.ts b/matrixgw_frontend/src/utils/RoomEventsManager.ts index 1598c95..5a4d041 100644 --- a/matrixgw_frontend/src/utils/RoomEventsManager.ts +++ b/matrixgw_frontend/src/utils/RoomEventsManager.ts @@ -50,7 +50,10 @@ export class RoomEventsManager { } processWsMessage(m: WsMessage) { - if (m.room_id !== this.room.id) return false; + if (m.room_id !== this.room.id) { + console.debug("Not an event for current room."); + return false; + } let data: MatrixEventData; if (m.type === "RoomReactionEvent") { diff --git a/matrixgw_frontend/src/widgets/messages/MainMessagesWidget.tsx b/matrixgw_frontend/src/widgets/messages/MainMessagesWidget.tsx index c268ff2..f6ac333 100644 --- a/matrixgw_frontend/src/widgets/messages/MainMessagesWidget.tsx +++ b/matrixgw_frontend/src/widgets/messages/MainMessagesWidget.tsx @@ -1,5 +1,6 @@ import { Divider } from "@mui/material"; import React from "react"; +import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent"; import { MatrixApiProfile, type UsersMap, @@ -7,6 +8,7 @@ import { import { MatrixApiRoom, type Room } from "../../api/matrix/MatrixApiRoom"; import { MatrixSyncApi } from "../../api/MatrixSyncApi"; import type { WsMessage } from "../../api/WsApi"; +import { RoomEventsManager } from "../../utils/RoomEventsManager"; import { AsyncWidget } from "../AsyncWidget"; import { useUserInfo } from "../dashboard/BaseAuthenticatedPage"; import { MatrixWS } from "./MatrixWS"; @@ -17,9 +19,8 @@ import { SpaceSelector } from "./SpaceSelector"; export function MainMessageWidget(): React.ReactElement { const [rooms, setRooms] = React.useState(); const [users, setUsers] = React.useState(); - const user = useUserInfo(); - const load = async () => { + const loadRoomsList = async () => { await MatrixSyncApi.Start(); const rooms = await MatrixApiRoom.ListJoined(); @@ -34,37 +35,17 @@ export function MainMessageWidget(): React.ReactElement { setUsers(await MatrixApiProfile.GetMultiple([...users])); }; - const handleEvent = (m: WsMessage) => { - // Add a new unread message - if ( - m.type === "RoomMessageEvent" && - !m.data["m.new_content"] && - m.sender !== user.info.matrix_user_id - ) { - setRooms((r) => { - const n = r ? [...r] : undefined; - const idx = n?.findIndex((el) => el.id === m.room_id); - if (idx) - n![idx] = { - ...n![idx], - number_unread_messages: n![idx].number_unread_messages + 1, - }; - return n; - }); - } - }; - return ( ( <_MainMessageWidget rooms={rooms!} users={users!} - onEvent={handleEvent} + onRoomsListUpdate={(cb) => setRooms((r) => cb(r!))} /> )} /> @@ -74,10 +55,12 @@ export function MainMessageWidget(): React.ReactElement { function _MainMessageWidget(p: { rooms: Room[]; users: UsersMap; - onEvent: (m: WsMessage) => void; + onRoomsListUpdate: (cb: (a: Room[]) => Room[]) => void; }): React.ReactElement { + const user = useUserInfo(); + const [space, setSpace] = React.useState(); - const [room, setRoom] = React.useState(); + const [currentRoom, setCurrentRoom] = React.useState(); const spaceRooms = React.useMemo(() => { return p.rooms @@ -87,33 +70,96 @@ function _MainMessageWidget(p: { ); }, [space, p.rooms]); + const [_refreshCount, setRefreshCount] = React.useState(0); + const [roomMgr, setRoomMgr] = React.useState(); + + const loadRoom = async () => { + setRoomMgr(undefined); + if (!currentRoom) { + console.warn("Cannot load manager for no room!"); + return; + } + const messages = await MatrixApiEvent.GetRoomEvents(currentRoom); + const mgr = new RoomEventsManager(currentRoom!, messages); + setRoomMgr(mgr); + }; + + const handleWsEvent = (m: WsMessage) => { + // Process messages for current room + if (roomMgr?.processWsMessage(m)) { + console.info("Current room updated!"); + setRefreshCount((c) => c + 1); + } + + // Add a new unread message on left sidebar + if ( + m.type === "RoomMessageEvent" && + !m.data["m.new_content"] && + m.sender !== user.info.matrix_user_id + ) { + p.onRoomsListUpdate((r) => { + const n = [...r]; + const idx = r.findIndex((el) => el.id === m.room_id); + if (idx) + n[idx] = { + ...n[idx], + number_unread_messages: n[idx].number_unread_messages + 1, + }; + return n; + }); + } + }; + return (
+ {/* Websocket */} +
+ +
+ + {/* Space selector */} + + {/* Separator */} + + {/* Room selector */} + + {/* Separator */} - {room === undefined && ( - <> - -
- No room selected. -
- + + {/* If no room is selected */} + {currentRoom === undefined && ( +
+ No room selected. +
+ )} + + {/* In case of room */} + {currentRoom && ( + ( + + )} + /> )} - {room && }
); } diff --git a/matrixgw_frontend/src/widgets/messages/MatrixWS.tsx b/matrixgw_frontend/src/widgets/messages/MatrixWS.tsx index 169c354..f4d4833 100644 --- a/matrixgw_frontend/src/widgets/messages/MatrixWS.tsx +++ b/matrixgw_frontend/src/widgets/messages/MatrixWS.tsx @@ -15,6 +15,12 @@ export function MatrixWS(p: { }): React.ReactElement { const snackbar = useSnackbar(); + // Keep only the latest version of onMessage + const cbRef = React.useRef(p.onMessage); + React.useEffect(() => { + cbRef.current = p.onMessage; + }, [p.onMessage]); + const [state, setState] = React.useState(State.Closed); const wsId = React.useRef(undefined); const [connCount, setConnCount] = React.useState(0); @@ -46,7 +52,7 @@ export function MatrixWS(p: { const dec = JSON.parse(msg.data); console.info("WS message", dec); - p.onMessage(dec); + cbRef.current(dec); }; return () => ws.close(); diff --git a/matrixgw_frontend/src/widgets/messages/RoomMessagesList.tsx b/matrixgw_frontend/src/widgets/messages/RoomMessagesList.tsx index 9070983..480adc9 100644 --- a/matrixgw_frontend/src/widgets/messages/RoomMessagesList.tsx +++ b/matrixgw_frontend/src/widgets/messages/RoomMessagesList.tsx @@ -38,7 +38,7 @@ import { AccountIcon } from "./AccountIcon"; export function RoomMessagesList(p: { room: Room; users: UsersMap; - mgr: RoomEventsManager; + manager: RoomEventsManager; }): React.ReactElement { const messagesEndRef = React.createRef(); @@ -46,7 +46,7 @@ export function RoomMessagesList(p: { React.useEffect(() => { if (messagesEndRef) messagesEndRef.current?.scrollIntoView({ behavior: "instant" }); - }, [p.mgr.messages.length]); + }, [p.manager.messages.length]); return (
- {p.mgr.messages.map((m, idx) => ( + {p.manager.messages.map((m, idx) => ( 0 && - p.mgr.messages[idx - 1].account === m.account && - m.time_sent - p.mgr.messages[idx - 1].time_sent < 60 * 3 * 1000 + p.manager.messages[idx - 1].account === m.account && + m.time_sent - p.manager.messages[idx - 1].time_sent < 60 * 3 * 1000 } firstMessageOfDay={ idx === 0 || m.time_sent_dayjs.startOf("day").unix() != - p.mgr.messages[idx - 1].time_sent_dayjs.startOf("day").unix() + p.manager.messages[idx - 1].time_sent_dayjs.startOf("day").unix() } /> ))} diff --git a/matrixgw_frontend/src/widgets/messages/RoomWidget.tsx b/matrixgw_frontend/src/widgets/messages/RoomWidget.tsx index c231cce..77d52f1 100644 --- a/matrixgw_frontend/src/widgets/messages/RoomWidget.tsx +++ b/matrixgw_frontend/src/widgets/messages/RoomWidget.tsx @@ -1,49 +1,19 @@ import React from "react"; -import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent"; import type { UsersMap } from "../../api/matrix/MatrixApiProfile"; import type { Room } from "../../api/matrix/MatrixApiRoom"; -import type { WsMessage } from "../../api/WsApi"; import { RoomEventsManager } from "../../utils/RoomEventsManager"; -import { AsyncWidget } from "../AsyncWidget"; -import { MatrixWS } from "./MatrixWS"; import { RoomMessagesList } from "./RoomMessagesList"; import { SendMessageForm } from "./SendMessageForm"; export function RoomWidget(p: { room: Room; users: UsersMap; - onEvent: (m: WsMessage) => void; + manager: RoomEventsManager; }): React.ReactElement { - const [_count, setCount] = React.useState(0); - const [roomMgr, setRoomMgr] = React.useState(); - - const load = async () => { - setRoomMgr(undefined); - const messages = await MatrixApiEvent.GetRoomEvents(p.room); - const mgr = new RoomEventsManager(p.room, messages); - setRoomMgr(mgr); - }; - - const handleNewMessage = (m: WsMessage) => { - if (roomMgr?.processWsMessage(m)) setCount((c) => c + 1); - p.onEvent(m); - }; - return ( - ( -
-
- -
- - -
- )} - /> +
+ + +
); }