@messenger-box/platform-mobile 10.0.3-alpha.5 → 10.0.3-alpha.50

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 (98) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/lib/compute.js +2 -3
  3. package/lib/compute.js.map +1 -1
  4. package/lib/index.js.map +1 -1
  5. package/lib/queries/inboxQueries.js +65 -0
  6. package/lib/queries/inboxQueries.js.map +1 -0
  7. package/lib/routes.json +2 -3
  8. package/lib/screens/inbox/DialogMessages.js +1 -1
  9. package/lib/screens/inbox/DialogMessages.js.map +1 -1
  10. package/lib/screens/inbox/DialogThreadMessages.js +4 -8
  11. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  12. package/lib/screens/inbox/DialogThreads.js +57 -12
  13. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  14. package/lib/screens/inbox/Inbox.js +1 -1
  15. package/lib/screens/inbox/Inbox.js.map +1 -1
  16. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  17. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  18. package/lib/screens/inbox/components/CachedImage/index.js +168 -46
  19. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  20. package/lib/screens/inbox/components/DialogItem.js +169 -0
  21. package/lib/screens/inbox/components/DialogItem.js.map +1 -0
  22. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +313 -0
  23. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  24. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +147 -31
  25. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  26. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js +6 -1
  27. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
  28. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  29. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  30. package/lib/screens/inbox/components/ThreadsViewItem.js +66 -55
  31. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  32. package/lib/screens/inbox/config/config.js +2 -2
  33. package/lib/screens/inbox/config/config.js.map +1 -1
  34. package/lib/screens/inbox/containers/ConversationView.js +1111 -434
  35. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  36. package/lib/screens/inbox/containers/Dialogs.js +193 -80
  37. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  38. package/lib/screens/inbox/containers/ThreadConversationView.js +725 -216
  39. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  40. package/lib/screens/inbox/containers/ThreadsView.js +83 -50
  41. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  42. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  43. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  44. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
  45. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
  46. package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
  47. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
  48. package/package.json +4 -4
  49. package/src/compute.ts +5 -6
  50. package/src/index.ts +2 -0
  51. package/src/navigation/InboxNavigation.tsx +3 -3
  52. package/src/queries/inboxQueries.ts +299 -0
  53. package/src/queries/index.d.ts +2 -0
  54. package/src/queries/index.ts +1 -0
  55. package/src/screens/inbox/DialogMessages.tsx +1 -1
  56. package/src/screens/inbox/DialogThreadMessages.tsx +7 -14
  57. package/src/screens/inbox/DialogThreads.tsx +55 -61
  58. package/src/screens/inbox/Inbox.tsx +1 -1
  59. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  60. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  61. package/src/screens/inbox/components/CachedImage/index.tsx +232 -61
  62. package/src/screens/inbox/components/DialogItem.tsx +306 -0
  63. package/src/screens/inbox/components/DialogsHeader.tsx +6 -13
  64. package/src/screens/inbox/components/DialogsListItem.tsx +262 -198
  65. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  66. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  67. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  68. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +337 -194
  69. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  70. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
  71. package/src/screens/inbox/components/SlackMessageContainer/SlackMessage.tsx +1 -1
  72. package/src/screens/inbox/components/SmartLoader.tsx +61 -0
  73. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  74. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +53 -55
  75. package/src/screens/inbox/components/ThreadsViewItem.tsx +178 -285
  76. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
  77. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
  78. package/src/screens/inbox/config/config.ts +2 -2
  79. package/src/screens/inbox/containers/ConversationView.tsx +1843 -702
  80. package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
  81. package/src/screens/inbox/containers/Dialogs.tsx +402 -204
  82. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +4 -4
  83. package/src/screens/inbox/containers/ThreadConversationView.tsx +1350 -319
  84. package/src/screens/inbox/containers/ThreadsView.tsx +105 -193
  85. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  86. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  87. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  88. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
  89. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  90. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
  91. package/src/screens/inbox/index.ts +37 -0
  92. package/src/screens/inbox/machines/threadsMachine.ts +147 -0
  93. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
  94. package/tsconfig.json +11 -54
  95. package/lib/screens/inbox/components/DialogsListItem.js +0 -171
  96. package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
  97. package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -171
  98. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
@@ -56,45 +56,255 @@ export default class Bubble extends React.Component<any> {
56
56
  }
57
57
 
