@messenger-box/platform-mobile 10.0.3-alpha.16 → 10.0.3-alpha.162

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 (95) hide show
  1. package/CHANGELOG.md +248 -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/module.js.map +1 -1
  6. package/lib/queries/inboxQueries.js +65 -0
  7. package/lib/queries/inboxQueries.js.map +1 -0
  8. package/lib/routes.json +13 -1
  9. package/lib/screens/inbox/DialogMessages.js +5 -3
  10. package/lib/screens/inbox/DialogMessages.js.map +1 -1
  11. package/lib/screens/inbox/DialogThreadMessages.js +3 -7
  12. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  13. package/lib/screens/inbox/DialogThreads.js +57 -18
  14. package/lib/screens/inbox/DialogThreads.js.map +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/ImageViewerModal.js.map +1 -1
  25. package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js +197 -0
  26. package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js.map +1 -0
  27. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +141 -31
  28. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  29. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
  30. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  31. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  32. package/lib/screens/inbox/components/ThreadsViewItem.js +66 -44
  33. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  34. package/lib/screens/inbox/config/config.js +2 -2
  35. package/lib/screens/inbox/config/config.js.map +1 -1
  36. package/lib/screens/inbox/containers/ConversationView.js +1205 -432
  37. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  38. package/lib/screens/inbox/containers/Dialogs.js +193 -80
  39. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  40. package/lib/screens/inbox/containers/ThreadConversationView.js +724 -207
  41. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  42. package/lib/screens/inbox/containers/ThreadsView.js +83 -50
  43. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  44. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  45. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  46. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
  47. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
  48. package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
  49. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
  50. package/package.json +5 -5
  51. package/src/index.ts +2 -0
  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 +2 -1
  56. package/src/screens/inbox/DialogThreadMessages.tsx +3 -11
  57. package/src/screens/inbox/DialogThreads.tsx +53 -60
  58. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  59. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  60. package/src/screens/inbox/components/CachedImage/index.tsx +232 -61
  61. package/src/screens/inbox/components/DialogItem.tsx +306 -0
  62. package/src/screens/inbox/components/DialogsListItem.tsx +230 -170
  63. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  64. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  65. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  66. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +330 -171
  67. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  68. package/src/screens/inbox/components/SlackMessageContainer/PaymentMessage.tsx +199 -0
  69. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
  70. package/src/screens/inbox/components/SmartLoader.tsx +61 -0
  71. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  72. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +41 -24
  73. package/src/screens/inbox/components/ThreadsViewItem.tsx +177 -265
  74. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
  75. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
  76. package/src/screens/inbox/config/config.ts +2 -2
  77. package/src/screens/inbox/containers/ConversationView.tsx +2004 -698
  78. package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
  79. package/src/screens/inbox/containers/Dialogs.tsx +402 -196
  80. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +2 -2
  81. package/src/screens/inbox/containers/ThreadConversationView.tsx +1337 -301
  82. package/src/screens/inbox/containers/ThreadsView.tsx +105 -186
  83. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  84. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  85. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  86. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
  87. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  88. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
  89. package/src/screens/inbox/index.ts +37 -0
  90. package/src/screens/inbox/machines/threadsMachine.ts +147 -0
  91. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
  92. package/lib/screens/inbox/components/DialogsListItem.js +0 -175
  93. package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
  94. package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -165
  95. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
@@ -16,23 +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/graphql';
25
+ } from '../../../queries/inboxQueries';
27
26
  import { startCase } from 'lodash-es';
28
27
  import colors from 'tailwindcss/colors';
29
28
 
30
29
  const createdAtText = (value: string) => {
31
30
  if (!value) return '';
32
- let date = new Date(value);
33
- if (isToday(date)) return 'Today';
34
- if (isYesterday(date)) return 'Yesterday';
35
- 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
+ }
36
48
  };
37
49
 
