@messenger-box/platform-mobile 10.0.3-alpha.34 → 10.0.3-alpha.37

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 (34) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/screens/inbox/components/CachedImage/index.js +125 -93
  3. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  4. package/lib/screens/inbox/components/DialogsListItem.js +80 -256
  5. package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
  6. package/lib/screens/inbox/components/ServiceDialogsListItem.js +222 -324
  7. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
  8. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +0 -2
  9. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  10. package/lib/screens/inbox/containers/ConversationView.js +487 -888
  11. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  12. package/lib/screens/inbox/containers/Dialogs.js +243 -547
  13. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  14. package/lib/screens/inbox/containers/ThreadConversationView.js +409 -1364
  15. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  16. package/package.json +4 -4
  17. package/src/screens/inbox/components/CachedImage/index.tsx +191 -140
  18. package/src/screens/inbox/components/DialogsListItem.tsx +112 -345
  19. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +316 -437
  20. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +2 -4
  21. package/src/screens/inbox/containers/ConversationView.tsx +676 -993
  22. package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
  23. package/src/screens/inbox/containers/Dialogs.tsx +345 -636
  24. package/src/screens/inbox/containers/ThreadConversationView.tsx +661 -1887
  25. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +0 -175
  26. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +0 -1
  27. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +0 -191
  28. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +0 -1
  29. package/lib/screens/inbox/containers/workflow/conversation-xstate.js +0 -380
  30. package/lib/screens/inbox/containers/workflow/conversation-xstate.js.map +0 -1
  31. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +0 -211
  32. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +0 -1
  33. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js +0 -438
  34. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import React__default,{useRef,useCallback,useEffect,useState,useMemo}from'react';import {Box,FlatList,Center,Spinner,Text,Heading,Input,InputField}from'@admin-layout/gluestack-ui-mobile';import {Ionicons}from'@expo/vector-icons';import {useSelector}from'react-redux';import {useRoute,useNavigation,useFocusEffect}from'@react-navigation/native';import {orderBy}from'lodash-es';import {DialogsListItem}from'../components/DialogsListItem.js';import {ServiceDialogsListItem}from'../components/ServiceDialogsListItem.js';import {useGetChannelsByUserWithServiceChannelsQuery}from'common/graphql';import {RoomType}from'common';import {userSelector}from'@adminide-stack/user-auth0-client';import {config}from'../config/config.js';import colors from'tailwindcss/colors';import'./workflow/dialogs-xstate.js';var __defProp = Object.defineProperty;
