diff --git a/src/api/nitro-query/createNitroQuery.ts b/src/api/nitro-query/createNitroQuery.ts index 1bf73ff..44a570f 100644 --- a/src/api/nitro-query/createNitroQuery.ts +++ b/src/api/nitro-query/createNitroQuery.ts @@ -23,6 +23,14 @@ export interface NitroQueryConfig * Maps the parser event to the data the component cares about. */ select?: (event: TParser) => TData; + /** + * Optional predicate to ignore parser events that don't match this + * query (typically used as a correlation-key filter on a globally + * shared event stream — e.g. `e => e.getParser()?.roomId === roomId`). + * When the predicate returns false, the listener stays registered + * and keeps waiting; the timeout still applies. + */ + accept?: (event: TParser) => boolean; /** * Max time to wait for the response before rejecting (default 15s). */ @@ -52,11 +60,11 @@ export const useNitroQuery = ( config: NitroQueryConfig ): UseQueryResult => { - const { key, request, parser, select, timeoutMs = 15_000, enabled, staleTime, refetchOnMount } = config; + const { key, request, parser, select, accept, timeoutMs = 15_000, enabled, staleTime, refetchOnMount } = config; const options: UseQueryOptions = { queryKey: key, - queryFn: () => awaitNitroResponse({ key, request, parser, select, timeoutMs }), + queryFn: () => awaitNitroResponse({ key, request, parser, select, accept, timeoutMs }), enabled, staleTime, refetchOnMount @@ -71,11 +79,11 @@ export const useNitroQuery = ( * can use the same plumbing imperatively. */ export const awaitNitroResponse = ( - config: Pick, 'request' | 'parser' | 'select' | 'timeoutMs'> + config: Pick, 'request' | 'parser' | 'select' | 'accept' | 'timeoutMs'> ): Promise => new Promise((resolve, reject) => { - const { request, parser: ParserCtor, select, timeoutMs = 15_000 } = config; + const { request, parser: ParserCtor, select, accept, timeoutMs = 15_000 } = config; let settled = false; let timeoutHandle: ReturnType | null = null; @@ -90,6 +98,7 @@ export const awaitNitroResponse = ( listener = new (ParserCtor as any)((event: TParser) => { if(settled) return; + if(accept && !accept(event)) return; settled = true; cleanup(); diff --git a/src/components/mod-tools/views/room/ModToolsChatlogView.tsx b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx index b3a4a39..65061be 100644 --- a/src/components/mod-tools/views/room/ModToolsChatlogView.tsx +++ b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx @@ -1,8 +1,7 @@ import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useState } from 'react'; -import { SendMessageComposer } from '../../../../api'; +import { FC } from 'react'; +import { useNitroQuery } from '../../../../api/nitro-query'; import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; -import { useMessageEvent } from '../../../../hooks'; import { ChatlogView } from '../chatlog/ChatlogView'; interface ModToolsChatlogViewProps @@ -14,22 +13,16 @@ interface ModToolsChatlogViewProps export const ModToolsChatlogView: FC = props => { const { roomId = null, onCloseClick = null } = props; - const [ roomChatlog, setRoomChatlog ] = useState(null); - useMessageEvent(RoomChatlogEvent, event => - { - const parser = event.getParser(); - - if(!parser || parser.data.roomId !== roomId) return; - - setRoomChatlog(parser.data); + const { data: roomChatlog } = useNitroQuery({ + key: [ 'nitro', 'mod-tools', 'room-chatlog', roomId ], + request: () => new GetRoomChatlogMessageComposer(roomId), + parser: RoomChatlogEvent, + accept: e => e.getParser()?.data.roomId === roomId, + select: e => e.getParser().data, + enabled: roomId !== null }); - useEffect(() => - { - SendMessageComposer(new GetRoomChatlogMessageComposer(roomId)); - }, [ roomId ]); - if(!roomChatlog) return null; return ( diff --git a/src/components/mod-tools/views/tickets/CfhChatlogView.tsx b/src/components/mod-tools/views/tickets/CfhChatlogView.tsx index 9923fa9..33cc52d 100644 --- a/src/components/mod-tools/views/tickets/CfhChatlogView.tsx +++ b/src/components/mod-tools/views/tickets/CfhChatlogView.tsx @@ -1,8 +1,7 @@ import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useState } from 'react'; -import { SendMessageComposer } from '../../../../api'; +import { FC } from 'react'; +import { useNitroQuery } from '../../../../api/nitro-query'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; -import { useMessageEvent } from '../../../../hooks'; import { ChatlogView } from '../chatlog/ChatlogView'; interface CfhChatlogViewProps @@ -14,22 +13,16 @@ interface CfhChatlogViewProps export const CfhChatlogView: FC = props => { const { onCloseClick = null, issueId = null } = props; - const [ chatlogData, setChatlogData ] = useState(null); - useMessageEvent(CfhChatlogEvent, event => - { - const parser = event.getParser(); - - if(!parser || parser.data.issueId !== issueId) return; - - setChatlogData(parser.data); + const { data: chatlogData } = useNitroQuery({ + key: [ 'nitro', 'mod-tools', 'cfh-chatlog', issueId ], + request: () => new GetCfhChatlogMessageComposer(issueId), + parser: CfhChatlogEvent, + accept: e => e.getParser()?.data.issueId === issueId, + select: e => e.getParser().data, + enabled: issueId !== null }); - useEffect(() => - { - SendMessageComposer(new GetCfhChatlogMessageComposer(issueId)); - }, [ issueId ]); - return (