@droppii-org/chat-sdk 0.7.13 → 0.7.14

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 (44) hide show
  1. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageResultItem.d.ts +10 -0
  2. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageResultItem.d.ts.map +1 -0
  3. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageResultItem.js +30 -0
  4. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageSection.d.ts +12 -0
  5. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageSection.d.ts.map +1 -0
  6. package/dist/components/conversation-inbox/contact-search/ContactSearchMessageSection.js +14 -0
  7. package/dist/components/conversation-inbox/contact-search/ContactSearchMessagesTab.d.ts +11 -0
  8. package/dist/components/conversation-inbox/contact-search/ContactSearchMessagesTab.d.ts.map +1 -0
  9. package/dist/components/conversation-inbox/contact-search/ContactSearchMessagesTab.js +31 -0
  10. package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.d.ts +5 -1
  11. package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.d.ts.map +1 -1
  12. package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.js +54 -9
  13. package/dist/components/conversation-inbox/contact-search/constants.js +2 -2
  14. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  15. package/dist/components/message/GroupMembersDrawer.js +35 -6
  16. package/dist/components/message/GroupMembersPanelCrm.d.ts +5 -1
  17. package/dist/components/message/GroupMembersPanelCrm.d.ts.map +1 -1
  18. package/dist/components/message/GroupMembersPanelCrm.js +7 -3
  19. package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
  20. package/dist/components/message/footer/mention/useMentionOptions.js +26 -5
  21. package/dist/hooks/group/useGroupMembers.d.ts +8 -1
  22. package/dist/hooks/group/useGroupMembers.d.ts.map +1 -1
  23. package/dist/hooks/group/useGroupMembers.js +83 -15
  24. package/dist/hooks/group/useSearchGroupMembers.d.ts.map +1 -1
  25. package/dist/hooks/group/useSearchGroupMembers.js +11 -2
  26. package/dist/hooks/search/useAppMessageSearch.d.ts +317 -0
  27. package/dist/hooks/search/useAppMessageSearch.d.ts.map +1 -0
  28. package/dist/hooks/search/useAppMessageSearch.js +53 -0
  29. package/dist/hooks/search/useSearchGlobalMessages.d.ts +306 -0
  30. package/dist/hooks/search/useSearchGlobalMessages.d.ts.map +1 -0
  31. package/dist/hooks/search/useSearchGlobalMessages.js +15 -0
  32. package/dist/hooks/search/useSearchThreadMessages.d.ts +115 -36
  33. package/dist/hooks/search/useSearchThreadMessages.d.ts.map +1 -1
  34. package/dist/hooks/search/useSearchThreadMessages.js +5 -52
  35. package/dist/screens/conversation-inbox/index.d.ts +2 -0
  36. package/dist/screens/conversation-inbox/index.d.ts.map +1 -1
  37. package/dist/screens/conversation-inbox/index.js +2 -2
  38. package/dist/services/query.d.ts +1 -0
  39. package/dist/services/query.d.ts.map +1 -1
  40. package/dist/services/query.js +1 -0
  41. package/dist/styles/global.css +1 -1
  42. package/dist/types/dto.d.ts +15 -2
  43. package/dist/types/dto.d.ts.map +1 -1
  44. package/package.json +1 -1
@@ -1,41 +1,106 @@
1
- import { useCallback, useEffect, useState } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { CbEvents } from "@droppii-org/wasm-client-sdk";
3
3
  import { DChatSDK } from "../../constants/sdk";
