@messenger-box/platform-mobile 10.0.3-alpha.18 → 10.0.3-alpha.20

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 (23) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/screens/inbox/components/DialogsListItem.js +423 -50
  3. package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
  4. package/lib/screens/inbox/components/ServiceDialogsListItem.js +375 -51
  5. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
  6. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +175 -0
  7. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +1 -0
  8. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +191 -0
  9. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +1 -0
  10. package/lib/screens/inbox/containers/Dialogs.js +382 -181
  11. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  12. package/lib/screens/inbox/containers/ThreadConversationView.js +536 -48
  13. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  14. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +1 -25
  15. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +1 -1
  16. package/package.json +2 -2
  17. package/src/screens/inbox/components/DialogsListItem.tsx +624 -107
  18. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +506 -114
  19. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +35 -17
  20. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
  21. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
  22. package/src/screens/inbox/containers/Dialogs.tsx +531 -281
  23. package/src/screens/inbox/containers/ThreadConversationView.tsx +812 -37
@@ -1,4 +1,4 @@
1
- import React__default,{useRef,useCallback,useEffect,useState,useMemo}from'react';import {Box,FlatList,Center,Spinner,Heading,Input,InputField,Text}from'@admin-layout/gluestack-ui-mobile';import {Ionicons}from'@expo/vector-icons';import {useSelector,useDispatch}from'react-redux';import {useRoute,useNavigation,useIsFocused,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 {Actions,BaseState,MainState}from'./workflow/dialogs-xstate.js';var __defProp = Object.defineProperty;
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;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -17,6 +17,30 @@ 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
+ };
20
44
  function useSafeMachine(machine) {
21
45
  const [state, setState] = useState({
22
46
  context: {
@@ -28,50 +52,76 @@ function useSafeMachine(machine) {
28
52
  selectedChannelId: null,
29
53
  channelRole: null,
30
54
  channelFilters: {},
31
- supportServices: false
55
+ supportServices: false,
56
+ page: 1,
57
+ hasMoreChannels: true,
58
+ loadingMore: false
32
59
  },
33
60
  value: "idle"
34
61
  });
35
62
  const send = useCallback((event) => {
63
+ var _a, _b, _c, _d;
36
64
  try {
37
- console.log("Dialogs Event received:", event.type);
65
+ console.log("Event received:", event.type);
38
66
  if (event.type === Actions.INITIAL_CONTEXT) {
39
67
  setState((prev) => {
40
- var _a, _b, _c, _d;
68
+ var _a2, _b2, _c2, _d2;
41
69
  return __spreadProps(__spreadValues({}, prev), {
42
70
  context: __spreadProps(__spreadValues({}, prev.context), {
43
- channelRole: ((_a = event.data) == null ? void 0 : _a.channelRole) || null,
44
- channelFilters: ((_b = event.data) == null ? void 0 : _b.channelFilters) || {},
45
- supportServices: ((_c = event.data) == null ? void 0 : _c.supportServices) || false,
46
- selectedChannelId: ((_d = event.data) == null ? void 0 : _d.selectedChannelId) || null
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
47
78
  }),
48
79
  value: BaseState.FetchChannels
49
80
  });
50
81
  });
51
- } else if (event.type === Actions.SET_SEARCH_QUERY) {
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);
52
84
  setState((prev) => {
53
- var _a;
85
+ var _a2, _b2, _c2, _d2, _e;
54
86
  return __spreadProps(__spreadValues({}, prev), {
55
87
  context: __spreadProps(__spreadValues({}, prev.context), {
56
- searchQuery: ((_a = event.data) == null ? void 0 : _a.searchQuery) || ""
57
- })
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
58
95
  });
59
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
+ }));
60
109
  } else if (event.type === Actions.REFRESH_CHANNELS) {
61
110
  setState((prev) => __spreadProps(__spreadValues({}, prev), {
62
111
  context: __spreadProps(__spreadValues({}, prev.context), {
63
- refreshing: true
112
+ refreshing: true,
113
+ page: 1,
114
+ hasMoreChannels: true
64
115
  }),
65
116
  value: MainState.RefreshChannels
66
117
  }));
67
118
  } else if (event.type === Actions.SELECT_CHANNEL) {
68
119
  setState((prev) => {
69
- var _a;
120
+ var _a2;
70
121
  return __spreadProps(__spreadValues({}, prev), {
71
122
  context: __spreadProps(__spreadValues({}, prev.context), {
72
- selectedChannelId: ((_a = event.data) == null ? void 0 : _a.channelId) || null
73
- }),
74
- value: MainState.SelectChannel
123
+ selectedChannelId: ((_a2 = event.data) == null ? void 0 : _a2.channelId) || null
124
+ })
75
125
  });
76
126
  });
77
127
  } else if (event.type === Actions.START_LOADING) {
@@ -81,54 +131,55 @@ function useSafeMachine(machine) {
81
131
  })
82
132
  }));