58
58
  renderMessageImage() {
59
- if (this.props.currentMessage.image) {
60
- const { containerStyle, wrapperStyle, ...messageImageProps } = this.props;
59
+ const { currentMessage, containerStyle, wrapperStyle, ...messageImageProps } = this.props;
60
+
61
+ // Check if we have multiple images
62
+ if (currentMessage.images && Array.isArray(currentMessage.images) && currentMessage.images.length > 0) {
63
+ // Filter out any invalid or empty image URLs first
64
+ const validImages = currentMessage.images.filter((url) => url && typeof url === 'string');
65
+
66
+ // If no valid images after filtering, don't render anything
67
+ if (validImages.length === 0) {
68
+ return null;
69
+ }
70
+
71
+ // Render multiple images in a scrollable horizontal row
72
+ return (
73
+ <View style={{ marginVertical: 0 }}>
74
+ <View
75
+ style={{
76
+ flexDirection: 'row',
77
+ flexWrap: 'wrap',
78
+ gap: 8,
79
+ }}
80
+ >
81
+ {validImages.map((imageUrl, index) => {
82
+ // Check if this is a local image
83
+ const isLocalImage =
84
+ imageUrl.startsWith('file:') ||
85
+ imageUrl.startsWith('data:') ||
86
+ imageUrl.startsWith('content:') ||
87
+ (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://'));
88
+
89
+ const imageSize =
90
+ validImages.length === 1
91
+ ? { width: windowWidth * 0.6, height: windowWidth * 0.4 }
92
+ : { width: windowWidth * 0.3, height: windowWidth * 0.3 };
93
+
94
+ // Show upload indicator if this message is uploading
95
+ const isUploading = currentMessage.isUploading;
96
+
97
+ return (
98
+ <TouchableHighlight
99
+ key={`image-${index}-${currentMessage._id}`}
100
+ underlayColor={'transparent'}
101
+ onPress={() => {
102
+ // Don't allow viewing while uploading
103
+ if (isUploading) return;
104
+
105
+ // Create a message-like object with this image for the viewer
106
+ const imageObject = {
107
+ _id: `${currentMessage._id}-img-${index}`,
108
+ image: imageUrl,
109
+ };
110
+ this.props.setImageViewer(imageObject, true);
111
+ }}
112
+ >
113
+ <View
114
+ style={{
115
+ ...imageSize,
116
+ maxHeight: 200,
117
+ borderRadius: 8,
118
+ overflow: 'hidden',
119
+ borderWidth: 1,
120
+ borderColor: '#e0e0e0',
121
+ backgroundColor: '#f7f7f7',
122
+ }}
123
+ >
124
+ {isLocalImage ? (
125
+ // For local images, use direct Image component with no loading state
126
+ <View style={{ width: '100%', height: '100%' }}>
127
+ <MessageImage
128
+ {...messageImageProps}
129
+ currentMessage={{ ...currentMessage, image: imageUrl }}
130
+ imageStyle={{
131
+ width: '100%',
132
+ height: '100%',
133
+ borderRadius: 8,
134
+ }}
135
+ />
136
+
137
+ {/* Show upload indicator if needed */}
138
+ {isUploading && (
139
+ <View
140
+ style={{
141
+ position: 'absolute',
142
+ top: 0,
143
+ left: 0,
144
+ right: 0,
145
+ bottom: 0,
146
+ backgroundColor: 'rgba(0,0,0,0.2)',
147
+ justifyContent: 'center',
148
+ alignItems: 'center',
149
+ }}
150
+ >
151
+ <Text style={{ color: 'white', fontWeight: 'bold' }}>
152
+ Uploading...
153
+ </Text>
154
+ </View>
155
+ )}
156
+ </View>
157
+ ) : (
158
+ // For remote images, use CachedImage with loading placeholder
159
+ <CachedImage
160
+ style={[styles.slackImage, { width: '100%', height: '100%' }]}
161
+ cacheKey={`${currentMessage._id}-img-${index}-slack-bubble-imageKey`}
162
+ source={{
163
+ uri: imageUrl,
164
+ expiresIn: 86400,
165
+ }}
166
+ resizeMode={'cover'}
167
+ alt={'image'}
168
+ placeholderContent={
169
+ <View
170
+ style={[
171
+ styles.slackImage,
172
+ {
173
+ width: '100%',
174
+ height: '100%',
175
+ backgroundColor: '#e1e1e1',
176
+ justifyContent: 'center',
177
+ alignItems: 'center',
178
+ borderRadius: 8,
179
+ },
180
+ ]}
181
+ >
182
+ <Text>{isUploading ? 'Uploading...' : 'Loading...'}</Text>
183
+ </View>
184
+ }
185
+ />
186
+ )}
187
+ </View>
188
+ </TouchableHighlight>
189
+ );
190
+ })}
191
+ </View>
192
+ </View>
193
+ );
194
+ }
195
+
196
+ // Fall back to single image rendering if no images array
197
+ if (currentMessage.image) {
61
198
  if (this.props.renderMessageImage) {
62
199
  return this.props.renderMessageImage(messageImageProps);
63
200
  }
64
- const { image, _id } = messageImageProps?.currentMessage;
201
+ const { image, _id } = currentMessage;
202
+
203
+ // Add validation for image URL
204
+ if (!image || typeof image !== 'string') {
205
+ return null;
206
+ }
65
207
 
208
+ // Check if this is a local image (from device camera/library)
209
+ const isLocalImage =
210
+ image.startsWith('file:') ||
211
+ image.startsWith('data:') ||
212
+ image.startsWith('content:') ||
213
+ // Check if the image is a pendingUpload by checking if it doesn't start with http/https
214
+ (!image.startsWith('http://') && !image.startsWith('https://'));
215
+
216
+ // Check uploading state
217
+ const isUploading = currentMessage.isUploading;
218
+
219
+ // Class components can't use hooks like useMemo
220
+ // Directly render the CachedImage instead
66
221
  return (
67
222
  <TouchableHighlight
68
- // underlayColor={'#c0c0c0'}
69
223
  underlayColor={'transparent'}
70
- style={{ width: '100%' }}
71
- onPress={() => this.props.setImageViewer(messageImageProps?.currentMessage, true)}
224
+ style={{ width: '100%', marginVertical: 0 }}
225
+ onPress={() => {
226
+ // Don't allow viewing while uploading
227
+ if (isUploading) return;
228
+ this.props.setImageViewer(currentMessage, true);
229
+ }}
72
230
  >
73
231
  <View
74
232
  style={{
75
- width: windowWidth - (windowWidth - 150),
76
- height: windowHeight - (windowHeight - 100),
233
+ width: windowWidth * 0.6, // 60% of screen width
234
+ height: windowWidth * 0.4, // Maintain aspect ratio
235
+ maxHeight: 200,
236
+ borderRadius: 8,
237
+ overflow: 'hidden',
238
+ borderWidth: 1,
239
+ borderColor: '#e0e0e0',
240
+ backgroundColor: '#f7f7f7',
77
241
  }}
78
242
  >
79
- {/* <MessageImage
80
- {...messageImageProps}
81
- imageStyle={[styles.slackImage, messageImageProps.imageStyle]}
82
- /> */}
83
- <CachedImage
84
- style={[styles.slackImage, { width: '100%', height: '100%' }]}
85
- cacheKey={`${_id}-slack-bubble-imageKey`}
86
- source={{
87
- uri: image,
88
- //headers: `Authorization: Bearer ${token}`,
89
- expiresIn: 86400,
90
- }}
91
- resizeMode={'cover'}
92
- alt={'image'}
93
- />
243
+ {isLocalImage ? (
244
+ // For local images, use direct Image component with no loading state
245
+ <View style={{ width: '100%', height: '100%', position: 'relative' }}>
246
+ <MessageImage
247
+ {...messageImageProps}
248
+ imageStyle={{
249
+ width: '100%',
250
+ height: '100%',
251
+ borderRadius: 8,
252
+ }}
253
+ />
254
+
255
+ {/* Show upload indicator if needed */}
256
+ {isUploading && (
257
+ <View
258
+ style={{
259
+ position: 'absolute',
260
+ top: 0,
261
+ left: 0,
262
+ right: 0,
263
+ bottom: 0,
264
+ backgroundColor: 'rgba(0,0,0,0.2)',
265
+ justifyContent: 'center',
266
+ alignItems: 'center',
267
+ }}
268
+ >
269
+ <Text style={{ color: 'white', fontWeight: 'bold' }}>Uploading...</Text>
270
+ </View>
271
+ )}
272
+ </View>
273
+ ) : (
274
+ // For remote images, use CachedImage with loading placeholder
275
+ <CachedImage
276
+ style={[styles.slackImage, { width: '100%', height: '100%' }]}
277
+ cacheKey={`${_id}-slack-bubble-imageKey`}
278
+ source={{
279
+ uri: image,
280
+ expiresIn: 86400,
281
+ }}
282
+ resizeMode={'cover'}
283
+ alt={'image'}
284
+ placeholderContent={
285
+ <View
286
+ style={[
287
+ styles.slackImage,
288
+ {
289
+ width: '100%',
290
+ height: '100%',
291
+ backgroundColor: '#e1e1e1',
292
+ justifyContent: 'center',
293
+ alignItems: 'center',
294
+ borderRadius: 8,
295
+ },
296
+ ]}
297
+ >
298
+ <Text>{isUploading ? 'Uploading...' : 'Loading...'}</Text>
299
+ </View>
300
+ }
301
+ />
302
+ )}
94
303
  </View>
95
304
  </TouchableHighlight>
96
305
  );
97
306
  }
307
+
98
308
  return null;
99
309
  }
100
310
 
@@ -74,7 +74,7 @@ export default class Message extends React.Component<any> {
74
74
  const avatarProps: any = this.getInnerComponentProps();
75
75
 
76
76
  return (
77
- <Avatar size={'sm'} bg={'transparent'} borderRadius={'$none'} marginRight={'$2'}>
77
+ <Avatar size={'sm'} className="bg-transparent rounded-none mr-2">
78
78
  <AvatarFallbackText>
79
79
  {isSameUserAndSameDay ? '' : avatarProps?.currentMessage?.user?.name[0]}
80
80
  </AvatarFallbackText>
@@ -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;
@@ -0,0 +1,41 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /**
4
+ * Shared SubscriptionHandler for Apollo subscribeToMore
5
+ *
6
+ * @param subscribeToMore - Apollo subscribeToMore function
7
+ * @param document - GraphQL subscription document
8
+ * @param variables - Variables for the subscription
9
+ * @param updateQuery - Apollo updateQuery function
10
+ * @param onError - Optional error handler
11
+ * @param enabled - If false, disables the subscription
12
+ */
13
+ export function SubscriptionHandler({
14
+ subscribeToMore,
15
+ document,
16
+ variables,
17
+ updateQuery,
18
+ onError,
19
+ enabled = true,
20
+ }: {
21
+ subscribeToMore: Function;
22
+ document: any;
23
+ variables: Record<string, any>;
24
+ updateQuery: (prev: any, { subscriptionData }: any) => any;
25
+ onError?: (error: any) => void;
26
+ enabled?: boolean;
27
+ }) {
28
+ useEffect(() => {
29
+ if (!enabled) return;
30
+ const unsubscribe = subscribeToMore({
31
+ document,
32
+ variables,
33
+ updateQuery,
34
+ onError,
35
+ });
36
+ return () => {
37
+ if (unsubscribe && typeof unsubscribe === 'function') unsubscribe();
38
+ };
39
+ }, [subscribeToMore, document, JSON.stringify(variables), updateQuery, onError, enabled]);
40
+ return null;
41
+ }
@@ -16,22 +16,35 @@ import { format, isToday, isYesterday } from 'date-fns';
16
16
  import { useFocusEffect } from '@react-navigation/native';
17
17
  import { IChannel, IUserAccount } from 'common';
18
18
  import {
19
+ THREAD_CREATED_UPDATED,
20
+ CHAT_MESSAGE_ADDED,
19
21
  useThreadMessagesQuery,
22
+ useThreadCreatedUpdatedSubscription,
23
+ useThreadChatMessageAddedSubscription,
20
24
  useMessagesQuery,
21
- useUserAccountQuery,
22
- useOnThreadCreatedUpdatedSubscription,
23
- useOnThreadChatMessageAddedSubscription,
24
- OnThreadCreatedUpdatedDocument as THREAD_CHAT_ADDED,
25
- OnThreadChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
26
- } from 'common/lib/generated/generated.js';
25
+ } from '../../../queries/inboxQueries';
27
26
  import { startCase } from 'lodash-es';
27
+ import colors from 'tailwindcss/colors';
28
28
 
29
29
  const createdAtText = (value: string) => {
30
30
  if (!value) return '';
31
- let date = new Date(value);
32
- if (isToday(date)) return 'Today';
33
- if (isYesterday(date)) return 'Yesterday';
34
- return format(new Date(value), 'MMM dd, yyyy');
31
+
32
+ try {
33
+ // Validate the date before processing
34
+ const timestamp = new Date(value).getTime();
35
+ if (isNaN(timestamp)) {
36
+ console.warn(`Invalid date value in createdAtText: ${value}`);
37
+ return 'Unknown date';
38
+ }
39
+
40
+ let date = new Date(value);
41
+ if (isToday(date)) return 'Today';
42
+ if (isYesterday(date)) return 'Yesterday';
43
+ return format(date, 'MMM dd, yyyy');
44
+ } catch (error) {
45
+ console.error(`Error processing date in createdAtText: ${value}`, error);
46
+ return 'Unknown date';
47
+ }
35
48
  };
36
49
 
37
50
  export interface IDialogListChannel extends IChannel {
@@ -165,34 +178,14 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
165
178
  return (
166
179
  <Pressable
167
180
  onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id, channel?.title, postParentId)}
168
- borderWidth={'$1'}
169
- borderRadius={'$md'}
170
- borderColor={'$trueGray200'}
171
- flex={1}
172
- $dark-borderColor="$coolGray600"
173
- $dark-backgroundColor="$trueGray700"
174
- $light-backgroundColor="$trueGray50"
175
- $light-borderColor="$trueGray200"
181
+ className="flex-1 border rounded-md border-gray-200 dark:border-gray-600 dark:bg-gray-700"
176
182
  >
177
- <HStack
178
- // px={2}
179
- // pl={3}
180
- py={'$3'}
181
- space={'sm'}
182
- w={'100%'}
183
- flex={1}
184
- // direction={'row'}
185
- justifyContent={'space-between'}
186
- alignItems={'center'}
187
- >
188
- <Box flex={0.1} alignItems={'flex-start'} pl={'$3'}>
183
+ <HStack space={'sm'} className="flex-1 w-[100%] py-3 justify-between items-center">
184
+ <Box className="flex-[0.1] items-start pl-3">
189
185
  <Avatar
190
186
  key={'support-service-channels-key-' + channel?.id}
191
- bg={'transparent'}
192
187
  size={'sm'}
193
- top={'$0'}
194
- right={'$0'}
195
- zIndex={1}
188
+ className="bg-transparent top-0 right-0 z-[1]"
196
189
  >
197
190
  <AvatarFallbackText> {startCase(channel?.creator?.username?.charAt(0))}</AvatarFallbackText>
198
191
  <AvatarImage
@@ -204,13 +197,13 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
204
197
  />
205
198
  </Avatar>
206
199
  </Box>
207
- <Box flex={0.9}>
200
+ <Box className="flex-[0.9]">
208
201
  <ServiceChannelWithLastMessage
209
202
  channel={channel}
210
203
  lastMessage={lastMessage}
211
204
  subscribeToNewMessages={() =>
212
205
  subscribeToMore({
213
- document: THREAD_CHAT_ADDED,
206
+ document: THREAD_CREATED_UPDATED,
214
207
  variables: {
215
208
  channelId: channel?.id?.toString(),
216
209
  postParentId: postParentId ? servicePostParentId : null,
@@ -269,31 +262,36 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
269
262
 
270
263
  const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscribeToNewMessages }: any) => {
271
264
  React.useEffect(() => subscribeToNewMessages(), []);
265
+
266
+ // Define message display text
267
+ let displayMessage = 'No messages yet';
268
+
269
+ if (lastMessage) {
270
+ // Check for file attachments
271
+ const hasFileAttachments = lastMessage.files?.data?.length > 0;
272
+
273
+ if (hasFileAttachments) {
274
+ displayMessage = '📎 File attachment';
275
+ } else if (lastMessage.message && lastMessage.message.trim() !== '') {
276
+ displayMessage = lastMessage.message;
277
+ } else {
278
+ displayMessage = '(Empty message)';
279
+ }
280
+ }
281
+
272
282
  return (
273
- <HStack space={'sm'} flex={1} justifyContent={'center'} alignItems={'center'}>
274
- <Box flex={0.8}>
275
- <Text color="$trueGray600" fontSize="$lg" flexWrap={'wrap'} fontWeight="$semibold">
283
+ <HStack space={'sm'} className="flex-1 justify-center items-center">
284
+ <Box className="flex-[0.8]">
285
+ <Text color={colors.gray[600]} className="text-lg flex-wrap font-semibold">
276
286
  {channel?.title}
277
287
  </Text>
278
- <Text color="$trueGray600" numberOfLines={1}>
279
- {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
280
- ? lastMessageCreatorAndMembers?.message ?? ''
281
- : lastMessage?.message ?? ''} */}
282
- {lastMessage?.message ?? ''}
288
+ <Text color={colors.gray[600]} numberOfLines={1}>
289
+ {displayMessage}
283
290
  </Text>
284
291
  </Box>
285
292
 
286
- <Box flex={0.2}>
287
- {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id) ? (
288
- <Text color="gray.500">
289
- {lastMessageCreatorAndMembers
290
- ? createdAtText(lastMessageCreatorAndMembers?.createdAt)
291
- : ''}
292
- </Text>
293
- ) : (
294
- <Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
295
- )} */}
296
- <Text color="$trueGray500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
293
+ <Box className="flex-[0.2]">
294
+ <Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
297
295
  </Box>
298
296
  </HStack>
299
297
  );