@@ -260,6 +260,10 @@ export default function SupportScreen({
260260 streamUserId,
261261} : SupportScreenProps ) {
262262 const { client, setActiveChannel, channel : activeChannel } = useChatContext ( ) ;
263+ const [ messageMatchCids , setMessageMatchCids ] = useState < Set < string > > (
264+ new Set ( )
265+ ) ;
266+ const [ messageSearchPending , setMessageSearchPending ] = useState ( false ) ;
263267 const [ isSupportTutorialActive , setIsSupportTutorialActive ] = useState ( false ) ;
264268 const [ hasSupportTutorialEnded , setHasSupportTutorialEnded ] = useState ( false ) ;
265269 const [ activeTutorialStep , setActiveTutorialStep ] = useState < number | null > (
@@ -598,18 +602,97 @@ export default function SupportScreen({
598602 filters . closed = { $eq : true } ;
599603 }
600604
601- if ( searchQuery . trim ( ) ) {
602- filters . name = { $autocomplete : searchQuery } ;
605+ const trimmedQuery = searchQuery . trim ( ) ;
606+
607+ useEffect ( ( ) => {
608+ if ( ! trimmedQuery ) {
609+ setMessageMatchCids ( new Set ( ) ) ;
610+ setMessageSearchPending ( false ) ;
611+ return ;
612+ }
613+ setMessageSearchPending ( true ) ;
614+ let cancelled = false ;
615+ const timer = setTimeout ( async ( ) => {
616+ try {
617+ const res = await fetch (
618+ `/api/tickets/search?q=${ encodeURIComponent ( trimmedQuery ) } ` ,
619+ { cache : "no-store" }
620+ ) ;
621+ if ( ! res . ok ) throw new Error ( await res . text ( ) ) ;
622+ const data = ( await res . json ( ) ) as { cids ?: unknown } ;
623+ if ( cancelled ) return ;
624+ const cids = new Set < string > ( ) ;
625+ if ( Array . isArray ( data . cids ) ) {
626+ for ( const cid of data . cids ) {
627+ if ( typeof cid === "string" && cid ) cids . add ( cid ) ;
628+ }
629+ }
630+ setMessageMatchCids ( cids ) ;
631+ } catch {
632+ if ( ! cancelled ) setMessageMatchCids ( new Set ( ) ) ;
633+ } finally {
634+ if ( ! cancelled ) setMessageSearchPending ( false ) ;
635+ }
636+ } , 350 ) ;
637+ return ( ) => {
638+ cancelled = true ;
639+ clearTimeout ( timer ) ;
640+ } ;
641+ } , [ trimmedQuery ] ) ;
642+
643+ if ( trimmedQuery ) {
644+ filters . $or = [
645+ { name : { $autocomplete : trimmedQuery } } ,
646+ { partnerName : { $autocomplete : trimmedQuery } } ,
647+ { createdByName : { $autocomplete : trimmedQuery } } ,
648+ ...( messageMatchCids . size > 0
649+ ? [ { cid : { $in : [ ...messageMatchCids ] } } ]
650+ : [ ] ) ,
651+ ] ;
603652 }
604653
605654 const channelRenderFilterFn = ( channels : ChannelType [ ] ) => {
655+ const q = searchQuery . trim ( ) . toLowerCase ( ) ;
606656 return channels . filter ( ( channel ) => {
607657 const channelData = channel . data as ExtraChannelData ;
608- if ( activeTab === "Unresolved" ) {
609- return channelData ?. closed !== true ;
610- } else {
611- return channelData ?. closed === true ;
658+ const isOpen = channelData ?. closed !== true ;
659+ const matchesTab =
660+ activeTab === "Unresolved" ? isOpen : ! isOpen ;
661+ if ( ! matchesTab ) {
662+ return false ;
663+ }
664+ if ( ! q ) {
665+ return true ;
666+ }
667+ const title = String ( channelData ?. name ?? "" ) . toLowerCase ( ) ;
668+ const partner = String (
669+ channelData ?. partnerName ?? ""
670+ ) . toLowerCase ( ) ;
671+ const creator = String (
672+ channelData ?. createdByName ?? ""
673+ ) . toLowerCase ( ) ;
674+ if ( title . includes ( q ) || partner . includes ( q ) || creator . includes ( q ) ) {
675+ return true ;
676+ }
677+ const members = Object . values ( channel . state ?. members ?? { } ) ;
678+ for ( const member of members ) {
679+ const memberName = String (
680+ ( member as { user ?: { name ?: unknown } } ) ?. user ?. name ?? ""
681+ ) . toLowerCase ( ) ;
682+ if ( memberName && memberName . includes ( q ) ) {
683+ return true ;
684+ }
685+ }
686+ const lastText = String (
687+ channel . lastMessage ?.( ) ?. text ?? ""
688+ ) . toLowerCase ( ) ;
689+ if ( lastText && lastText . includes ( q ) ) {
690+ return true ;
691+ }
692+ if ( messageMatchCids . has ( channel . cid ) ) {
693+ return true ;
612694 }
695+ return false ;
613696 } ) ;
614697 } ;
615698
@@ -647,17 +730,27 @@ export default function SupportScreen({
647730 ] }
648731 Preview = { ChannelPreviewWrapper }
649732 Paginator = { InfiniteScroll }
650- EmptyStateIndicator = { ( ) =>
651- isSupportTutorialActive ? null : (
733+ EmptyStateIndicator = { ( ) => {
734+ if ( isSupportTutorialActive ) return null ;
735+ if ( messageSearchPending && trimmedQuery ) {
736+ return (
737+ < div className = "w-full flex flex-col justify-center gap-2 my-8" >
738+ < p className = "text-center text-gray-primary/60" >
739+ Searching messages…
740+ </ p >
741+ </ div >
742+ ) ;
743+ }
744+ return (
652745 < div className = "w-full flex flex-col justify-center gap-2 my-8" >
653746 < ChatCircleSlash
654747 size = { 48 }
655748 className = "mx-auto text-gray-primary/40"
656749 />
657750 < p className = "text-center" > No tickets found.</ p >
658751 </ div >
659- )
660- }
752+ ) ;
753+ } }
661754 />
662755 </ div >
663756 </ div >
0 commit comments