1
+ import React__default,{useState,useRef,useCallback,useEffect}from'react';import {Box,FlatList,Center,Spinner,Text,Heading,Input,InputField}from'@admin-layout/gluestack-ui-mobile';import {Ionicons}from'@expo/vector-icons';import {useSelector}from'react-redux';import {useRoute,useNavigation,useFocusEffect}from'@react-navigation/native';import {DialogsListItem}from'../components/DialogsListItem.js';import {ServiceDialogsListItem}from'../components/ServiceDialogsListItem.js';import {useGetChannelsByUserWithServiceChannelsQuery,OnChatMessageAddedDocument}from'common/graphql';import {RoomType}from'common';import {userSelector}from'@adminide-stack/user-auth0-client';import {config}from'../config/config.js';import colors from'tailwindcss/colors';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -17,173 +17,6 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- const Actions = {
21
- INITIAL_CONTEXT: "INITIAL_CONTEXT",
22
- ERROR_HANDLED: "ERROR_HANDLED",
23
- FETCH_CHANNELS: "FETCH_CHANNELS",
24
- APPEND_CHANNELS: "APPEND_CHANNELS",
25
- REFRESH_CHANNELS: "REFRESH_CHANNELS",
26
- SELECT_CHANNEL: "SELECT_CHANNEL",
27
- START_LOADING: "START_LOADING",
28
- STOP_LOADING: "STOP_LOADING",
29
- LOAD_MORE_CHANNELS: "LOAD_MORE_CHANNELS",
30
- SET_SEARCH_QUERY: "SET_SEARCH_QUERY"
31
- };
32
- const BaseState = {
33
- Idle: "idle",
34
- Error: "error",
35
- Loading: "loading",
36
- Done: "done",
37
- FetchChannels: "fetchChannels"
38
- };
39
- const MainState = {
40
- RefreshChannels: "refreshChannels",
41
- SelectChannel: "selectChannel",
42
- LoadMoreChannels: "loadMoreChannels"
43
- };
44
- function useSafeMachine(machine) {
45
- const [state, setState] = useState({
46
- context: {
47
- channels: [],
48
- refreshing: false,
49
- loading: false,
50
- error: null,
51
- searchQuery: "",
52
- selectedChannelId: null,
53
- channelRole: null,
54
- channelFilters: {},
55
- supportServices: false,
56
- page: 1,
57
- hasMoreChannels: true,
58
- loadingMore: false
59
- },
60
- value: "idle"
61
- });
62
- const send = useCallback((event) => {
63
- var _a, _b, _c, _d;
64
- try {
65
- console.log("Event received:", event.type);
66
- if (event.type === Actions.INITIAL_CONTEXT) {
67
- setState((prev) => {
68
- var _a2, _b2, _c2, _d2;
69
- return __spreadProps(__spreadValues({}, prev), {
70
- context: __spreadProps(__spreadValues({}, prev.context), {
71
- channelRole: ((_a2 = event.data) == null ? void 0 : _a2.channelRole) || null,
72
- channelFilters: ((_b2 = event.data) == null ? void 0 : _b2.channelFilters) || {},
73
- supportServices: ((_c2 = event.data) == null ? void 0 : _c2.supportServices) || false,
74
- selectedChannelId: ((_d2 = event.data) == null ? void 0 : _d2.selectedChannelId) || null,
75
- loading: true,
76
- page: 1,
77
- hasMoreChannels: true
78
- }),
79
- value: BaseState.FetchChannels
80
- });
81
- });
82
- } else if (event.type === Actions.FETCH_CHANNELS) {
83
- console.log("Setting channels:", ((_b = (_a = event.data) == null ? void 0 : _a.channels) == null ? void 0 : _b.length) || 0);
84
- setState((prev) => {
85
- var _a2, _b2, _c2, _d2, _e;
86
- return __spreadProps(__spreadValues({}, prev), {
87
- context: __spreadProps(__spreadValues({}, prev.context), {
88
- channels: ((_a2 = event.data) == null ? void 0 : _a2.channels) || [],
89
- hasMoreChannels: (((_c2 = (_b2 = event.data) == null ? void 0 : _b2.channels) == null ? void 0 : _c2.length) || 0) > 0,
90
- loading: ((_d2 = event.data) == null ? void 0 : _d2.stopLoading) ? false : prev.context.loading,
91
- refreshing: ((_e = event.data) == null ? void 0 : _e.stopLoading) ? false : prev.context.refreshing,
92
- loadingMore: false
93
- }),
94
- value: BaseState.Idle
95
- });
96
- });
97
- } else if (event.type === Actions.APPEND_CHANNELS) {
98
- const newChannels = ((_c = event.data) == null ? void 0 : _c.channels) || [];
99
- console.log("Appending channels:", newChannels.length);
100
- setState((prev) => __spreadProps(__spreadValues({}, prev), {
101
- context: __spreadProps(__spreadValues({}, prev.context), {
102
- channels: [...prev.context.channels, ...newChannels],
103
- hasMoreChannels: newChannels.length >= 10,
104
- page: prev.context.page + 1,
105
- loadingMore: false
106
- }),
107
- value: BaseState.Idle
108
- }));
109
- } else if (event.type === Actions.REFRESH_CHANNELS) {
110
- setState((prev) => __spreadProps(__spreadValues({}, prev), {
111
- context: __spreadProps(__spreadValues({}, prev.context), {
112
- refreshing: true,
113
- page: 1,
114
- hasMoreChannels: true
115
- }),
116
- value: MainState.RefreshChannels
117
- }));
118
- } else if (event.type === Actions.SELECT_CHANNEL) {
119
- setState((prev) => {
120
- var _a2;
121
- return __spreadProps(__spreadValues({}, prev), {
122
- context: __spreadProps(__spreadValues({}, prev.context), {
123
- selectedChannelId: ((_a2 = event.data) == null ? void 0 : _a2.channelId) || null
124
- })
125
- });
126
- });
127
- } else if (event.type === Actions.START_LOADING) {
128
- setState((prev) => __spreadProps(__spreadValues({}, prev), {
129
- context: __spreadProps(__spreadValues({}, prev.context), {
130
- loading: true
131
- })
132
- }));
133
- } else if (event.type === Actions.STOP_LOADING) {
134
- console.log("Explicitly stopping loading state");
135
- setState((prev) => __spreadProps(__spreadValues({}, prev), {
136
- context: __spreadProps(__spreadValues({}, prev.context), {
137
- loading: false,
138
- refreshing: false,
139
- loadingMore: false
140
- }),
141
- value: prev.value === BaseState.FetchChannels ? BaseState.Idle : prev.value
142
- }));
143
- } else if (event.type === Actions.LOAD_MORE_CHANNELS) {
144
- setState((prev) => __spreadProps(__spreadValues({}, prev), {
145
- context: __spreadProps(__spreadValues({}, prev.context), {
146
- loadingMore: true
147
- }),
148
- value: MainState.LoadMoreChannels
149
- }));
150
- } else if (event.type === Actions.SET_SEARCH_QUERY) {
151
- setState((prev) => {
152
- var _a2;
153
- return __spreadProps(__spreadValues({}, prev), {
154
- context: __spreadProps(__spreadValues({}, prev.context), {
155
- searchQuery: ((_a2 = event.data) == null ? void 0 : _a2.searchQuery) || ""
156
- })
157
- });
158
- });
159
- } else if (event.type === Actions.ERROR_HANDLED) {
160
- console.log("Error handled:", (_d = event.data) == null ? void 0 : _d.message);
161
- setState((prev) => {
162
- var _a2;
163
- return __spreadProps(__spreadValues({}, prev), {
164
- context: __spreadProps(__spreadValues({}, prev.context), {
165
- error: ((_a2 = event.data) == null ? void 0 : _a2.message) || null,
166
- loading: false,
167
- refreshing: false,
168
- loadingMore: false
169
- }),
170
- value: BaseState.Idle
171
- });
172
- });
173
- }
174
- } catch (error) {
175
- console.error("Error handling event:", error);
176
- }
177
- }, []);
178
- const stateWithMatches = useMemo(() => {
179
- return __spreadProps(__spreadValues({}, state), {
180
- matches: (checkState) => {
181
- return state.value === checkState;
182
- }
183
- });
184
- }, [state]);
185
- return [stateWithMatches, send];
186
- }
187
20
  const DialogsComponent = (props) => {
188
21
  var _a;
189
22
  const {
@@ -198,79 +31,23 @@ const DialogsComponent = (props) => {
198
31
  } = useRoute();
199
32
  const auth = useSelector(userSelector);
200
33
  const navigation = useNavigation();
34
+ const [searchQuery, setSearchQuery] = useState("");
35
+ const [selectedChannelId, setSelectedChannelId] = useState((params == null ? void 0 : params.channelId) || null);
36
+ const [page, setPage] = useState(1);
37
+ const [isLoadingMore, setIsLoadingMore] = useState(false);
201
38
  const isMountedRef = useRef(true);
202
- const [state, send] = useSafeMachine();
203
- useCallback(() => {
204
- try {
205
- return (state == null ? void 0 : state.context) || {};
206
- } catch (error) {
207
- console.error("Error accessing state.context:", error);
208
- return {};
209
- }
210
- }, [state]);
211
- const safeContextProperty = useCallback((property, defaultValue = null) => {
212
- var _a2, _b;
213
- try {
214
- return (_b = (_a2 = state == null ? void 0 : state.context) == null ? void 0 : _a2[property]) != null ? _b : defaultValue;
215
- } catch (error) {
216
- console.error(`Error accessing state.context.${property}:`, error);
217
- return defaultValue;
218
- }
219
- }, [state]);
220
- const safeMatches = useCallback((stateValue) => {
221
- var _a2;
222
- try {
223
- return ((_a2 = state == null ? void 0 : state.matches) == null ? void 0 : _a2.call(state, stateValue)) || false;
224
- } catch (error) {
225
- console.error(`Error calling state.matches with ${stateValue}:`, error);
226
- return false;
227
- }
228
- }, [state]);
229
- const safeSend = useCallback((event) => {
230
- try {
231
- send(event);
232
- } catch (error) {
233
- console.error("Error sending event to state machine:", error, event);
234
- }
235
- }, [send]);
236
- const channels = safeContextProperty("channels", []);
237
- const refreshing = safeContextProperty("refreshing", false);
238
- const loading = safeContextProperty("loading", false);
239
- const searchQuery = safeContextProperty("searchQuery", "");
240
- const selectedChannelId = safeContextProperty("selectedChannelId", null);
241
- const loadingMore = safeContextProperty("loadingMore", false);
242
- const hasMoreChannels = safeContextProperty("hasMoreChannels", true);
243
- const page = safeContextProperty("page", 1);
244
- const stateRef = useRef(state);
245
- useEffect(() => {
246
- stateRef.current = state;
247
- }, [state]);
248
- const safeGetContext = useCallback(() => {
249
- if (stateRef.current && stateRef.current.context) {
250
- return stateRef.current.context;
251
- }
252
- return {
253
- channels: [],
254
- refreshing: false,
255
- loading: false,
256
- error: null,
257
- searchQuery: "",
258
- selectedChannelId: null,
259
- channelRole: null,
260
- channelFilters: {},
261
- supportServices: false,
262
- page: 1,
263
- hasMoreChannels: true,
264
- loadingMore: false
265
- };
266
- }, []);
267
- useEffect(() => {
268
- return () => {
269
- isMountedRef.current = false;
270
- };
271
- }, []);
39
+ const focusRefreshRef = useRef(null);
40
+ const lastRefreshTimeRef = useRef(Date.now());
41
+ const MIN_REFRESH_INTERVAL = 2e3;
42
+ const lastNavigationTimestamp = useRef(0);
43
+ const activeChannelRef = useRef(null);
44
+ const resetActiveChannelTimeoutRef = useRef(null);
272
45
  const {
273
- refetch: getChannelsRefetch
46
+ data,
47
+ loading,
48
+ refetch,
49
+ fetchMore,
50
+ subscribeToMore
274
51
  } = useGetChannelsByUserWithServiceChannelsQuery({
275
52
  variables: {
276
53
  role: channelRole,
@@ -284,236 +61,189 @@ const DialogsComponent = (props) => {
284
61
  },
285
62
  fetchPolicy: "cache-and-network",
286
63
  nextFetchPolicy: "network-only",
287
- notifyOnNetworkStatusChange: true,
288
- skip: true
64
+ notifyOnNetworkStatusChange: true
289
65
  });
290
- const fetchChannelsDirectly = useCallback(async (pageNum = 1, append = false) => {
291
- var _a2, _b, _c;
292
- try {
293
- const context = safeGetContext();
294
- console.log(`\u{1F4AB} FETCHING channels (page: ${pageNum}, append: ${append})`);
295
- const skipCount = (pageNum - 1) * 15;
296
- const fetchPromise = getChannelsRefetch({
297
- role: channelRole,
298
- criteria: channelFilters,
299
- supportServices: supportServices ? true : false,
300
- supportServiceCriteria: {
301
- type: RoomType.Service
302
- },
303
- limit: 15,
304
- skip: skipCount
305
- });
306
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout")), 8e3));
307
- const result = await Promise.race([fetchPromise, timeoutPromise]);
308
- const data = (result == null ? void 0 : result.data) || {};
309
- const allChannels = [...(_a2 = data == null ? void 0 : data.supportServiceChannels) != null ? _a2 : [], ...(_b = data == null ? void 0 : data.channelsByUser) != null ? _b : []];
310
- const filteredChannels = (_c = allChannels == null ? void 0 : allChannels.filter((c) => {
311
- if (!c || !c.members)
312
- return false;
313
- for (const member of c.members) {
314
- if (member && member.user && member.user.id !== (auth == null ? void 0 : auth.id) && member.user.__typename === "UserAccount") {
315
- return true;
316
- }
317
- }
66
+ const processChannels = useCallback((rawChannels = []) => {
67
+ if (!rawChannels || !rawChannels.length)
68
+ return [];
69
+ const filteredChannels2 = rawChannels.filter((c) => {
70
+ if (!c || !c.members)
318
71
  return false;
319
- })) != null ? _c : [];
320
- const sortedChannels = filteredChannels.sort((a, b) => {
321
- const dateA = new Date(a.updatedAt);
322
- const dateB = new Date(b.updatedAt);
323
- return dateB.getTime() - dateA.getTime();
324
- }) || [];
325
- console.log(`\u{1F4CA} Processed channels: ${sortedChannels.length} (page: ${pageNum}, skip: ${skipCount})`);
326
- if (isMountedRef.current) {
327
- if (append) {
328
- safeSend({
329
- type: Actions.APPEND_CHANNELS,
330
- data: {
331
- channels: sortedChannels
332
- }
333
- });
334
- } else {
335
- safeSend({
336
- type: Actions.FETCH_CHANNELS,
337
- data: {
338
- channels: sortedChannels,
339
- stopLoading: true
340
- }
341
- });
72
+ for (const member of c.members) {
73
+ if (member && member.user && member.user.id !== (auth == null ? void 0 : auth.id) && member.user.__typename === "UserAccount") {
74
+ return true;
342
75
  }
343
76
  }
344
- } catch (error) {
345
- console.error("Error fetching channels:", error);
346
- if (isMountedRef.current) {
347
- safeSend({
348
- type: Actions.ERROR_HANDLED,
349
- data: {
350
- message: "Failed to fetch channels"
351
- }
77
+ return false;
78
+ });
79
+ return filteredChannels2.map((channel) => {
80
+ if (channel.lastMessage) {
81
+ return __spreadProps(__spreadValues({}, channel), {
82
+ lastMessage: __spreadProps(__spreadValues({}, channel.lastMessage), {
83
+ id: channel.lastMessage.id,
84
+ message: channel.lastMessage.message,
85
+ createdAt: channel.lastMessage.createdAt || channel.lastMessage.updatedAt,
86
+ updatedAt: channel.lastMessage.updatedAt || channel.lastMessage.createdAt,
87
+ userId: channel.lastMessage.userId,
88
+ channelId: channel.lastMessage.channelId || channel.id
89
+ })
352
90
  });
353
91
  }
354
- }
355
- }, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
92
+ return channel;
93
+ });
94
+ }, [auth == null ? void 0 : auth.id]);
95
+ const sortChannels = useCallback((channels2) => {
96
+ if (!channels2 || !channels2.length)
97
+ return [];
98
+ return [...channels2].sort((a, b) => {
99
+ const dateA = new Date((a == null ? void 0 : a.updatedAt) || (a == null ? void 0 : a.createdAt)).getTime();
100
+ const dateB = new Date((b == null ? void 0 : b.updatedAt) || (b == null ? void 0 : b.createdAt)).getTime();
101
+ return dateB - dateA;
102
+ });
103
+ }, []);
104
+ const allChannels = [...(data == null ? void 0 : data.supportServiceChannels) || [], ...(data == null ? void 0 : data.channelsByUser) || []];
105
+ const channels = sortChannels(processChannels(allChannels));
356
106
  useEffect(() => {
357
- if (loading) {
358
- const safetyTimeout = setTimeout(() => {
359
- console.log("\u26A0\uFE0F Safety timeout triggered - forcing loading state to stop");
360
- if (isMountedRef.current) {
361
- safeSend({
362
- type: Actions.STOP_LOADING
363
- });
364
- }
365
- }, 3e3);
366
- return () => clearTimeout(safetyTimeout);
367
- }
368
- }, [loading, safeSend]);
369
- const fastRefresh = useCallback(async () => {
370
- var _a2, _b, _c;
371
- try {
372
- console.log("\u{1F504} Fast refreshing channels...");
373
- const clearRefreshingTimeout = setTimeout(() => {
374
- if (isMountedRef.current) {
375
- console.log("\u26A0\uFE0F Fast refresh timeout - stopping refresh state");
376
- safeSend({
377
- type: Actions.STOP_LOADING
107
+ if (!auth || !auth.id)
108
+ return;
109
+ console.log("\u{1F4F1} Setting up global message subscription for dialog updates");
110
+ const unsubscribe = subscribeToMore({
111
+ document: OnChatMessageAddedDocument,
112
+ variables: {},
113
+ updateQuery: (prev, {
114
+ subscriptionData
115
+ }) => {
116
+ var _a2, _b;
117
+ try {
118
+ if (!subscriptionData.data || !isMountedRef.current)
119
+ return prev;
120
+ const subData = subscriptionData.data;
121
+ const newMessage = subData.chatMessageAdded;
122
+ console.log("\u{1F4F1} Dialog subscription received message update:", newMessage == null ? void 0 : newMessage.id);
123
+ if (!newMessage || !newMessage.channelId)
124
+ return prev;
125
+ const channelId = newMessage.channelId.toString();
126
+ let foundInDirectChannels = false;
127
+ let foundInServiceChannels = false;
128
+ const directChannelIndex = (_a2 = prev.channelsByUser) == null ? void 0 : _a2.findIndex((c) => c.id.toString() === channelId);
129
+ if (directChannelIndex !== void 0 && directChannelIndex >= 0) {
130
+ foundInDirectChannels = true;
131
+ }
132
+ const serviceChannelIndex = (_b = prev.supportServiceChannels) == null ? void 0 : _b.findIndex((c) => c.id.toString() === channelId);
133
+ if (serviceChannelIndex !== void 0 && serviceChannelIndex >= 0) {
134
+ foundInServiceChannels = true;
135
+ }
136
+ const result = __spreadProps(__spreadValues({}, prev), {
137
+ channelsByUser: [...prev.channelsByUser || []],
138
+ supportServiceChannels: [...prev.supportServiceChannels || []]
378
139
  });
379
- }
380
- }, 3e3);
381
- const {
382
- data
383
- } = await getChannelsRefetch({
384
- role: channelRole,
385
- criteria: channelFilters,
386
- supportServices: supportServices ? true : false,
387
- supportServiceCriteria: {
388
- type: RoomType.Service
389
- },
390
- limit: 10,
391
- skip: 0
392
- });
393
- clearTimeout(clearRefreshingTimeout);
394
- if (!isMountedRef.current)
395
- return;
396
- const allChannels = [...(_a2 = data == null ? void 0 : data.supportServiceChannels) != null ? _a2 : [], ...(_b = data == null ? void 0 : data.channelsByUser) != null ? _b : []];
397
- const filteredChannels = (_c = allChannels == null ? void 0 : allChannels.filter((c) => c.members.some((u) => {
398
- var _a3;
399
- return u !== null && ((_a3 = u == null ? void 0 : u.user) == null ? void 0 : _a3.id) != (auth == null ? void 0 : auth.id) && u.user.__typename == "UserAccount";
400
- }))) != null ? _c : [];
401
- const sortedChannels = filteredChannels && orderBy(filteredChannels, ["updatedAt"], ["desc"]) || [];
402
- console.log(`\u{1F4CA} Fast refresh completed: ${sortedChannels.length} channels`);
403
- if (isMountedRef.current) {
404
- safeSend({
405
- type: Actions.FETCH_CHANNELS,
406
- data: {
407
- channels: sortedChannels,
408
- stopLoading: true
140
+ if (foundInDirectChannels && directChannelIndex >= 0) {
141
+ const channel = __spreadValues({}, result.channelsByUser[directChannelIndex]);
142
+ channel.lastMessage = newMessage;
143
+ channel.updatedAt = newMessage.createdAt || new Date().toISOString();
144
+ result.channelsByUser[directChannelIndex] = channel;
409
145
  }
410
- });
411
- }
412
- } catch (error) {
413
- console.error("Error during fast refresh:", error);
414
- if (isMountedRef.current) {
415
- safeSend({
416
- type: Actions.STOP_LOADING
417
- });
146
+ if (foundInServiceChannels && serviceChannelIndex >= 0) {
147
+ const channel = __spreadValues({}, result.supportServiceChannels[serviceChannelIndex]);
148
+ channel.lastMessage = newMessage;
149
+ channel.updatedAt = newMessage.createdAt || new Date().toISOString();
150
+ result.supportServiceChannels[serviceChannelIndex] = channel;
151
+ }
152
+ return result;
153
+ } catch (error) {
154
+ console.error("Error in dialog subscription handler:", error);
155
+ return prev;
156
+ }
418
157
  }
419
- }
420
- }, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
158
+ });
159
+ return () => {
160
+ console.log("\u{1F4F1} Cleaning up dialog message subscription");
161
+ unsubscribe();
162
+ };
163
+ }, [auth == null ? void 0 : auth.id, subscribeToMore]);
421
164
  useEffect(() => {
422
- const context = safeGetContext();
423
- const isAlreadyFetching = context.refreshing || context.loading;
424
- if (!isAlreadyFetching) {
425
- if (safeMatches(BaseState.FetchChannels)) {
426
- console.log("\u{1F504} Fetching channels...");
427
- fetchChannelsDirectly(1, false);
428
- } else if (safeMatches(MainState.RefreshChannels)) {
429
- console.log("\u{1F504} Refreshing channels...");
430
- fetchChannelsDirectly(1, false);
431
- } else if (safeMatches(MainState.LoadMoreChannels)) {
432
- console.log("\u{1F504} Loading more channels...");
433
- fetchChannelsDirectly(page, true);
165
+ return () => {
166
+ isMountedRef.current = false;
167
+ if (resetActiveChannelTimeoutRef.current) {
168
+ clearTimeout(resetActiveChannelTimeoutRef.current);
434
169
  }
435
- } else {
436
- console.log("\u23E9 Skipping fetch because isAlreadyFetching:", isAlreadyFetching);
437
- }
438
- }, [fetchChannelsDirectly, safeMatches, safeGetContext, state.value, page]);
439
- useEffect(() => {
440
- console.log("State changed to:", state.value);
441
- console.log("Context:", JSON.stringify({
442
- channelsCount: channels.length,
443
- loading,
444
- refreshing
445
- }));
446
- }, [state.value, channels.length, loading, refreshing]);
447
- useEffect(() => {
448
- if (isMountedRef.current) {
449
- console.log("\u{1F680} Initializing state machine with props", {
450
- channelRole,
451
- channelFilters,
452
- supportServices,
453
- selectedChannelId: params == null ? void 0 : params.channelId
454
- });
455
- safeSend({
456
- type: Actions.INITIAL_CONTEXT,
457
- data: {
458
- channelRole,
459
- channelFilters,
460
- supportServices,
461
- selectedChannelId: params == null ? void 0 : params.channelId
462
- }
463
- });
464
- const initSafetyTimeout = setTimeout(() => {
465
- if (isMountedRef.current && loading) {
466
- console.log("\u26A0\uFE0F Init safety timeout triggered - forcing loading state to stop");
467
- safeSend({
468
- type: Actions.STOP_LOADING
469
- });
470
- }
471
- }, 8e3);
472
- return () => clearTimeout(initSafetyTimeout);
473
- }
170
+ };
474
171
  }, []);
475
- const focusRefreshRef = useRef(null);
476
172
  useFocusEffect(useCallback(() => {
477
- let hasTriggeredRefresh = false;
478
173
  const now = Date.now();
479
- const lastRefresh = focusRefreshRef.current;
480
- const shouldRefresh = lastRefresh === null || now - lastRefresh > 2e3;
481
- const context = safeGetContext();
482
- const isAlreadyFetching = context.refreshing || context.loading;
483
- if (isMountedRef.current && !hasTriggeredRefresh && !isAlreadyFetching && shouldRefresh && (channels.length > 0 || safeMatches(BaseState.Idle))) {
484
- hasTriggeredRefresh = true;
485
- focusRefreshRef.current = now;
486
- console.log("\u{1F504} Focus effect: triggering fast refresh");
487
- safeSend({
488
- type: Actions.START_LOADING,
489
- data: {
490
- refreshing: true
491
- }
492
- });
493
- setTimeout(() => {
494
- if (isMountedRef.current) {
495
- fastRefresh();
496
- }
497
- }, 100);
498
- } else {
499
- console.log("\u23E9 Skipping focus refresh:", {
500
- isAlreadyFetching,
501
- hasTriggeredRefresh,
502
- shouldRefresh,
503
- timeGap: lastRefresh === null ? "first refresh" : now - lastRefresh
504
- });
174
+ if (now - lastNavigationTimestamp.current > 300) {
175
+ activeChannelRef.current = null;
176
+ console.log("Reset active channel reference on focus");
505
177
  }
506
178
  return () => {
507
- hasTriggeredRefresh = false;
179
+ lastNavigationTimestamp.current = Date.now();
508
180
  };
509
- }, [safeSend, channels.length, safeMatches, safeGetContext, fastRefresh]));
510
- const handleSelectChannel = useCallback((id, title) => {
511
- safeSend({
512
- type: Actions.SELECT_CHANNEL,
513
- data: {
514
- channelId: id
181
+ }, []));
182
+ useFocusEffect(useCallback(() => {
183
+ console.log("\u{1F4F1} Focus effect triggered for Dialogs screen");
184
+ const performRefresh = () => {
185
+ const now = Date.now();
186
+ if (now - lastRefreshTimeRef.current < MIN_REFRESH_INTERVAL) {
187
+ console.log("\u23E9 Skipping refresh: too soon after previous refresh");
188
+ return;
515
189
  }
190
+ console.log("\u{1F504} Performing refresh on screen focus");
191
+ if (isMountedRef.current) {
192
+ lastRefreshTimeRef.current = now;
193
+ refetch();
194
+ }
195
+ };
196
+ const focusRefreshTimeout = setTimeout(performRefresh, 100);
197
+ return () => clearTimeout(focusRefreshTimeout);
198
+ }, [refetch]));
199
+ const handlePullToRefresh = useCallback(() => {
200
+ const now = Date.now();
201
+ focusRefreshRef.current = now;
202
+ console.log("\u{1F504} Pull-to-refresh triggered");
203
+ refetch();
204
+ }, [refetch]);
205
+ const handleLoadMore = useCallback(() => {
206
+ if (isLoadingMore || !data || channels.length < 10) {
207
+ console.log("Skip loading more: already loading or all data loaded");
208
+ return;
209
+ }
210
+ console.log("Loading more channels at page:", page + 1);
211
+ setIsLoadingMore(true);
212
+ fetchMore({
213
+ variables: {
214
+ skip: page * 15
215
+ },
216
+ updateQuery: (prev, {
217
+ fetchMoreResult
218
+ }) => {
219
+ setIsLoadingMore(false);
220
+ setPage((prevPage) => prevPage + 1);
221
+ if (!fetchMoreResult)
222
+ return prev;
223
+ return __spreadProps(__spreadValues({}, fetchMoreResult), {
224
+ channelsByUser: [...prev.channelsByUser || [], ...fetchMoreResult.channelsByUser || []],
225
+ supportServiceChannels: [...prev.supportServiceChannels || [], ...fetchMoreResult.supportServiceChannels || []]
226
+ });
227
+ }
228
+ }).catch((error) => {
229
+ console.error("Error loading more channels:", error);
230
+ setIsLoadingMore(false);
516
231
  });
232
+ }, [fetchMore, isLoadingMore, data, channels.length, page]);
233
+ const handleSelectChannel = useCallback((id, title) => {
234
+ if (activeChannelRef.current === id) {
235
+ console.log("\u{1F4F1} Ignoring repeated tap on channel:", id);
236
+ return;
237
+ }
238
+ activeChannelRef.current = id;
239
+ if (resetActiveChannelTimeoutRef.current) {
240
+ clearTimeout(resetActiveChannelTimeoutRef.current);
241
+ }
242
+ resetActiveChannelTimeoutRef.current = setTimeout(() => {
243
+ activeChannelRef.current = null;
244
+ }, 2e3);
245
+ setSelectedChannelId(id);
246
+ console.log("\u{1F4F1} Navigating to channel:", id);
517
247
  navigation.navigate(config.INBOX_MESSEGE_PATH, {
518
248
  channelId: id,
519
249
  role: channelRole,
@@ -521,14 +251,21 @@ const DialogsComponent = (props) => {
521
251
  hideTabBar: true,
522
252
  timestamp: new Date().getTime()
523
253
  });
524
- }, [navigation, channelRole, safeSend]);
254
+ }, [navigation, channelRole]);
525
255
  const handleSelectServiceChannel = useCallback((id, title, postParentId) => {
526
- safeSend({
527
- type: Actions.SELECT_CHANNEL,
528
- data: {
529
- channelId: id
530
- }
531
- });
256
+ if (activeChannelRef.current === id) {
257
+ console.log("\u{1F4F1} Ignoring repeated tap on service channel:", id);
258
+ return;
259
+ }
260
+ activeChannelRef.current = id;
261
+ if (resetActiveChannelTimeoutRef.current) {
262
+ clearTimeout(resetActiveChannelTimeoutRef.current);
263
+ }
264
+ resetActiveChannelTimeoutRef.current = setTimeout(() => {
265
+ activeChannelRef.current = null;
266
+ }, 2e3);
267
+ setSelectedChannelId(id);
268
+ console.log("\u{1F4F1} Navigating to service channel:", id);
532
269
  navigation.navigate(postParentId || postParentId === 0 ? config.THREAD_MESSEGE_PATH : config.THREADS_PATH, {
533
270
  channelId: id,
534
271
  role: channelRole,
@@ -536,102 +273,61 @@ const DialogsComponent = (props) => {
536
273
  postParentId,
537
274
  hideTabBar: true
538
275
  });
539
- }, [navigation, channelRole, safeSend]);
540
- const handlePullToRefresh = useCallback(() => {
541
- if (refreshing) {
542
- console.log("\u23E9 Skipping refresh because already refreshing");
543
- return;
544
- }
545
- const now = Date.now();
546
- focusRefreshRef.current = now;
547
- console.log("\u{1F504} Pull-to-refresh triggered");
548
- safeSend({
549
- type: Actions.START_LOADING,
550
- data: {
551
- refreshing: true
552
- }
553
- });
554
- fastRefresh();
555
- }, [safeSend, refreshing, fastRefresh]);
276
+ }, [navigation, channelRole]);
556
277
  const handleSearchChange = useCallback((text) => {
557
- safeSend({
558
- type: Actions.SET_SEARCH_QUERY,
559
- data: {
560
- searchQuery: text
278
+ setSearchQuery(text);
279
+ }, []);
280
+ const filteredChannels = useCallback(() => {
281
+ if (!searchQuery.trim())
282
+ return channels;
283
+ const query = searchQuery.toLowerCase();
284
+ return channels.filter((channel) => {
285
+ if (channel.title && channel.title.toLowerCase().includes(query)) {
286
+ return true;
561
287
  }
562
- });
563
- }, [safeSend]);
564
- const handleLoadMore = useCallback(() => {
565
- if (!loadingMore && hasMoreChannels) {
566
- console.log("Loading more channels at page:", page + 1);
567
- safeSend({
568
- type: Actions.LOAD_MORE_CHANNELS
569
- });
570
- } else {
571
- console.log("Skip loading more: loadingMore=", loadingMore, "hasMoreChannels=", hasMoreChannels);
572
- }
573
- }, [safeSend, loadingMore, hasMoreChannels, page]);
574
- return /* @__PURE__ */ React__default.createElement(Box, { className: "p-2" }, /* @__PURE__ */ React__default.createElement(
575
- FlatList,
576
- {
577
- data: channels,
578
- onRefresh: handlePullToRefresh,
579
- refreshing,
580
- contentContainerStyle: {
581
- minHeight: "100%"
582
- },
583
- ItemSeparatorComponent: () => /* @__PURE__ */ React__default.createElement(Box, { className: "h-0.5 bg-gray-200" }),
584
- renderItem: ({
585
- item: channel
586
- }) => {
587
- const key = `${channel.type === RoomType.Service ? "service" : "direct"}-${channel.id}`;
588
- return (channel == null ? void 0 : channel.type) === RoomType.Service ? /* @__PURE__ */ React__default.createElement(ServiceDialogsListItem, { key, onOpen: handleSelectServiceChannel, currentUser: auth, channel, refreshing, selectedChannelId, role: channelRole }) : /* @__PURE__ */ React__default.createElement(
589
- DialogsListItem,
590
- {
591
- key,
592
- onOpen: handleSelectChannel,
593
- currentUser: auth,
594
- channel,
595
- selectedChannelId,
596
- forceRefresh: false
288
+ if (channel.members) {
289
+ for (const member of channel.members) {
290
+ const user = member == null ? void 0 : member.user;
291
+ if (!user)
292
+ continue;
293
+ const fullName = `${user.givenName || ""} ${user.familyName || ""}`.toLowerCase();
294
+ if (fullName.includes(query)) {
295
+ return true;
296
+ }
297
+ if (user.username && user.username.toLowerCase().includes(query)) {
298
+ return true;
597
299
  }
598
- );
599
- },
600
- ListFooterComponent: () => loadingMore ? /* @__PURE__ */ React__default.createElement(Center, { className: "py-4" }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "small" })) : null,
601
- onEndReached: handleLoadMore,
602
- onEndReachedThreshold: 0.5,
603
- initialNumToRender: 5,
604
- maxToRenderPerBatch: 5,
605
- windowSize: 5,
606
- removeClippedSubviews: true,
607
- updateCellsBatchingPeriod: 100,
608
- getItemLayout: (data, index) => ({
609
- length: 80,
610
- offset: 80 * index,
611
- index
612
- }),
613
- keyExtractor: (item) => `channel-${item.id}`,
614
- ListEmptyComponent: () => {
615
- console.log("Rendering ListEmptyComponent", {
616
- loading,
617
- refreshing,
618
- stateValue: state.value
619
- });
620
- if (loading && channels.length === 0) {
621
- return /* @__PURE__ */ React__default.createElement(Center, { className: "flex-1 justify-center items-center", style: {
622
- height: 300
623
- } }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "large" }), /* @__PURE__ */ React__default.createElement(Text, { className: "mt-4 text-gray-500" }, "Loading conversations..."));
624
300
  }
625
- return /* @__PURE__ */ React__default.createElement(Box, { className: "p-6" }, /* @__PURE__ */ React__default.createElement(Box, { className: "mb-6" }, /* @__PURE__ */ React__default.createElement(Heading, { className: "text-2xl font-bold" }, "Direct Messages"), /* @__PURE__ */ React__default.createElement(Text, { className: "text-gray-600 mt-1" }, "Private conversations with other users")), /* @__PURE__ */ React__default.createElement(Input, { className: "mb-8 h-[50] rounded-md border-gray-300 border", size: "md", style: {
626
- paddingVertical: 8,
627
- marginBottom: 10,
628
- borderColor: "#d1d5db",
629
- borderRadius: 10
630
- } }, /* @__PURE__ */ React__default.createElement(InputField, { placeholder: "Search messages...", onChangeText: handleSearchChange, value: searchQuery })), /* @__PURE__ */ React__default.createElement(Center, { className: "items-center", style: {
631
- paddingVertical: 5
632
- } }, /* @__PURE__ */ React__default.createElement(Box, { className: "w-16 h-16 rounded-full bg-blue-500 flex items-center justify-center mb-5" }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "chatbubble-ellipses", size: 30, color: "white" })), /* @__PURE__ */ React__default.createElement(Text, { className: "text-2xl font-bold text-center mb-2" }, "No messages yet"), /* @__PURE__ */ React__default.createElement(Text, { className: "text-gray-600 text-center mb-8" }, "When you start conversations with others,", "\n", "they'll appear here.")));
633
301
  }
302
+ return false;
303
+ });
304
+ }, [channels, searchQuery]);
305
+ const displayChannels = filteredChannels();
306
+ return /* @__PURE__ */ React__default.createElement(Box, { className: "p-2" }, /* @__PURE__ */ React__default.createElement(FlatList, { data: displayChannels, onRefresh: handlePullToRefresh, refreshing: loading && !isLoadingMore, contentContainerStyle: {
307
+ minHeight: "100%"
308
+ }, ItemSeparatorComponent: () => /* @__PURE__ */ React__default.createElement(Box, { className: "h-0.5 bg-gray-200" }), renderItem: ({
309
+ item: channel
310
+ }) => {
311
+ const key = `${channel.type === RoomType.Service ? "service" : "direct"}-${channel.id}`;
312
+ return (channel == null ? void 0 : channel.type) === RoomType.Service ? /* @__PURE__ */ React__default.createElement(ServiceDialogsListItem, { key, onOpen: handleSelectServiceChannel, currentUser: auth, channel, refreshing: loading, selectedChannelId, role: channelRole }) : /* @__PURE__ */ React__default.createElement(DialogsListItem, { key, onOpen: handleSelectChannel, currentUser: auth, channel, selectedChannelId, forceRefresh: true });
313
+ }, ListFooterComponent: () => isLoadingMore ? /* @__PURE__ */ React__default.createElement(Center, { className: "py-4" }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "small" })) : null, onEndReached: handleLoadMore, onEndReachedThreshold: 0.5, initialNumToRender: 5, maxToRenderPerBatch: 5, windowSize: 5, removeClippedSubviews: true, updateCellsBatchingPeriod: 100, getItemLayout: (data2, index) => ({
314
+ length: 80,
315
+ offset: 80 * index,
316
+ index
317
+ }), keyExtractor: (item) => `channel-${item.id}`, ListEmptyComponent: () => {
318
+ if (loading && displayChannels.length === 0) {
319
+ return /* @__PURE__ */ React__default.createElement(Center, { className: "flex-1 justify-center items-center", style: {
320
+ height: 300
321
+ } }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "large" }), /* @__PURE__ */ React__default.createElement(Text, { className: "mt-4 text-gray-500" }, "Loading conversations..."));
634
322
  }
635
- ));
323
+ return /* @__PURE__ */ React__default.createElement(Box, { className: "p-6" }, /* @__PURE__ */ React__default.createElement(Box, { className: "mb-6" }, /* @__PURE__ */ React__default.createElement(Heading, { className: "text-2xl font-bold" }, "Direct Messages"), /* @__PURE__ */ React__default.createElement(Text, { className: "text-gray-600 mt-1" }, "Private conversations with other users")), /* @__PURE__ */ React__default.createElement(Input, { className: "mb-8 h-[50] rounded-md border-gray-300 border", size: "md", style: {
324
+ paddingVertical: 8,
325
+ marginBottom: 10,
326
+ borderColor: "#d1d5db",
327
+ borderRadius: 10
328
+ } }, /* @__PURE__ */ React__default.createElement(InputField, { placeholder: "Search messages...", onChangeText: handleSearchChange, value: searchQuery })), /* @__PURE__ */ React__default.createElement(Center, { className: "items-center", style: {
329
+ paddingVertical: 5
330
+ } }, /* @__PURE__ */ React__default.createElement(Box, { className: "w-16 h-16 rounded-full bg-blue-500 flex items-center justify-center mb-5" }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "chatbubble-ellipses", size: 30, color: "white" })), /* @__PURE__ */ React__default.createElement(Text, { className: "text-2xl font-bold text-center mb-2" }, "No messages yet"), /* @__PURE__ */ React__default.createElement(Text, { className: "text-gray-600 text-center mb-8" }, "When you start conversations with others,", "\n", "they'll appear here.")));
331
+ } }));
636
332
  };
637
333
  const Dialogs = React__default.memo(DialogsComponent);export{Dialogs};//# sourceMappingURL=Dialogs.js.map