@droppii-org/chat-sdk 0.7.7 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/components/conversation/ThreadCard.d.ts +2 -1
  2. package/dist/components/conversation/ThreadCard.d.ts.map +1 -1
  3. package/dist/components/conversation/ThreadCard.js +2 -2
  4. package/dist/components/conversation-detail/ConversationDetailHeader.d.ts +5 -1
  5. package/dist/components/conversation-detail/ConversationDetailHeader.d.ts.map +1 -1
  6. package/dist/components/conversation-detail/ConversationDetailHeader.js +3 -3
  7. package/dist/components/conversation-detail/ConversationMoreOptionPanel.d.ts.map +1 -1
  8. package/dist/components/conversation-detail/ConversationMoreOptionPanel.js +3 -1
  9. package/dist/components/conversation-detail/ThreadProfilePanel.d.ts +7 -1
  10. package/dist/components/conversation-detail/ThreadProfilePanel.d.ts.map +1 -1
  11. package/dist/components/conversation-detail/ThreadProfilePanel.js +13 -3
  12. package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts +7 -0
  13. package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts.map +1 -0
  14. package/dist/components/conversation-detail/profile/PinThreadLimitModal.js +14 -0
  15. package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts +15 -0
  16. package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts.map +1 -0
  17. package/dist/components/conversation-detail/profile/ThreadProfileActionRows.js +20 -0
  18. package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts +13 -0
  19. package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts.map +1 -0
  20. package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.js +36 -0
  21. package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts +13 -0
  22. package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts.map +1 -0
  23. package/dist/components/conversation-detail/thread-search/ThreadSearchContent.js +70 -0
  24. package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts +11 -0
  25. package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts.map +1 -0
  26. package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.js +12 -0
  27. package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts +11 -0
  28. package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts.map +1 -0
  29. package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.js +24 -0
  30. package/dist/components/conversation-detail/thread-search/utils.d.ts +8 -0
  31. package/dist/components/conversation-detail/thread-search/utils.d.ts.map +1 -0
  32. package/dist/components/conversation-detail/thread-search/utils.js +17 -0
  33. package/dist/components/conversation-inbox/ConversationInboxItem.d.ts +3 -1
  34. package/dist/components/conversation-inbox/ConversationInboxItem.d.ts.map +1 -1
  35. package/dist/components/conversation-inbox/ConversationInboxItem.js +4 -6
  36. package/dist/components/conversation-inbox/ConversationInboxList.d.ts +3 -1
  37. package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
  38. package/dist/components/conversation-inbox/ConversationInboxList.js +2 -2
  39. package/dist/components/conversation-inbox/ConversationThreadActions.d.ts +12 -0
  40. package/dist/components/conversation-inbox/ConversationThreadActions.d.ts.map +1 -0
  41. package/dist/components/conversation-inbox/ConversationThreadActions.js +58 -0
  42. package/dist/components/conversation-inbox/index.d.ts +2 -2
  43. package/dist/components/conversation-inbox/index.d.ts.map +1 -1
  44. package/dist/components/conversation-inbox/index.js +1 -1
  45. package/dist/components/group/MemberPermissionPanel.d.ts.map +1 -1
  46. package/dist/components/group/MemberPermissionPanel.js +12 -23
  47. package/dist/components/message/toolbox/MessageToolboxMenu.d.ts +7 -0
  48. package/dist/components/message/toolbox/MessageToolboxMenu.d.ts.map +1 -1
  49. package/dist/components/message/toolbox/MessageToolboxMenu.js +1 -1
  50. package/dist/constants/moreOption.d.ts +1 -0
  51. package/dist/constants/moreOption.d.ts.map +1 -1
  52. package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
  53. package/dist/hooks/conversation/useBotFlow.js +42 -23
  54. package/dist/hooks/conversation/useConversationTarget.d.ts +4 -0
  55. package/dist/hooks/conversation/useConversationTarget.d.ts.map +1 -0
  56. package/dist/hooks/conversation/useConversationTarget.js +23 -0
  57. package/dist/hooks/conversation/usePinConversation.d.ts +10 -0
  58. package/dist/hooks/conversation/usePinConversation.d.ts.map +1 -0
  59. package/dist/hooks/conversation/usePinConversation.js +52 -0
  60. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  61. package/dist/hooks/global/useGlobalEvent.js +3 -0
  62. package/dist/hooks/group/useJoinPublicGroup.d.ts.map +1 -1
  63. package/dist/hooks/group/useJoinPublicGroup.js +9 -1
  64. package/dist/hooks/message/holdMessageHighlight.d.ts +6 -0
  65. package/dist/hooks/message/holdMessageHighlight.d.ts.map +1 -0
  66. package/dist/hooks/message/holdMessageHighlight.js +22 -0
  67. package/dist/hooks/message/useMessage.d.ts +1 -0
  68. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  69. package/dist/hooks/message/useMessage.js +14 -9
  70. package/dist/hooks/message/useMessageListScroll.d.ts +3 -1
  71. package/dist/hooks/message/useMessageListScroll.d.ts.map +1 -1
  72. package/dist/hooks/message/useMessageListScroll.js +35 -3
  73. package/dist/hooks/message/useSendMessage.d.ts +1 -1
  74. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  75. package/dist/hooks/message/useSendMessage.js +358 -285
  76. package/dist/hooks/search/useSearchThreadMessages.d.ts +222 -0
  77. package/dist/hooks/search/useSearchThreadMessages.d.ts.map +1 -0
  78. package/dist/hooks/search/useSearchThreadMessages.js +60 -0
  79. package/dist/locales/vi/conversation-inbox.json +31 -0
  80. package/dist/screens/conversation-detail/index.d.ts +5 -1
  81. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  82. package/dist/screens/conversation-detail/index.js +29 -3
  83. package/dist/screens/conversation-inbox/index.d.ts +6 -0
  84. package/dist/screens/conversation-inbox/index.d.ts.map +1 -1
  85. package/dist/screens/conversation-inbox/index.js +3 -3
  86. package/dist/services/query.d.ts +3 -0
  87. package/dist/services/query.d.ts.map +1 -1
  88. package/dist/services/query.js +3 -0
  89. package/dist/services/routes.d.ts +2 -0
  90. package/dist/services/routes.d.ts.map +1 -1
  91. package/dist/services/routes.js +2 -0
  92. package/dist/store/conversation.d.ts.map +1 -1
  93. package/dist/store/conversation.js +10 -6
  94. package/dist/store/type.d.ts +3 -0
  95. package/dist/store/type.d.ts.map +1 -1
  96. package/dist/styles/global.css +1 -1
  97. package/dist/types/conversation.d.ts +8 -0
  98. package/dist/types/conversation.d.ts.map +1 -1
  99. package/dist/utils/common.d.ts +7 -0
  100. package/dist/utils/common.d.ts.map +1 -1
  101. package/dist/utils/common.js +42 -13
  102. package/dist/utils/sendQueue.d.ts +2 -0
  103. package/dist/utils/sendQueue.d.ts.map +1 -0
  104. package/dist/utils/sendQueue.js +14 -0
  105. package/package.json +1 -1
  106. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts +0 -8
  107. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts.map +0 -1
  108. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.js +0 -31