4
- const GROUP_MEMBER_LIST_OFFSET = 0;
5
- const GROUP_MEMBER_LIST_COUNT = 999;
6
- export const useGroupMembers = (groupID) => {
4
+ const DEFAULT_PAGE_SIZE = 999;
5
+ const appendNewMembers = (loaded, page) => {
6
+ const loadedIDs = new Set(loaded.map((member) => member.userID));
7
+ return [...loaded, ...page.filter((member) => !loadedIDs.has(member.userID))];
8
+ };
9
+ export const useGroupMembers = (groupID, { pageSize = DEFAULT_PAGE_SIZE } = {}) => {
7
10
  const [members, setMembers] = useState([]);
8
11
  const [isLoading, setIsLoading] = useState(false);
12
+ const [isLoadingMore, setIsLoadingMore] = useState(false);
13
+ const [hasMore, setHasMore] = useState(false);
9
14
  const [error, setError] = useState(undefined);
10
- const fetchMembers = useCallback(async () => {
15
+ const membersRef = useRef(members);
16
+ membersRef.current = members;
17
+ // Bumped by every reload so a page that answers after it is dropped.
18
+ const loadIdRef = useRef(0);
19
+ const isLoadingMoreRef = useRef(false);
20
+ // Mirrors hasMore synchronously so no page is requested while a reload is in flight.
21
+ const hasMoreRef = useRef(false);
22
+ const updateHasMore = useCallback((value) => {
23
+ hasMoreRef.current = value;
24
+ setHasMore(value);
25
+ }, []);
26
+ const reload = useCallback(async (count, showSpinner) => {
27
+ var _a;
28
+ const loadId = ++loadIdRef.current;
29
+ updateHasMore(false);
11
30
  if (!groupID) {
12
31
  setMembers([]);
13
32
  setError(undefined);
33
+ setIsLoading(false);
14
34
  return;
15
35
  }
16
- setIsLoading(true);
36
+ if (showSpinner)
37
+ setIsLoading(true);
17
38
  setError(undefined);
18
39
  try {
19
40
  const { data } = await DChatSDK.getGroupMemberList({
20
41
  groupID,
21
42
  filter: 0,
22
- offset: GROUP_MEMBER_LIST_OFFSET,
23
- count: GROUP_MEMBER_LIST_COUNT,
43
+ offset: 0,
44
+ count,
24
45
  });
46
+ if (loadId !== loadIdRef.current)
47
+ return;
25
48
  setMembers(data !== null && data !== void 0 ? data : []);
49
+ updateHasMore(((_a = data === null || data === void 0 ? void 0 : data.length) !== null && _a !== void 0 ? _a : 0) === count);
26
50
  }
27
51
  catch (err) {
52
+ if (loadId !== loadIdRef.current)
53
+ return;
28
54
  console.error("Error fetching group member list:", err);
29
55
  setMembers([]);
30
56
  setError("load_group_member_list_failed");
31
57
  }
32
58
  finally {
33
- setIsLoading(false);
59
+ if (loadId === loadIdRef.current)
60
+ setIsLoading(false);
34
61
  }
35
- }, [groupID]);
62
+ }, [groupID, updateHasMore]);
36
63
  useEffect(() => {
37
- void fetchMembers();
38
- }, [fetchMembers]);
64
+ setMembers([]);
65
+ void reload(pageSize, true);
66
+ }, [reload, pageSize]);
67
+ // Re-reads every row already shown, without a spinner, so a refetch never
68
+ // cuts a scrolled list short or jumps it back to the top.
69
+ const refetch = useCallback(() => reload(Math.max(pageSize, membersRef.current.length), false), [reload, pageSize]);
70
+ const loadMore = useCallback(async () => {
71
+ if (!groupID || !hasMoreRef.current || isLoadingMoreRef.current)
72
+ return;
73
+ const loadId = loadIdRef.current;
74
+ isLoadingMoreRef.current = true;
75
+ setIsLoadingMore(true);
76
+ try {
77
+ const { data } = await DChatSDK.getGroupMemberList({
78
+ groupID,
79
+ filter: 0,
80
+ offset: membersRef.current.length,
81
+ count: pageSize,
82
+ });
83
+ if (loadId !== loadIdRef.current)
84
+ return;
85
+ const page = data !== null && data !== void 0 ? data : [];
86
+ const loadedIDs = new Set(membersRef.current.map((member) => member.userID));
87
+ const hasNewRows = page.some((member) => !loadedIDs.has(member.userID));
88
+ setMembers((prev) => appendNewMembers(prev, page));
89
+ // A page of only known rows means core's order shifted; stop instead of re-requesting it.
90
+ updateHasMore(page.length === pageSize && hasNewRows);
91
+ }
92
+ catch (err) {
93
+ if (loadId !== loadIdRef.current)
94
+ return;
95
+ // Stop paging rather than retry on every scroll tick; reopening reloads.
96
+ console.error("Error fetching more group members:", err);
97
+ updateHasMore(false);
98
+ }
99
+ finally {
100
+ isLoadingMoreRef.current = false;
101
+ setIsLoadingMore(false);
102
+ }
103
+ }, [groupID, pageSize, updateHasMore]);
39
104
  useEffect(() => {
40
105
  if (!groupID)
41
106
  return;
@@ -44,7 +109,7 @@ export const useGroupMembers = (groupID) => {
44
109
  setMembers((prev) => prev.filter((m) => m.userID !== data.userID));
45
110
  }
46
111
  };
47
- const onMemberAdded = () => void fetchMembers();
112
+ const onMemberAdded = () => void refetch();
48
113
  // BE pushes the member's full updated record (roleLevel + the
49
114
  // permissions[] it reset to) whenever a role/permission change is
50
115
  // applied — e.g. setGroupMemberRoleLevel resets permissions to the new
@@ -65,7 +130,7 @@ export const useGroupMembers = (groupID) => {
65
130
  DChatSDK.off(CbEvents.OnGroupMemberAdded, onMemberAdded);
66
131
  DChatSDK.off(CbEvents.OnGroupMemberInfoChanged, onMemberInfoChanged);
67
132
  };
68
- }, [groupID, fetchMembers]);
133
+ }, [groupID, refetch]);
69
134
  const patchMemberRole = useCallback((userID, roleLevel) => {
70
135
  setMembers((prev) => prev.map((member) => member.userID === userID ? Object.assign(Object.assign({}, member), { roleLevel }) : member));
71
136
  }, []);