38
50
  export interface IDialogListChannel extends IChannel {
@@ -191,7 +203,7 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
191
203
  lastMessage={lastMessage}
192
204
  subscribeToNewMessages={() =>
193
205
  subscribeToMore({
194
- document: THREAD_CHAT_ADDED,
206
+ document: THREAD_CREATED_UPDATED,
195
207
  variables: {
196
208
  channelId: channel?.id?.toString(),
197
209
  postParentId: postParentId ? servicePostParentId : null,
@@ -250,6 +262,23 @@ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemPro
250
262
 
251
263
  const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscribeToNewMessages }: any) => {
252
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
+
253
282
  return (
254
283
  <HStack space={'sm'} className="flex-1 justify-center items-center">
255
284
  <Box className="flex-[0.8]">
@@ -257,23 +286,11 @@ const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscr
257
286
  {channel?.title}
258
287
  </Text>
259
288
  <Text color={colors.gray[600]} numberOfLines={1}>
260
- {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
261
- ? lastMessageCreatorAndMembers?.message ?? ''
262
- : lastMessage?.message ?? ''} */}
263
- {lastMessage?.message ?? ''}
289
+ {displayMessage}
264
290
  </Text>
265
291
  </Box>
266
292
 
267
293
  <Box className="flex-[0.2]">
268
- {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id) ? (
269
- <Text color="gray.500">
270
- {lastMessageCreatorAndMembers
271
- ? createdAtText(lastMessageCreatorAndMembers?.createdAt)
272
- : ''}
273
- </Text>
274
- ) : (
275
- <Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
276
- )} */}
277
294
  <Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
278
295
  </Box>
279
296
  </HStack>
@@ -2,51 +2,47 @@ import React, { useMemo } from 'react';
2
2
  import {
3
3
  VStack,
4
4
  Text,
5
- Image,
6
5
  Pressable,
7
6
  HStack,
8
7
  Box,
9
- AvatarGroup,
10
8
  Avatar,
11
9
  AvatarFallbackText,
12
10
  AvatarImage,
13
- AvatarBadge,
14
- View,
15
11
  Button,
16
12
  ButtonText,
13
+ Icon,
14
+ Badge,
15
+ BadgeText,
16
+ Link,
17
+ LinkText,
17
18
  } from '@admin-layout/gluestack-ui-mobile';
18
19
  import { format, isToday, isYesterday } from 'date-fns';
19
20
  import { useFocusEffect } from '@react-navigation/native';
20
21
  import { IChannel, IUserAccount } from 'common';
21
- import {
22
- useThreadMessagesQuery,
23
- useMessagesQuery,
24
- useUserAccountQuery,
25
- useOnThreadChatMessageAddedSubscription,
26
- useOnThreadCreatedUpdatedSubscription,
27
- } from 'common/graphql';
28
22
  import { startCase } from 'lodash-es';
29
23
  import colors from 'tailwindcss/colors';
24
+ import { useSelector } from 'react-redux';
25
+ import { userSelector } from '@adminide-stack/user-auth0-client';
30
26
 
31
- const createdAtText = (value: string) => {
27
+ const timeFormat = (value: string) => {
32
28
  if (!value) return '';
33
29
  let date = new Date(value);
34
- if (isToday(date)) return 'Today';
35
- if (isYesterday(date)) return 'Yesterday';
36
- return format(new Date(value), 'MMM dd, yyyy');
30
+ if (isToday(date)) return format(date, 'h:mm a').toUpperCase();
31
+ return format(date, 'MMM do').toUpperCase();
37
32
  };
38
33
 
39
34
  export interface IDialogListChannel extends IChannel {
40
35
  users: IUserAccount[];
41
36
  }
42
37
 
43
- export interface IDialogListItemProps {
44
- currentUser?: any;
45
- users?: any;
46
- thread?: any;
47
- onOpen: (id: any, title: any, postParentId?: any) => void;
48
- role?: any;
49
- setData?: any;
38
+ export interface ThreadViewItemProps {
39
+ id: string;
40
+ post: any;
41
+ channel: any;
42
+ replies: any[];
43
+ onPress: (id: any, title: any, postParentId?: any) => void;
44
+ channelId?: string;
45
+ channelsDetail?: any;
50
46
  }
51
47
 
52
48
  /**
@@ -54,267 +50,183 @@ export interface IDialogListItemProps {
54
50
  * - Get Reservation info: reservation date, status
55
51
  * - Add ability to get property information: name, logo
56
52
  */
57
- export const ThreadViewItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
58
- currentUser,
59
- // users,
60
- thread,
61
- onOpen,
62
- role,
63
- setData,
53
+ export const ThreadViewItemComponent: React.FC<ThreadViewItemProps> = function ThreadViewItem({
54
+ id,
55
+ post,
56
+ channel,
57
+ replies,
58
+ onPress,
59
+ channelId,
60
+ channelsDetail,
64
61
  }) {
65
- // const { data: threadCreatedUpdated } = useOnThreadCreatedUpdatedSubscription({
66
- // variables: {
67
- // channelId: thread?.channel?.id?.toString(),
68
- // postParentId: thread?.post?.id?.toString(),
69
- // },
70
- // });
71
-
72
- useFocusEffect(
73
- React.useCallback(() => {
74
- // Do something when the screen is focused
75
- return () => {
76
- // Do something when the screen is unfocused
77
- // Useful for cleanup functions
78
- };
79
- }, []),
80
- );
81
-
82
- const threadPostReply = React.useMemo(() => {
83
- if (!thread?.replies) return null;
84
- return thread?.replies;
85
- }, [thread]);
62
+ const currentUser = useSelector(userSelector);
86
63
 
87
- // React.useEffect(() => {
88
- // if (threadCreatedUpdated?.threadCreatedUpdated?.data) setData(threadCreatedUpdated?.threadCreatedUpdated?.data);
89
- // }, [threadCreatedUpdated?.threadCreatedUpdated]);
64
+ // Prepare thread replies for display
65
+ const threadReplies = useMemo(() => {
66
+ return replies || [];
67
+ }, [replies]);
90
68
 
91
- // const threadPostReply = React.useMemo(() => {
92
- // if (!thread?.replies) return null;
93
- // if (threadCreatedUpdated?.threadCreatedUpdated?.data?.replies?.length) {
94
- // return threadCreatedUpdated?.threadCreatedUpdated?.data?.replies;
95
- // } else return thread?.replies;
96
- // }, [thread, threadCreatedUpdated]);
97
-
98
- // const lastMessage = useMemo(() => {
99
- // if (!threadPost) {
100
- // return null;
101
- // }
102
- // const replies = threadPost?.replies?.filter((p: any) => p?.message !== '') ?? [];
103
- // if (replies?.length) {
104
- // return replies[0];
105
- // // return replies[replies.length - 1];
106
- // } else {
107
- // const post = threadPost?.post ?? null;
108
- // return post ? post?.post : null;
109
- // }
110
- // }, [threadPost]);
69
+ if (!threadReplies || threadReplies.length === 0) {
70
+ return null;
71
+ }
111
72
 
112
- // const participants: any = React.useMemo(() => {
113
- // if (!thread?.participants?.length) return null;
114
- // return thread?.participants?.filter((u: any) => u?.user?.id !== currentUser?.id) ?? [];
115
- // }, [thread]);
73
+ // Get the last reply for the thread preview
74
+ const lastReply = threadReplies[0]; // Most recent reply should be first in the array
75
+ // Get total number of replies
76
+ const totalReplies = threadReplies.length;
116
77
 
117
- // const allParticipantsNames: any = React.useMemo(() => {
118
- // if (!participants?.length) return null;
119
- // return (
120
- // participants
121
- // ?.map((p: any) => {
122
- // return p?.user?.givenName + ' ' + p?.user?.familyName ?? '';
123
- // })
124
- // ?.join(', ') ?? ''
125
- // );
126
- // }, [participants]);
78
+ // Get the first user in the thread as the primary user
79
+ const primaryUser = channel?.users?.[0] || lastReply?.author;
80
+ const channelName = channel?.title || `${primaryUser?.givenName || ''} ${primaryUser?.familyName || ''}`;
127
81
 
128
- if (!threadPostReply || threadPostReply?.length == 0) {
129
- return <></>;
130
- }
82
+ // Determine if the current user is in the thread
83
+ const userIsInThread = channel?.users?.some((user: any) => user.id === currentUser?.id);
131
84
 
132
85
  return (
133
- <VStack
134
- space={'sm'}
135
- className="flex-1 py-2 px-2 border rounded-md bg-white border-gray-200 dark:border-white dark:bg-white"
86
+ <Pressable
87
+ onPress={() => onPress(channel?.id, 'Thread', post?.id)}
88
+ style={{
89
+ marginVertical: 5,
90
+ backgroundColor: 'white',
91
+ borderRadius: 10,
92
+ paddingVertical: 5,
93
+ elevation: 1,
94
+ shadowColor: '#000',
95
+ shadowOffset: { width: 0, height: 1 },
96
+ shadowOpacity: 0.1,
97
+ shadowRadius: 2,
98
+ }}
136
99
  >
137
- <HStack space={'sm'} className="py-2 w-[100%] flex-1 justify-between items-center">
138
- <Box className="flex-1">
139
- {/* <HStack flex={1} space={5} py={2} alignItems={'baseline'}>
140
- <Box>
141
- <Avatar.Badge size={4} left={0} zIndex={1} bg="green.800" />
142
- </Box>
143
- <Box>
144
- <Text color="gray.600" fontSize="lg" flexWrap={'wrap'} fontWeight="semibold">
145
- {allParticipantsNames || ''}
146
- </Text>
147
- </Box>
100
+ <Box className="mb-3">
101
+ <VStack space="md">
102
+ {/* Thread header with green dot and users */}
103
+ {/* <HStack space="sm" className="px-4 items-center">
104
+ <Box
105
+ className="bg-green-500 rounded-full"
106
+ style={{ width: 8, height: 8 }}
107
+ />
108
+ <Text className="text-base text-gray-900">{channelName}</Text>
148
109
  </HStack> */}
149
- <HStack space={'sm'} className="flex-1 justify-center items-center">
150
- <Box className="flex-1">
151
- {/* <HStack space={2} py={2}>
152
- <Box>
110
+
111
+ {/* Thread members */}
112
+ <Text className="text-sm font-medium text-gray-600 px-4 pt-2">
113
+ {channel?.users?.map((user: any) => user?.givenName || user?.username)?.join(', ')}
114
+ </Text>
115
+
116
+ {/* Thread messages preview - show up to 3 most recent messages */}
117
+ {threadReplies.slice(0, 3).map((reply: any, index: number) => {
118
+ // Group consecutive messages from the same user
119
+ const previousReply = index > 0 ? threadReplies.slice(0, 3)[index - 1] : null;
120
+ const isConsecutiveReply = previousReply && previousReply.author?.id === reply.author?.id;
121
+
122
+ return (
123
+ <HStack key={reply.id || index} space="md" className="px-4 py-1">
124
+ {!isConsecutiveReply ? (
153
125
  <Avatar
154
- bg={'transparent'}
155
- size={8}
156
- _image={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
157
- source={{
158
- uri: thread?.post?.author?.picture,
126
+ size="md"
127
+ style={{
128
+ width: 40,
129
+ height: 40,
130
+ backgroundColor:
131
+ reply?.author?.id === currentUser?.id ? '#2EB67D' : '#E8A54A',
159
132
  }}
160
133
  >
161
- {startCase(thread?.post?.author?.username?.charAt(0))}
134
+ <AvatarFallbackText>
135
+ {startCase(reply?.author?.username?.charAt(0) || 'U')}
136
+ </AvatarFallbackText>
137
+ {reply?.author?.picture && (
138
+ <AvatarImage
139
+ alt={reply?.author?.username || 'User'}
140
+ source={{
141
+ uri: reply?.author?.picture,
142
+ }}
143
+ />
144
+ )}
162
145
  </Avatar>
163
- </Box>
164
- <Box>
165
- <HStack space={4}>
166
- <Text>
167
- {thread?.post?.author?.givenName + ' ' + thread?.post?.author?.familyName ??
168
- ''}
169
- </Text>
170
- <Text color="gray.500">
171
- {thread?.post ? createdAtText(thread?.post?.createdAt) : ''}
172
- </Text>
173
- </HStack>
174
- <Text color="gray.600" noOfLines={2}>
175
- {thread?.post?.message ?? ''}
176
- </Text>
177
- {!thread?.replies?.length && (
178
- <Button
179
- size={'xs'}
180
- w={150}
181
- variant={'outline'}
182
- _text={{ fontSize: 12, color: '#000' }}
183
- onPress={() =>
184
- onOpen(thread?.channel?.id, thread?.channel?.title, thread?.post?.id)
185
- }
186
- >
187
- Reply
188
- </Button>
146
+ ) : (
147
+ <Box style={{ width: 40 }} />
148
+ )}
149
+
150
+ <VStack space="xs" className="flex-1">
151
+ {!isConsecutiveReply && (
152
+ <HStack space="sm" className="items-center">
153
+ <Text className="font-bold text-gray-900">
154
+ {reply?.author?.givenName || reply?.author?.username || 'User'}
155
+ </Text>
156
+ <Text className="text-xs text-gray-500">
157
+ {timeFormat(reply?.createdAt)}
158
+ </Text>
159
+ </HStack>
189
160
  )}
190
- </Box>
191
- </HStack> */}
192
- {threadPostReply?.length > 0 && (
193
- <>
194
- {threadPostReply
195
- ?.slice(0, 2)
196
- ?.reverse()
197
- ?.map((reply: any, index: any) => (
198
- <HStack key={index} space={'sm'} className="pb-2 pt-1">
199
- <Box>
200
- <Avatar
201
- key={'thread-view-key-' + index}
202
- size={'md'}
203
- className="bg-transparent top-0 right-0 z-[1]"
204
- >
205
- <AvatarFallbackText>
206
- {' '}
207
- {startCase(reply?.author?.username?.charAt(0))}
208
- </AvatarFallbackText>
209
- <AvatarImage
210
- alt="image"
211
- style={{
212
- borderRadius: 6,
213
- borderWidth: 2,
214
- borderColor: '#fff',
215
- }}
216
- source={{
217
- uri: reply?.author?.picture,
218
- }}
219
- />
220
- </Avatar>
221
- </Box>
222
- <Box>
223
- <HStack space={'md'}>
224
- <Text>
225
- {reply?.author?.givenName ?? '' ?? ''}{' '}
226
- {reply?.author?.familyName ?? '' ?? ''}
227
- {/* {lastMessage?.author?.givenName +
228
- ' ' +
229
- lastMessage?.author?.familyName ?? ''} */}
230
- </Text>
231
- <Text color={colors.gray[500]}>
232
- {reply?.createdAt ? createdAtText(reply?.createdAt) : ''}
233
- {/* {lastMessage ? createdAtText(lastMessage?.createdAt) : ''} */}
234
- </Text>
235
- </HStack>
236
- <VStack space={'sm'}>
237
- {reply?.message && (
238
- <Text color={colors.gray[600]} numberOfLines={2}>
239
- {reply?.message.length < 70
240
- ? `${reply?.message}`
241
- : `${reply?.message.substring(0, 68)}....`}
242
- </Text>
243
- )}
244
- {/* <Text color="gray.600" noOfLines={2}>
245
- {reply?.message
246
- ? reply?.message.length < 70
247
- ? `${reply?.message}`
248
- : `${reply?.message.substring(0, 68)}....`
249
- : ''}
250
- </Text> */}
251
161
 
252
- <>
253
- {reply?.files?.data?.length > 0 &&
254
- reply?.files?.data?.map((f: any, index: any) => (
255
- <Box>
256
- <Avatar
257
- key={'thread-view-other-key-' + index}
258
- className="bg-transparent"
259
- size={'md'}
260
- >
261
- <AvatarFallbackText> I</AvatarFallbackText>
262
- <AvatarImage
263
- alt="image"
264
- style={{
265
- borderRadius: 6,
266
- borderWidth: 2,
267
- borderColor: '#fff',
268
- }}
269
- source={{
270
- uri: f?.url,
271
- }}
272
- />
273
- </Avatar>
274
- </Box>
275
- ))}
276
- </>
277
- </VStack>
162
+ {reply?.message && (
163
+ <Text color={colors.gray[700]} numberOfLines={2} className="text-base">
164
+ {reply?.message}
165
+ {reply?.edited && <Text className="text-xs text-gray-500"> (edited)</Text>}
166
+ </Text>
167
+ )}
278
168
 
279
- {(threadPostReply?.length == 1 || index !== 0) && (
280
- <Button
281
- size={'xs'}
282
- className="w-[150]"
283
- variant={'outline'}
284
- onPress={() =>
285
- onOpen(
286
- thread?.channel?.id,
287
- thread?.channel?.title,
288
- thread?.post?.id,
289
- )
290
- }
291
- >
292
- <ButtonText style={{ fontSize: 12, color: '#000' }}>
293
- Reply
294
- </ButtonText>
295
- </Button>
296
- )}
169
+ {reply.email && <Text className="text-blue-500">{reply.email}</Text>}
170
+
171
+ {reply?.files?.data?.length > 0 && (
172
+ <HStack space="sm" className="my-1">
173
+ {reply?.files?.data?.map((file: any, fileIndex: number) => (
174
+ <Box
175
+ key={fileIndex}
176
+ className="overflow-hidden"
177
+ style={{ width: 80, height: 80 }}
178
+ >
179
+ <AvatarImage
180
+ alt="attachment"
181
+ className="rounded-none border-none"
182
+ style={{
183
+ width: '100%',
184
+ height: '100%',
185
+ }}
186
+ source={{
187
+ uri: file?.url,
188
+ }}
189
+ />
297
190
  </Box>
298
- </HStack>
299
- ))}
300
- </>
301
- )}
302
- </Box>
303
- </HStack>
304
- </Box>
305
- </HStack>
306
- {/* <HStack>
307
- <Box flex={0.06} alignItems={'flex-start'}></Box>
308
- <Button
309
- size={'xs'}
310
- variant={'outline'}
311
- _text={{ fontSize: 12, color: '#000' }}
312
- onPress={() => onOpen(thread?.channel?.id, thread?.channel?.title, postParentId)}
313
- >
314
- Reply
315
- </Button>
316
- </HStack> */}
317
- </VStack>
191
+ ))}
192
+ </HStack>
193
+ )}
194
+ </VStack>
195
+ </HStack>
196
+ );
197
+ })}
198
+
199
+ {/* Show more replies indicator */}
200
+ {totalReplies > 3 && (
201
+ <HStack className="px-4 items-center" space="sm">
202
+ <Box style={{ width: 40 }} />
203
+ <Link onPress={() => onPress(channel?.id, 'Thread', post?.id)}>
204
+ <LinkText className="text-blue-600 mt-1">
205
+ {totalReplies - 3} more {totalReplies - 3 === 1 ? 'reply' : 'replies'}
206
+ </LinkText>
207
+ </Link>
208
+ </HStack>
209
+ )}
210
+
211
+ {/* Reply button */}
212
+ <Box className="px-4 pb-2">
213
+ <Button
214
+ size="sm"
215
+ className="self-start rounded-full"
216
+ variant="outline"
217
+ style={{
218
+ borderColor: '#E2E8F0',
219
+ paddingHorizontal: 16,
220
+ paddingVertical: 6,
221
+ }}
222
+ onPress={() => onPress(channel?.id, 'Thread', post?.id)}
223
+ >
224
+ <ButtonText style={{ fontSize: 14, color: colors.gray[800] }}>Reply</ButtonText>
225
+ </Button>
226
+ </Box>
227
+ </VStack>
228
+ </Box>
229
+ </Pressable>
318
230
  );
319
231
  };
320
232