1- import React , {
2- useRef ,
3- useState ,
4- useReducer ,
5- } from 'react' ;
6- import { SendbirdError } from '@sendbird/chat' ;
7- import type { MessageSearchQuery } from '@sendbird/chat/message' ;
1+ import React , { createContext , useRef , useContext , useCallback , useEffect } from 'react' ;
82import type { GroupChannel } from '@sendbird/chat/groupChannel' ;
3+ import { MessageSearchQuery } from '@sendbird/chat/message' ;
4+ import { ClientSentMessages } from '../../../types' ;
5+ import { SendbirdError } from '@sendbird/chat' ;
96import type { MessageSearchQueryParams } from '@sendbird/chat/lib/__definition' ;
107
118import useSendbirdStateContext from '../../../hooks/useSendbirdStateContext' ;
12- import { ClientSentMessages } from '../../../types' ;
13-
14- import messageSearchReducer from './dux/reducers' ;
15- import messageSearchInitialState , { State as MessageSearchReducerState } from './dux/initialState' ;
169
1710import useSetChannel from './hooks/useSetChannel' ;
1811import useGetSearchMessages from './hooks/useGetSearchedMessages' ;
19- import useScrollCallback , {
20- CallbackReturn as UseScrollCallbackType ,
21- } from './hooks/useScrollCallback' ;
12+ import useScrollCallback from './hooks/useScrollCallback' ;
2213import useSearchStringEffect from './hooks/useSearchStringEffect' ;
2314import { CoreMessageType } from '../../../utils' ;
15+ import { createStore } from '../../../utils/storeManager' ;
16+ import { useStore } from '../../../hooks/useStore' ;
2417
2518export interface MessageSearchProviderProps {
2619 channelUrl : string ;
@@ -31,130 +24,160 @@ export interface MessageSearchProviderProps {
3124 onResultClick ?( message : ClientSentMessages ) : void ;
3225}
3326
34- interface MessageSearchProviderInterface extends MessageSearchProviderProps {
35- requestString ?: string ;
36- retryCount : number ;
37- setRetryCount : React . Dispatch < React . SetStateAction < number > > ;
38- selectedMessageId : number ;
39- setSelectedMessageId : React . Dispatch < React . SetStateAction < number > > ;
40- messageSearchDispatcher : ( props : { type : string , payload : any } ) => void ;
41- scrollRef : React . RefObject < HTMLDivElement > ;
42- allMessages : MessageSearchReducerState [ 'allMessages' ] ;
27+ export interface MessageSearchState extends MessageSearchProviderProps {
28+ channelUrl : string ;
29+ allMessages : ClientSentMessages [ ] ;
4330 loading : boolean ;
4431 isInvalid : boolean ;
45- currentChannel : GroupChannel ;
46- currentMessageSearchQuery : MessageSearchQuery ;
32+ initialized : boolean ;
33+ currentChannel : GroupChannel | null ;
34+ currentMessageSearchQuery : MessageSearchQuery | null ;
4735 hasMoreResult : boolean ;
48- onScroll : UseScrollCallbackType ;
49- handleRetryToConnect : ( ) => void ;
50- handleOnScroll : ( e : React . BaseSyntheticEvent ) => void ;
36+ retryCount : number ;
37+ selectedMessageId : number | null ;
38+ requestString : string ;
39+ onScroll ?: ReturnType < typeof useScrollCallback > ;
40+ handleOnScroll ?: ( e : React . BaseSyntheticEvent ) => void ;
41+ scrollRef ?: React . RefObject < HTMLDivElement > ;
5142}
5243
53- const MessageSearchContext = React . createContext < MessageSearchProviderInterface | null > ( null ) ;
54-
55- const MessageSearchProvider : React . FC < MessageSearchProviderProps > = ( props : MessageSearchProviderProps ) => {
56- const {
57- // message search props
58- channelUrl,
59- searchString,
60- messageSearchQuery,
61- onResultLoaded,
62- onResultClick,
63- } = props ;
64-
65- const globalState = useSendbirdStateContext ( ) ;
66-
67- // hook variables
68- const [ retryCount , setRetryCount ] = useState ( 0 ) ; // this is a trigger flag for activating useGetSearchMessages
69- const [ selectedMessageId , setSelectedMessageId ] = useState ( 0 ) ;
70- const [ messageSearchStore , messageSearchDispatcher ] = useReducer ( messageSearchReducer , messageSearchInitialState ) ;
71- const {
72- allMessages,
73- loading,
74- isInvalid,
75- currentChannel,
76- currentMessageSearchQuery,
77- hasMoreResult,
78- } = messageSearchStore ;
79-
80- const logger = globalState ?. config ?. logger ;
81- const sdk = globalState ?. stores ?. sdkStore ?. sdk ;
82- const sdkInit = globalState ?. stores ?. sdkStore ?. initialized ;
83- const scrollRef = useRef < HTMLDivElement > ( null ) ;
84- const handleOnScroll = ( e : React . BaseSyntheticEvent ) => {
85- const scrollElement = e . target as HTMLDivElement ;
86- const {
87- scrollTop,
88- scrollHeight,
89- clientHeight,
90- } = scrollElement ;
44+ const initialState : MessageSearchState = {
45+ channelUrl : '' ,
46+ allMessages : [ ] ,
47+ loading : false ,
48+ isInvalid : false ,
49+ initialized : false ,
50+ currentChannel : null ,
51+ currentMessageSearchQuery : null ,
52+ messageSearchQuery : null ,
53+ hasMoreResult : false ,
54+ retryCount : 0 ,
55+ selectedMessageId : null ,
56+ searchString : '' ,
57+ requestString : '' ,
58+ } ;
9159
92- if ( ! hasMoreResult ) {
93- return ;
94- }
95- if ( scrollTop + clientHeight >= scrollHeight ) {
96- onScroll ( ( ) => {
97- // after load more searched messages
98- } ) ;
99- }
100- } ;
60+ export const MessageSearchContext = createContext < ReturnType < typeof createStore < MessageSearchState > > | null > ( null ) ;
61+
62+ const MessageSearchManager : React . FC < MessageSearchProviderProps > = ( {
63+ channelUrl,
64+ searchString,
65+ messageSearchQuery,
66+ onResultLoaded,
67+ onResultClick,
68+ } ) => {
69+ const { state, updateState } = useMessageSearchStore ( ) ;
70+ const { config, stores } = useSendbirdStateContext ( ) ;
71+ const sdk = stores ?. sdkStore ?. sdk ;
72+ const sdkInit = stores ?. sdkStore ?. initialized ;
73+ const { logger } = config ;
74+ const scrollRef = useRef < HTMLDivElement > ( null ) ;
10175
10276 useSetChannel (
10377 { channelUrl, sdkInit } ,
104- { sdk, logger, messageSearchDispatcher } ,
78+ { sdk, logger } ,
10579 ) ;
10680
107- const requestString = useSearchStringEffect ( { searchString : searchString ?? '' } , { messageSearchDispatcher } ) ;
81+ const requestString = useSearchStringEffect (
82+ { searchString : searchString ?? '' } ,
83+ ) ;
10884
10985 useGetSearchMessages (
110- { currentChannel, channelUrl, requestString, messageSearchQuery, onResultLoaded, retryCount } ,
111- { sdk, logger, messageSearchDispatcher } ,
86+ {
87+ currentChannel : state . currentChannel ,
88+ channelUrl,
89+ requestString,
90+ messageSearchQuery,
91+ onResultLoaded,
92+ } ,
93+ { sdk, logger } ,
11294 ) ;
11395
11496 const onScroll = useScrollCallback (
115- { currentMessageSearchQuery , hasMoreResult , onResultLoaded } ,
116- { logger, messageSearchDispatcher } ,
97+ { onResultLoaded } ,
98+ { logger } ,
11799 ) ;
118100
119- const handleRetryToConnect = ( ) => {
120- setRetryCount ( retryCount + 1 ) ;
121- } ;
122- return (
123- < MessageSearchContext . Provider value = { {
101+ const handleOnScroll = useCallback ( ( e : React . BaseSyntheticEvent ) => {
102+ const scrollElement = e . target as HTMLDivElement ;
103+ const { scrollTop, scrollHeight, clientHeight } = scrollElement ;
104+
105+ if ( ! state . hasMoreResult ) {
106+ return ;
107+ }
108+ if ( scrollTop + clientHeight >= scrollHeight ) {
109+ onScroll ( ( ) => {
110+ // after load more searched messages
111+ } ) ;
112+ }
113+ } , [ state . hasMoreResult , onScroll ] ) ;
114+
115+ useEffect ( ( ) => {
116+ updateState ( {
124117 channelUrl,
125118 searchString,
126- requestString,
127119 messageSearchQuery,
128- onResultLoaded,
129120 onResultClick,
130- retryCount,
131- setRetryCount,
132- selectedMessageId,
133- setSelectedMessageId,
134- messageSearchDispatcher,
135- allMessages,
136- loading,
137- isInvalid,
138- currentChannel,
139- currentMessageSearchQuery,
140- hasMoreResult,
141121 onScroll,
142- scrollRef,
143- handleRetryToConnect,
144122 handleOnScroll,
145- } } >
146- { props ?. children }
123+ scrollRef,
124+ requestString,
125+ } ) ;
126+ } , [ channelUrl , searchString , messageSearchQuery , onResultClick , updateState , requestString ] ) ;
127+
128+ return null ;
129+ } ;
130+
131+ const createMessageSearchStore = ( ) => createStore ( initialState ) ;
132+ const InternalMessageSearchProvider : React . FC < React . PropsWithChildren < unknown > > = ( { children } ) => {
133+ const storeRef = useRef ( createMessageSearchStore ( ) ) ;
134+
135+ return (
136+ < MessageSearchContext . Provider value = { storeRef . current } >
137+ { children }
147138 </ MessageSearchContext . Provider >
148139 ) ;
149140} ;
150141
142+ const MessageSearchProvider : React . FC < MessageSearchProviderProps > = ( {
143+ children,
144+ channelUrl,
145+ searchString,
146+ messageSearchQuery,
147+ onResultLoaded,
148+ onResultClick,
149+ } ) => {
150+
151+ return (
152+ < InternalMessageSearchProvider >
153+ < MessageSearchManager
154+ channelUrl = { channelUrl }
155+ searchString = { searchString }
156+ messageSearchQuery = { messageSearchQuery }
157+ onResultLoaded = { onResultLoaded }
158+ onResultClick = { onResultClick }
159+ />
160+ { children }
161+ </ InternalMessageSearchProvider >
162+ ) ;
163+ } ;
164+
151165const useMessageSearchContext = ( ) => {
152- const context = React . useContext ( MessageSearchContext ) ;
166+ const context = useContext ( MessageSearchContext ) ;
153167 if ( ! context ) throw new Error ( 'MessageSearchContext not found. Use within the MessageSearch module.' ) ;
154168 return context ;
155169} ;
156170
157171export {
158172 MessageSearchProvider ,
159173 useMessageSearchContext ,
174+ MessageSearchManager ,
175+ } ;
176+
177+ /**
178+ * A specialized hook for MessageSearch state management
179+ * @returns {ReturnType<typeof createStore<MessageSearchState>> }
180+ */
181+ const useMessageSearchStore = ( ) => {
182+ return useStore ( MessageSearchContext , state => state , initialState ) ;
160183} ;
0 commit comments