@@ -76,8 +141,11 @@ export const useGroupMembers = (groupID) => {
76
141
  return {
77
142
  members,
78
143
  isLoading,
144
+ isLoadingMore,
145
+ hasMore,
79
146
  error,
80
- refetch: fetchMembers,
147
+ refetch,
148
+ loadMore,
81
149
  patchMemberRole,
82
150
  patchMemberPermissions,
83
151
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useSearchGroupMembers.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useSearchGroupMembers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAM/D,UAAU,2BAA2B;IACnC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,GAAG,SAAS,EAC3B,SAAS,MAAM,KACd,2BAkCF,CAAC"}
1
+ {"version":3,"file":"useSearchGroupMembers.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useSearchGroupMembers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAM/D,UAAU,2BAA2B;IACnC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,GAAG,SAAS,EAC3B,SAAS,MAAM,KACd,2BAwCF,CAAC"}
@@ -1,13 +1,17 @@
1
- import { useCallback, useEffect, useState } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { DChatSDK } from "../../constants/sdk";
3
3
  const SEARCH_GROUP_MEMBER_OFFSET = 0;
4
4
  const SEARCH_GROUP_MEMBER_COUNT = 999;
5
5
  export const useSearchGroupMembers = (groupID, keyword) => {
6
6
  const [results, setResults] = useState([]);
7
7
  const [isSearching, setIsSearching] = useState(false);
8
+ // Typing fires a search per keystroke; only the latest one may land.
9
+ const searchIdRef = useRef(0);
8
10
  const search = useCallback(async () => {
11
+ const searchId = ++searchIdRef.current;
9
12
  if (!groupID || !keyword.trim()) {
10
13
  setResults([]);
14
+ setIsSearching(false);
11
15
  return;
12
16
  }
13
17
  setIsSearching(true);
@@ -20,14 +24,19 @@ export const useSearchGroupMembers = (groupID, keyword) => {
20
24
  offset: SEARCH_GROUP_MEMBER_OFFSET,
21
25
  count: SEARCH_GROUP_MEMBER_COUNT,
22
26
  });
27
+ if (searchId !== searchIdRef.current)
28
+ return;
23
29
  setResults(data !== null && data !== void 0 ? data : []);
24
30
  }
25
31
  catch (err) {
32
+ if (searchId !== searchIdRef.current)
33
+ return;
26
34
  console.error("Error searching group members:", err);
27
35
  setResults([]);
28
36
  }
29
37
  finally {
30
- setIsSearching(false);
38
+ if (searchId === searchIdRef.current)
39
+ setIsSearching(false);
31
40
  }
32
41
  }, [groupID, keyword]);
33
42
  useEffect(() => {
@@ -0,0 +1,317 @@
1
+ import { MessageType } from "@droppii-org/wasm-client-sdk";
2
+ import type { Pageable } from "../../types/dto";
3
+ export declare const APP_MESSAGE_SEARCH_CONTENT_TYPES: MessageType[];
4
+ interface UseAppMessageSearchParams {
5
+ queryKey: readonly unknown[];
6
+ /** Already trimmed; an empty term never searches. */
7
+ searchTerm: string;
8
+ /** One thread; omitted searches every thread the viewer has joined. */
9
+ conversationId?: string;
10
+ enabled: boolean;
11
+ staleTime?: number;
12
+ }
13
+ /** chat-service `POST /app/messages/search`, newest first, more pages on demand. */
14
+ export declare const useAppMessageSearch: <TItem extends {
15
+ chatLog: {
16
+ clientMsgID: string;
17
+ };
18
+ }>({ queryKey, searchTerm, conversationId, enabled, staleTime, }: UseAppMessageSearchParams) => {
19
+ results: TItem[];
20
+ data: import("@tanstack/react-query").InfiniteData<{
21
+ data: TItem[];
22
+ pageable: Pageable;
23
+ }, unknown>;
24
+ error: Error;
25
+ isError: true;
26
+ isPending: false;
27
+ isLoading: false;
28
+ isLoadingError: false;
29
+ isRefetchError: true;
30
+ isSuccess: false;
31
+ isPlaceholderData: false;
32
+ status: "error";
33
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
34
+ data: TItem[];
35
+ pageable: Pageable;
36
+ }, unknown>, Error>>;
37
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
38
+ data: TItem[];
39
+ pageable: Pageable;
40
+ }, unknown>, Error>>;
41
+ hasNextPage: boolean;
42
+ hasPreviousPage: boolean;
43
+ isFetchNextPageError: boolean;
44
+ isFetchingNextPage: boolean;
45
+ isFetchPreviousPageError: boolean;
46
+ isFetchingPreviousPage: boolean;
47
+ dataUpdatedAt: number;
48
+ errorUpdatedAt: number;
49
+ failureCount: number;
50
+ failureReason: Error | null;
51
+ errorUpdateCount: number;
52
+ isFetched: boolean;
53
+ isFetchedAfterMount: boolean;
54
+ isFetching: boolean;
55
+ isInitialLoading: boolean;
56
+ isPaused: boolean;
57
+ isRefetching: boolean;
58
+ isStale: boolean;
59
+ isEnabled: boolean;
60
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
61
+ data: TItem[];
62
+ pageable: Pageable;
63
+ }, unknown>, Error>>;
64
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
65
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
66
+ data: TItem[];
67
+ pageable: Pageable;
68
+ }, unknown>>;
69
+ } | {
70
+ results: TItem[];
71
+ data: import("@tanstack/react-query").InfiniteData<{
72
+ data: TItem[];
73
+ pageable: Pageable;
74
+ }, unknown>;
75
+ error: null;
76
+ isError: false;
77
+ isPending: false;
78
+ isLoading: false;
79
+ isLoadingError: false;
80
+ isRefetchError: false;
81
+ isFetchNextPageError: false;
82
+ isFetchPreviousPageError: false;
83
+ isSuccess: true;
84
+ isPlaceholderData: false;
85
+ status: "success";
86
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
87
+ data: TItem[];
88
+ pageable: Pageable;
89
+ }, unknown>, Error>>;
90
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
91
+ data: TItem[];
92
+ pageable: Pageable;
93
+ }, unknown>, Error>>;
94
+ hasNextPage: boolean;
95
+ hasPreviousPage: boolean;
96
+ isFetchingNextPage: boolean;
97
+ isFetchingPreviousPage: boolean;
98
+ dataUpdatedAt: number;
99
+ errorUpdatedAt: number;
100
+ failureCount: number;
101
+ failureReason: Error | null;
102
+ errorUpdateCount: number;
103
+ isFetched: boolean;
104
+ isFetchedAfterMount: boolean;
105
+ isFetching: boolean;
106
+ isInitialLoading: boolean;
107
+ isPaused: boolean;
108
+ isRefetching: boolean;
109
+ isStale: boolean;
110
+ isEnabled: boolean;
111
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
112
+ data: TItem[];
113
+ pageable: Pageable;
114
+ }, unknown>, Error>>;
115
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
116
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
117
+ data: TItem[];
118
+ pageable: Pageable;
119
+ }, unknown>>;
120
+ } | {
121
+ results: TItem[];
122
+ data: undefined;
123
+ error: Error;
124
+ isError: true;
125
+ isPending: false;
126
+ isLoading: false;
127
+ isLoadingError: true;
128
+ isRefetchError: false;
129
+ isFetchNextPageError: false;
130
+ isFetchPreviousPageError: false;
131
+ isSuccess: false;
132
+ isPlaceholderData: false;
133
+ status: "error";
134
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
135
+ data: TItem[];
136
+ pageable: Pageable;
137
+ }, unknown>, Error>>;
138
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
139
+ data: TItem[];
140
+ pageable: Pageable;
141
+ }, unknown>, Error>>;
142
+ hasNextPage: boolean;
143
+ hasPreviousPage: boolean;
144
+ isFetchingNextPage: boolean;
145
+ isFetchingPreviousPage: boolean;
146
+ dataUpdatedAt: number;
147
+ errorUpdatedAt: number;
148
+ failureCount: number;
149
+ failureReason: Error | null;
150
+ errorUpdateCount: number;
151
+ isFetched: boolean;
152
+ isFetchedAfterMount: boolean;
153
+ isFetching: boolean;
154
+ isInitialLoading: boolean;
155
+ isPaused: boolean;
156
+ isRefetching: boolean;
157
+ isStale: boolean;
158
+ isEnabled: boolean;
159
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
160
+ data: TItem[];
161
+ pageable: Pageable;
162
+ }, unknown>, Error>>;
163
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
164
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
165
+ data: TItem[];
166
+ pageable: Pageable;
167
+ }, unknown>>;
168
+ } | {
169
+ results: TItem[];
170
+ data: undefined;
171
+ error: null;
172
+ isError: false;
173
+ isPending: true;
174
+ isLoading: true;
175
+ isLoadingError: false;
176
+ isRefetchError: false;
177
+ isFetchNextPageError: false;
178
+ isFetchPreviousPageError: false;
179
+ isSuccess: false;
180
+ isPlaceholderData: false;
181
+ status: "pending";
182
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
183
+ data: TItem[];
184
+ pageable: Pageable;
185
+ }, unknown>, Error>>;
186
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
187
+ data: TItem[];
188
+ pageable: Pageable;
189
+ }, unknown>, Error>>;
190
+ hasNextPage: boolean;
191
+ hasPreviousPage: boolean;
192
+ isFetchingNextPage: boolean;
193
+ isFetchingPreviousPage: boolean;
194
+ dataUpdatedAt: number;
195
+ errorUpdatedAt: number;
196
+ failureCount: number;
197
+ failureReason: Error | null;
198
+ errorUpdateCount: number;
199
+ isFetched: boolean;
200
+ isFetchedAfterMount: boolean;
201
+ isFetching: boolean;
202
+ isInitialLoading: boolean;
203
+ isPaused: boolean;
204
+ isRefetching: boolean;
205
+ isStale: boolean;
206
+ isEnabled: boolean;
207
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
208
+ data: TItem[];
209
+ pageable: Pageable;
210
+ }, unknown>, Error>>;
211
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
212
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
213
+ data: TItem[];
214
+ pageable: Pageable;
215
+ }, unknown>>;
216
+ } | {
217
+ results: TItem[];
218
+ data: undefined;
219
+ error: null;
220
+ isError: false;
221
+ isPending: true;
222
+ isLoadingError: false;
223
+ isRefetchError: false;
224
+ isFetchNextPageError: false;
225
+ isFetchPreviousPageError: false;
226
+ isSuccess: false;
227
+ isPlaceholderData: false;
228
+ status: "pending";
229
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
230
+ data: TItem[];
231
+ pageable: Pageable;
232
+ }, unknown>, Error>>;
233
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
234
+ data: TItem[];
235
+ pageable: Pageable;
236
+ }, unknown>, Error>>;
237
+ hasNextPage: boolean;
238
+ hasPreviousPage: boolean;
239
+ isFetchingNextPage: boolean;
240
+ isFetchingPreviousPage: boolean;
241
+ dataUpdatedAt: number;
242
+ errorUpdatedAt: number;
243
+ failureCount: number;
244
+ failureReason: Error | null;
245
+ errorUpdateCount: number;
246
+ isFetched: boolean;
247
+ isFetchedAfterMount: boolean;
248
+ isFetching: boolean;
249
+ isLoading: boolean;
250
+ isInitialLoading: boolean;
251
+ isPaused: boolean;
252
+ isRefetching: boolean;
253
+ isStale: boolean;
254
+ isEnabled: boolean;
255
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
256
+ data: TItem[];
257
+ pageable: Pageable;
258
+ }, unknown>, Error>>;
259
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
260
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
261
+ data: TItem[];
262
+ pageable: Pageable;
263
+ }, unknown>>;
264
+ } | {
265
+ results: TItem[];
266
+ data: import("@tanstack/react-query").InfiniteData<{
267
+ data: TItem[];
268
+ pageable: Pageable;
269
+ }, unknown>;
270
+ isError: false;
271
+ error: null;
272
+ isPending: false;
273
+ isLoading: false;
274
+ isLoadingError: false;
275
+ isRefetchError: false;
276
+ isSuccess: true;
277
+ isPlaceholderData: true;
278
+ isFetchNextPageError: false;
279
+ isFetchPreviousPageError: false;
280
+ status: "success";
281
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
282
+ data: TItem[];
283
+ pageable: Pageable;
284
+ }, unknown>, Error>>;
285
+ fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<{
286
+ data: TItem[];
287
+ pageable: Pageable;
288
+ }, unknown>, Error>>;
289
+ hasNextPage: boolean;
290
+ hasPreviousPage: boolean;
291
+ isFetchingNextPage: boolean;
292
+ isFetchingPreviousPage: boolean;
293
+ dataUpdatedAt: number;
294
+ errorUpdatedAt: number;
295
+ failureCount: number;
296
+ failureReason: Error | null;
297
+ errorUpdateCount: number;
298
+ isFetched: boolean;
299
+ isFetchedAfterMount: boolean;
300
+ isFetching: boolean;
301
+ isInitialLoading: boolean;
302
+ isPaused: boolean;
303
+ isRefetching: boolean;
304
+ isStale: boolean;
305
+ isEnabled: boolean;
306
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<{
307
+ data: TItem[];
308
+ pageable: Pageable;
309
+ }, unknown>, Error>>;
310
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
311
+ promise: Promise<import("@tanstack/react-query").InfiniteData<{
312
+ data: TItem[];
313
+ pageable: Pageable;
314
+ }, unknown>>;
315
+ };
316
+ export {};
317
+ //# sourceMappingURL=useAppMessageSearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAppMessageSearch.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/useAppMessageSearch.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAK3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,eAAO,MAAM,gCAAgC,eAK5C,CAAC;AAIF,UAAU,yBAAyB;IACjC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,GAC9B,KAAK,SAAS;IAAE,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAClD,+DAMC,yBAAyB;;;cAKqB,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;;;;;;;;;;;;;;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;;;cAA3B,KAAK,EAAE;kBAAY,QAAQ;;CAuC3E,CAAC"}
@@ -0,0 +1,53 @@
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 { ENDPOINTS } from "../../services/routes";
8
+ import useAuthStore from "../../store/auth";
9
+ // Text, link, quote and mention messages; media, stickers and system messages are not searchable.
10
+ export const APP_MESSAGE_SEARCH_CONTENT_TYPES = [
11
+ MessageType.TextMessage,
12
+ MessageType.UrlTextMessage,
13
+ MessageType.QuoteMessage,
14
+ MessageType.AtTextMessage,
15
+ ];
16
+ const APP_MESSAGE_SEARCH_PAGE_SIZE = PAGE_SIZE.medium;
17
+ /** chat-service `POST /app/messages/search`, newest first, more pages on demand. */
18
+ export const useAppMessageSearch = ({ queryKey, searchTerm, conversationId, enabled, staleTime, }) => {
19
+ const query = useInfiniteQuery({
20
+ initialPageParam: 1,
21
+ queryKey,
22
+ queryFn: async ({ pageParam }) => {
23
+ const res = await apiInstance.post(ENDPOINTS.chatService.searchAppMessages, Object.assign(Object.assign({}, (conversationId ? { conversationId } : {})), { searchTerm, contentTypes: APP_MESSAGE_SEARCH_CONTENT_TYPES, page: pageParam, pageSize: APP_MESSAGE_SEARCH_PAGE_SIZE, applicationType: useAuthStore.getState().applicationType }));
24
+ return res.data;
25
+ },
26
+ // totalElements is always 0, so a short page marks the end. A hit BE drops
27
+ // after paging (rare) can end the list one page early.
28
+ getNextPageParam: (lastPage, pages) => {
29
+ var _a, _b;
30
+ 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) < APP_MESSAGE_SEARCH_PAGE_SIZE
31
+ ? undefined
32
+ : pages.length + 1;
33
+ },
34
+ enabled: enabled && searchTerm !== "",
35
+ retry: false,
36
+ refetchOnWindowFocus: false,
37
+ staleTime,
38
+ });
39
+ // New messages shift the offset pages, so a hit can come back on the next page too.
40
+ const results = useMemo(() => {
41
+ var _a, _b;
42
+ const seen = new Set();
43
+ 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) => {
44
+ var _a;
45
+ const id = (_a = item.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID;
46
+ if (!id || seen.has(id))
47
+ return false;
48
+ seen.add(id);
49
+ return true;
50
+ });
51
+ }, [query.data]);
52
+ return Object.assign(Object.assign({}, query), { results });
53
+ };