83
133
  } else if (event.type === Actions.STOP_LOADING) {
134
+ console.log("Explicitly stopping loading state");
84
135
  setState((prev) => __spreadProps(__spreadValues({}, prev), {
85
136
  context: __spreadProps(__spreadValues({}, prev.context), {
86
- loading: false
87
- })
137
+ loading: false,
138
+ refreshing: false,
139
+ loadingMore: false
140
+ }),
141
+ value: prev.value === BaseState.FetchChannels ? BaseState.Idle : prev.value
88
142
  }));
89
- } else if (event.type === "FETCH_CHANNELS_SUCCESS") {
90
- setState((prev) => {
91
- var _a;
92
- return __spreadProps(__spreadValues({}, prev), {
93
- context: __spreadProps(__spreadValues({}, prev.context), {
94
- channels: ((_a = event.data) == null ? void 0 : _a.channels) || [],
95
- loading: false,
96
- refreshing: false
97
- }),
98
- value: BaseState.Idle
99
- });
100
- });
101
- } else if (event.type === "REFRESH_CHANNELS_SUCCESS") {
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) {
102
151
  setState((prev) => {
103
- var _a;
152
+ var _a2;
104
153
  return __spreadProps(__spreadValues({}, prev), {
105
154
  context: __spreadProps(__spreadValues({}, prev.context), {
106
- channels: ((_a = event.data) == null ? void 0 : _a.channels) || [],
107
- refreshing: false
108
- }),
109
- value: BaseState.Idle
155
+ searchQuery: ((_a2 = event.data) == null ? void 0 : _a2.searchQuery) || ""
156
+ })
110
157
  });
111
158
  });
112
- } else if (event.type === "ERROR") {
159
+ } else if (event.type === Actions.ERROR_HANDLED) {
160
+ console.log("Error handled:", (_d = event.data) == null ? void 0 : _d.message);
113
161
  setState((prev) => {
114
- var _a;
162
+ var _a2;
115
163
  return __spreadProps(__spreadValues({}, prev), {
116
164
  context: __spreadProps(__spreadValues({}, prev.context), {
117
- error: ((_a = event.data) == null ? void 0 : _a.message) || "An error occurred",
165
+ error: ((_a2 = event.data) == null ? void 0 : _a2.message) || null,
118
166
  loading: false,
119
- refreshing: false
167
+ refreshing: false,
168
+ loadingMore: false
120
169
  }),
121
- value: BaseState.Error
170
+ value: BaseState.Idle
122
171
  });
123
172
  });
124
173
  }
125
- } catch (err) {
126
- console.error("Error in send function:", err);
174
+ } catch (error) {
175
+ console.error("Error handling event:", error);
127
176
  }
128
177
  }, []);
129
178
  const stateWithMatches = useMemo(() => {
130
179
  return __spreadProps(__spreadValues({}, state), {
131
- matches: (value) => state.value === value
180
+ matches: (checkState) => {
181
+ return state.value === checkState;
182
+ }
132
183
  });
133
184
  }, [state]);
134
185
  return [stateWithMatches, send];
@@ -146,9 +197,7 @@ const DialogsComponent = (props) => {
146
197
  params
147
198
  } = useRoute();
