From ef313adcfaf07f204d76b7ca45e61f4abc26a1ae Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 20 May 2026 20:30:41 +0200 Subject: [PATCH] feat(mod-tools): reactive ModToolsUserView (online dot + refresh on sanction) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ModToolsUserView used a one-shot ModeratorUserInfoData snapshot taken at panel-open time. Two consequences: - The online/offline icon (rendered next to userName) was frozen on the value at open. If the target user joined/left while the panel stayed open, the icon kept lying. - After the moderator applied a sanction via ModToolsUserModActionView the user info window stayed open with stale cfhCount / banCount / cautionCount / lastSanctionTime; you had to close and reopen to see the bump. Fix shape mirrors the ModToolsView selected-user dot from yesterday: - Read useRoomUserListSnapshot in the component (outside any useBetween scope — useSyncExternalStore constraint). If the target user is in the current room they're online; fall back to userInfo.online otherwise. Tooltip surfaces which path produced the value. - Subscribe to ModeratorActionResultMessageEvent (parser carries userId + success). On a successful action targeting THIS userId, re-send GetModeratorUserInfoMessageComposer so the table re-fetches. --- .../mod-tools/views/user/ModToolsUserView.tsx | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/components/mod-tools/views/user/ModToolsUserView.tsx b/src/components/mod-tools/views/user/ModToolsUserView.tsx index 6f65700..8a2620d 100644 --- a/src/components/mod-tools/views/user/ModToolsUserView.tsx +++ b/src/components/mod-tools/views/user/ModToolsUserView.tsx @@ -1,8 +1,8 @@ -import { CreateLinkEvent, GetModeratorUserInfoMessageComposer, ModeratorUserInfoData, ModeratorUserInfoEvent } from '@nitrots/nitro-renderer'; +import { CreateLinkEvent, GetModeratorUserInfoMessageComposer, ModeratorActionResultMessageEvent, ModeratorUserInfoData, ModeratorUserInfoEvent } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useState } from 'react'; import { FriendlyTime, LocalizeText, SendMessageComposer } from '../../../../api'; import { Button, Column, DraggableWindowPosition, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; -import { useMessageEvent } from '../../../../hooks'; +import { useMessageEvent, useRoomUserListSnapshot } from '../../../../hooks'; import { ModToolsUserModActionView } from './ModToolsUserModActionView'; import { ModToolsUserRoomVisitsView } from './ModToolsUserRoomVisitsView'; import { ModToolsUserSendMessageView } from './ModToolsUserSendMessageView'; @@ -20,6 +20,15 @@ export const ModToolsUserView: FC = props => const [ sendMessageVisible, setSendMessageVisible ] = useState(false); const [ modActionVisible, setModActionVisible ] = useState(false); const [ roomVisitsVisible, setRoomVisitsVisible ] = useState(false); + // Reactive presence: if the target user is currently in the room + // we're observing, they're online — irrespective of what the + // one-shot ModeratorUserInfoData.online said when the panel opened. + const roomUserList = useRoomUserListSnapshot(); + const isPresentInCurrentRoom = useMemo( + () => roomUserList.some(user => user && (user.webID === userId)), + [ roomUserList, userId ] + ); + const isOnline = isPresentInCurrentRoom || !!(userInfo && userInfo.online); const userProperties = useMemo(() => { @@ -95,6 +104,19 @@ export const ModToolsUserView: FC = props => setUserInfo(parser.data); }); + // Refresh counters (cfhCount / banCount / cautionCount / + // lastSanctionTime) after the moderator applies a sanction on THIS + // user — otherwise the table stays frozen on the values at panel + // open. Parser carries userId so we can filter precisely. + useMessageEvent(ModeratorActionResultMessageEvent, event => + { + const parser = event.getParser(); + + if(!parser || !parser.success || parser.userId !== userId) return; + + SendMessageComposer(new GetModeratorUserInfoMessageComposer(userId)); + }); + useEffect(() => { SendMessageComposer(new GetModeratorUserInfoMessageComposer(userId)); @@ -120,7 +142,7 @@ export const ModToolsUserView: FC = props => { property.value } { property.showOnline && - } + } );