@messenger-box/platform-mobile 10.0.3-alpha.19 → 10.0.3-alpha.22
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.
- package/CHANGELOG.md +8 -0
- package/lib/screens/inbox/components/CachedImage/index.js +0 -19
- package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
- package/lib/screens/inbox/components/DialogsListItem.js +423 -50
- package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +375 -51
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +175 -0
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +1 -0
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +191 -0
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +1 -0
- package/lib/screens/inbox/containers/Dialogs.js +536 -66
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +95 -23
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +211 -0
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +1 -0
- package/package.json +2 -2
- package/src/screens/inbox/components/CachedImage/index.tsx +9 -9
- package/src/screens/inbox/components/DialogsListItem.tsx +624 -107
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +506 -114
- package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +35 -17
- package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
- package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
- package/src/screens/inbox/containers/Dialogs.tsx +711 -169
- package/src/screens/inbox/containers/ThreadConversationView.tsx +151 -35
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import React__default,{useState,
|
|
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
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
2
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
6
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -14,6 +16,174 @@ var __spreadValues = (a, b) => {
|
|
|
14
16
|
}
|
|
15
17
|
return a;
|
|
16
18
|
};
|
|
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
|
+
}
|
|
17
187
|
const DialogsComponent = (props) => {
|
|
18
188
|
var _a;
|
|
19
189
|
const {
|
|
@@ -27,13 +197,79 @@ const DialogsComponent = (props) => {
|
|
|
27
197
|
params
|
|
28
198
|
} = useRoute();
|
|
29
199
|
const auth = useSelector(userSelector);
|
|
30
|
-
useDispatch();
|
|
31
200
|
const navigation = useNavigation();
|
|
32
|
-
|
|
33
|
-
const [
|
|
201
|
+
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
|
+
}, []);
|
|
34
272
|
const {
|
|
35
|
-
data: userChannels,
|
|
36
|
-
loading: userChannelsLoading,
|
|
37
273
|
refetch: getChannelsRefetch
|
|
38
274
|
} = useGetChannelsByUserWithServiceChannelsQuery({
|
|
39
275
|
variables: {
|
|
@@ -42,81 +278,315 @@ const DialogsComponent = (props) => {
|
|
|
42
278
|
supportServices: supportServices ? true : false,
|
|
43
279
|
supportServiceCriteria: {
|
|
44
280
|
type: RoomType.Service
|
|
45
|
-
}
|
|
46
|
-
|
|
281
|
+
},
|
|
282
|
+
limit: 15,
|
|
283
|
+
skip: 0
|
|
284
|
+
},
|
|
285
|
+
fetchPolicy: "cache-and-network",
|
|
286
|
+
nextFetchPolicy: "network-only",
|
|
287
|
+
notifyOnNetworkStatusChange: true,
|
|
288
|
+
skip: true
|
|
47
289
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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})`);
|
|
315
|
+
if (isMountedRef.current) {
|
|
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
|
+
}
|
|
331
|
+
safeSend({
|
|
332
|
+
type: Actions.STOP_LOADING
|
|
333
|
+
});
|
|
56
334
|
}
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error("Error fetching channels:", error);
|
|
337
|
+
if (isMountedRef.current) {
|
|
338
|
+
safeSend({
|
|
339
|
+
type: Actions.ERROR_HANDLED,
|
|
340
|
+
data: {
|
|
341
|
+
message: "Failed to fetch channels"
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
|
|
347
|
+
useEffect(() => {
|
|
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);
|
|
358
|
+
}
|
|
359
|
+
}, [loading, safeSend]);
|
|
360
|
+
const fastRefresh = useCallback(async () => {
|
|
62
361
|
var _a2, _b, _c;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
78
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`);
|
|
394
|
+
if (isMountedRef.current) {
|
|
395
|
+
safeSend({
|
|
396
|
+
type: Actions.FETCH_CHANNELS,
|
|
397
|
+
data: {
|
|
398
|
+
channels: sortedChannels,
|
|
399
|
+
stopLoading: true
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.error("Error during fast refresh:", error);
|
|
405
|
+
if (isMountedRef.current) {
|
|
406
|
+
safeSend({
|
|
407
|
+
type: Actions.STOP_LOADING
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}, [getChannelsRefetch, channelRole, channelFilters, supportServices, auth == null ? void 0 : auth.id, safeSend]);
|
|
412
|
+
useEffect(() => {
|
|
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);
|
|
425
|
+
}
|
|
79
426
|
} else {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
+
}
|
|
85
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);
|
|
86
464
|
}
|
|
87
465
|
}, []);
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
466
|
+
const focusRefreshRef = useRef(null);
|
|
467
|
+
useFocusEffect(useCallback(() => {
|
|
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
|
+
}
|
|
97
483
|
});
|
|
484
|
+
setTimeout(() => {
|
|
485
|
+
if (isMountedRef.current) {
|
|
486
|
+
fastRefresh();
|
|
487
|
+
}
|
|
488
|
+
}, 100);
|
|
98
489
|
} else {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
hideTabBar: true
|
|
490
|
+
console.log("\u23E9 Skipping focus refresh:", {
|
|
491
|
+
isAlreadyFetching,
|
|
492
|
+
hasTriggeredRefresh,
|
|
493
|
+
shouldRefresh,
|
|
494
|
+
timeGap: lastRefresh === null ? "first refresh" : now - lastRefresh
|
|
105
495
|
});
|
|
106
496
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
497
|
+
return () => {
|
|
498
|
+
hasTriggeredRefresh = false;
|
|
499
|
+
};
|
|
500
|
+
}, [safeSend, channels.length, safeMatches, safeGetContext, fastRefresh]));
|
|
501
|
+
const handleSelectChannel = useCallback((id, title) => {
|
|
502
|
+
safeSend({
|
|
503
|
+
type: Actions.SELECT_CHANNEL,
|
|
504
|
+
data: {
|
|
505
|
+
channelId: id
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
navigation.navigate(config.INBOX_MESSEGE_PATH, {
|
|
509
|
+
channelId: id,
|
|
112
510
|
role: channelRole,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
511
|
+
title,
|
|
512
|
+
hideTabBar: true,
|
|
513
|
+
timestamp: new Date().getTime()
|
|
514
|
+
});
|
|
515
|
+
}, [navigation, channelRole, safeSend]);
|
|
516
|
+
const handleSelectServiceChannel = useCallback((id, title, postParentId) => {
|
|
517
|
+
safeSend({
|
|
518
|
+
type: Actions.SELECT_CHANNEL,
|
|
519
|
+
data: {
|
|
520
|
+
channelId: id
|
|
521
|
+
}
|
|
522
|
+
});
|
|
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
|
|
560
|
+
});
|
|
561
|
+
} else {
|
|
562
|
+
console.log("Skip loading more: loadingMore=", loadingMore, "hasMoreChannels=", hasMoreChannels);
|
|
563
|
+
}
|
|
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: {
|
|
117
566
|
minHeight: "100%"
|
|
118
567
|
}, ItemSeparatorComponent: () => /* @__PURE__ */ React__default.createElement(Box, { className: "h-0.5 bg-gray-200" }), renderItem: ({
|
|
119
568
|
item: channel
|
|
120
|
-
}) =>
|
|
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..."));
|
|
581
|
+
}
|
|
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}` }));
|
|
121
591
|
};
|
|
122
592
|
const Dialogs = React__default.memo(DialogsComponent);export{Dialogs};//# sourceMappingURL=Dialogs.js.map
|