@messenger-box/platform-mobile 10.0.3-alpha.36 → 10.0.3-alpha.38
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 +74 -288
- package/lib/screens/inbox/components/DialogsListItem.js.map +1 -1
- package/lib/screens/inbox/components/ServiceDialogsListItem.js +184 -415
- 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 +621 -951
- package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
- package/lib/screens/inbox/containers/Dialogs.js +212 -628
- 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 +3 -3
- package/src/screens/inbox/components/CachedImage/index.tsx +191 -140
- package/src/screens/inbox/components/DialogsListItem.tsx +122 -386
- package/src/screens/inbox/components/ServiceDialogsListItem.tsx +69 -377
- package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +2 -4
- package/src/screens/inbox/containers/ConversationView.tsx +793 -1064
- package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
- package/src/screens/inbox/containers/Dialogs.tsx +301 -763
- 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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.3-alpha.38](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.37...v10.0.3-alpha.38) (2025-04-25)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
9
|
+
|
|
10
|
+
## [10.0.3-alpha.37](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.36...v10.0.3-alpha.37) (2025-04-25)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
13
|
+
|
|
6
14
|
## [10.0.3-alpha.36](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.35...v10.0.3-alpha.36) (2025-04-23)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @messenger-box/platform-mobile
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React__default,{useState,useRef,useEffect}from'react';import {
|
|
1
|
+
import React__default,{useState,useRef,useCallback,useEffect,useMemo}from'react';import {View,Text,Image}from'react-native';import*as FileSystem from'expo-file-system';import {IMAGE_CACHE_FOLDER}from'./consts.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -17,17 +17,30 @@ var __spreadValues = (a, b) => {
|
|
|
17
17
|
return a;
|
|
18
18
|
};
|
|
19
19
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
const downloadTracker = /* @__PURE__ */ new Map();
|
|
20
33
|
const ensureCacheDirectory = async () => {
|
|
21
34
|
try {
|
|
22
35
|
const dirInfo = await FileSystem.getInfoAsync(IMAGE_CACHE_FOLDER);
|
|
23
36
|
if (!dirInfo.exists) {
|
|
24
|
-
console.log("Creating cache directory:", IMAGE_CACHE_FOLDER);
|
|
25
37
|
await FileSystem.makeDirectoryAsync(IMAGE_CACHE_FOLDER, {
|
|
26
38
|
intermediates: true
|
|
27
39
|
});
|
|
28
40
|
}
|
|
41
|
+
return true;
|
|
29
42
|
} catch (error) {
|
|
30
|
-
|
|
43
|
+
return false;
|
|
31
44
|
}
|
|
32
45
|
};
|
|
33
46
|
const validateImageUri = (uri) => {
|
|
@@ -37,143 +50,162 @@ const validateImageUri = (uri) => {
|
|
|
37
50
|
try {
|
|
38
51
|
new URL(uri);
|
|
39
52
|
} catch (e) {
|
|
40
|
-
console.log("Invalid URL format:", uri);
|
|
41
53
|
return null;
|
|
42
54
|
}
|
|
43
55
|
return uri;
|
|
44
56
|
};
|
|
45
|
-
const CachedImage = (props) => {
|
|
46
|
-
const {
|
|
57
|
+
const CachedImage = React__default.memo((props) => {
|
|
58
|
+
const _a = props, {
|
|
47
59
|
source,
|
|
48
60
|
cacheKey,
|
|
49
|
-
placeholderContent
|
|
50
|
-
|
|
61
|
+
placeholderContent,
|
|
62
|
+
style,
|
|
63
|
+
resizeMode,
|
|
64
|
+
alt
|
|
65
|
+
} = _a, restProps = __objRest(_a, [
|
|
66
|
+
"source",
|
|
67
|
+
"cacheKey",
|
|
68
|
+
"placeholderContent",
|
|
69
|
+
"style",
|
|
70
|
+
"resizeMode",
|
|
71
|
+
"alt"
|
|
72
|
+
]);
|
|
51
73
|
const {
|
|
52
74
|
uri: originalUri,
|
|
53
75
|
headers,
|
|
54
|
-
expiresIn
|
|
76
|
+
expiresIn = 86400
|
|
55
77
|
} = source;
|
|
56
78
|
const uri = validateImageUri(originalUri);
|
|
57
79
|
const fileURI = `${IMAGE_CACHE_FOLDER}${cacheKey}`;
|
|
58
|
-
const [imgUri, setImgUri] = useState(
|
|
80
|
+
const [imgUri, setImgUri] = useState(null);
|
|
59
81
|
const [loadError, setLoadError] = useState(false);
|
|
60
82
|
const [useFallbackUri, setUseFallbackUri] = useState(false);
|
|
83
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
61
84
|
const componentIsMounted = useRef(true);
|
|
85
|
+
const hasAttemptedLoad = useRef(false);
|
|
62
86
|
const requestOption = headers ? {
|
|
63
87
|
headers
|
|
64
88
|
} : {};
|
|
65
|
-
const
|
|
66
|
-
var
|
|
89
|
+
const downloadCallback = useCallback((downloadProgress) => {
|
|
90
|
+
var _a2;
|
|
67
91
|
if (componentIsMounted.current === false) {
|
|
68
|
-
|
|
92
|
+
downloadTracker.delete(cacheKey);
|
|
93
|
+
(_a2 = downloadResumableRef.current) == null ? void 0 : _a2.pauseAsync();
|
|
69
94
|
FileSystem.deleteAsync(fileURI, {
|
|
70
95
|
idempotent: true
|
|
71
96
|
});
|
|
72
97
|
}
|
|
73
|
-
};
|
|
74
|
-
const downloadResumableRef = useRef(uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} else {
|
|
81
|
-
console.log("Image URI is invalid, not loading");
|
|
82
|
-
setLoadError(true);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
console.log("Cache key:", cacheKey);
|
|
86
|
-
initCache();
|
|
87
|
-
return () => {
|
|
88
|
-
componentIsMounted.current = false;
|
|
89
|
-
};
|
|
90
|
-
}, []);
|
|
91
|
-
const loadImage = async () => {
|
|
98
|
+
}, [fileURI, cacheKey]);
|
|
99
|
+
const downloadResumableRef = useRef(uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, downloadCallback) : null);
|
|
100
|
+
const loadImage = useCallback(async () => {
|
|
101
|
+
if (!uri || hasAttemptedLoad.current)
|
|
102
|
+
return;
|
|
103
|
+
hasAttemptedLoad.current = true;
|
|
104
|
+
setIsLoading(true);
|
|
92
105
|
try {
|
|
106
|
+
if (downloadTracker.has(cacheKey)) {
|
|
107
|
+
await downloadTracker.get(cacheKey);
|
|
108
|
+
if (componentIsMounted.current) {
|
|
109
|
+
setImgUri(fileURI);
|
|
110
|
+
setIsLoading(false);
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
93
114
|
const metadata = await FileSystem.getInfoAsync(fileURI);
|
|
94
115
|
const expired = expiresIn && new Date().getTime() / 1e3 - (metadata == null ? void 0 : metadata.modificationTime) > expiresIn;
|
|
95
|
-
console.log({
|
|
96
|
-
expiresIn,
|
|
97
|
-
expired
|
|
98
|
-
});
|
|
99
116
|
if (!metadata.exists || (metadata == null ? void 0 : metadata.size) === 0 || expired) {
|
|
100
|
-
if (componentIsMounted.current)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
if (!componentIsMounted.current)
|
|
118
|
+
return;
|
|
119
|
+
if (expired && metadata.exists) {
|
|
120
|
+
await FileSystem.deleteAsync(fileURI, {
|
|
121
|
+
idempotent: true
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!uri) {
|
|
125
|
+
setLoadError(true);
|
|
126
|
+
setIsLoading(false);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!downloadResumableRef.current) {
|
|
130
|
+
setUseFallbackUri(true);
|
|
131
|
+
setImgUri(uri);
|
|
132
|
+
setIsLoading(false);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const downloadPromise = downloadResumableRef.current.downloadAsync();
|
|
137
|
+
downloadTracker.set(cacheKey, downloadPromise);
|
|
138
|
+
const response = await downloadPromise;
|
|
139
|
+
downloadTracker.delete(cacheKey);
|
|
140
|
+
if (componentIsMounted.current) {
|
|
141
|
+
if (response && response.status === 200) {
|
|
142
|
+
setImgUri(fileURI);
|
|
122
143
|
} else {
|
|
123
|
-
console.log("Failed to download image, status:", response == null ? void 0 : response.status);
|
|
124
|
-
console.log("Falling back to original URI");
|
|
125
144
|
setUseFallbackUri(true);
|
|
126
145
|
setImgUri(uri);
|
|
127
146
|
FileSystem.deleteAsync(fileURI, {
|
|
128
147
|
idempotent: true
|
|
129
148
|
});
|
|
130
149
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
150
|
+
setIsLoading(false);
|
|
151
|
+
}
|
|
152
|
+
} catch (downloadError) {
|
|
153
|
+
downloadTracker.delete(cacheKey);
|
|
154
|
+
if (componentIsMounted.current) {
|
|
134
155
|
setUseFallbackUri(true);
|
|
135
156
|
setImgUri(uri);
|
|
157
|
+
setIsLoading(false);
|
|
136
158
|
}
|
|
137
159
|
}
|
|
138
160
|
} else {
|
|
161
|
+
setImgUri(fileURI);
|
|
162
|
+
setIsLoading(false);
|
|
139
163
|
}
|
|
140
164
|
} catch (err) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
setImgUri(uri);
|
|
165
|
+
if (componentIsMounted.current) {
|
|
166
|
+
setUseFallbackUri(true);
|
|
167
|
+
setImgUri(uri);
|
|
168
|
+
setIsLoading(false);
|
|
169
|
+
}
|
|
147
170
|
}
|
|
148
|
-
};
|
|
149
|
-
|
|
171
|
+
}, [uri, fileURI, cacheKey, expiresIn]);
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
const setup = async () => {
|
|
174
|
+
const directoryExists = await ensureCacheDirectory();
|
|
175
|
+
if (directoryExists && uri) {
|
|
176
|
+
loadImage();
|
|
177
|
+
} else {
|
|
178
|
+
setLoadError(true);
|
|
179
|
+
setIsLoading(false);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
setup();
|
|
183
|
+
return () => {
|
|
184
|
+
componentIsMounted.current = false;
|
|
185
|
+
};
|
|
186
|
+
}, [uri, loadImage]);
|
|
187
|
+
const defaultPlaceholder = useMemo(() => /* @__PURE__ */ React__default.createElement(View, { style: [{
|
|
150
188
|
width: "100%",
|
|
151
189
|
height: "100%",
|
|
152
190
|
backgroundColor: "#e1e1e1",
|
|
153
191
|
justifyContent: "center",
|
|
154
192
|
alignItems: "center",
|
|
155
193
|
borderRadius: 3
|
|
156
|
-
} }, /* @__PURE__ */ React__default.createElement(Text, null, "Image not available"));
|
|
157
|
-
if (!imgUri) {
|
|
194
|
+
}, style] }, /* @__PURE__ */ React__default.createElement(Text, null, "Image not available")), [style]);
|
|
195
|
+
if (isLoading || loadError || !imgUri) {
|
|
158
196
|
return placeholderContent || defaultPlaceholder;
|
|
159
197
|
}
|
|
160
|
-
return /* @__PURE__ */ React__default.createElement(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
setImgUri(uri);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
};export{CachedImage as default};//# sourceMappingURL=index.js.map
|
|
198
|
+
return /* @__PURE__ */ React__default.createElement(Image, __spreadProps(__spreadValues({}, restProps), { style, source: __spreadProps(__spreadValues({}, source), {
|
|
199
|
+
uri: useFallbackUri ? uri : imgUri
|
|
200
|
+
}), resizeMode, onError: (e) => {
|
|
201
|
+
if (useFallbackUri) {
|
|
202
|
+
setLoadError(true);
|
|
203
|
+
setImgUri(null);
|
|
204
|
+
} else {
|
|
205
|
+
setUseFallbackUri(true);
|
|
206
|
+
setImgUri(uri);
|
|
207
|
+
}
|
|
208
|
+
} }));
|
|
209
|
+
}, (prevProps, nextProps) => {
|
|
210
|
+
return prevProps.cacheKey === nextProps.cacheKey && prevProps.source.uri === nextProps.source.uri && prevProps.style === nextProps.style;
|
|
211
|
+
});export{CachedImage as default};//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/screens/inbox/components/CachedImage/index.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef } from 'react';\nimport { Image, View, Text } from 'react-native';\n// import { Image } from \"react-native\"\nimport * as FileSystem from 'expo-file-system';\n\nimport * as CONST from './consts';\n\n// Ensure the cache directory exists\nconst ensureCacheDirectory = async () => {\n try {\n const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);\n if (!dirInfo.exists) {\n console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);\n await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });\n }\n } catch (error) {\n console.error('Failed to create cache directory:', error);\n }\n};\n\n// Validate and sanitize the image URL\nconst validateImageUri = (uri: string): string | null => {\n if (!uri) return null;\n\n // Trim whitespace\n uri = uri.trim();\n\n // Check if it's a valid URL format\n try {\n new URL(uri);\n } catch (e) {\n console.log('Invalid URL format:', uri);\n return null;\n }\n\n // Add more validation as needed for your specific case\n return uri;\n};\n\nconst CachedImage = (props: any) => {\n const { source, cacheKey, placeholderContent } = props;\n const { uri: originalUri, headers, expiresIn } = source;\n\n // Validate and sanitize the URI\n const uri = validateImageUri(originalUri);\n\n const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;\n\n const [imgUri, setImgUri] = useState<any>(fileURI);\n const [loadError, setLoadError] = useState<boolean>(false);\n const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);\n\n const componentIsMounted = useRef(true);\n const requestOption = headers ? { headers } : {};\n\n const _callback = (downloadProgress: any) => {\n if (componentIsMounted.current === false) {\n downloadResumableRef.current?.pauseAsync();\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n };\n\n const downloadResumableRef = useRef(\n uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, _callback) : null,\n );\n\n useEffect(() => {\n const initCache = async () => {\n await ensureCacheDirectory();\n if (uri) {\n loadImage();\n } else {\n console.log('Image URI is invalid, not loading');\n setLoadError(true);\n }\n };\n\n // console.log('CachedImage loading with URI:', uri);\n console.log('Cache key:', cacheKey);\n\n initCache();\n\n return () => {\n componentIsMounted.current = false;\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const loadImage = async () => {\n try {\n // Use the cached image if it exists\n const metadata: any = await FileSystem.getInfoAsync(fileURI);\n const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;\n console.log({ expiresIn, expired });\n\n // console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });\n // console.log({ metadata });\n\n if (!metadata.exists || metadata?.size === 0 || expired) {\n if (componentIsMounted.current) {\n setImgUri(null);\n\n if (expired) {\n await FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n // download to cache\n setImgUri(null);\n\n // console.log('Downloading image from URI:', uri);\n if (!uri) {\n // console.log('Image URI is undefined or null');\n setLoadError(true);\n return;\n }\n\n if (!downloadResumableRef.current) {\n console.log('Download resumable is null');\n setUseFallbackUri(true);\n setImgUri(uri);\n return;\n }\n\n try {\n const response: any = await downloadResumableRef.current.downloadAsync();\n // console.log('Download response:', response);\n\n if (componentIsMounted.current && response && response.status === 200) {\n setImgUri(`${fileURI}?`); // deep clone to force re-render\n // console.log('Image cached successfully, new URI:', `${fileURI}?`);\n } else {\n console.log('Failed to download image, status:', response?.status);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly\n }\n } catch (downloadError) {\n console.log('Error downloading image:', downloadError);\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }\n } else {\n //console.log('Using cached image at:', fileURI);\n }\n } catch (err) {\n console.log({ err });\n console.log('Falling back to original URI');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n };\n\n //console.log({ placeholderContent, imgUri, loadError, useFallbackUri });\n\n // Default placeholder if none is provided\n const defaultPlaceholder = (\n <View\n style={{\n width: '100%',\n height: '100%',\n backgroundColor: '#e1e1e1',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: 3,\n }}\n >\n <Text>Image not available</Text>\n </View>\n );\n\n if (!imgUri) {\n return placeholderContent || defaultPlaceholder;\n }\n\n return (\n <Image\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...props}\n source={{\n ...source,\n uri: useFallbackUri ? uri : imgUri,\n }}\n onError={(e) => {\n console.log('Image loading error:', e.nativeEvent.error);\n // If we're already using the fallback URI and still getting an error,\n // then show the placeholder\n if (useFallbackUri) {\n setLoadError(true);\n setImgUri(null);\n } else {\n console.log('Falling back to original URI after onError');\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }}\n />\n );\n};\n\nexport const CacheManager = {\n addToCache: async ({ file, key }: any) => {\n await FileSystem.copyAsync({\n from: file,\n to: `${CONST.IMAGE_CACHE_FOLDER}${key}`,\n });\n // const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`)\n // return uri\n const uri = await CacheManager.getCachedUri({ key });\n return uri;\n },\n\n getCachedUri: async ({ key }: any) => {\n const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`);\n return uri;\n },\n\n downloadAsync: async ({ uri, key, options }: any) => {\n return await FileSystem.downloadAsync(uri, `${CONST.IMAGE_CACHE_FOLDER}${key}`, options);\n },\n};\n\nexport default CachedImage;\n"],"names":["CONST.IMAGE_CACHE_FOLDER","React"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/screens/inbox/components/CachedImage/index.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef, useMemo, useCallback } from 'react';\nimport { Image, View, Text } from 'react-native';\n// import { Image } from \"react-native\"\nimport * as FileSystem from 'expo-file-system';\n\nimport * as CONST from './consts';\n\n// Global download tracking to prevent duplicate downloads\nconst downloadTracker = new Map();\n\n// Ensure the cache directory exists\nconst ensureCacheDirectory = async () => {\n try {\n const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);\n if (!dirInfo.exists) {\n // console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);\n await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });\n }\n return true;\n } catch (error) {\n // console.error('Failed to create cache directory:', error);\n return false;\n }\n};\n\n// Validate and sanitize the image URL\nconst validateImageUri = (uri: string): string | null => {\n if (!uri) return null;\n\n // Trim whitespace\n uri = uri.trim();\n\n // Check if it's a valid URL format\n try {\n new URL(uri);\n } catch (e) {\n // console.log('Invalid URL format:', uri);\n return null;\n }\n\n // Add more validation as needed for your specific case\n return uri;\n};\n\nconst CachedImage = React.memo(\n (props: any) => {\n const { source, cacheKey, placeholderContent, style, resizeMode, alt, ...restProps } = props;\n const { uri: originalUri, headers, expiresIn = 86400 } = source;\n\n // Validate and sanitize the URI\n const uri = validateImageUri(originalUri);\n const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;\n\n const [imgUri, setImgUri] = useState<string | null>(null);\n const [loadError, setLoadError] = useState<boolean>(false);\n const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n\n const componentIsMounted = useRef(true);\n const hasAttemptedLoad = useRef(false);\n const requestOption = headers ? { headers } : {};\n\n // Create a memoized download callback\n const downloadCallback = useCallback(\n (downloadProgress: any) => {\n if (componentIsMounted.current === false) {\n downloadTracker.delete(cacheKey);\n downloadResumableRef.current?.pauseAsync();\n FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n },\n [fileURI, cacheKey],\n );\n\n // Create a memoized download resumable\n const downloadResumableRef = useRef(\n uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, downloadCallback) : null,\n );\n\n // Memoized load image function to avoid recreating on every render\n const loadImage = useCallback(async () => {\n if (!uri || hasAttemptedLoad.current) return;\n\n hasAttemptedLoad.current = true;\n setIsLoading(true);\n\n try {\n // Check if this image is already being downloaded\n if (downloadTracker.has(cacheKey)) {\n // Wait for the existing download to complete\n await downloadTracker.get(cacheKey);\n if (componentIsMounted.current) {\n setImgUri(fileURI);\n setIsLoading(false);\n }\n return;\n }\n\n // Use the cached image if it exists\n const metadata: any = await FileSystem.getInfoAsync(fileURI);\n const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;\n\n if (!metadata.exists || metadata?.size === 0 || expired) {\n if (!componentIsMounted.current) return;\n\n if (expired && metadata.exists) {\n await FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n\n if (!uri) {\n setLoadError(true);\n setIsLoading(false);\n return;\n }\n\n if (!downloadResumableRef.current) {\n setUseFallbackUri(true);\n setImgUri(uri);\n setIsLoading(false);\n return;\n }\n\n try {\n // Record this download in the global tracker\n const downloadPromise = downloadResumableRef.current.downloadAsync();\n downloadTracker.set(cacheKey, downloadPromise);\n\n const response: any = await downloadPromise;\n\n // Remove from tracker when done\n downloadTracker.delete(cacheKey);\n\n if (componentIsMounted.current) {\n if (response && response.status === 200) {\n setImgUri(fileURI);\n } else {\n setUseFallbackUri(true);\n setImgUri(uri);\n FileSystem.deleteAsync(fileURI, { idempotent: true });\n }\n setIsLoading(false);\n }\n } catch (downloadError) {\n downloadTracker.delete(cacheKey);\n if (componentIsMounted.current) {\n setUseFallbackUri(true);\n setImgUri(uri);\n setIsLoading(false);\n }\n }\n } else {\n // Use cached version\n setImgUri(fileURI);\n setIsLoading(false);\n }\n } catch (err) {\n if (componentIsMounted.current) {\n setUseFallbackUri(true);\n setImgUri(uri);\n setIsLoading(false);\n }\n }\n }, [uri, fileURI, cacheKey, expiresIn]);\n\n // Setup effect\n useEffect(() => {\n const setup = async () => {\n const directoryExists = await ensureCacheDirectory();\n if (directoryExists && uri) {\n loadImage();\n } else {\n setLoadError(true);\n setIsLoading(false);\n }\n };\n\n setup();\n\n return () => {\n componentIsMounted.current = false;\n };\n }, [uri, loadImage]);\n\n // Default placeholder\n const defaultPlaceholder = useMemo(\n () => (\n <View\n style={[\n {\n width: '100%',\n height: '100%',\n backgroundColor: '#e1e1e1',\n justifyContent: 'center',\n alignItems: 'center',\n borderRadius: 3,\n },\n style,\n ]}\n >\n <Text>Image not available</Text>\n </View>\n ),\n [style],\n );\n\n // Show placeholder while loading or if there's an error\n if (isLoading || loadError || !imgUri) {\n return placeholderContent || defaultPlaceholder;\n }\n\n // Actual image component\n return (\n <Image\n {...restProps}\n style={style}\n source={{\n ...source,\n uri: useFallbackUri ? uri : imgUri,\n }}\n resizeMode={resizeMode}\n onError={(e) => {\n if (useFallbackUri) {\n setLoadError(true);\n setImgUri(null);\n } else {\n setUseFallbackUri(true);\n setImgUri(uri);\n }\n }}\n />\n );\n },\n (prevProps, nextProps) => {\n // Custom comparison function for memoization\n return (\n prevProps.cacheKey === nextProps.cacheKey &&\n prevProps.source.uri === nextProps.source.uri &&\n prevProps.style === nextProps.style\n );\n },\n);\n\nexport const CacheManager = {\n addToCache: async ({ file, key }: any) => {\n await ensureCacheDirectory();\n await FileSystem.copyAsync({\n from: file,\n to: `${CONST.IMAGE_CACHE_FOLDER}${key}`,\n });\n const uri = await CacheManager.getCachedUri({ key });\n return uri;\n },\n\n getCachedUri: async ({ key }: any) => {\n const uri = await FileSystem.getContentUriAsync(`${CONST.IMAGE_CACHE_FOLDER}${key}`);\n return uri;\n },\n\n downloadAsync: async ({ uri, key, options }: any) => {\n await ensureCacheDirectory();\n return await FileSystem.downloadAsync(uri, `${CONST.IMAGE_CACHE_FOLDER}${key}`, options);\n },\n\n clearCache: async () => {\n try {\n await FileSystem.deleteAsync(CONST.IMAGE_CACHE_FOLDER, { idempotent: true });\n await ensureCacheDirectory();\n } catch (error) {\n console.error('Error clearing cache:', error);\n }\n },\n};\n\nexport default CachedImage;\n"],"names":["CONST.IMAGE_CACHE_FOLDER","React","_a"],"mappings":"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"}
|