@@ -0,0 +1,222 @@
1
+ import { MessageType } from "@droppii-org/wasm-client-sdk";
2
+ import type { PagedMessageResponse } from "../../types/dto";
3
+ export declare const THREAD_SEARCH_CONTENT_TYPES: MessageType[];
4
+ /** Messages of one conversation matching `searchTerm`, newest first (app endpoint). */
5
+ export declare const useSearchThreadMessages: (conversationId: string, searchTerm: string) => {
6
+ results: import("../../types/dto").MessageResultItem[];
7
+ data: import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>;
8
+ error: Error;
9
+ isError: true;
10
+ isPending: false;
11
+ isLoading: false;
12
+ isLoadingError: false;
13
+ isRefetchError: true;
14
+ isSuccess: false;
15
+ isPlaceholderData: false;
16
+ status: "error";
17
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
18
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
19
+ hasNextPage: boolean;
20
+ hasPreviousPage: boolean;
21
+ isFetchNextPageError: boolean;
22
+ isFetchingNextPage: boolean;
23
+ isFetchPreviousPageError: boolean;
24
+ isFetchingPreviousPage: boolean;
25
+ dataUpdatedAt: number;
26
+ errorUpdatedAt: number;
27
+ failureCount: number;
28
+ failureReason: Error | null;
29
+ errorUpdateCount: number;
30
+ isFetched: boolean;
31
+ isFetchedAfterMount: boolean;
32
+ isFetching: boolean;
33
+ isInitialLoading: boolean;
34
+ isPaused: boolean;
35
+ isRefetching: boolean;
36
+ isStale: boolean;
37
+ isEnabled: boolean;
38
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
39
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
40
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
41
+ } | {
42
+ results: import("../../types/dto").MessageResultItem[];
43
+ data: import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>;
44
+ error: null;
45
+ isError: false;
46
+ isPending: false;
47
+ isLoading: false;
48
+ isLoadingError: false;
49
+ isRefetchError: false;
50
+ isFetchNextPageError: false;
51
+ isFetchPreviousPageError: false;
52
+ isSuccess: true;
53
+ isPlaceholderData: false;
54
+ status: "success";
55
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
56
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
57
+ hasNextPage: boolean;
58
+ hasPreviousPage: boolean;
59
+ isFetchingNextPage: boolean;
60
+ isFetchingPreviousPage: boolean;
61
+ dataUpdatedAt: number;
62
+ errorUpdatedAt: number;
63
+ failureCount: number;
64
+ failureReason: Error | null;
65
+ errorUpdateCount: number;
66
+ isFetched: boolean;
67
+ isFetchedAfterMount: boolean;
68
+ isFetching: boolean;
69
+ isInitialLoading: boolean;
70
+ isPaused: boolean;
71
+ isRefetching: boolean;
72
+ isStale: boolean;
73
+ isEnabled: boolean;
74
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
75
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
76
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
77
+ } | {
78
+ results: import("../../types/dto").MessageResultItem[];
79
+ data: undefined;
80
+ error: Error;
81
+ isError: true;
82
+ isPending: false;
83
+ isLoading: false;
84
+ isLoadingError: true;
85
+ isRefetchError: false;
86
+ isFetchNextPageError: false;
87
+ isFetchPreviousPageError: false;
88
+ isSuccess: false;
89
+ isPlaceholderData: false;
90
+ status: "error";
91
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
92
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
93
+ hasNextPage: boolean;
94
+ hasPreviousPage: boolean;
95
+ isFetchingNextPage: boolean;
96
+ isFetchingPreviousPage: boolean;
97
+ dataUpdatedAt: number;
98
+ errorUpdatedAt: number;
99
+ failureCount: number;
100
+ failureReason: Error | null;
101
+ errorUpdateCount: number;
102
+ isFetched: boolean;
103
+ isFetchedAfterMount: boolean;
104
+ isFetching: boolean;
105
+ isInitialLoading: boolean;
106
+ isPaused: boolean;
107
+ isRefetching: boolean;
108
+ isStale: boolean;
109
+ isEnabled: boolean;
110
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
111
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
112
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
113
+ } | {
114
+ results: import("../../types/dto").MessageResultItem[];
115
+ data: undefined;
116
+ error: null;
117
+ isError: false;
118
+ isPending: true;
119
+ isLoading: true;
120
+ isLoadingError: false;
121
+ isRefetchError: false;
122
+ isFetchNextPageError: false;
123
+ isFetchPreviousPageError: false;
124
+ isSuccess: false;
125
+ isPlaceholderData: false;
126
+ status: "pending";
127
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
128
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
129
+ hasNextPage: boolean;
130
+ hasPreviousPage: boolean;
131
+ isFetchingNextPage: boolean;
132
+ isFetchingPreviousPage: boolean;
133
+ dataUpdatedAt: number;
134
+ errorUpdatedAt: number;
135
+ failureCount: number;
136
+ failureReason: Error | null;
137
+ errorUpdateCount: number;
138
+ isFetched: boolean;
139
+ isFetchedAfterMount: boolean;
140
+ isFetching: boolean;
141
+ isInitialLoading: boolean;
142
+ isPaused: boolean;
143
+ isRefetching: boolean;
144
+ isStale: boolean;
145
+ isEnabled: boolean;
146
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
147
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
148
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
149
+ } | {
150
+ results: import("../../types/dto").MessageResultItem[];
151
+ data: undefined;
152
+ error: null;
153
+ isError: false;
154
+ isPending: true;
155
+ isLoadingError: false;
156
+ isRefetchError: false;
157
+ isFetchNextPageError: false;
158
+ isFetchPreviousPageError: false;
159
+ isSuccess: false;
160
+ isPlaceholderData: false;
161
+ status: "pending";
162
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
163
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
164
+ hasNextPage: boolean;
165
+ hasPreviousPage: boolean;
166
+ isFetchingNextPage: boolean;
167
+ isFetchingPreviousPage: boolean;
168
+ dataUpdatedAt: number;
169
+ errorUpdatedAt: number;
170
+ failureCount: number;
171
+ failureReason: Error | null;
172
+ errorUpdateCount: number;
173
+ isFetched: boolean;
174
+ isFetchedAfterMount: boolean;
175
+ isFetching: boolean;
176
+ isLoading: boolean;
177
+ isInitialLoading: boolean;
178
+ isPaused: boolean;
179
+ isRefetching: boolean;
180
+ isStale: boolean;
181
+ isEnabled: boolean;
182
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
183
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
184
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
185
+ } | {
186
+ results: import("../../types/dto").MessageResultItem[];
187
+ data: import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>;
188
+ isError: false;
189
+ error: null;
190
+ isPending: false;
191
+ isLoading: false;
192
+ isLoadingError: false;
193
+ isRefetchError: false;
194
+ isSuccess: true;
195
+ isPlaceholderData: true;
196
+ isFetchNextPageError: false;
197
+ isFetchPreviousPageError: false;
198
+ status: "success";
199
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
200
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
201
+ hasNextPage: boolean;
202
+ hasPreviousPage: boolean;
203
+ isFetchingNextPage: boolean;
204
+ isFetchingPreviousPage: boolean;
205
+ dataUpdatedAt: number;
206
+ errorUpdatedAt: number;
207
+ failureCount: number;
208
+ failureReason: Error | null;
209
+ errorUpdateCount: number;
210
+ isFetched: boolean;
211
+ isFetchedAfterMount: boolean;
212
+ isFetching: boolean;
213
+ isInitialLoading: boolean;
214
+ isPaused: boolean;
215
+ isRefetching: boolean;
216
+ isStale: boolean;
217
+ isEnabled: boolean;
218
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>, Error>>;
219
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
220
+ promise: Promise<import("@tanstack/react-query").InfiniteData<PagedMessageResponse, unknown>>;
221
+ };
222
+ //# sourceMappingURL=useSearchThreadMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSearchThreadMessages.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/useSearchThreadMessages.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAM3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,eAAO,MAAM,2BAA2B,eAKvC,CAAC;AAIF,uFAAuF;AACvF,eAAO,MAAM,uBAAuB,GAClC,gBAAgB,MAAM,EACtB,YAAY,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CnB,CAAC"}
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { useInfiniteQuery } from "@tanstack/react-query";
4
+ import { MessageType } from "@droppii-org/wasm-client-sdk";
5
+ import { PAGE_SIZE } from "../../constants";
6
+ import { apiInstance } from "../../services/api";
7
+ import { QUERY_KEYS } from "../../services/query";
8
+ import { ENDPOINTS } from "../../services/routes";
9
+ import useAuthStore from "../../store/auth";
10
+ // Text, link, quote and mention messages; media, stickers and system messages are not searchable.
11
+ export const THREAD_SEARCH_CONTENT_TYPES = [
12
+ MessageType.TextMessage,
13
+ MessageType.UrlTextMessage,
14
+ MessageType.QuoteMessage,
15
+ MessageType.AtTextMessage,
16
+ ];
17
+ const THREAD_SEARCH_PAGE_SIZE = PAGE_SIZE.medium;
18
+ /** Messages of one conversation matching `searchTerm`, newest first (app endpoint). */
19
+ export const useSearchThreadMessages = (conversationId, searchTerm) => {
20
+ const term = searchTerm.trim();
21
+ const query = useInfiniteQuery({
22
+ initialPageParam: 1,
23
+ queryKey: [QUERY_KEYS.SEARCH_THREAD_MESSAGES, conversationId, term],
24
+ queryFn: async ({ pageParam }) => {
25
+ const res = await apiInstance.post(ENDPOINTS.chatService.searchAppMessages, {
26
+ conversationId,
27
+ searchTerm: term,
28
+ contentTypes: THREAD_SEARCH_CONTENT_TYPES,
29
+ page: pageParam,
30
+ pageSize: THREAD_SEARCH_PAGE_SIZE,
31
+ applicationType: useAuthStore.getState().applicationType,
32
+ });
33
+ return res.data;
34
+ },
35
+ // The endpoint leaves totalElements at 0, so a short page marks the end.
36
+ getNextPageParam: (lastPage, pages) => {
37
+ var _a, _b;
38
+ return ((_b = (_a = lastPage === null || lastPage === void 0 ? void 0 : lastPage.data) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) < THREAD_SEARCH_PAGE_SIZE
39
+ ? undefined
40
+ : pages.length + 1;
41
+ },
42
+ enabled: !!conversationId && term !== "",
43
+ retry: false,
44
+ refetchOnWindowFocus: false,
45
+ });
46
+ // New messages shift the offset pages, so a hit can come back on the next page too.
47
+ const results = useMemo(() => {
48
+ var _a, _b;
49
+ const seen = new Set();
50
+ return ((_b = (_a = query.data) === null || _a === void 0 ? void 0 : _a.pages.flatMap((page) => { var _a; return (_a = page === null || page === void 0 ? void 0 : page.data) !== null && _a !== void 0 ? _a : []; })) !== null && _b !== void 0 ? _b : []).filter((item) => {
51
+ var _a;
52
+ const id = (_a = item.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID;
53
+ if (!id || seen.has(id))
54
+ return false;
55
+ seen.add(id);
56
+ return true;
57
+ });
58
+ }, [query.data]);
59
+ return Object.assign(Object.assign({}, query), { results });
60
+ };
@@ -85,6 +85,11 @@
85
85
  "unmute_success": "Đã bật thông báo",
86
86
  "mute_failed": "Không thể tắt thông báo. Vui lòng thử lại.",
87
87
  "unmute_failed": "Không thể bật thông báo. Vui lòng thử lại."
88
+ },
89
+ "pin": {
90
+ "pin_action": "Ghim",
91
+ "unpin_action": "Bỏ ghim",
92
+ "pinned_icon_label": "Đã ghim"
88
93
  }
89
94
  },
