@messenger-box/platform-mobile 10.0.3-alpha.23 → 10.0.3-alpha.232

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 (116) hide show
  1. package/lib/components/messages-container-ui/BuildModeView.js +428 -0
  2. package/lib/components/messages-container-ui/BuildModeView.js.map +1 -0
  3. package/lib/components/messages-container-ui/MessagesContainerUI.js +55 -0
  4. package/lib/components/messages-container-ui/MessagesContainerUI.js.map +1 -0
  5. package/lib/components/messages-container-ui/PlanModeView.js +336 -0
  6. package/lib/components/messages-container-ui/PlanModeView.js.map +1 -0
  7. package/lib/compute.js +2 -3
  8. package/lib/compute.js.map +1 -1
  9. package/lib/index.js +1 -1
  10. package/lib/index.js.map +1 -1
  11. package/lib/module.js.map +1 -1
  12. package/lib/queries/inboxQueries.js +62 -0
  13. package/lib/queries/inboxQueries.js.map +1 -0
  14. package/lib/routes.json +2 -3
  15. package/lib/screens/inbox/DialogMessages.js +8 -3
  16. package/lib/screens/inbox/DialogMessages.js.map +1 -1
  17. package/lib/screens/inbox/DialogThreadMessages.js +6 -11
  18. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  19. package/lib/screens/inbox/DialogThreads.js +9 -11
  20. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  21. package/lib/screens/inbox/Inbox.js.map +1 -1
  22. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  23. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  24. package/lib/screens/inbox/components/CachedImage/index.js +125 -96
  25. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  26. package/lib/screens/inbox/components/DialogItem.js +160 -0
  27. package/lib/screens/inbox/components/DialogItem.js.map +1 -0
  28. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +315 -0
  29. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  30. package/lib/screens/inbox/components/SlackMessageContainer/ImageViewerModal.js +3 -1
  31. package/lib/screens/inbox/components/SlackMessageContainer/ImageViewerModal.js.map +1 -1
  32. package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js +194 -0
  33. package/lib/screens/inbox/components/SlackMessageContainer/PaymentMessage.js.map +1 -0
  34. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +149 -36
  35. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  36. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js +4 -5
  37. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
  38. package/lib/screens/inbox/components/SubscriptionHandler.js +22 -0
  39. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  40. package/lib/screens/inbox/components/ThreadsViewItem.js +2 -4
  41. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  42. package/lib/screens/inbox/config/config.js +4 -2
  43. package/lib/screens/inbox/config/config.js.map +1 -1
  44. package/lib/screens/inbox/containers/ConversationView.js +1093 -1090
  45. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  46. package/lib/screens/inbox/containers/Dialogs.js +130 -577
  47. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  48. package/lib/screens/inbox/containers/ThreadConversationView.js +864 -1408
  49. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  50. package/lib/screens/inbox/containers/ThreadsView.js +9 -15
  51. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  52. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  53. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  54. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +1 -1
  55. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -1
  56. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -1
  57. package/package.json +10 -8
  58. package/CHANGELOG.md +0 -172
  59. package/jest.config.js +0 -24
  60. package/lib/screens/inbox/components/DialogsListItem.js +0 -548
  61. package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
  62. package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -489
  63. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
  64. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js +0 -175
  65. package/lib/screens/inbox/components/workflow/dialogs-list-item-xstate.js.map +0 -1
  66. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js +0 -191
  67. package/lib/screens/inbox/components/workflow/service-dialogs-list-item-xstate.js.map +0 -1
  68. package/lib/screens/inbox/containers/workflow/conversation-xstate.js +0 -380
  69. package/lib/screens/inbox/containers/workflow/conversation-xstate.js.map +0 -1
  70. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +0 -211
  71. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +0 -1
  72. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js +0 -438
  73. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js.map +0 -1
  74. package/rollup.config.mjs +0 -45
  75. package/src/components/index.ts +0 -0
  76. package/src/compute.ts +0 -63
  77. package/src/index.ts +0 -7
  78. package/src/module.ts +0 -10
  79. package/src/navigation/InboxNavigation.tsx +0 -102
  80. package/src/navigation/index.ts +0 -1
  81. package/src/screens/inbox/DialogMessages.tsx +0 -21
  82. package/src/screens/inbox/DialogThreadMessages.tsx +0 -97
  83. package/src/screens/inbox/DialogThreads.tsx +0 -125
  84. package/src/screens/inbox/Inbox.tsx +0 -17
  85. package/src/screens/inbox/components/CachedImage/consts.ts +0 -6
  86. package/src/screens/inbox/components/CachedImage/index.tsx +0 -223
  87. package/src/screens/inbox/components/DialogsHeader.tsx +0 -30
  88. package/src/screens/inbox/components/DialogsListItem.tsx +0 -819
  89. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +0 -679
  90. package/src/screens/inbox/components/SlackMessageContainer/ImageViewerModal.tsx +0 -113
  91. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +0 -313
  92. package/src/screens/inbox/components/SlackMessageContainer/SlackMessage.tsx +0 -145
  93. package/src/screens/inbox/components/SlackMessageContainer/index.ts +0 -3
  94. package/src/screens/inbox/components/SmartLoader.tsx +0 -61
  95. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +0 -301
  96. package/src/screens/inbox/components/ThreadsViewItem.tsx +0 -233
  97. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +0 -145
  98. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +0 -159
  99. package/src/screens/inbox/config/config.ts +0 -15
  100. package/src/screens/inbox/config/index.ts +0 -1
  101. package/src/screens/inbox/containers/ConversationView.tsx +0 -1784
  102. package/src/screens/inbox/containers/Dialogs.tsx +0 -829
  103. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +0 -119
  104. package/src/screens/inbox/containers/ThreadConversationView.tsx +0 -2295
  105. package/src/screens/inbox/containers/ThreadsView.tsx +0 -224
  106. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +0 -20
  107. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +0 -313
  108. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +0 -196
  109. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +0 -401
  110. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +0 -136
  111. package/src/screens/inbox/index.ts +0 -37
  112. package/src/screens/inbox/machines/threadsMachine.ts +0 -147
  113. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +0 -163
  114. package/src/screens/index.ts +0 -4
  115. package/tsconfig.json +0 -13
  116. package/webpack.config.js +0 -58
