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

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 (32) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/screens/inbox/DialogThreads.js +52 -12
  3. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  4. package/lib/screens/inbox/components/CachedImage/index.js +0 -19
  5. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  6. package/lib/screens/inbox/components/ThreadsViewItem.js +66 -44
  7. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  8. package/lib/screens/inbox/containers/ConversationView.js +36 -34
  9. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  10. package/lib/screens/inbox/containers/Dialogs.js +82 -37
  11. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  12. package/lib/screens/inbox/containers/ThreadConversationView.js +282 -219
  13. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  14. package/lib/screens/inbox/containers/ThreadsView.js +83 -50
  15. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  16. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
  17. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
  18. package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
  19. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
  20. package/package.json +2 -2
  21. package/src/screens/inbox/DialogThreads.tsx +49 -53
  22. package/src/screens/inbox/components/CachedImage/index.tsx +9 -9
  23. package/src/screens/inbox/components/SmartLoader.tsx +61 -0
  24. package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
  25. package/src/screens/inbox/containers/ConversationView.tsx +32 -30
  26. package/src/screens/inbox/containers/Dialogs.tsx +57 -22
  27. package/src/screens/inbox/containers/ThreadConversationView.tsx +467 -484
  28. package/src/screens/inbox/containers/ThreadsView.tsx +102 -183
  29. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
  30. package/src/screens/inbox/index.ts +37 -0
  31. package/src/screens/inbox/machines/threadsMachine.ts +147 -0
  32. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
@@ -7,9 +7,17 @@ import { useFocusEffect } from '@react-navigation/native';
7
7
  import { useSelector } from 'react-redux';
8
8
  import { config } from './config';
9
9
  import colors from 'tailwindcss/colors';
10
+ import { useSafeDialogThreadsMachine } from './hooks/useSafeDialogThreadsMachine';
11
+ import { Actions, BaseState } from './workflow/dialog-threads-xstate';
10
12
  const { MESSAGES_PER_PAGE } = config;
11
13
 
12
14
  export function DialogThreads({ channelId, postParentId, role }) {
15
+ // Use the XState machine for state management
16
+ const [state, send] = useSafeDialogThreadsMachine();
17
+ const { context, value } = state;
18
+ const { channelsDetail, loading, error } = context;
19
+
20
+ // Fetch channel details
13
21
  const {
14
22
  data: channelData,
15
23
  loading: channelLoading,
@@ -20,6 +28,7 @@ export function DialogThreads({ channelId, postParentId, role }) {
20
28
  },
21
29
  });
22
30
 
31
+ // Fetch thread messages
23
32
  const {
24
33
  data: threadsData,
25
34
  loading: threadLoading,
@@ -33,14 +42,46 @@ export function DialogThreads({ channelId, postParentId, role }) {
33
42
  limit: MESSAGES_PER_PAGE,
34
43
  repliesLimit2: 5,
35
44
  },
36
- // fetchPolicy: 'cache-and-network',
37
45
  });
38
46
 
