@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.
- package/CHANGELOG.md +8 -0
- package/lib/screens/inbox/DialogThreads.js +52 -12
- package/lib/screens/inbox/DialogThreads.js.map +1 -1
- 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/ThreadsViewItem.js +66 -44
- package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +36 -34
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +82 -37
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +282 -219
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadsView.js +83 -50
- package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
- package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
- package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
- package/package.json +2 -2
- package/src/screens/inbox/DialogThreads.tsx +49 -53
- package/src/screens/inbox/components/CachedImage/index.tsx +9 -9
- package/src/screens/inbox/components/SmartLoader.tsx +61 -0
- package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
- package/src/screens/inbox/containers/ConversationView.tsx +32 -30
- package/src/screens/inbox/containers/Dialogs.tsx +57 -22
- package/src/screens/inbox/containers/ThreadConversationView.tsx +467 -484
- package/src/screens/inbox/containers/ThreadsView.tsx +102 -183
- package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
- package/src/screens/inbox/index.ts +37 -0
- package/src/screens/inbox/machines/threadsMachine.ts +147 -0
- 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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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;
|