90
95
  "thread_detail": {
@@ -93,6 +98,32 @@
93
98
  "input_placeholder": "Nhập tin nhắn...",
94
99
  "view_only_notice": "Bạn cần tham gia nhóm để gửi tin nhắn",
95
100
  "resolve_failed": "Không thể mở cuộc trò chuyện",
101
+ "search": {
102
+ "open": "Tìm tin nhắn",
103
+ "back": "Quay lại",
104
+ "placeholder": "Tìm kiếm",
105
+ "initial": "Bạn có thể tìm kiếm theo nội dung tin nhắn",
106
+ "no_result_title": "Không tìm thấy kết quả nào",
107
+ "no_result_hint": "Hãy thử lại với cách viết khác hoặc kết hợp cụm từ khác phù hợp hơn.",
108
+ "failed": "Không tải được kết quả. Vui lòng thử lại",
109
+ "you": "Bạn"
110
+ },
111
+ "profile": {
112
+ "open": "Tuỳ chọn",
113
+ "search": "Tìm tin nhắn",
114
+ "orders": "Đơn hàng đã tạo cho {{name}}",
115
+ "create_group": "Tạo nhóm trò chuyện với {{name}}",
116
+ "add_to_group": "Thêm vào nhóm",
117
+ "pin": "Ghim trò chuyện",
118
+ "unpin": "Bỏ ghim trò chuyện",
119
+ "delete_history": "Xoá lịch sử trò chuyện",
120
+ "pin_success": "Đã ghim đoạn chat thành công",
121
+ "unpin_success": "Đã bỏ ghim đoạn chat thành công",
122
+ "pin_failed": "Có lỗi xảy ra vui lòng thử lại",
123
+ "pin_limit_title": "Không thể ghim đoạn chat",
124
+ "pin_limit_desc": "Bạn đã ghim số đoạn chat tối đa. Để ghim đoạn chat này, trước tiên bạn phải bỏ ghim đoạn chat khác.",
125
+ "pin_limit_confirm": "OK"
126
+ },
96
127
  "more_option": {
97
128
  "toggle": "Tùy chọn khác",
98
129
  "media": "Ảnh/Video",
@@ -11,7 +11,11 @@ export interface DChatConversationDetailProps extends ConversationDetailInputPro
11
11
  onCopyMessageLink?: (conversationId: string, clientMsgID: string) => void;
12
12
  /** Called instead of the SDK's default toast when a jumped-to message turns out to be revoked. */
13
13
  onSearchMessageRevoked?: () => void;
14
+ /** BIZ profile design: header ☰ icon plus quick actions and action rows in the profile panel. Defaults to false. */
15
+ showProfileActions?: boolean;
16
+ /** BIZ search in this thread: header search icon and the profile "Tìm tin nhắn" entry. Defaults to false. */
17
+ showThreadSearch?: boolean;
14
18
  }
15
- declare const DChatConversationDetail: ({ className, children, onBack, conversationId, messageId, userId, groupId, botId, onCopyMessageLink, onSearchMessageRevoked, ...inputProps }: DChatConversationDetailProps) => import("react/jsx-runtime").JSX.Element | null;
19
+ declare const DChatConversationDetail: ({ className, children, onBack, conversationId, messageId, userId, groupId, botId, onCopyMessageLink, onSearchMessageRevoked, showProfileActions, showThreadSearch, ...inputProps }: DChatConversationDetailProps) => import("react/jsx-runtime").JSX.Element | null;
16
20
  export default DChatConversationDetail;
17
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAYrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AAQrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,8IAc9B,4BAA4B,mDA6Q9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAarF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AASrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,oHAAoH;IACpH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,6GAA6G;IAC7G,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,oLAgB9B,4BAA4B,mDAwT9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
- import { useEffect, useState } from "react";
14
+ import { useEffect, useRef, useState } from "react";
15
15
  import { useTranslation } from "react-i18next";
16
16
  import { useChatContext } from "../../context/ChatContext";
17
17
  import { useChatNavigate } from "../../hooks/conversation/useChatNavigate";
@@ -22,6 +22,7 @@ import { Icon } from "../../components/icon";
22
22
  import useAuthStore from "../../store/auth";
23
23
  import useConversationStore from "../../store/conversation";
24
24
  import ThreadProfilePanel from "../../components/conversation-detail/ThreadProfilePanel";
25
+ import ThreadSearchPanel from "../../components/conversation-detail/thread-search/ThreadSearchPanel";
25
26
  import MediaResourcePanel from "../../components/media-resources/MediaResourcePanel";
26
27
  import { MediaResourceTabKey } from "../../components/media-resources/constants";
27
28
  import { ConversationMessageList, ConversationDetailHeader, ConversationDetailInput, PinnedMessageBar, } from "../../components/conversation-detail";
@@ -29,17 +30,19 @@ import TypingIndicatorBar from "../../components/conversation-detail/TypingIndic
29
30
  import { BotButtonMessage, BotInactiveNotice, BotMenuSheet, BotStartButton, BotSuggest, CsSessionConfirmModal, } from "../../components/conversation-detail/bot";
30
31
  import { useBotFlow } from "../../hooks/conversation/useBotFlow";
31
32
  import { useCanPinMessage } from "../../hooks/message/useCanPinMessage";
33
+ import { useIsJoinedGroup } from "../../hooks/session/useIsJoinedGroup";
32
34
  import { BOT_TYPE } from "../../constants/botFlow";
33
35
  import { useResolveConversation, } from "../../hooks/conversation/useResolveConversation";
34
36
  import { nextConsultantReturnTarget, useConsultantChatNavigation, } from "../../hooks/conversation/useConsultantChatNavigation";
35
37
  import { isBotPeer, isSupportSessionAgentView } from "../../utils/conversation";
38
+ import { PeerType } from "../../types/conversation";
36
39
  import { COMPOSER_DISMISS_ZONE_ATTR } from "../../hooks/common/useOutsideTapDismiss";
37
40
  const DChatConversationDetail = (_a) => {
38
41
  var _b;
39
42
  var { className, children, onBack, conversationId, messageId, userId, groupId, botId,
40
43
  // Destructured out of the rest spread on purpose: everything left in
41
44
  // inputProps goes to ConversationDetailInput, which has no business with it.
42
- onCopyMessageLink, onSearchMessageRevoked } = _a, inputProps = __rest(_a, ["className", "children", "onBack", "conversationId", "messageId", "userId", "groupId", "botId", "onCopyMessageLink", "onSearchMessageRevoked"]);
45
+ onCopyMessageLink, onSearchMessageRevoked, showProfileActions = false, showThreadSearch = false } = _a, inputProps = __rest(_a, ["className", "children", "onBack", "conversationId", "messageId", "userId", "groupId", "botId", "onCopyMessageLink", "onSearchMessageRevoked", "showProfileActions", "showThreadSearch"]);
43
46
  const { t } = useTranslation("conversation-inbox");
44
47
  const { useUrlState = true, user } = useChatContext();
45
48
  const onNavigate = useChatNavigate();
@@ -68,6 +71,29 @@ const DChatConversationDetail = (_a) => {
68
71
  const hasMenuItems = botFlow.menuItems.length > 0;
69
72
  const [isProfileOpen, { setTrue: openProfile, setFalse: closeProfile }] = useBoolean(false);
70
73
  const [resourceTab, setResourceTab] = useState(null);
74
+ const [isSearchOpen, { setTrue: openSearch, setFalse: closeSearch }] = useBoolean(false);
75
+ const openSearchFromProfile = () => {
76
+ closeProfile();
77
+ openSearch();
78
+ };
79
+ // The search API only serves members: hide it while the check says no or is pending.
80
+ // A failed check keeps it (the API still gates); a 1-1 exposes no groupID and is the viewer's own.
81
+ const { isJoined, isError: isJoinCheckFailed, refetch: refetchIsJoined, } = useIsJoinedGroup(showThreadSearch ? conversation === null || conversation === void 0 ? void 0 : conversation.groupID : undefined);
82
+ const isNonMember = (isViewOnlyMember && (conversation === null || conversation === void 0 ? void 0 : conversation.peerType) === PeerType.GROUP) ||
83
+ (!!(conversation === null || conversation === void 0 ? void 0 : conversation.groupID) && !isJoinCheckFailed && isJoined !== true);
84
+ const canSearch = showThreadSearch && !isNonMember;
85
+ // Being added to a group already open view-only syncs as an update, not a join event: re-check.
86
+ const wasViewOnlyRef = useRef(isViewOnlyMember);
87
+ useEffect(() => {
88
+ if (wasViewOnlyRef.current && !isViewOnlyMember && showThreadSearch) {
89
+ void refetchIsJoined();
90
+ }
91
+ wasViewOnlyRef.current = isViewOnlyMember;
92
+ }, [isViewOnlyMember, showThreadSearch, refetchIsJoined]);
93
+ // Search belongs to one thread; another thread opening in place (or losing membership) closes it.
94
+ useEffect(() => {
95
+ closeSearch();
96
+ }, [conversation === null || conversation === void 0 ? void 0 : conversation.conversationID, isNonMember, closeSearch]);
71
97
  const { returnTarget: consultantReturnTarget, returnToBotThread, clearReturnTarget, setReturnTarget, } = useConsultantChatNavigation();
72
98
  useEffect(() => {
73
99
  const next = nextConsultantReturnTarget(consultantReturnTarget, conversation);
@@ -141,6 +167,6 @@ const DChatConversationDetail = (_a) => {
141
167
  !botFlow.flowIsEnd &&
142
168
  botFlow.shouldShowButtons &&
143
169
  botFlow.currentButtonsBlock ? (_jsx(BotButtonMessage, { buttons: botFlow.currentButtonsBlock.data.buttons, disabled: botFlow.isProcessing, onSelect: botFlow.selectButton, onRestart: botFlow.restart })) : null;
144
- return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack, onProfileClick: openProfile }), _jsx(PinnedMessageBar, { canUnpin: canPinMessage }), _jsxs("div", { [COMPOSER_DISMISS_ZONE_ATTR]: "", className: "relative flex min-h-0 flex-1 flex-col", children: [children !== null && children !== void 0 ? children : (_jsx(ConversationMessageList, { bottomSlot: botButtonsSlot, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked })), _jsx(TypingIndicatorBar, { conversationId: conversation.conversationID })] }), footer, isBotThread && (_jsxs(_Fragment, { children: [_jsx(BotMenuSheet, { open: isMenuOpen, items: botFlow.menuItems, disabled: botFlow.isProcessing, onClose: closeMenu, onSelect: botFlow.selectMenuOption }), _jsx(CsSessionConfirmModal, { open: botFlow.isCsConfirmOpen, loading: botFlow.isProcessing, onCancel: botFlow.cancelMenuOption, onConfirm: botFlow.confirmEndCsSession })] })), _jsx(ThreadProfilePanel, { open: isProfileOpen, conversation: conversation, onClose: closeProfile, onSelectResource: setResourceTab }), _jsx(MediaResourcePanel, { open: resourceTab !== null, initialTab: resourceTab !== null && resourceTab !== void 0 ? resourceTab : MediaResourceTabKey.Image, onClose: () => setResourceTab(null) })] }));
170
+ return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack, onProfileClick: openProfile, onProfileIconClick: showProfileActions ? openProfile : undefined, onSearchClick: canSearch ? openSearch : undefined }), _jsx(PinnedMessageBar, { canUnpin: canPinMessage }), _jsxs("div", { [COMPOSER_DISMISS_ZONE_ATTR]: "", className: "relative flex min-h-0 flex-1 flex-col", children: [children !== null && children !== void 0 ? children : (_jsx(ConversationMessageList, { bottomSlot: botButtonsSlot, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked })), _jsx(TypingIndicatorBar, { conversationId: conversation.conversationID })] }), footer, isBotThread && (_jsxs(_Fragment, { children: [_jsx(BotMenuSheet, { open: isMenuOpen, items: botFlow.menuItems, disabled: botFlow.isProcessing, onClose: closeMenu, onSelect: botFlow.selectMenuOption }), _jsx(CsSessionConfirmModal, { open: botFlow.isCsConfirmOpen, loading: botFlow.isProcessing, onCancel: botFlow.cancelMenuOption, onConfirm: botFlow.confirmEndCsSession })] })), _jsx(ThreadProfilePanel, { open: isProfileOpen, conversation: conversation, onClose: closeProfile, onSelectResource: setResourceTab, showActions: showProfileActions, onSearch: canSearch ? openSearchFromProfile : undefined, hideSearch: showThreadSearch && !canSearch }), showThreadSearch && (_jsx(ThreadSearchPanel, { open: isSearchOpen && canSearch, conversation: conversation, onClose: closeSearch, onSearchMessageRevoked: onSearchMessageRevoked }, conversation.conversationID)), _jsx(MediaResourcePanel, { open: resourceTab !== null, initialTab: resourceTab !== null && resourceTab !== void 0 ? resourceTab : MediaResourceTabKey.Image, onClose: () => setResourceTab(null) })] }));
145
171
  };