148
199
  const auth = useSelector(userSelector);
149
- useDispatch();
150
200
  const navigation = useNavigation();
151
- const isFocused = useIsFocused();
152
201
  const isMountedRef = useRef(true);
153
202
  const [state, send] = useSafeMachine();
154
203
  useCallback(() => {
@@ -168,7 +217,7 @@ const DialogsComponent = (props) => {
168
217
  return defaultValue;
169
218
  }
170
219
  }, [state]);
171
- useCallback((stateValue) => {
220
+ const safeMatches = useCallback((stateValue) => {
172
221
  var _a2;
173
222
  try {
174
223
  return ((_a2 = state == null ? void 0 : state.matches) == null ? void 0 : _a2.call(state, stateValue)) || false;
@@ -184,18 +233,43 @@ const DialogsComponent = (props) => {
184
233
  console.error("Error sending event to state machine:", error, event);
185
234
  }
186
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);
187
244
  const stateRef = useRef(state);
188
245
  useEffect(() => {
189
246
  stateRef.current = state;
190
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
+ }, []);
191
267
  useEffect(() => {
192
268
  return () => {
193
269
  isMountedRef.current = false;
194
270
  };
195
271
  }, []);
196
272
  const {
197
- data: userChannels,
198
- loading: userChannelsLoading,
199
273
  refetch: getChannelsRefetch
200
274
  } = useGetChannelsByUserWithServiceChannelsQuery({
201
275
  variables: {
@@ -204,188 +278,315 @@ const DialogsComponent = (props) => {
204
278
  supportServices: supportServices ? true : false,
205
279
  supportServiceCriteria: {
206
280
  type: RoomType.Service
207
- }
281
+ },
282
+ limit: 15,
283
+ skip: 0
208
284
  },
209
- onCompleted: (data) => {
210
- var _a2, _b;
285
+ fetchPolicy: "cache-and-network",
286
+ nextFetchPolicy: "network-only",
287
+ notifyOnNetworkStatusChange: true,
288
+ skip: true
289
+ });
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 {
297
+ data
298
+ } = await getChannelsRefetch({
299
+ role: channelRole,
300
+ criteria: channelFilters,
301
+ supportServices: supportServices ? true : false,
302
+ supportServiceCriteria: {
303
+ type: RoomType.Service
304
+ },
305
+ limit: 15,
306
+ skip: skipCount
307
+ });
308
+ const allChannels = [...(_a2 = data == null ? void 0 : data.supportServiceChannels) != null ? _a2 : [], ...(_b = data == null ? void 0 : data.channelsByUser) != null ? _b : []];
309
+ const filteredChannels = (_c = allChannels == null ? void 0 : allChannels.filter((c) => c.members.some((u) => {
310
+ var _a3;
311
+ 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";
312
+ }))) != null ? _c : [];
313
+ const sortedChannels = filteredChannels && orderBy(filteredChannels, ["updatedAt"], ["desc"]) || [];
314
+ console.log(`\u{1F4CA} Processed channels: ${sortedChannels.length} (page: ${pageNum}, skip: ${skipCount})`);
211
315
  if (isMountedRef.current) {
212
- const allChannels = [...(_a2 = data == null ? void 0 : data.supportServiceChannels) != null ? _a2 : [], ...(_b = data == null ? void 0 : data.channelsByUser) != null ? _b : []];
316
+ if (append) {
317
+ safeSend({
318
+ type: Actions.APPEND_CHANNELS,
319
+ data: {
320
+ channels: sortedChannels
321
+ }
322
+ });
323
+ } else {
324
+ safeSend({
325
+ type: Actions.FETCH_CHANNELS,
326
+ data: {
327
+ channels: sortedChannels
328
+ }
329
+ });
330
+ }
213
331
  safeSend({
214
- type: "FETCH_CHANNELS_SUCCESS",
215
- data: {
216
- channels: allChannels
217
- }
332
+ type: Actions.STOP_LOADING
218
333
  });
219
334
  }
220
- },
221
- onError: (error) => {
335
+ } catch (error) {
336
+ console.error("Error fetching channels:", error);
222
337
  if (isMountedRef.current) {
223
338
  safeSend({
224
- type: "ERROR",
339
+ type: Actions.ERROR_HANDLED,
225
340
  data: {
226
- message: error.message
341
+ message: "Failed to fetch channels"
227
342
  }
228
343
  });
229
344
  }
230
345
  }
231
- });
346
+ }, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
232
347
  useEffect(() => {
233
- console.log("Setting initial context");
234
- safeSend({
235
- type: Actions.INITIAL_CONTEXT,
236
- data: {
237
- channelRole,
238
- channelFilters: channelFiltersRef.current,
239
- supportServices,
240
- selectedChannelId: params == null ? void 0 : params.channelId
241
- }
242
- });
243
- }, []);
244
- const hasRefreshedRef = useRef(false);
245
- const channelFiltersRef = useRef(channelFilters);
246
- const refreshChannels = useCallback(() => {
247
- if (safeContextProperty("refreshing", false)) {
248
- console.log("Skipping refresh - already in progress");
249
- return Promise.resolve();
348
+ if (loading) {
349
+ const safetyTimeout = setTimeout(() => {
350
+ console.log("\u26A0\uFE0F Safety timeout triggered - forcing loading state to stop");
351
+ if (isMountedRef.current) {
352
+ safeSend({
353
+ type: Actions.STOP_LOADING
354
+ });
355
+ }
356
+ }, 5e3);
357
+ return () => clearTimeout(safetyTimeout);
250
358
  }
251
- console.log("Starting channel refresh");
252
- safeSend({
253
- type: Actions.REFRESH_CHANNELS
254
- });
255
- const currentFilters = channelFiltersRef.current;
256
- return getChannelsRefetch({
257
- role: channelRole,
258
- criteria: currentFilters,
259
- supportServices: supportServices ? true : false,
260
- supportServiceCriteria: {
261
- type: RoomType.Service
262
- }
263
- }).then((data) => {
264
- var _a2, _b, _c, _d;
359
+ }, [loading, safeSend]);
360
+ const fastRefresh = useCallback(async () => {
361
+ var _a2, _b, _c;
362
+ try {
363
+ console.log("\u{1F504} Fast refreshing channels...");
364
+ const clearRefreshingTimeout = setTimeout(() => {
365
+ if (isMountedRef.current) {
366
+ console.log("\u26A0\uFE0F Fast refresh timeout - stopping refresh state");
367
+ safeSend({
368
+ type: Actions.STOP_LOADING
369
+ });
370
+ }
371
+ }, 3e3);
372
+ const {
373
+ data
374
+ } = await getChannelsRefetch({
375
+ role: channelRole,
376
+ criteria: channelFilters,
377
+ supportServices: supportServices ? true : false,
378
+ supportServiceCriteria: {
379
+ type: RoomType.Service
380
+ },
381
+ limit: 10,
382
+ skip: 0
383
+ });
384
+ clearTimeout(clearRefreshingTimeout);
385
+ if (!isMountedRef.current)
386
+ return;
387
+ const allChannels = [...(_a2 = data == null ? void 0 : data.supportServiceChannels) != null ? _a2 : [], ...(_b = data == null ? void 0 : data.channelsByUser) != null ? _b : []];
388
+ const filteredChannels = (_c = allChannels == null ? void 0 : allChannels.filter((c) => c.members.some((u) => {
389
+ var _a3;
390
+ 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";
391
+ }))) != null ? _c : [];
392
+ const sortedChannels = filteredChannels && orderBy(filteredChannels, ["updatedAt"], ["desc"]) || [];
393
+ console.log(`\u{1F4CA} Fast refresh completed: ${sortedChannels.length} channels`);
265
394
  if (isMountedRef.current) {
266
- const allChannels = [...(_b = (_a2 = data == null ? void 0 : data.data) == null ? void 0 : _a2.supportServiceChannels) != null ? _b : [], ...(_d = (_c = data == null ? void 0 : data.data) == null ? void 0 : _c.channelsByUser) != null ? _d : []];
267
- console.log(`Refresh completed, found ${allChannels.length} channels`);
268
395
  safeSend({
269
- type: "REFRESH_CHANNELS_SUCCESS",
396
+ type: Actions.FETCH_CHANNELS,
270
397
  data: {
271
- channels: allChannels
398
+ channels: sortedChannels,
399
+ stopLoading: true
272
400
  }
273
401
  });
274
402
  }
275
- }).catch((error) => {
403
+ } catch (error) {
404
+ console.error("Error during fast refresh:", error);
276
405
  if (isMountedRef.current) {
277
- console.error("Channel refresh error:", error.message);
278
406
  safeSend({
279
- type: "ERROR",
280
- data: {
281
- message: error.message
282
- }
407
+ type: Actions.STOP_LOADING
283
408
  });
284
409
  }
285
- });
286
- }, [channelRole, supportServices, getChannelsRefetch, safeSend, safeContextProperty]);
410
+ }
411
+ }, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
287
412
  useEffect(() => {
288
- const filtersChanged = JSON.stringify(channelFiltersRef.current) !== JSON.stringify(channelFilters);
289
- if (filtersChanged) {
290
- console.log("Channel filters changed, updating ref");
291
- channelFiltersRef.current = channelFilters;
292
- if (isMountedRef.current && safeContextProperty("channelRole") !== null) {
293
- console.log("Refreshing due to filter change");
294
- refreshChannels();
413
+ const context = safeGetContext();
414
+ const isAlreadyFetching = context.refreshing || context.loading;
415
+ if (!isAlreadyFetching) {
416
+ if (safeMatches(BaseState.FetchChannels)) {
417
+ console.log("\u{1F504} Fetching channels...");
418
+ fetchChannelsDirectly(1, false);
419
+ } else if (safeMatches(MainState.RefreshChannels)) {
420
+ console.log("\u{1F504} Refreshing channels...");
421
+ fetchChannelsDirectly(1, false);
422
+ } else if (safeMatches(MainState.LoadMoreChannels)) {
423
+ console.log("\u{1F504} Loading more channels...");
424
+ fetchChannelsDirectly(page, true);
295
425
  }
426
+ } else {
427
+ console.log("\u23E9 Skipping fetch because isAlreadyFetching:", isAlreadyFetching);
428
+ }
429
+ }, [fetchChannelsDirectly, safeMatches, safeGetContext, state.value, page]);
430
+ useEffect(() => {
431
+ console.log("State changed to:", state.value);
432
+ console.log("Context:", JSON.stringify({
433
+ channelsCount: channels.length,
434
+ loading,
435
+ refreshing
436
+ }));
437
+ }, [state.value, channels.length, loading, refreshing]);
438
+ useEffect(() => {
439
+ if (isMountedRef.current) {
440
+ console.log("\u{1F680} Initializing state machine with props", {
441
+ channelRole,
442
+ channelFilters,
443
+ supportServices,
444
+ selectedChannelId: params == null ? void 0 : params.channelId
445
+ });
446
+ safeSend({
447
+ type: Actions.INITIAL_CONTEXT,
448
+ data: {
449
+ channelRole,
450
+ channelFilters,
451
+ supportServices,
452
+ selectedChannelId: params == null ? void 0 : params.channelId
453
+ }
454
+ });
455
+ const initSafetyTimeout = setTimeout(() => {
456
+ if (isMountedRef.current && loading) {
457
+ console.log("\u26A0\uFE0F Init safety timeout triggered - forcing loading state to stop");
458
+ safeSend({
459
+ type: Actions.STOP_LOADING
460
+ });
461
+ }
462
+ }, 8e3);
463
+ return () => clearTimeout(initSafetyTimeout);
296
464
  }
297
- }, [channelFilters, refreshChannels, safeContextProperty]);
465
+ }, []);
466
+ const focusRefreshRef = useRef(null);
298
467
  useFocusEffect(useCallback(() => {
299
- if (!isFocused)
300
- return;
301
- console.log("Screen focused, checking if refresh needed");
302
- if (isMountedRef.current && !hasRefreshedRef.current) {
303
- console.log("Refreshing on focus");
304
- hasRefreshedRef.current = true;
305
- refreshChannels();
468
+ let hasTriggeredRefresh = false;
469
+ const now = Date.now();
470
+ const lastRefresh = focusRefreshRef.current;
471
+ const shouldRefresh = lastRefresh === null || now - lastRefresh > 2e3;
472
+ const context = safeGetContext();
473
+ const isAlreadyFetching = context.refreshing || context.loading;
474
+ if (isMountedRef.current && !hasTriggeredRefresh && !isAlreadyFetching && shouldRefresh && (channels.length > 0 || safeMatches(BaseState.Idle))) {
475
+ hasTriggeredRefresh = true;
476
+ focusRefreshRef.current = now;
477
+ console.log("\u{1F504} Focus effect: triggering fast refresh");
478
+ safeSend({
479
+ type: Actions.START_LOADING,
480
+ data: {
481
+ refreshing: true
482
+ }
483
+ });
484
+ setTimeout(() => {
485
+ if (isMountedRef.current) {
486
+ fastRefresh();
487
+ }
488
+ }, 100);
489
+ } else {
490
+ console.log("\u23E9 Skipping focus refresh:", {
491
+ isAlreadyFetching,
492
+ hasTriggeredRefresh,
493
+ shouldRefresh,
494
+ timeGap: lastRefresh === null ? "first refresh" : now - lastRefresh
495
+ });
306
496
  }
307
497
  return () => {
308
- console.log("Screen unfocused, resetting refresh state");
309
- hasRefreshedRef.current = false;
498
+ hasTriggeredRefresh = false;
310
499
  };
311
- }, [isFocused, refreshChannels]));
312
- const handleRefresh = useCallback(() => {
313
- if (safeContextProperty("refreshing", false)) {
314
- console.log("Manual refresh ignored - refresh already in progress");
315
- return;
316
- }
317
- console.log("Manual refresh triggered");
318
- refreshChannels();
319
- }, [refreshChannels, safeContextProperty]);
320
- const channels = React__default.useMemo(() => {
321
- var _a2, _b, _c;
322
- const allChannels = [...(_a2 = userChannels == null ? void 0 : userChannels.supportServiceChannels) != null ? _a2 : [], ...(_b = userChannels == null ? void 0 : userChannels.channelsByUser) != null ? _b : []];
323
- let uChannels = (_c = allChannels == null ? void 0 : allChannels.filter((c) => c.members.some((u) => {
324
- var _a3;
325
- 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";
326
- }))) != null ? _c : [];
327
- return uChannels && orderBy(uChannels, ["updatedAt"], ["desc"]) || [];
328
- }, [userChannels, auth == null ? void 0 : auth.id]);
500
+ }, [safeSend, channels.length, safeMatches, safeGetContext, fastRefresh]));
329
501
  const handleSelectChannel = useCallback((id, title) => {
330
- var _a2;
331
502
  safeSend({
332
503
  type: Actions.SELECT_CHANNEL,
333
504
  data: {
334
505
  channelId: id
335
506
  }
336
507
  });
337
- if (params == null ? void 0 : params.channelId) {
338
- navigation.navigate(config.INBOX_MESSEGE_PATH, {
339
- channelId: params == null ? void 0 : params.channelId,
340
- role: params == null ? void 0 : params.role,
341
- title: (_a2 = params == null ? void 0 : params.title) != null ? _a2 : null,
342
- hideTabBar: true
343
- });
344
- } else {
345
- navigation.navigate(config.INBOX_MESSEGE_PATH, {
346
- channelId: id,
347
- role: channelRole,
348
- title,
349
- hideTabBar: true
350
- });
351
- }
352
- }, [params, navigation, channelRole, safeSend]);
508
+ navigation.navigate(config.INBOX_MESSEGE_PATH, {
509
+ channelId: id,
510
+ role: channelRole,
511
+ title,
512
+ hideTabBar: true,
513
+ timestamp: new Date().getTime()
514
+ });
515
+ }, [navigation, channelRole, safeSend]);
353
516
  const handleSelectServiceChannel = useCallback((id, title, postParentId) => {
354
- var _a2;
355
517
  safeSend({
356
518
  type: Actions.SELECT_CHANNEL,
357
519
  data: {
358
520
  channelId: id
359
521
  }
360
522
  });
361
- if (params == null ? void 0 : params.channelId) {
362
- navigation.navigate((params == null ? void 0 : params.postParentId) || (params == null ? void 0 : params.postParentId) == 0 ? config.THREAD_MESSEGE_PATH : config.THREADS_PATH, {
363
- channelId: params == null ? void 0 : params.channelId,
364
- role: params == null ? void 0 : params.role,
365
- title: (_a2 = params == null ? void 0 : params.title) != null ? _a2 : null,
366
- postParentId: params == null ? void 0 : params.postParentId,
367
- hideTabBar: true
523
+ navigation.navigate(postParentId || postParentId === 0 ? config.THREAD_MESSEGE_PATH : config.THREADS_PATH, {
524
+ channelId: id,
525
+ role: channelRole,
526
+ title,
527
+ postParentId,
528
+ hideTabBar: true
529
+ });
530
+ }, [navigation, channelRole, safeSend]);
531
+ const handlePullToRefresh = useCallback(() => {
532
+ if (refreshing) {
533
+ console.log("\u23E9 Skipping refresh because already refreshing");
534
+ return;
535
+ }
536
+ const now = Date.now();
537
+ focusRefreshRef.current = now;
538
+ console.log("\u{1F504} Pull-to-refresh triggered");
539
+ safeSend({
540
+ type: Actions.START_LOADING,
541
+ data: {
542
+ refreshing: true
543
+ }
544
+ });
545
+ fastRefresh();
546
+ }, [safeSend, refreshing, fastRefresh]);
547
+ const handleSearchChange = useCallback((text) => {
548
+ safeSend({
549
+ type: Actions.SET_SEARCH_QUERY,
550
+ data: {
551
+ searchQuery: text
552
+ }
553
+ });
554
+ }, [safeSend]);
555
+ const handleLoadMore = useCallback(() => {
556
+ if (!loadingMore && hasMoreChannels) {
557
+ console.log("Loading more channels at page:", page + 1);
558
+ safeSend({
559
+ type: Actions.LOAD_MORE_CHANNELS
368
560
  });
369
561
  } else {
370
- navigation.navigate(postParentId || postParentId == 0 ? config.THREAD_MESSEGE_PATH : config.THREADS_PATH, {
371
- channelId: id,
372
- role: channelRole,
373
- title,
374
- postParentId,
375
- hideTabBar: true
376
- });
562
+ console.log("Skip loading more: loadingMore=", loadingMore, "hasMoreChannels=", hasMoreChannels);
377
563
  }
378
- }, [params, navigation, channelRole, safeSend]);
379
- const searchQuery = safeContextProperty("searchQuery", "");
380
- return /* @__PURE__ */ React__default.createElement(Box, { className: "p-2" }, /* @__PURE__ */ React__default.createElement(FlatList, { data: channels && (channels == null ? void 0 : channels.length) > 0 ? channels : [], onRefresh: handleRefresh, refreshing: safeContextProperty("refreshing", false), contentContainerStyle: {
564
+ }, [safeSend, loadingMore, hasMoreChannels, page]);
565
+ return /* @__PURE__ */ React__default.createElement(Box, { className: "p-2" }, /* @__PURE__ */ React__default.createElement(FlatList, { data: channels, onRefresh: handlePullToRefresh, refreshing, contentContainerStyle: {
381
566
  minHeight: "100%"
382
567
  }, ItemSeparatorComponent: () => /* @__PURE__ */ React__default.createElement(Box, { className: "h-0.5 bg-gray-200" }), renderItem: ({
383
568
  item: channel
384
- }) => (channel == null ? void 0 : channel.type) === RoomType.Service ? /* @__PURE__ */ React__default.createElement(ServiceDialogsListItem, { onOpen: handleSelectServiceChannel, currentUser: auth, channel, refreshing: safeContextProperty("refreshing", false), selectedChannelId: safeContextProperty("selectedChannelId", params == null ? void 0 : params.channelId), role: channelRole }) : /* @__PURE__ */ React__default.createElement(DialogsListItem, { onOpen: handleSelectChannel, currentUser: auth, channel, selectedChannelId: safeContextProperty("selectedChannelId", params == null ? void 0 : params.channelId) }), ListEmptyComponent: () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, userChannelsLoading || safeContextProperty("loading", false) ? /* @__PURE__ */ React__default.createElement(Center, { className: "flex-1 justify-center items-center" }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500] })) : /* @__PURE__ */ React__default.createElement(Box, { className: "p-5" }, /* @__PURE__ */ React__default.createElement(Heading, null, "Chat"), /* @__PURE__ */ React__default.createElement(Input, { className: `h-[50] mt-3 rounded-[50] border-gray-200 border ` }, /* @__PURE__ */ React__default.createElement(InputField, { placeholder: "Search", value: searchQuery, onChangeText: (text) => safeSend({
385
- type: Actions.SET_SEARCH_QUERY,
386
- data: {
387
- searchQuery: text
569
+ }) => {
570
+ return (channel == null ? void 0 : channel.type) === RoomType.Service ? /* @__PURE__ */ React__default.createElement(ServiceDialogsListItem, { key: `service-${channel.id}`, onOpen: handleSelectServiceChannel, currentUser: auth, channel, refreshing, selectedChannelId, role: channelRole }) : /* @__PURE__ */ React__default.createElement(DialogsListItem, { key: `direct-${channel.id}`, onOpen: handleSelectChannel, currentUser: auth, channel, selectedChannelId, forceRefresh: true });
571
+ }, ListFooterComponent: () => loadingMore ? /* @__PURE__ */ React__default.createElement(Center, { className: "py-4" }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "small" })) : null, onEndReached: handleLoadMore, onEndReachedThreshold: 0.3, initialNumToRender: 10, maxToRenderPerBatch: 10, windowSize: 10, removeClippedSubviews: true, updateCellsBatchingPeriod: 50, ListEmptyComponent: () => {
572
+ console.log("Rendering ListEmptyComponent", {
573
+ loading,
574
+ refreshing,
575
+ stateValue: state.value
576
+ });
577
+ if (loading && channels.length === 0) {
578
+ return /* @__PURE__ */ React__default.createElement(Center, { className: "flex-1 justify-center items-center", style: {
579
+ height: 300
580
+ } }, /* @__PURE__ */ React__default.createElement(Spinner, { color: colors.blue[500], size: "large" }), /* @__PURE__ */ React__default.createElement(Text, { className: "mt-4 text-gray-500" }, "Loading conversations..."));
388
581
  }
389
- }) })), /* @__PURE__ */ React__default.createElement(Center, { className: "mt-6" }, /* @__PURE__ */ React__default.createElement(Ionicons, { name: "chatbubbles", size: 50 }), /* @__PURE__ */ React__default.createElement(Text, null, "You don't have any messages yet!")))), keyExtractor: (item, index) => "key" + index }));
582
+ 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: {
583
+ paddingVertical: 8,
584
+ marginBottom: 10,
585
+ borderColor: "#d1d5db",
586
+ borderRadius: 10
587
+ } }, /* @__PURE__ */ React__default.createElement(InputField, { placeholder: "Search messages...", onChangeText: handleSearchChange, value: searchQuery })), /* @__PURE__ */ React__default.createElement(Center, { className: "items-center", style: {
588
+ paddingVertical: 5
589
+ } }, /* @__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.")));
590
+ }, keyExtractor: (item) => `channel-${item.id}` }));
390
591
  };
391
592
  const Dialogs = React__default.memo(DialogsComponent);export{Dialogs};//# sourceMappingURL=Dialogs.js.map