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

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 (31) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/routes.json +14 -1
  3. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  4. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  5. package/lib/screens/inbox/components/CachedImage/index.js +125 -16
  6. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  7. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +32 -21
  8. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  9. package/lib/screens/inbox/containers/ConversationView.js +1175 -400
  10. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  11. package/lib/screens/inbox/containers/Dialogs.js +290 -21
  12. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  13. package/lib/screens/inbox/containers/ThreadConversationView.js +858 -351
  14. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  15. package/lib/screens/inbox/containers/workflow/conversation-xstate.js +380 -0
  16. package/lib/screens/inbox/containers/workflow/conversation-xstate.js.map +1 -0
  17. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +235 -0
  18. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +1 -0
  19. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js +438 -0
  20. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js.map +1 -0
  21. package/package.json +4 -4
  22. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  23. package/src/screens/inbox/components/CachedImage/index.tsx +137 -17
  24. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +35 -9
  25. package/src/screens/inbox/containers/ConversationView.tsx +1510 -641
  26. package/src/screens/inbox/containers/Dialogs.tsx +415 -123
  27. package/src/screens/inbox/containers/ThreadConversationView.tsx +1053 -288
  28. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  29. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  30. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  31. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useMemo, useEffect, useState } from 'react';
1
+ import React, { useCallback, useMemo, useEffect, useState, useRef } from 'react';
2
2
  import {
3
3
  FlatList,
4
4
  Box,
@@ -22,6 +22,7 @@ import { userSelector } from '@adminide-stack/user-auth0-client';
22
22
  import { CHANGE_SETTINGS_ACTION } from '@admin-layout/client';
23
23
  import { config } from '../config';
24
24
  import colors from 'tailwindcss/colors';
25
+ import { dialogsXstate, Actions as DialogsActions, BaseState, MainState } from './workflow/dialogs-xstate';
25
26
 
26
27
  export interface InboxProps {
27
28
  channelFilters?: Record<string, unknown>;
@@ -29,6 +30,155 @@ export interface InboxProps {
29
30
  supportServices: boolean;
30
31
  }
31
32
 
33
+ // Define state type for the state machine
34
+ interface SafeStateType {
35
+ context: {
36
+ channels: any[];
37
+ refreshing: boolean;
38
+ loading: boolean;
39
+ error: string | null;
40
+ searchQuery: string;
41
+ selectedChannelId: string | null;
42
+ channelRole: string | null;
43
+ channelFilters: Record<string, any>;
44
+ supportServices: boolean;
45
+ };
46
+ value: string;
47
+ matches?: (stateValue: string) => boolean;
48
+ }
49
+
50
+ // Interface for the return type to ensure proper typing
51
+ type UseSafeMachineReturnType = [SafeStateType & { matches: (stateValue: string) => boolean }, (event: any) => void];
52
+
53
+ // Create a safer version of useMachine to handle potential errors
54
+ function useSafeMachine(machine): UseSafeMachineReturnType {
55
+ // Initialize with default state
56
+ const [state, setState] = useState<SafeStateType>({
57
+ context: {
58
+ channels: [],
59
+ refreshing: false,
60
+ loading: false,
61
+ error: null,
62
+ searchQuery: '',
63
+ selectedChannelId: null,
64
+ channelRole: null,
65
+ channelFilters: {},
66
+ supportServices: false,
67
+ },
68
+ value: 'idle',
69
+ });
70
+
71
+ // Create a safe send function
72
+ const send = useCallback((event) => {
73
+ try {
74
+ // Log event for debugging
75
+ console.log('Dialogs Event received:', event.type);
76
+
77
+ // Handle specific events manually
78
+ if (event.type === DialogsActions.INITIAL_CONTEXT) {
79
+ setState((prev) => ({
80
+ ...prev,
81
+ context: {
82
+ ...prev.context,
83
+ channelRole: event.data?.channelRole || null,
84
+ channelFilters: event.data?.channelFilters || {},
85
+ supportServices: event.data?.supportServices || false,
86
+ selectedChannelId: event.data?.selectedChannelId || null,
87
+ },
88
+ value: BaseState.FetchChannels,
89
+ }));
90
+ } else if (event.type === DialogsActions.SET_SEARCH_QUERY) {
91
+ setState((prev) => ({
92
+ ...prev,
93
+ context: {
94
+ ...prev.context,
95
+ searchQuery: event.data?.searchQuery || '',
96
+ },
97
+ }));
98
+ } else if (event.type === DialogsActions.REFRESH_CHANNELS) {
99
+ setState((prev) => ({
100
+ ...prev,
101
+ context: {
102
+ ...prev.context,
103
+ refreshing: true,
104
+ },
105
+ value: MainState.RefreshChannels,
106
+ }));
107
+ } else if (event.type === DialogsActions.SELECT_CHANNEL) {
108
+ setState((prev) => ({
109
+ ...prev,
110
+ context: {
111
+ ...prev.context,
112
+ selectedChannelId: event.data?.channelId || null,
113
+ },
114
+ value: MainState.SelectChannel,
115
+ }));
116
+ } else if (event.type === DialogsActions.START_LOADING) {
117
+ setState((prev) => ({
118
+ ...prev,
119
+ context: {
120
+ ...prev.context,
121
+ loading: true,
122
+ },
123
+ }));
124
+ } else if (event.type === DialogsActions.STOP_LOADING) {
125
+ setState((prev) => ({
126
+ ...prev,
127
+ context: {
128
+ ...prev.context,
129
+ loading: false,
130
+ },
131
+ }));
132
+ } else if (event.type === 'FETCH_CHANNELS_SUCCESS') {
133
+ setState((prev) => ({
134
+ ...prev,
135
+ context: {
136
+ ...prev.context,
137
+ channels: event.data?.channels || [],
138
+ loading: false,
139
+ refreshing: false,
140
+ },
141
+ value: BaseState.Idle,
142
+ }));
143
+ } else if (event.type === 'REFRESH_CHANNELS_SUCCESS') {
144
+ setState((prev) => ({
145
+ ...prev,
146
+ context: {
147
+ ...prev.context,
148
+ channels: event.data?.channels || [],
149
+ refreshing: false,
150
+ },
151
+ value: BaseState.Idle,
152
+ }));
153
+ } else if (event.type === 'ERROR') {
154
+ setState((prev) => ({
155
+ ...prev,
156
+ context: {
157
+ ...prev.context,
158
+ error: event.data?.message || 'An error occurred',
159
+ loading: false,
160
+ refreshing: false,
161
+ },
162
+ value: BaseState.Error,
163
+ }));
164
+ }
165
+ } catch (err) {
166
+ console.error('Error in send function:', err);
167
+ }
168
+ }, []);
169
+
170
+ // Add a matches method for state compatibility
171
+ const stateWithMatches = useMemo(() => {
172
+ return {
173
+ ...state,
174
+ matches: (value: string) => state.value === value,
175
+ };
176
+ }, [state]);
177
+
178
+ // Return as a tuple to match useMachine API
179
+ return [stateWithMatches, send];
180
+ }
181
+
32
182
  const DialogsComponent = (props: InboxProps) => {
33
183
  const { channelFilters: channelFilterProp, channelRole, supportServices } = props;
34
184
  const channelFilters = { ...channelFilterProp };
@@ -38,8 +188,70 @@ const DialogsComponent = (props: InboxProps) => {
38
188
  const dispatch = useDispatch();
39
189
  const navigation = useNavigation<any>();
40
190
  const isFocused = useIsFocused();
41
- const [refreshing, setRefresh] = useState<boolean>(false);
42
- // const [userDirectChannel, setUserDirectChannel] = useState<any>([]);
191
+ const isMountedRef = useRef(true);
192
+
193
+ // Use our safer custom implementation instead of the problematic useMachine
194
+ const [state, send] = useSafeMachine(dialogsXstate);
195
+
196
+ // Define safe functions first to avoid "used before declaration" errors
197
+ const safeContext = useCallback(() => {
198
+ try {
199
+ return state?.context || {};
200
+ } catch (error) {
201
+ console.error('Error accessing state.context:', error);
202
+ return {};
203
+ }
204
+ }, [state]);
205
+
206
+ const safeContextProperty = useCallback(
207
+ (property, defaultValue = null) => {
208
+ try {
209
+ return state?.context?.[property] ?? defaultValue;
210
+ } catch (error) {
211
+ console.error(`Error accessing state.context.${property}:`, error);
212
+ return defaultValue;
213
+ }
214
+ },
215
+ [state],
216
+ );
217
+
218
+ const safeMatches = useCallback(
219
+ (stateValue) => {
220
+ try {
221
+ return state?.matches?.(stateValue) || false;
222
+ } catch (error) {
223
+ console.error(`Error calling state.matches with ${stateValue}:`, error);
224
+ return false;
225
+ }
226
+ },
227
+ [state],
228
+ );
229
+
230
+ const safeSend = useCallback(
231
+ (event) => {
232
+ try {
233
+ send(event);
234
+ } catch (error) {
235
+ console.error('Error sending event to state machine:', error, event);
236
+ }
237
+ },
238
+ [send],
239
+ );
240
+
241
+ // Use a ref to track the current machine snapshot for safer access
242
+ const stateRef = useRef(state);
243
+
244
+ // Keep the ref updated with the latest snapshot
245
+ useEffect(() => {
246
+ stateRef.current = state;
247
+ }, [state]);
248
+
249
+ // Use cleanup function to prevent setting state after unmount
250
+ useEffect(() => {
251
+ return () => {
252
+ isMountedRef.current = false;
253
+ };
254
+ }, []);
43
255
 
44
256
  const {
45
257
  data: userChannels,
@@ -54,50 +266,145 @@ const DialogsComponent = (props: InboxProps) => {
54
266
  type: RoomType.Service,
55
267
  },
56
268
  },
269
+ onCompleted: (data) => {
270
+ if (isMountedRef.current) {
271
+ const allChannels = [...(data?.supportServiceChannels ?? []), ...(data?.channelsByUser ?? [])];
272
+ safeSend({
273
+ type: 'FETCH_CHANNELS_SUCCESS',
274
+ data: { channels: allChannels },
275
+ });
276
+ }
277
+ },
278
+ onError: (error) => {
279
+ if (isMountedRef.current) {
280
+ safeSend({
281
+ type: 'ERROR',
282
+ data: { message: error.message },
283
+ });
284
+ }
285
+ },
57
286
  });
58
287
 
59
- // const {
60
- // data: userChannels,
61
- // loading: userChannelsLoading,
62
- // refetch: getChannelsRefetch,
63
- // } = useGetChannelsByUserQuery({
64
- // variables: {
65
- // role: channelRole,
66
- // criteria: channelFilters,
67
- // },
68
- // onCompleted: (data: any) => {
69
- // setRefresh(false);
70
- // },
71
- // });
288
+ // Set initial context once on mount, but don't fetch data as useFocusEffect will handle it
289
+ useEffect(() => {
290
+ console.log('Setting initial context');
291
+ // Only set the initial context with configuration, but don't trigger data fetching
292
+ // This prevents double fetching with useFocusEffect
293
+ safeSend({
294
+ type: DialogsActions.INITIAL_CONTEXT,
295
+ data: {
296
+ channelRole,
297
+ channelFilters: channelFiltersRef.current,
298
+ supportServices,
299
+ selectedChannelId: params?.channelId,
300
+ },
301
+ });
302
+ // eslint-disable-next-line react-hooks/exhaustive-deps
303
+ }, []); // Empty dependency array ensures this runs only once on mount
72
304
 
73
- useFocusEffect(
74
- React.useCallback(() => {
75
- // Do something when the screen is focused
76
- setRefresh(false);
77
- //getChannelsRefetch({ role: channelRole, criteria: channelFilters });
78
- getChannelsRefetch({
79
- role: channelRole,
80
- criteria: channelFilters,
81
- supportServices: supportServices ? true : false,
82
- supportServiceCriteria: {
83
- type: RoomType.Service,
84
- },
305
+ // Ref to track if we've already refreshed to prevent infinite loop
306
+ const hasRefreshedRef = useRef(false);
307
+ // Ref to store the current channelFilters to detect real changes
308
+ const channelFiltersRef = useRef(channelFilters);
309
+
310
+ // Shared function to handle channel refreshing
311
+ const refreshChannels = useCallback(() => {
312
+ // Skip if already refreshing to prevent loops
313
+ if (safeContextProperty('refreshing', false)) {
314
+ console.log('Skipping refresh - already in progress');
315
+ return Promise.resolve();
316
+ }
317
+
318
+ console.log('Starting channel refresh');
319
+
320
+ // Start refreshing
321
+ safeSend({
322
+ type: DialogsActions.REFRESH_CHANNELS,
323
+ });
324
+
325
+ // Use ref for filters to avoid dependency cycles
326
+ const currentFilters = channelFiltersRef.current;
327
+
328
+ // Fetch the channels
329
+ return getChannelsRefetch({
330
+ role: channelRole,
331
+ criteria: currentFilters,
332
+ supportServices: supportServices ? true : false,
333
+ supportServiceCriteria: {
334
+ type: RoomType.Service,
335
+ },
336
+ })
337
+ .then((data) => {
338
+ if (isMountedRef.current) {
339
+ const allChannels = [
340
+ ...(data?.data?.supportServiceChannels ?? []),
341
+ ...(data?.data?.channelsByUser ?? []),
342
+ ];
343
+ console.log(`Refresh completed, found ${allChannels.length} channels`);
344
+ safeSend({
345
+ type: 'REFRESH_CHANNELS_SUCCESS',
346
+ data: { channels: allChannels },
347
+ });
348
+ }
349
+ })
350
+ .catch((error) => {
351
+ if (isMountedRef.current) {
352
+ console.error('Channel refresh error:', error.message);
353
+ safeSend({
354
+ type: 'ERROR',
355
+ data: { message: error.message },
356
+ });
357
+ }
85
358
  });
359
+ }, [channelRole, supportServices, getChannelsRefetch, safeSend, safeContextProperty]);
360
+
361
+ // Update the channelFiltersRef when channelFilters changes
362
+ useEffect(() => {
363
+ const filtersChanged = JSON.stringify(channelFiltersRef.current) !== JSON.stringify(channelFilters);
364
+ if (filtersChanged) {
365
+ console.log('Channel filters changed, updating ref');
366
+ channelFiltersRef.current = channelFilters;
367
+
368
+ // Only refresh if already mounted and initialized
369
+ if (isMountedRef.current && safeContextProperty('channelRole') !== null) {
370
+ console.log('Refreshing due to filter change');
371
+ refreshChannels();
372
+ }
373
+ }
374
+ }, [channelFilters, refreshChannels, safeContextProperty]);
375
+
376
+ // Handle focus effects
377
+ useFocusEffect(
378
+ useCallback(() => {
379
+ if (!isFocused) return;
380
+
381
+ console.log('Screen focused, checking if refresh needed');
382
+
383
+ // Only refresh on focus if we're not already loading and haven't refreshed
384
+ if (isMountedRef.current && !hasRefreshedRef.current) {
385
+ console.log('Refreshing on focus');
386
+ hasRefreshedRef.current = true;
387
+ refreshChannels();
388
+ }
389
+
86
390
  return () => {
87
- // Do something when the screen is unfocused
88
- // Useful for cleanup functions
391
+ // Reset the ref when the screen loses focus
392
+ console.log('Screen unfocused, resetting refresh state');
393
+ hasRefreshedRef.current = false;
89
394
  };
90
- }, [channelFilters]),
395
+ }, [isFocused, refreshChannels]),
91
396
  );
92
397
 
93
- // const channels = React.useMemo(() => {
94
- // if (!userChannels?.channelsByUser?.length) return null;
95
- // let uChannels: any =
96
- // userChannels?.channelsByUser?.filter((c: any) =>
97
- // c.members.some((u: any) => u !== null && u?.user?.id != auth?.id && u.user.__typename == 'UserAccount'),
98
- // ) ?? [];
99
- // return (uChannels && orderBy(uChannels, ['updatedAt'], ['desc'])) || [];
100
- // }, [userChannels]);
398
+ const handleRefresh = useCallback(() => {
399
+ // Don't allow manual refresh while already refreshing
400
+ if (safeContextProperty('refreshing', false)) {
401
+ console.log('Manual refresh ignored - refresh already in progress');
402
+ return;
403
+ }
404
+
405
+ console.log('Manual refresh triggered');
406
+ refreshChannels();
407
+ }, [refreshChannels, safeContextProperty]);
101
408
 
102
409
  const channels = React.useMemo(() => {
103
410
  const allChannels = [...(userChannels?.supportServiceChannels ?? []), ...(userChannels?.channelsByUser ?? [])];
@@ -106,102 +413,78 @@ const DialogsComponent = (props: InboxProps) => {
106
413
  c.members.some((u: any) => u !== null && u?.user?.id != auth?.id && u.user.__typename == 'UserAccount'),
107
414
  ) ?? [];
108
415
  return (uChannels && orderBy(uChannels, ['updatedAt'], ['desc'])) || [];
109
- }, [userChannels]);
110
-
111
- // useEffect(() => {
112
- // setTimeout(() => {
113
- // dispatch({
114
- // type: CHANGE_SETTINGS_ACTION,
115
- // payload: {
116
- // footerRender: false,
117
- // },
118
- // } as any);
119
- // }, 0);
120
- // return () => {
121
- // dispatch({
122
- // type: CHANGE_SETTINGS_ACTION,
123
- // payload: {
124
- // footerRender: true,
125
- // },
126
- // } as any);
127
- // };
128
- // }, []);
129
-
130
- // useEffect(() => {
131
- // if (userChannels?.channelsByUser) {
132
- // if (userChannels?.channelsByUser?.length == 0) {
133
- // setUserDirectChannel([]);
134
- // }
135
- // //Direct channel
136
- // let userDirectChannels: any =
137
- // userChannels?.channelsByUser
138
- // ?.filter((i: any) => i.type == 'DIRECT')
139
- // ?.filter((c: any) =>
140
- // c.members.some((u: any) => u?.user?.id != auth?.id && u.user.__typename == 'UserAccount'),
141
- // ) ?? [];
142
-
143
- // if (userDirectChannels?.length > 0) setUserDirectChannel(userDirectChannels);
144
- // }
145
- // }, [userChannels?.channelsByUser]);
146
-
147
- const handleSelectChannel = useCallback((id: any, title: any) => {
148
- if (params?.channelId) {
149
- navigation.navigate(config.INBOX_MESSEGE_PATH as any, {
150
- channelId: params?.channelId,
151
- role: params?.role,
152
- title: params?.title ?? null,
153
- hideTabBar: true,
154
- });
155
- } else {
156
- navigation.navigate(config.INBOX_MESSEGE_PATH as any, {
157
- channelId: id,
158
- role: channelRole,
159
- title: title,
160
- hideTabBar: true,
416
+ }, [userChannels, auth?.id]);
417
+
418
+ const handleSelectChannel = useCallback(
419
+ (id: any, title: any) => {
420
+ safeSend({
421
+ type: DialogsActions.SELECT_CHANNEL,
422
+ data: { channelId: id },
161
423
  });
162
- }
163
- }, []);
164
424
 
165
- const handleSelectServiceChannel = useCallback((id: any, title: any, postParentId: any) => {
166
- if (params?.channelId) {
167
- navigation.navigate(
168
- params?.postParentId || params?.postParentId == 0
169
- ? config.THREAD_MESSEGE_PATH
170
- : (config.THREADS_PATH as any),
171
- {
425
+ if (params?.channelId) {
426
+ navigation.navigate(config.INBOX_MESSEGE_PATH as any, {
172
427
  channelId: params?.channelId,
173
428
  role: params?.role,
174
429
  title: params?.title ?? null,
175
- postParentId: params?.postParentId,
176
430
  hideTabBar: true,
177
- },
178
- );
179
- } else {
180
- navigation.navigate(
181
- postParentId || postParentId == 0 ? config.THREAD_MESSEGE_PATH : (config.THREADS_PATH as any),
182
- {
431
+ });
432
+ } else {
433
+ navigation.navigate(config.INBOX_MESSEGE_PATH as any, {
183
434
  channelId: id,
184
435
  role: channelRole,
185
436
  title: title,
186
- postParentId: postParentId,
187
437
  hideTabBar: true,
188
- },
189
- );
190
- }
191
- }, []);
438
+ });
439
+ }
440
+ },
441
+ [params, navigation, channelRole, safeSend],
442
+ );
192
443
 
193
- const handleRefresh = useCallback(() => {
194
- //if(userChannels?.channelsByUser?.length != channels?.length)setRefresh(true);
195
- setRefresh(true);
196
- getChannelsRefetch({ role: channelRole, criteria: channelFilters })?.finally(() => setRefresh(false));
197
- }, []);
444
+ const handleSelectServiceChannel = useCallback(
445
+ (id: any, title: any, postParentId: any) => {
446
+ safeSend({
447
+ type: DialogsActions.SELECT_CHANNEL,
448
+ data: { channelId: id },
449
+ });
450
+
451
+ if (params?.channelId) {
452
+ navigation.navigate(
453
+ params?.postParentId || params?.postParentId == 0
454
+ ? config.THREAD_MESSEGE_PATH
455
+ : (config.THREADS_PATH as any),
456
+ {
457
+ channelId: params?.channelId,
458
+ role: params?.role,
459
+ title: params?.title ?? null,
460
+ postParentId: params?.postParentId,
461
+ hideTabBar: true,
462
+ },
463
+ );
464
+ } else {
465
+ navigation.navigate(
466
+ postParentId || postParentId == 0 ? config.THREAD_MESSEGE_PATH : (config.THREADS_PATH as any),
467
+ {
468
+ channelId: id,
469
+ role: channelRole,
470
+ title: title,
471
+ postParentId: postParentId,
472
+ hideTabBar: true,
473
+ },
474
+ );
475
+ }
476
+ },
477
+ [params, navigation, channelRole, safeSend],
478
+ );
479
+
480
+ const searchQuery = safeContextProperty('searchQuery', '');
198
481
 
199
482
  return (
200
483
  <Box className="p-2">
201
484
  <FlatList
202
485
  data={channels && channels?.length > 0 ? channels : []}
203
486
  onRefresh={handleRefresh}
204
- refreshing={refreshing}
487
+ refreshing={safeContextProperty('refreshing', false)}
205
488
  contentContainerStyle={{ minHeight: '100%' }}
206
489
  ItemSeparatorComponent={() => <Box className="h-0.5 bg-gray-200" />}
207
490
  renderItem={({ item: channel }: any) =>
@@ -210,8 +493,8 @@ const DialogsComponent = (props: InboxProps) => {
210
493
  onOpen={handleSelectServiceChannel}
211
494
  currentUser={auth}
212
495
  channel={channel}
213
- refreshing={refreshing}
214
- selectedChannelId={params?.channelId}
496
+ refreshing={safeContextProperty('refreshing', false)}
497
+ selectedChannelId={safeContextProperty('selectedChannelId', params?.channelId)}
215
498
  role={channelRole}
216
499
  />
217
500
  ) : (
@@ -219,13 +502,13 @@ const DialogsComponent = (props: InboxProps) => {
219
502
  onOpen={handleSelectChannel}
220
503
  currentUser={auth}
221
504
  channel={channel}
222
- selectedChannelId={params?.channelId}
505
+ selectedChannelId={safeContextProperty('selectedChannelId', params?.channelId)}
223
506
  />
224
507
  )
225
508
  }
226
509
  ListEmptyComponent={() => (
227
510
  <>
228
- {userChannelsLoading ? (
511
+ {userChannelsLoading || safeContextProperty('loading', false) ? (
229
512
  <Center className="flex-1 justify-center items-center">
230
513
  <Spinner color={colors.blue[500]} />
231
514
  </Center>
@@ -233,7 +516,16 @@ const DialogsComponent = (props: InboxProps) => {
233
516
  <Box className="p-5">
234
517
  <Heading>Chat</Heading>
235
518
  <Input className={`h-[50] mt-3 rounded-[50] border-gray-200 border `}>
236
- <InputField placeholder="Search" />
519
+ <InputField
520
+ placeholder="Search"
521
+ value={searchQuery}
522
+ onChangeText={(text) =>
523
+ safeSend({
524
+ type: DialogsActions.SET_SEARCH_QUERY,
525
+ data: { searchQuery: text },
526
+ })
527
+ }
528
+ />
237
529
  </Input>
238
530
  <Center className="mt-6">
239
531
  <Ionicons name="chatbubbles" size={50} />