146
172
  export default DChatConversationDetail;
@@ -20,6 +20,12 @@ export interface DChatConversationInboxProps {
20
20
  onSearchMessageRevoked?: () => void;
21
21
  /** Shows the sticker picker entry in the thread composer. Defaults to true. */
22
22
  showSticker?: boolean;
23
+ /** Forwarded to the detail screen — see DChatConversationDetailProps.showProfileActions. */
24
+ showProfileActions?: boolean;
25
+ /** BIZ thread list: Ghim / Bỏ ghim in the swipe actions plus a right-click menu (mute, pin). Defaults to false. */
26
+ showPinThread?: boolean;
27
+ /** Forwarded to the detail screen — see DChatConversationDetailProps.showThreadSearch. */
28
+ showThreadSearch?: boolean;
23
29
  }
24
30
  declare const DChatConversationInbox: (props: DChatConversationInboxProps) => import("react/jsx-runtime").JSX.Element;
25
31
  export default DChatConversationInbox;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-inbox/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,2BAA2B;IAC1C,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,6FAA6F;IAC7F,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAsOD,QAAA,MAAM,sBAAsB,GAAI,OAAO,2BAA2B,4CAQjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-inbox/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/D,MAAM,WAAW,2BAA2B;IAC1C,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,6FAA6F;IAC7F,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4FAA4F;IAC5F,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mHAAmH;IACnH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA4OD,QAAA,MAAM,sBAAsB,GAAI,OAAO,2BAA2B,4CAQjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