@@ -1,301 +0,0 @@
1
- import React, { useMemo } from 'react';
2
- import {
3
- Text,
4
- Image,
5
- Pressable,
6
- HStack,
7
- Box,
8
- AvatarGroup,
9
- Avatar,
10
- AvatarFallbackText,
11
- AvatarImage,
12
- AvatarBadge,
13
- View,
14
- } from '@admin-layout/gluestack-ui-mobile';
15
- import { format, isToday, isYesterday } from 'date-fns';
16
- import { useFocusEffect } from '@react-navigation/native';
17
- import { IChannel, IUserAccount } from 'common';
18
- import {
19
- useThreadMessagesQuery,
20
- useMessagesQuery,
21
- useUserAccountQuery,
22
- useOnThreadCreatedUpdatedSubscription,
23
- useOnThreadChatMessageAddedSubscription,
24
- OnThreadCreatedUpdatedDocument as THREAD_CHAT_ADDED,
25
- OnThreadChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
26
- } from 'common/graphql';
27
- import { startCase } from 'lodash-es';
28
- import colors from 'tailwindcss/colors';
29
-
30
- const createdAtText = (value: string) => {
31
- if (!value) return '';
32
-
33
- try {
34
- // Validate the date before processing
35
- const timestamp = new Date(value).getTime();
36
- if (isNaN(timestamp)) {
37
- console.warn(`Invalid date value in createdAtText: ${value}`);
38
- return 'Unknown date';
39
- }
40
-
41
- let date = new Date(value);
42
- if (isToday(date)) return 'Today';
43
- if (isYesterday(date)) return 'Yesterday';
44
- return format(date, 'MMM dd, yyyy');
45
- } catch (error) {
46
- console.error(`Error processing date in createdAtText: ${value}`, error);
47
- return 'Unknown date';
48
- }
49
- };
50
-
51
- export interface IDialogListChannel extends IChannel {
52
- users: IUserAccount[];
53
- }
54
-
55
- export interface IDialogListItemProps {
56
- currentUser?: any;
57
- users?: any;
58
- selectedChannelId?: any;
59
- channel?: any;
60
- onOpen: (id: any, title: any, postParentId?: any) => void;
61
- refreshing: boolean;
62
- role: any;
63
- }
64
-
65
- /**
66
- * TODO:
67
- * - Get Reservation info: reservation date, status
68
- * - Add ability to get property information: name, logo
69
- */
70
- export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
71
- currentUser,
72
- // users,
73
- selectedChannelId,
74
- channel,
75
- onOpen,
76
- refreshing,
77
- role,
78
- }) {
79
- const [servicePostParentId, setServicePostParentId] = React.useState(null);
80
- const {
81
- data: threadMessages,
82
- loading: threadMessageLoading,
83
- error,
84
- refetch: refetchThreadMessages,
85
- subscribeToMore,
86
- } = useThreadMessagesQuery({
87
- variables: {
88
- channelId: channel?.id?.toString(),
89
- role,
90
- limit: 2,
91
- },
92
- fetchPolicy: 'cache-and-network',
93
- });
94
-
95
- useFocusEffect(
96
- React.useCallback(() => {
97
- // Do something when the screen is focused
98
- // refetchMessages({ channelId: channel?.id?.toString(), limit: 25 });
99
- refetchThreadMessages({ channelId: channel?.id?.toString(), role, limit: 2 });
100
- return () => {
101
- // Do something when the screen is unfocused
102
- // Useful for cleanup functions
103
- };
104
- }, [refreshing]),
105
- );
106
-
107
- const lastMessage = useMemo(() => {
108
- if (!threadMessages?.threadMessages?.data?.length) {
109
- return null;
110
- }
111
- const { data }: any = threadMessages.threadMessages;
112
- const replies =
113
- data
114
- ?.map((t: any) => t?.replies)
115
- ?.flat(1)
116
- ?.filter((p: any) => p?.message !== '') ?? [];
117
- if (replies?.length) {
118
- return replies[0];
119
- // return replies[replies.length - 1];
120
- } else {
121
- const post =
122
- data?.find((t: any) => {
123
- return t?.post?.message !== '';
124
- }) ??
125
- data?.find((t: any) => {
126
- return t?.post;
127
- }) ??
128
- null;
129
- return post ? post?.post : null;
130
- }
131
- }, [threadMessages]);
132
-
133
- React.useEffect(() => {
134
- if (lastMessage) {
135
- const sParentId = lastMessage?.parentId ? lastMessage?.parentId : lastMessage?.id;
136
- setServicePostParentId(sParentId);
137
- }
138
- }, [lastMessage]);
139
-
140
- const creatorAndMembersId = React.useMemo(() => {
141
- if (!channel?.members) return null;
142
- const membersIds: any =
143
- channel?.members
144
- ?.filter((m: any) => m !== null && m?.user?.id !== currentUser?.id)
145
- ?.map((mu: any) => mu?.user?.id) ?? [];
146
- const creatorId: any = channel?.creator?.id;
147
- const mergedIds: any = [].concat(membersIds, creatorId) ?? [];
148
- return mergedIds?.filter((m: any, pos: any) => mergedIds?.indexOf(m) === pos) ?? [];
149
- }, [channel]);
150
-
151
- const postParentId = React.useMemo(() => {
152
- if (!creatorAndMembersId?.length) return null;
153
-
154
- return creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
155
- ? null
156
- : lastMessage?.parentId
157
- ? lastMessage?.parentId
158
- : lastMessage?.id ?? 0;
159
- }, [creatorAndMembersId, lastMessage]);
160
-
161
- // const { data: threadCreatedUpdated } = useOnThreadCreatedUpdatedSubscription({
162
- // variables: {
163
- // channelId: channel?.id?.toString(),
164
- // postParentId:
165
- // postParentId == null
166
- // ? null
167
- // : lastMessage?.parentId
168
- // ? lastMessage?.parentId ?? null
169
- // : lastMessage?.id ?? null,
170
- // },
171
- // });
172
-
173
- // React.useEffect(() => {
174
- // if (threadCreatedUpdated?.threadCreatedUpdated?.data) {
175
- // refetchThreadMessages({ channelId: channel?.id?.toString(), role, limit: 2 });
176
- // }
177
- // }, [threadCreatedUpdated]);
178
-
179
- return (
180
- <Pressable
181
- onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id, channel?.title, postParentId)}
182
- className="flex-1 border rounded-md border-gray-200 dark:border-gray-600 dark:bg-gray-700"
183
- >
184
- <HStack space={'sm'} className="flex-1 w-[100%] py-3 justify-between items-center">
185
- <Box className="flex-[0.1] items-start pl-3">
186
- <Avatar
187
- key={'support-service-channels-key-' + channel?.id}
188
- size={'sm'}
189
- className="bg-transparent top-0 right-0 z-[1]"
190
- >
191
- <AvatarFallbackText> {startCase(channel?.creator?.username?.charAt(0))}</AvatarFallbackText>
192
- <AvatarImage
193
- alt="user image"
194
- style={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
195
- source={{
196
- uri: channel?.creator?.picture,
197
- }}
198
- />
199
- </Avatar>
200
- </Box>
201
- <Box className="flex-[0.9]">
202
- <ServiceChannelWithLastMessage
203
- channel={channel}
204
- lastMessage={lastMessage}
205
- subscribeToNewMessages={() =>
206
- subscribeToMore({
207
- document: THREAD_CHAT_ADDED,
208
- variables: {
209
- channelId: channel?.id?.toString(),
210
- postParentId: postParentId ? servicePostParentId : null,
211
- },
212
- updateQuery: (prev, { subscriptionData }: any) => {
213
- if (!subscriptionData.data) return prev;
214
-
215
- const newPostThreadData: any = subscriptionData?.data?.threadCreatedUpdated?.data;
216
- const newMessage: any = subscriptionData?.data?.threadCreatedUpdated?.lastMessage;
217
- const data = prev?.threadMessages?.data?.map((t: any) =>
218
- t.id === newPostThreadData?.id
219
- ? {
220
- ...t,
221
- replies: [...t?.replies, newMessage],
222
- replyCount: newPostThreadData?.replyCount,
223
- lastReplyAt: newPostThreadData?.lastReplyAt,
224
- updatedAt: newPostThreadData?.updatedAt,
225
- }
226
- : t,
227
- );
228
-
229
- return Object.assign({}, prev, {
230
- threadMessages: {
231
- ...prev?.threadMessages,
232
- // totalCount: prev?.threadMessages?.totalCount + 1,
233
- data: data,
234
- },
235
- });
236
- },
237
- })
238
- }
239
- />
240
- {/* <Text
241
- flex={1}
242
- color="gray.600"
243
- p={0}
244
- m={0}
245
- w={'100%'}
246
- justifyContent={''}
247
- fontSize="lg"
248
- fontWeight="semibold"
249
- >
250
- {title}
251
- </Text> */}
252
- {/* <Text flex={0.1} color="gray.600">
253
- {lastMessage?.message ?? ''}
254
- </Text> */}
255
- </Box>
256
- {/* <Text flex={0.2} color="gray.500">
257
- {lastMessage ? createdAtText(lastMessage?.createdAt) : ''}
258
- </Text> */}
259
- </HStack>
260
- </Pressable>
261
- );
262
- };
263
-
264
- const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscribeToNewMessages }: any) => {
265
- React.useEffect(() => subscribeToNewMessages(), []);
266
-
267
- // Define message display text
268
- let displayMessage = 'No messages yet';
269
-
270
- if (lastMessage) {
271
- // Check for file attachments
272
- const hasFileAttachments = lastMessage.files?.data?.length > 0;
273
-
274
- if (hasFileAttachments) {
275
- displayMessage = '📎 File attachment';
276
- } else if (lastMessage.message && lastMessage.message.trim() !== '') {
277
- displayMessage = lastMessage.message;
278
- } else {
279
- displayMessage = '(Empty message)';
280
- }
281
- }
282
-
283
- return (
284
- <HStack space={'sm'} className="flex-1 justify-center items-center">
285
- <Box className="flex-[0.8]">
286
- <Text color={colors.gray[600]} className="text-lg flex-wrap font-semibold">
287
- {channel?.title}
288
- </Text>
289
- <Text color={colors.gray[600]} numberOfLines={1}>
290
- {displayMessage}
291
- </Text>
292
- </Box>
293
-
294
- <Box className="flex-[0.2]">
295
- <Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
296
- </Box>
297
- </HStack>
298
- );
299
- });
300
-
301
- export const SupportServiceDialogsListItem = React.memo(SupportServiceDialogsListItemComponent);
@@ -1,233 +0,0 @@
1
- import React, { useMemo } from 'react';
2
- import {
3
- VStack,
4
- Text,
5
- Pressable,
6
- HStack,
7
- Box,
8
- Avatar,
9
- AvatarFallbackText,
10
- AvatarImage,
11
- Button,
12
- ButtonText,
13
- Icon,
14
- Badge,
15
- BadgeText,
16
- Link,
17
- LinkText,
18
- } from '@admin-layout/gluestack-ui-mobile';
19
- import { format, isToday, isYesterday } from 'date-fns';
20
- import { useFocusEffect } from '@react-navigation/native';
21
- import { IChannel, IUserAccount } from 'common';
22
- import { startCase } from 'lodash-es';
23
- import colors from 'tailwindcss/colors';
24
- import { useSelector } from 'react-redux';
25
- import { userSelector } from '@adminide-stack/user-auth0-client';
26
-
27
- const timeFormat = (value: string) => {
28
- if (!value) return '';
29
- let date = new Date(value);
30
- if (isToday(date)) return format(date, 'h:mm a').toUpperCase();
31
- return format(date, 'MMM do').toUpperCase();
32
- };
33
-
34
- export interface IDialogListChannel extends IChannel {
35
- users: IUserAccount[];
36
- }
37
-
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;
46
- }
47
-
48
- /**
49
- * TODO:
50
- * - Get Reservation info: reservation date, status
51
- * - Add ability to get property information: name, logo
52
- */
53
- export const ThreadViewItemComponent: React.FC<ThreadViewItemProps> = function ThreadViewItem({
54
- id,
55
- post,
56
- channel,
57
- replies,
58
- onPress,
59
- channelId,
60
- channelsDetail,
61
- }) {
62
- const currentUser = useSelector(userSelector);
63
-
64
- // Prepare thread replies for display
65
- const threadReplies = useMemo(() => {
66
- return replies || [];
67
- }, [replies]);
68
-
69
- if (!threadReplies || threadReplies.length === 0) {
70
- return null;
71
- }
72
-
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;
77
-
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 || ''}`;
81
-
82
- // Determine if the current user is in the thread
83
- const userIsInThread = channel?.users?.some((user: any) => user.id === currentUser?.id);
84
-
85
- return (
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
- }}
99
- >
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>
109
- </HStack> */}
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 ? (
125
- <Avatar
126
- size="md"
127
- style={{
128
- width: 40,
129
- height: 40,
130
- backgroundColor:
131
- reply?.author?.id === currentUser?.id ? '#2EB67D' : '#E8A54A',
132
- }}
133
- >
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
- )}
145
- </Avatar>
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>
160
- )}
161
-
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
- )}
168
-
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
- />
190
- </Box>
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>
230
- );
231
- };
232
-
233
- export const ThreadViewItem = React.memo(ThreadViewItemComponent);
@@ -1,145 +0,0 @@
1
- import { assign, setup } from 'xstate';
2
- import { merge } from 'lodash-es';
3
-
4
- export const enum Actions {
5
- INITIAL_CONTEXT = 'INITIAL_CONTEXT',
6
- ERROR_HANDLED = 'ERROR_HANDLED',
7
- FETCH_MESSAGES = 'FETCH_MESSAGES',
8
- UPDATE_MESSAGES = 'UPDATE_MESSAGES',
9
- SUBSCRIBE_TO_MESSAGES = 'SUBSCRIBE_TO_MESSAGES',
10
- SET_TITLE = 'SET_TITLE',
11
- START_LOADING = 'START_LOADING',
12
- STOP_LOADING = 'STOP_LOADING',
13
- }
14
-
15
- export const enum BaseState {
16
- Idle = 'idle',
17
- Error = 'error',
18
- FetchingMessages = 'fetchingMessages',
19
- }
20
-
21
- export const dialogsListItemXstate = setup({
22
- types: {
23
- context: {} as {
24
- channelId: string | null;
25
- currentUser: any;
26
- messages: any[];
27
- loading: boolean;
28
- error: string | null;
29
- title: string;
30
- channelMembers: any[];
31
- lastMessage: any;
32
- },
33
- },
34
- actions: {
35
- errorState: assign(({ context, event }) => {
36
- return {
37
- ...context,
38
- error: event.data?.message || 'An error occurred',
39
- loading: false,
40
- };
41
- }),
42
- setInitialContext: assign(({ context, event }) => {
43
- return merge({
44
- ...context,
45
- channelId: event.data?.channelId || null,
46
- currentUser: event.data?.currentUser || null,
47
- loading: true,
48
- });
49
- }),
50
- setMessages: assign(({ context, event }) => {
51
- return {
52
- ...context,
53
- messages: event.data?.messages || [],
54
- loading: false,
55
- };
56
- }),
57
- updateMessages: assign(({ context, event }) => {
58
- const newMessage = event.data?.message;
59
- if (!newMessage) return context;
60
-
61
- return {
62
- ...context,
63
- messages: [...context.messages, newMessage],
64
- };
65
- }),
66
- setTitle: assign(({ context, event }) => {
67
- return {
68
- ...context,
69
- title: event.data?.title || '',
70
- };
71
- }),
72
- startLoading: assign(({ context }) => {
73
- return {
74
- ...context,
75
- loading: true,
76
- };
77
- }),
78
- stopLoading: assign(({ context }) => {
79
- return {
80
- ...context,
81
- loading: false,
82
- };
83
- }),
84
- },
85
- }).createMachine({
86
- id: 'dialogs-list-item',
87
- initial: BaseState.Idle,
88
- context: {
89
- channelId: null,
90
- currentUser: null,
91
- messages: [],
92
- loading: false,
93
- error: null,
94
- title: '',
95
- channelMembers: [],
96
- lastMessage: null,
97
- },
98
- states: {
99
- [BaseState.Idle]: {
100
- on: {
101
- [Actions.INITIAL_CONTEXT]: {
102
- target: BaseState.FetchingMessages,
103
- actions: ['setInitialContext'],
104
- },
105
- [Actions.UPDATE_MESSAGES]: {
106
- target: BaseState.Idle,
107
- actions: ['updateMessages'],
108
- },
109
- [Actions.SET_TITLE]: {
110
- target: BaseState.Idle,
111
- actions: ['setTitle'],
112
- },
113
- [Actions.START_LOADING]: {
114
- target: BaseState.Idle,
115
- actions: ['startLoading'],
116
- },
117
- [Actions.STOP_LOADING]: {
118
- target: BaseState.Idle,
119
- actions: ['stopLoading'],
120
- },
121
- },
122
- },
123
- [BaseState.Error]: {
124
- entry: ['errorState'],
125
- on: {
126
- [Actions.ERROR_HANDLED]: {
127
- target: BaseState.Idle,
128
- },
129
- },
130
- },
131
- [BaseState.FetchingMessages]: {
132
- invoke: {
133
- src: 'fetchMessages',
134
- input: ({ context, event }) => ({ context, event }),
135
- onDone: {
136
- target: BaseState.Idle,
137
- actions: ['setMessages'],
138
- },
139
- onError: {
140
- target: BaseState.Error,
141
- },
142
- },
143
- },
144
- },
145
- } as any);