@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,31 +1,85 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { Image } from 'react-native';
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
+ // Ensure the cache directory exists
9
+ const ensureCacheDirectory = async () => {
10
+ try {
11
+ const dirInfo = await FileSystem.getInfoAsync(CONST.IMAGE_CACHE_FOLDER);
12
+ if (!dirInfo.exists) {
13
+ console.log('Creating cache directory:', CONST.IMAGE_CACHE_FOLDER);
14
+ await FileSystem.makeDirectoryAsync(CONST.IMAGE_CACHE_FOLDER, { intermediates: true });
15
+ }
16
+ } catch (error) {
17
+ console.error('Failed to create cache directory:', error);
18
+ }
19
+ };
20
+
21
+ // Validate and sanitize the image URL
22
+ const validateImageUri = (uri: string): string | null => {
23
+ if (!uri) return null;
24
+
25
+ // Trim whitespace
26
+ uri = uri.trim();
27
+
28
+ // Check if it's a valid URL format
29
+ try {
30
+ new URL(uri);
31
+ } catch (e) {
32
+ console.log('Invalid URL format:', uri);
33
+ return null;
34
+ }
35
+
36
+ // Add more validation as needed for your specific case
37
+ return uri;
38
+ };
39
+
8
40
  const CachedImage = (props: any) => {
9
41
  const { source, cacheKey, placeholderContent } = props;
10
- const { uri, headers, expiresIn } = source;
42
+ const { uri: originalUri, headers, expiresIn } = source;
43
+
44
+ // Validate and sanitize the URI
45
+ const uri = validateImageUri(originalUri);
46
+
11
47
  const fileURI = `${CONST.IMAGE_CACHE_FOLDER}${cacheKey}`;
12
48
 
13
49
  const [imgUri, setImgUri] = useState<any>(fileURI);
50
+ const [loadError, setLoadError] = useState<boolean>(false);
51
+ const [useFallbackUri, setUseFallbackUri] = useState<boolean>(false);
14
52
 
15
53
  const componentIsMounted = useRef(true);
16
54
  const requestOption = headers ? { headers } : {};
17
55
 
18
56
  const _callback = (downloadProgress: any) => {
19
57
  if (componentIsMounted.current === false) {
20
- downloadResumableRef.current.pauseAsync();
58
+ downloadResumableRef.current?.pauseAsync();
21
59
  FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly
22
60
  }
23
61
  };
24
62
 
25
- const downloadResumableRef = useRef(FileSystem.createDownloadResumable(uri, fileURI, requestOption, _callback));
63
+ const downloadResumableRef = useRef(
64
+ uri ? FileSystem.createDownloadResumable(uri, fileURI, requestOption, _callback) : null,
65
+ );
26
66
 
27
67
  useEffect(() => {
28
- loadImage();
68
+ const initCache = async () => {
69
+ await ensureCacheDirectory();
70
+ if (uri) {
71
+ loadImage();
72
+ } else {
73
+ console.log('Image URI is invalid, not loading');
74
+ setLoadError(true);
75
+ }
76
+ };
77
+
78
+ console.log('CachedImage loading with URI:', uri);
79
+ console.log('Cache key:', cacheKey);
80
+
81
+ initCache();
82
+
29
83
  return () => {
30
84
  componentIsMounted.current = false;
31
85
  };
@@ -36,10 +90,11 @@ const CachedImage = (props: any) => {
36
90
  // Use the cached image if it exists
37
91
  const metadata: any = await FileSystem.getInfoAsync(fileURI);
38
92
  const expired = expiresIn && new Date().getTime() / 1000 - metadata?.modificationTime > expiresIn;
39
- // console.log({expiresIn, expired})
93
+ console.log({ expiresIn, expired });
94
+
95
+ console.log({ modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000 });
96
+ console.log({ metadata });
40
97
 
41
- // console.log({modificationTime: metadata.modificationTime, currentTime: new Date().getTime() / 1000})
42
- // console.log({metadata})
43
98
  if (!metadata.exists || metadata?.size === 0 || expired) {
44
99
  if (componentIsMounted.current) {
45
100
  setImgUri(null);
@@ -50,21 +105,73 @@ const CachedImage = (props: any) => {
50
105
  // download to cache
51
106
  setImgUri(null);
52
107
 
53
- const response: any = await downloadResumableRef.current.downloadAsync();
54
- if (componentIsMounted.current && response.status === 200) {
55
- setImgUri(`${fileURI}?`); // deep clone to force re-render
108
+ console.log('Downloading image from URI:', uri);
109
+ if (!uri) {
110
+ console.log('Image URI is undefined or null');
111
+ setLoadError(true);
112
+ return;
56
113
  }
57
- if (response.status !== 200) {
58
- FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly
114
+
115
+ if (!downloadResumableRef.current) {
116
+ console.log('Download resumable is null');
117
+ setUseFallbackUri(true);
118
+ setImgUri(uri);
119
+ return;
120
+ }
121
+
122
+ try {
123
+ const response: any = await downloadResumableRef.current.downloadAsync();
124
+ console.log('Download response:', response);
125
+
126
+ if (componentIsMounted.current && response && response.status === 200) {
127
+ setImgUri(`${fileURI}?`); // deep clone to force re-render
128
+ console.log('Image cached successfully, new URI:', `${fileURI}?`);
129
+ } else {
130
+ console.log('Failed to download image, status:', response?.status);
131
+ console.log('Falling back to original URI');
132
+ setUseFallbackUri(true);
133
+ setImgUri(uri);
134
+ FileSystem.deleteAsync(fileURI, { idempotent: true }); // delete file locally if it was not downloaded properly
135
+ }
136
+ } catch (downloadError) {
137
+ console.log('Error downloading image:', downloadError);
138
+ console.log('Falling back to original URI');
139
+ setUseFallbackUri(true);
140
+ setImgUri(uri);
59
141
  }
60
142
  }
143
+ } else {
144
+ console.log('Using cached image at:', fileURI);
61
145
  }
62
146
  } catch (err) {
63
- // console.log({ err })
147
+ console.log({ err });
148
+ console.log('Falling back to original URI');
149
+ setUseFallbackUri(true);
150
+ setImgUri(uri);
64
151
  }
65
152
  };
66
- // console.log({placeholderContent})
67
- if (!imgUri) return placeholderContent || null;
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
+ }
68
175
 
69
176
  return (
70
177
  <Image
@@ -72,7 +179,20 @@ const CachedImage = (props: any) => {
72
179
  {...props}
73
180
  source={{
74
181
  ...source,
75
- uri: imgUri,
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
+ } else {
192
+ console.log('Falling back to original URI after onError');
193
+ setUseFallbackUri(true);
194
+ setImgUri(uri);
195
+ }
76
196
  }}
77
197
  />
78
198
  );
@@ -63,33 +63,59 @@ export default class Bubble extends React.Component<any> {
63
63
  }
64
64
  const { image, _id } = messageImageProps?.currentMessage;
65
65
 
66
+ // Add validation for image URL
67
+ if (!image || typeof image !== 'string') {
68
+ console.log('Invalid image URL:', image);
69
+ return null;
70
+ }
71
+
72
+ // Log the image URL for debugging
73
+ console.log('Rendering message image:', image);
74
+
66
75
  return (
67
76
  <TouchableHighlight
68
- // underlayColor={'#c0c0c0'}
69
77
  underlayColor={'transparent'}
70
- style={{ width: '100%' }}
78
+ style={{ width: '100%', marginVertical: 5 }}
71
79
  onPress={() => this.props.setImageViewer(messageImageProps?.currentMessage, true)}
72
80
  >
73
81
  <View
74
82
  style={{
75
- width: windowWidth - (windowWidth - 150),
76
- height: windowHeight - (windowHeight - 100),
83
+ width: windowWidth * 0.6, // 60% of screen width
84
+ height: windowWidth * 0.4, // Maintain aspect ratio
85
+ maxHeight: 200,
86
+ borderRadius: 8,
87
+ overflow: 'hidden',
88
+ borderWidth: 1,
89
+ borderColor: '#e0e0e0',
90
+ backgroundColor: '#f7f7f7',
77
91
  }}
78
92
  >
79
- {/* <MessageImage
80
- {...messageImageProps}
81
- imageStyle={[styles.slackImage, messageImageProps.imageStyle]}
82
- /> */}
83
93
  <CachedImage
84
94
  style={[styles.slackImage, { width: '100%', height: '100%' }]}
85
95
  cacheKey={`${_id}-slack-bubble-imageKey`}
86
96
  source={{
87
97
  uri: image,
88
- //headers: `Authorization: Bearer ${token}`,
89
98
  expiresIn: 86400,
90
99
  }}
91
100
  resizeMode={'cover'}
92
101
  alt={'image'}
102
+ placeholderContent={
103
+ <View
104
+ style={[
105
+ styles.slackImage,
106
+ {
107
+ width: '100%',
108
+ height: '100%',
109
+ backgroundColor: '#e1e1e1',
110
+ justifyContent: 'center',
111
+ alignItems: 'center',
112
+ borderRadius: 8,
113
+ },
114
+ ]}
115
+ >
116
+ <Text>Loading...</Text>
117
+ </View>
118
+ }
93
119
  />
94
120
  </View>
95
121
  </TouchableHighlight>