@@ -77,7 +77,7 @@ const useInboxConversationList = (chatCategory) => {
77
77
  const isApplicationTypeValid = Object.values(DChatApplicationType).includes(applicationType);
78
78
  return Object.assign(Object.assign({}, useConversationList({ enabled: isApplicationTypeValid, chatCategory })), { isApplicationTypeValid });
79
79
  };
80
- const DChatConversationInboxBody = ({ onSelectThread, className, moreOptions, showSearch = true, headerTitle, headerRightSlot, onCopyMessageLink, onSearchMessageRevoked, showSticker, target, conversationList, }) => {
80
+ const DChatConversationInboxBody = ({ onSelectThread, className, moreOptions, showSearch = true, headerTitle, headerRightSlot, onCopyMessageLink, onSearchMessageRevoked, showSticker, showProfileActions, showPinThread, showThreadSearch, target, conversationList, }) => {
81
81
  const { t } = useTranslation("conversation-inbox");
82
82
  const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
83
83
  const removedFromGroupModalOpen = useConversationStore((state) => state.removedFromGroupModalOpen);
@@ -99,13 +99,13 @@ const DChatConversationInboxBody = ({ onSelectThread, className, moreOptions, sh
99
99
  groupId ||
100
100
  botId);
101
101
  if (hasConversationTarget) {
102
- return (_jsx(DChatConversationDetail, { className: className, moreOptions: moreOptions, conversationId: threadId !== null && threadId !== void 0 ? threadId : undefined, userId: userId, groupId: groupId, botId: botId, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked, messageId: messageId, showSticker: showSticker }));
102
+ return (_jsx(DChatConversationDetail, { className: className, moreOptions: moreOptions, conversationId: threadId !== null && threadId !== void 0 ? threadId : undefined, userId: userId, groupId: groupId, botId: botId, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked, messageId: messageId, showSticker: showSticker, showProfileActions: showProfileActions, showThreadSearch: showThreadSearch }));
103
103
  }
104
104
  return (_jsxs("div", { "data-testid": "conversation-inbox-root", className: clsx(
105
105
  // `relative` + `overflow-hidden` keep ContactSearchPanel's Drawer
106
106
  // (getContainer={false}) inside this column instead of escaping to
107
107
  // the viewport — same containment the conversation detail root uses.
108
- "relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationInboxHeader, { onOpenSearch: showSearch ? openSearch : undefined, title: headerTitle, rightSlot: headerRightSlot }), !conversationList.isApplicationTypeValid ? (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Empty, { image: _jsx("div", { className: "flex justify-center", children: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-[var(--dc-color-primary-light)]" }) }), description: t("empty.no_conversations") }) })) : (_jsx(ConversationInboxList, { items: conversationList.items, isLoading: conversationList.isLoading, isFetchingNextPage: conversationList.isFetchingNextPage, hasNextPage: conversationList.hasNextPage, onLoadMore: conversationList.fetchNextPage, onSelectThread: onSelectThread })), _jsx(ContactSearchPanel, { open: isSearchOpen, onClose: closeSearch })] }));
108
+ "relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationInboxHeader, { onOpenSearch: showSearch ? openSearch : undefined, title: headerTitle, rightSlot: headerRightSlot }), !conversationList.isApplicationTypeValid ? (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Empty, { image: _jsx("div", { className: "flex justify-center", children: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-[var(--dc-color-primary-light)]" }) }), description: t("empty.no_conversations") }) })) : (_jsx(ConversationInboxList, { items: conversationList.items, isLoading: conversationList.isLoading, isFetchingNextPage: conversationList.isFetchingNextPage, hasNextPage: conversationList.hasNextPage, onLoadMore: conversationList.fetchNextPage, onSelectThread: onSelectThread, showPinThread: showPinThread })), _jsx(ContactSearchPanel, { open: isSearchOpen, onClose: closeSearch })] }));
109
109
  };
