@messenger-box/platform-mobile 10.0.3-alpha.34 → 10.0.3-alpha.37
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 +125 -93
- package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
- package/lib/screens/inbox/components/DialogsListItem.js +80 -256
- package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +222 -324
- package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +0 -2
- package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
- package/lib/screens/inbox/containers/ConversationView.js +487 -888
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +243 -547
- package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
- package/lib/screens/inbox/containers/ThreadConversationView.js +409 -1364
- package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
- package/package.json +4 -4
- package/src/screens/inbox/components/CachedImage/index.tsx +191 -140
- package/src/screens/inbox/components/DialogsListItem.tsx +112 -345
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +316 -437
- package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +2 -4
- package/src/screens/inbox/containers/ConversationView.tsx +676 -993
- package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
- package/src/screens/inbox/containers/Dialogs.tsx +345 -636
- package/src/screens/inbox/containers/ThreadConversationView.tsx +661 -1887
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +0 -175
- package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +0 -1
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +0 -191
- package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +0 -1
- package/lib/screens/inbox/containers/workflow/conversation-xstate.js +0 -380
- package/lib/screens/inbox/containers/workflow/conversation-xstate.js.map +0 -1
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +0 -211
- package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +0 -1
- package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js +0 -438
- package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-box/platform-mobile",
|
|
3
|
-
"version": "10.0.3-alpha.
|
|
3
|
+
"version": "10.0.3-alpha.37",
|
|
4
4
|
"description": "Sample core for higher packages to depend on",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"watch-ts": "tsc --watch"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@messenger-box/core": "10.0.3-alpha.
|
|
26
|
-
"@messenger-box/platform-client": "10.0.3-alpha.
|
|
25
|
+
"@messenger-box/core": "10.0.3-alpha.36",
|
|
26
|
+
"@messenger-box/platform-client": "10.0.3-alpha.37",
|
|
27
27
|
"base-64": "1.0.0",
|
|
28
28
|
"react-native-gifted-chat": "1.0.4"
|
|
29
29
|
},
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"typescript": {
|
|
44
44
|
"definition": "lib/index.d.ts"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "4a360a1be756050ed8c3c1cd61a037c6109f8866"
|
|
47
47
|
}
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef } from 'react';
|
|
1
|
+
import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react';
|
|
2
2
|
import { Image, View, Text } from 'react-native';
|
|
3
3
|
// import { Image } from "react-native"
|
|
4
4
|
import * as FileSystem from 'expo-file-system';
|
|
5
5
|
|
|
6
6
|
import * as CONST from './consts';
|
|
7
7
|
|
|
8
|
+
// Global download tracking to prevent duplicate downloads
|
|
9
|
+
const downloadTracker = new Map();
|
|
10
|
+
|
|
8
11
|
// Ensure the cache directory exists
|
|
9
12
|
const ensureCacheDirectory = async () => {
|
|
10
13
|
try {
|
|
11
14
|
const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);
|
|
12
15
|
if (!dirInfo.exists) {
|
|
13
|
-
console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);
|
|
16
|
+
// console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);
|
|
14
17
|
await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });
|
|
15
18
|
}
|
|
19
|
+
return true;
|
|
16
20
|
} catch (error) {
|
|
17
|
-
console.error('Failed to create cache directory:', error);
|
|
21
|
+
// console.error('Failed to create cache directory:', error);
|
|
22
|
+
return false;
|
|
18
23
|
}
|
|
19
24
|
};
|
|
20
25
|
|
|
@@ -29,7 +34,7 @@ const validateImageUri = (uri: string): string | null => {
|
|
|
29
34
|
try {
|
|
30
35
|
new URL(uri);
|
|
31
36
|
} catch (e) {
|
|
32
|
-
console.log('Invalid URL format:', uri);
|
|
37
|
+
// console.log('Invalid URL format:', uri);
|
|
33
38
|
return null;
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -37,175 +42,211 @@ const validateImageUri = (uri: string): string | null => {
|
|
|
37
42
|
return uri;
|
|
38
43
|
};
|
|
39
44
|
|
|
40
|
-
const CachedImage = (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
console.log({ expiresIn, expired });
|
|
45
|
+
const CachedImage = React.memo(
|
|
46
|
+
(props: any) => {
|
|
47
|
+
const { source, cacheKey, placeholderContent, style, resizeMode, alt, ...restProps } = props;
|
|
48
|
+
const { uri: originalUri, headers, expiresIn = 86400 } = source;
|
|
49
|
+
|
|
50
|
+
// Validate and sanitize the URI
|
|
51
|
+
const uri = validateImageUri(originalUri);
|
|
52
|
+
const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;
|
|
53
|
+
|
|
54
|
+
const [imgUri, setImgUri] = useState<string | null>(null);
|
|
55
|
+
const [loadError, setLoadError] = useState<boolean>(false);
|
|
56
|
+
const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);
|
|
57
|
+
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
58
|
+
|
|
59
|
+
const componentIsMounted = useRef(true);
|
|
60
|
+
const hasAttemptedLoad = useRef(false);
|
|
61
|
+
const requestOption = headers ? { headers } : {};
|
|
62
|
+
|
|
63
|
+
// Create a memoized download callback
|
|
64
|
+
const downloadCallback = useCallback(
|
|
65
|
+
(downloadProgress: any) => {
|
|
66
|
+
if (componentIsMounted.current === false) {
|
|
67
|
+
downloadTracker.delete(cacheKey);
|
|
68
|
+
downloadResumableRef.current?.pauseAsync();
|
|
69
|
+
FileSystem.deleteAsync(fileURI, { idempotent: true });
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
[fileURI, cacheKey],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Create a memoized download resumable
|
|
76
|
+
const downloadResumableRef = useRef(
|
|
77
|
+
uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, downloadCallback) : null,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Memoized load image function to avoid recreating on every render
|
|
81
|
+
const loadImage = useCallback(async () => {
|
|
82
|
+
if (!uri || hasAttemptedLoad.current) return;
|
|
83
|
+
|
|
84
|
+
hasAttemptedLoad.current = true;
|
|
85
|
+
setIsLoading(true);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
// Check if this image is already being downloaded
|
|
89
|
+
if (downloadTracker.has(cacheKey)) {
|
|
90
|
+
// Wait for the existing download to complete
|
|
91
|
+
await downloadTracker.get(cacheKey);
|
|
92
|
+
if (componentIsMounted.current) {
|
|
93
|
+
setImgUri(fileURI);
|
|
94
|
+
setIsLoading(false);
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
94
98
|
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
// Use the cached image if it exists
|
|
100
|
+
const metadata: any = await FileSystem.getInfoAsync(fileURI);
|
|
101
|
+
const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
setImgUri(null);
|
|
103
|
+
if (!metadata.exists || metadata?.size === 0 || expired) {
|
|
104
|
+
if (!componentIsMounted.current) return;
|
|
101
105
|
|
|
102
|
-
if (expired) {
|
|
106
|
+
if (expired && metadata.exists) {
|
|
103
107
|
await FileSystem.deleteAsync(fileURI, { idempotent: true });
|
|
104
108
|
}
|
|
105
|
-
// download to cache
|
|
106
|
-
setImgUri(null);
|
|
107
109
|
|
|
108
|
-
// console.log('Downloading image from URI:', uri);
|
|
109
110
|
if (!uri) {
|
|
110
|
-
// console.log('Image URI is undefined or null');
|
|
111
111
|
setLoadError(true);
|
|
112
|
+
setIsLoading(false);
|
|
112
113
|
return;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
if (!downloadResumableRef.current) {
|
|
116
|
-
console.log('Download resumable is null');
|
|
117
117
|
setUseFallbackUri(true);
|
|
118
118
|
setImgUri(uri);
|
|
119
|
+
setIsLoading(false);
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
// Record this download in the global tracker
|
|
125
|
+
const downloadPromise = downloadResumableRef.current.downloadAsync();
|
|
126
|
+
downloadTracker.set(cacheKey, downloadPromise);
|
|
127
|
+
|
|
128
|
+
const response: any = await downloadPromise;
|
|
129
|
+
|
|
130
|
+
// Remove from tracker when done
|
|
131
|
+
downloadTracker.delete(cacheKey);
|
|
132
|
+
|
|
133
|
+
if (componentIsMounted.current) {
|
|
134
|
+
if (response && response.status === 200) {
|
|
135
|
+
setImgUri(fileURI);
|
|
136
|
+
} else {
|
|
137
|
+
setUseFallbackUri(true);
|
|
138
|
+
setImgUri(uri);
|
|
139
|
+
FileSystem.deleteAsync(fileURI, { idempotent: true });
|
|
140
|
+
}
|
|
141
|
+
setIsLoading(false);
|
|
142
|
+
}
|
|
143
|
+
} catch (downloadError) {
|
|
144
|
+
downloadTracker.delete(cacheKey);
|
|
145
|
+
if (componentIsMounted.current) {
|
|
132
146
|
setUseFallbackUri(true);
|
|
133
147
|
setImgUri(uri);
|
|
134
|
-
|
|
148
|
+
setIsLoading(false);
|
|
135
149
|
}
|
|
136
|
-
} catch (downloadError) {
|
|
137
|
-
console.log('Error downloading image:', downloadError);
|
|
138
|
-
console.log('Falling back to original URI');
|
|
139
|
-
setUseFallbackUri(true);
|
|
140
|
-
setImgUri(uri);
|
|
141
150
|
}
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
//console.log('Using cached image at:', fileURI);
|
|
145
|
-
}
|
|
146
|
-
} catch (err) {
|
|
147
|
-
console.log({ err });
|
|
148
|
-
console.log('Falling back to original URI');
|
|
149
|
-
setUseFallbackUri(true);
|
|
150
|
-
setImgUri(uri);
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
//console.log({ placeholderContent, imgUri, loadError, useFallbackUri });
|
|
155
|
-
|
|
156
|
-
// Default placeholder if none is provided
|
|
157
|
-
const defaultPlaceholder = (
|
|
158
|
-
<View
|
|
159
|
-
style={{
|
|
160
|
-
width: '100%',
|
|
161
|
-
height: '100%',
|
|
162
|
-
backgroundColor: '#e1e1e1',
|
|
163
|
-
justifyContent: 'center',
|
|
164
|
-
alignItems: 'center',
|
|
165
|
-
borderRadius: 3,
|
|
166
|
-
}}
|
|
167
|
-
>
|
|
168
|
-
<Text>Image not available</Text>
|
|
169
|
-
</View>
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
if (!imgUri) {
|
|
173
|
-
return placeholderContent || defaultPlaceholder;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<Image
|
|
178
|
-
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
179
|
-
{...props}
|
|
180
|
-
source={{
|
|
181
|
-
...source,
|
|
182
|
-
uri: useFallbackUri ? uri : imgUri,
|
|
183
|
-
}}
|
|
184
|
-
onError={(e) => {
|
|
185
|
-
console.log('Image loading error:', e.nativeEvent.error);
|
|
186
|
-
// If we're already using the fallback URI and still getting an error,
|
|
187
|
-
// then show the placeholder
|
|
188
|
-
if (useFallbackUri) {
|
|
189
|
-
setLoadError(true);
|
|
190
|
-
setImgUri(null);
|
|
191
151
|
} else {
|
|
192
|
-
|
|
152
|
+
// Use cached version
|
|
153
|
+
setImgUri(fileURI);
|
|
154
|
+
setIsLoading(false);
|
|
155
|
+
}
|
|
156
|
+
} catch (err) {
|
|
157
|
+
if (componentIsMounted.current) {
|
|
193
158
|
setUseFallbackUri(true);
|
|
194
159
|
setImgUri(uri);
|
|
160
|
+
setIsLoading(false);
|
|
195
161
|
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
162
|
+
}
|
|
163
|
+
}, [uri, fileURI, cacheKey, expiresIn]);
|
|
164
|
+
|
|
165
|
+
// Setup effect
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const setup = async () => {
|
|
168
|
+
const directoryExists = await ensureCacheDirectory();
|
|
169
|
+
if (directoryExists && uri) {
|
|
170
|
+
loadImage();
|
|
171
|
+
} else {
|
|
172
|
+
setLoadError(true);
|
|
173
|
+
setIsLoading(false);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
setup();
|
|
178
|
+
|
|
179
|
+
return () => {
|
|
180
|
+
componentIsMounted.current = false;
|
|
181
|
+
};
|
|
182
|
+
}, [uri, loadImage]);
|
|
183
|
+
|
|
184
|
+
// Default placeholder
|
|
185
|
+
const defaultPlaceholder = useMemo(
|
|
186
|
+
() => (
|
|
187
|
+
<View
|
|
188
|
+
style={[
|
|
189
|
+
{
|
|
190
|
+
width: '100%',
|
|
191
|
+
height: '100%',
|
|
192
|
+
backgroundColor: '#e1e1e1',
|
|
193
|
+
justifyContent: 'center',
|
|
194
|
+
alignItems: 'center',
|
|
195
|
+
borderRadius: 3,
|
|
196
|
+
},
|
|
197
|
+
style,
|
|
198
|
+
]}
|
|
199
|
+
>
|
|
200
|
+
<Text>Image not available</Text>
|
|
201
|
+
</View>
|
|
202
|
+
),
|
|
203
|
+
[style],
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Show placeholder while loading or if there's an error
|
|
207
|
+
if (isLoading || loadError || !imgUri) {
|
|
208
|
+
return placeholderContent || defaultPlaceholder;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Actual image component
|
|
212
|
+
return (
|
|
213
|
+
<Image
|
|
214
|
+
{...restProps}
|
|
215
|
+
style={style}
|
|
216
|
+
source={{
|
|
217
|
+
...source,
|
|
218
|
+
uri: useFallbackUri ? uri : imgUri,
|
|
219
|
+
}}
|
|
220
|
+
resizeMode={resizeMode}
|
|
221
|
+
onError={(e) => {
|
|
222
|
+
if (useFallbackUri) {
|
|
223
|
+
setLoadError(true);
|
|
224
|
+
setImgUri(null);
|
|
225
|
+
} else {
|
|
226
|
+
setUseFallbackUri(true);
|
|
227
|
+
setImgUri(uri);
|
|
228
|
+
}
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
);
|
|
232
|
+
},
|
|
233
|
+
(prevProps, nextProps) => {
|
|
234
|
+
// Custom comparison function for memoization
|
|
235
|
+
return (
|
|
236
|
+
prevProps.cacheKey === nextProps.cacheKey &&
|
|
237
|
+
prevProps.source.uri === nextProps.source.uri &&
|
|
238
|
+
prevProps.style === nextProps.style
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
);
|
|
200
242
|
|
|
201
243
|
export const CacheManager = {
|
|
202
244
|
addToCache: async ({ file, key }: any) => {
|
|
245
|
+
await ensureCacheDirectory();
|
|
203
246
|
await FileSystem.copyAsync({
|
|
204
247
|
from: file,
|
|
205
248
|
to: `${CONST.IMAGE_CACHE_FOLDER}${key}`,
|
|
206
249
|
});
|
|
207
|
-
// const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`)
|
|
208
|
-
// return uri
|
|
209
250
|
const uri = await CacheManager.getCachedUri({ key });
|
|
210
251
|
return uri;
|
|
211
252
|
},
|
|
@@ -216,8 +257,18 @@ export const CacheManager = {
|
|
|
216
257
|
},
|
|
217
258
|
|
|
218
259
|
downloadAsync: async ({ uri, key, options }: any) => {
|
|
260
|
+
await ensureCacheDirectory();
|
|
219
261
|
return await FileSystem.downloadAsync(uri, `${CONST.IMAGE_CACHE_FOLDER}${key}`, options);
|
|
220
262
|
},
|
|
263
|
+
|
|
264
|
+
clearCache: async () => {
|
|
265
|
+
try {
|
|
266
|
+
await FileSystem.deleteAsync(CONST.IMAGE_CACHE_FOLDER, { idempotent: true });
|
|
267
|
+
await ensureCacheDirectory();
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Error clearing cache:', error);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
221
272
|
};
|
|
222
273
|
|
|
223
274
|
export default CachedImage;
|