39
- const channelsDetail = React.useMemo(() => {
40
- if (!channelData?.viewChannelDetail) return null;
41
- return channelData?.viewChannelDetail;
47
+ // Initialize the machine with props
48
+ React.useEffect(() => {
49
+ send({
50
+ type: Actions.INITIALIZE,
51
+ data: { channelId, postParentId, role },
52
+ });
53
+ }, [channelId, postParentId, role]);
54
+
55
+ // Update channel detail in state when data changes
56
+ React.useEffect(() => {
57
+ if (channelData?.viewChannelDetail) {
58
+ send({
59
+ type: Actions.SET_CHANNEL_DETAIL,
60
+ data: { channelsDetail: channelData.viewChannelDetail },
61
+ });
62
+ }
42
63
  }, [channelData]);
43
64
 
65
+ // Update thread data in state when data changes
66
+ React.useEffect(() => {
67
+ if (threadsData) {
68
+ send({
69
+ type: Actions.SET_THREADS,
70
+ data: { threadData: threadsData?.threadMessages?.data || [] },
71
+ });
72
+ }
73
+ }, [threadsData]);
74
+
75
+ // Handle errors
76
+ React.useEffect(() => {
77
+ if (threadsError) {
78
+ send({
79
+ type: Actions.ERROR,
80
+ data: { error: threadsError },
81
+ });
82
+ }
83
+ }, [threadsError]);
84
+
44
85
  const refetchChannelDetail = React.useCallback(
45
86
  (id: string) => {
46
87
  return channelRefetch({ id: id?.toString() });
@@ -57,24 +98,18 @@ export function DialogThreads({ channelId, postParentId, role }) {
57
98
  );
58
99
 
59
100
  return (
60
- // <Box bg={'white'} flex={1} pt={5}>
61
101
  <>
62
- {channelLoading ? (
102
+ {state.matches(BaseState.LoadingChannel) || channelLoading ? (
63
103
  <Spinner color={colors.blue[500]} />
64
104
  ) : (
65
105
  <>
66
- <Box
67
- // $dark-borderColor="$coolGray600"
68
- // $dark-backgroundColor="$trueGray700"
69
- // $light-backgroundColor="$trueGray50"
70
- className="flex-1 bg-gray-200 dark:border-gray-500 dark:bg-gray-500 "
71
- >
106
+ <Box className="flex-1 bg-gray-200 dark:border-gray-500 dark:bg-gray-500">
72
107
  <ThreadsView
73
108
  data={threadsData}
74
- loading={threadLoading}
109
+ loading={threadLoading || state.matches(BaseState.LoadingThreads)}
75
110
  refetch={threadsRefetch}
76
111
  subscribeToMore={threadsSubscribeToMore}
77
- error={threadsError}
112
+ error={error || threadsError}
78
113
  channelId={channelId}
79
114
  role={role}
80
115
  channelsDetail={channelsDetail}
@@ -85,45 +120,6 @@ export function DialogThreads({ channelId, postParentId, role }) {
85
120
  )}
86
121
  </>
87
122
  );
88
-
89
- // return (
90
- // // <Box bg={'white'} flex={1} pt={5}>
91
- // <>
92
- // {channelLoading ? (
93
- // <Spinner />
94
- // ) : (
95
- // <>
96
- // {postParentId || postParentId == 0 ? (
97
- // <Box bg={'white'} flex={1}>
98
- // <ThreadConversationView
99
- // channelId={channelId}
100
- // postParentId={postParentId}
101
- // channelsDetail={channelsDetail}
102
- // refetchChannelDetail={refetchChannelDetail}
103
- // />
104
- // </Box>
105
- // ) : (
106
- // <Box
107
- // flex={1}
108
- // _dark={{
109
- // borderColor: 'coolGray.600',
110
- // backgroundColor: 'gray.700',
111
- // }}
112
- // _light={{
113
- // backgroundColor: 'gray.50',
114
- // }}
115
- // >
116
- // <ThreadsView
117
- // channelId={channelId}
118
- // channelsDetail={channelsDetail}
119
- // refetchChannelDetail={refetchChannelDetail}
120
- // />
121
- // </Box>
122
- // )}
123
- // </>
124
- // )}
125
- // </>
126
- // );
127
123
  }
128
124
 
129
125
  export default DialogThreads;
@@ -75,7 +75,7 @@ const CachedImage = (props: any) => {
75
75
  }
76
76
  };
77
77
 
78
- console.log('CachedImage loading with URI:', uri);
78
+ // console.log('CachedImage loading with URI:', uri);
79
79
  console.log('Cache key:', cacheKey);
80
80
 
81
81
  initCache();
@@ -92,8 +92,8 @@ const CachedImage = (props: any) => {
92
92
  const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;
93
93
  console.log({ expiresIn, expired });
94
94
 
95
- console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });
96
- console.log({ metadata });
95
+ // console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });
96
+ // console.log({ metadata });
97
97
 
98
98
  if (!metadata.exists || metadata?.size === 0 || expired) {
99
99
  if (componentIsMounted.current) {
@@ -105,9 +105,9 @@ const CachedImage = (props: any) => {
105
105
  // download to cache
106
106
  setImgUri(null);
107
107
 
108
- console.log('Downloading image from URI:', uri);
108
+ // console.log('Downloading image from URI:', uri);
109
109
  if (!uri) {
110
- console.log('Image URI is undefined or null');
110
+ // console.log('Image URI is undefined or null');
111
111
  setLoadError(true);
112
112
  return;
113
113
  }
@@ -121,11 +121,11 @@ const CachedImage = (props: any) => {
121
121
 
122
122
  try {
123
123
  const response: any = await downloadResumableRef.current.downloadAsync();
124
- console.log('Download response:', response);
124
+ // console.log('Download response:', response);
125
125
 
126
126
  if (componentIsMounted.current && response && response.status === 200) {
127
127
  setImgUri(`${fileURI}?`); // deep clone to force re-render
128
- console.log('Image cached successfully, new URI:', `${fileURI}?`);
128
+ // console.log('Image cached successfully, new URI:', `${fileURI}?`);
129
129
  } else {
130
130
  console.log('Failed to download image, status:', response?.status);
131
131
  console.log('Falling back to original URI');
@@ -141,7 +141,7 @@ const CachedImage = (props: any) => {
141
141
  }
142
142
  }
143
143
  } else {
144
- console.log('Using cached image at:', fileURI);
144
+ //console.log('Using cached image at:', fileURI);
145
145
  }
146
146
  } catch (err) {
147
147
  console.log({ err });
@@ -151,7 +151,7 @@ const CachedImage = (props: any) => {
151
151
  }
152
152
  };
153
153
 
154
- console.log({ placeholderContent, imgUri, loadError, useFallbackUri });
154
+ //console.log({ placeholderContent, imgUri, loadError, useFallbackUri });
155
155
 
156
156
  // Default placeholder if none is provided
157
157
  const defaultPlaceholder = (
@@ -0,0 +1,61 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Spinner, Text, VStack, Button, ButtonText } from '@admin-layout/gluestack-ui-mobile';
3
+ import colors from 'tailwindcss/colors';
4
+
5
+ interface SmartLoaderProps {
6
+ isLoading: boolean;
7
+ timeoutMs?: number;
8
+ message?: string;
9
+ onRetry?: () => void;
10
+ }
11
+
12
+ /**
13
+ * SmartLoader component that automatically shows a timeout message
14
+ * if loading takes too long, preventing infinite loading states
15
+ */
16
+ export const SmartLoader: React.FC<SmartLoaderProps> = ({
17
+ isLoading,
18
+ timeoutMs = 20000, // Default 20 seconds
19
+ message = 'Taking longer than expected...',
20
+ onRetry,
21
+ }) => {
22
+ const [showTimeout, setShowTimeout] = useState(false);
23
+
24
+ useEffect(() => {
25
+ if (!isLoading) {
26
+ setShowTimeout(false);
27
+ return;
28
+ }
29
+
30
+ const timeoutId = setTimeout(() => {
31
+ if (isLoading) {
32
+ setShowTimeout(true);
33
+ }
34
+ }, timeoutMs);
35
+
36
+ return () => clearTimeout(timeoutId);
37
+ }, [isLoading, timeoutMs]);
38
+
39
+ if (!isLoading) return null;
40
+
41
+ return (
42
+ <Box className="flex-1 bg-gray-100 dark:bg-gray-800 items-center justify-center">
43
+ <VStack space="md" className="items-center">
44
+ <Spinner color={colors.blue[500]} size="large" />
45
+
46
+ {showTimeout && (
47
+ <VStack space="sm" className="p-4 items-center">
48
+ <Text className="text-gray-700 dark:text-gray-300 text-center">{message}</Text>
49
+ {onRetry && (
50
+ <Button onPress={onRetry} className="bg-blue-500 mt-3 rounded-full">
51
+ <ButtonText>Try Again</ButtonText>
52
+ </Button>
53
+ )}
54
+ </VStack>
55
+ )}
56
+ </VStack>
57
+ </Box>
58
+ );
59
+ };
60
+
61
+ export default SmartLoader;