110
110
  // ChatProvider's useUrlState prop picks which target-resolution variant
111
111
  // mounts — kept as two full components (not one with a conditional hook)
@@ -3,6 +3,7 @@ export declare const QUERY_KEYS: {
3
3
  GET_SESSION_SUMMARY: string;
4
4
  GET_SESSION_BY_TAG_OR_STATUS: string;
5
5
  SEARCH_MESSAGE: string;
6
+ SEARCH_THREAD_MESSAGES: string;
6
7
  UPDATE_SESSION: string;
7
8
  FETCH_EXTERNAL_LINK: string;
8
9
  FETCH_URL_METADATA: string;
@@ -26,6 +27,8 @@ export declare const QUERY_KEYS: {
26
27
  SESSION_LATEST_MESSAGE: string;
27
28
  CREATE_CONVERSATION: string;
28
29
  GET_CONVERSATION_DETAIL: string;
30
+ GET_CONVERSATION_TARGET: string;
31
+ PIN_CONVERSATION: string;
29
32
  RUN_BOT_FLOW: string;
30
33
  RESET_BOT_FLOW: string;
31
34
  CLOSE_BOT_SESSION: string;
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/services/query.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDtB,CAAC"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/services/query.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDtB,CAAC"}
@@ -3,6 +3,7 @@ export const QUERY_KEYS = {
3
3
  GET_SESSION_SUMMARY: "GET_SESSION_SUMMARY",
4
4
  GET_SESSION_BY_TAG_OR_STATUS: "GET_SESSION_BY_TAG_OR_STATUS",
5
5
  SEARCH_MESSAGE: "SEARCH_MESSAGE",
6
+ SEARCH_THREAD_MESSAGES: "SEARCH_THREAD_MESSAGES",
6
7
  UPDATE_SESSION: "UPDATE_SESSION",
7
8
  FETCH_EXTERNAL_LINK: "FETCH_EXTERNAL_LINK",
8
9
  FETCH_URL_METADATA: "FETCH_URL_METADATA",
@@ -26,6 +27,8 @@ export const QUERY_KEYS = {
26
27
  SESSION_LATEST_MESSAGE: "SESSION_LATEST_MESSAGE",
27
28
  CREATE_CONVERSATION: "CREATE_CONVERSATION",
28
29
  GET_CONVERSATION_DETAIL: "GET_CONVERSATION_DETAIL",
30
+ GET_CONVERSATION_TARGET: "GET_CONVERSATION_TARGET",
31
+ PIN_CONVERSATION: "PIN_CONVERSATION",
29
32
  RUN_BOT_FLOW: "RUN_BOT_FLOW",
30
33
  RESET_BOT_FLOW: "RESET_BOT_FLOW",
31
34
  CLOSE_BOT_SESSION: "CLOSE_BOT_SESSION",
@@ -37,6 +37,7 @@ export declare const ENDPOINTS: {
37
37
  searchPdpPortalGroups: string;
38
38
  createConversation: string;
39
39
  getConversationDetail: (conversationId: string) => string;
40
+ getConversationTarget: (conversationId: string) => string;
40
41
  runBotFlow: (conversationId: string) => string;
41
42
  resetBotFlow: (conversationId: string) => string;
42
43
  closeBotSession: (conversationId: string) => string;
@@ -45,6 +46,7 @@ export declare const ENDPOINTS: {
45
46
  getConversationByBotId: (botId: string) => string;
46
47
  getUrlMetadata: string;
47
48
  getMessageResources: string;
49
+ searchAppMessages: string;
48
50
  searchContacts: string;
49
51
  getStickerCategories: string;
50
52
  getStickersByCategory: (categoryId: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/services/routes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;;;mCAMS,MAAM;;0CAGC,MAAM,UAAU,MAAM;6BAEnC,MAAM;;oDAEiB,MAAM;uCAEnB,MAAM;kCAEX,MAAM;;oCAGJ,MAAM;mCAEP,MAAM;uCAEF,MAAM;;;;;;;;;iCAUZ,MAAM;4CAEK,MAAM;mCAEf,MAAM;yCAEA,MAAM;gCAEf,MAAM;;;;;;;;gDAYU,MAAM;qCAEjB,MAAM;uCAEJ,MAAM;0CAEH,MAAM;yCAEP,MAAM;8BAEjB,MAAM;wCACI,MAAM;;;;;4CAMF,MAAM;;;;;;;;;;;;CAa7C,CAAC"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/services/routes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;;;mCAMS,MAAM;;0CAGC,MAAM,UAAU,MAAM;6BAEnC,MAAM;;oDAEiB,MAAM;uCAEnB,MAAM;kCAEX,MAAM;;oCAGJ,MAAM;mCAEP,MAAM;uCAEF,MAAM;;;;;;;;;iCAUZ,MAAM;4CAEK,MAAM;mCAEf,MAAM;yCAEA,MAAM;gCAEf,MAAM;;;;;;;;gDAYU,MAAM;gDAEN,MAAM;qCAEjB,MAAM;uCAEJ,MAAM;0CAEH,MAAM;yCAEP,MAAM;8BAEjB,MAAM;wCACI,MAAM;;;;;;4CAOF,MAAM;;;;;;;;;;;;CAa7C,CAAC"}
@@ -37,6 +37,7 @@ export const ENDPOINTS = {
37
37
  searchPdpPortalGroups: "/chat-service/v1/pdp-portal/conversations/groups/query",
38
38
  createConversation: "/chat-service/v1/app/conversations",
39
39
  getConversationDetail: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}`,
40
+ getConversationTarget: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/target`,
40
41
  runBotFlow: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/bot-flows/run`,
41
42
  resetBotFlow: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/bot-flows/reset`,
42
43
  closeBotSession: (conversationId) => `/chat-service/v1/app/conversations/${conversationId}/session/close`,
@@ -45,6 +46,7 @@ export const ENDPOINTS = {
45
46
  getConversationByBotId: (botId) => `/chat-service/v1/app/bots/${botId}/conversation`,
46
47
  getUrlMetadata: "/chat-service/v1/utils/url-metadata",
47
48
  getMessageResources: "/chat-service/v1/app/messages/resources",
49
+ searchAppMessages: "/chat-service/v1/app/messages/search",
48
50
  searchContacts: "/chat-service/v1/app/contacts/search",
49
51
  getStickerCategories: "/chat-service/v1/app/sticker-categories",
50
52
  getStickersByCategory: (categoryId) => `/chat-service/v1/app/sticker-categories/${categoryId}/stickers`,
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,oFAOpB,CAAC;AAUX,eAAO,MAAM,cAAc,GAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,SAEhE,CAAC;AAEF,QAAA,MAAM,oBAAoB,gFAmhBvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,oFAOpB,CAAC;AAUX,eAAO,MAAM,cAAc,GAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,SAEhE,CAAC;AAEF,QAAA,MAAM,oBAAoB,gFA4hBvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
@@ -37,14 +37,13 @@ export const setUrlNavigate = (fn) => {
37
37
  const useConversationStore = create((set, get) => ({
38
38
  conversationData: null,
39
39
  setConversationData: (data, dataSearchClientMsgID, options) => {
40
+ var _a;
40
41
  void get().updateCurrentConversation(data, options);
41
- set({
42
- conversationData: data,
43
- selectedSourceId: (data === null || data === void 0 ? void 0 : data.conversationType) === SessionType.Group
42
+ set(Object.assign(Object.assign({ conversationData: data }, ((data === null || data === void 0 ? void 0 : data.conversationID) !== ((_a = get().conversationData) === null || _a === void 0 ? void 0 : _a.conversationID)
43
+ ? { heldHighlightClientMsgID: "" }
44
+ : {})), { selectedSourceId: (data === null || data === void 0 ? void 0 : data.conversationType) === SessionType.Group
44
45
  ? data === null || data === void 0 ? void 0 : data.groupID
45
- : data === null || data === void 0 ? void 0 : data.userID,
46
- searchClientMsgID: dataSearchClientMsgID,
47
- });
46
+ : data === null || data === void 0 ? void 0 : data.userID, searchClientMsgID: dataSearchClientMsgID }));
48
47
  },
49
48
  selectedConversationId: "",
50
49
  setSelectedConversationId: (threadId) => {
@@ -350,6 +349,7 @@ const useConversationStore = create((set, get) => ({
350
349
  conversationData: null,
351
350
  selectedConversationId: "",
352
351
  selectedSourceId: "",
352
+ heldHighlightClientMsgID: "",
353
353
  pendingResolveTarget: null,
354
354
  currentConversation: undefined,
355
355
  quotedMessage: null,
@@ -383,6 +383,10 @@ const useConversationStore = create((set, get) => ({
383
383
  setSearchClientMsgID: (clientMsgID) => {
384
384
  set({ searchClientMsgID: clientMsgID });
385
385
  },
386
+ heldHighlightClientMsgID: "",
387
+ setHeldHighlightClientMsgID: (clientMsgID) => {
388
+ set({ heldHighlightClientMsgID: clientMsgID });
389
+ },
386
390
  //quoted message
387
391
  quotedMessage: null,
388
392
  setQuotedMessage: (message) => {
@@ -88,6 +88,9 @@ export interface ConversationStore {
88
88
  }) => void;
89
89
  searchClientMsgID: string;
90
90
  setSearchClientMsgID: (clientMsgID: string) => void;
91
+ /** Jump target that keeps its highlight 5 s (in-thread search) instead of the short pulse. */
92
+ heldHighlightClientMsgID: string;
93
+ setHeldHighlightClientMsgID: (clientMsgID: string) => void;
91
94
  quotedMessage: MessageItem | null;
92
95
  setQuotedMessage: (message: MessageItem | null) => void;
93
96
  pinnedMessageList: MessageItem[];