@messenger-box/platform-mobile 0.0.1-alpha.362 → 0.0.1-alpha.365

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 (29) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/index.js +2281 -553
  3. package/lib/index.js.map +1 -1
  4. package/lib/screens/inbox/DialogThreadMessages.d.ts +7 -0
  5. package/lib/screens/inbox/DialogThreads.d.ts +6 -0
  6. package/lib/screens/inbox/components/SupportServiceDialogsListItem.d.ts +21 -0
  7. package/lib/screens/inbox/components/ThreadsViewItem.d.ts +18 -0
  8. package/lib/screens/inbox/config/config.d.ts +2 -0
  9. package/lib/screens/inbox/containers/Dialogs.d.ts +1 -0
  10. package/lib/screens/inbox/containers/SupportServiceDialogs.d.ts +6 -0
  11. package/lib/screens/inbox/containers/ThreadConversationView.d.ts +11 -0
  12. package/lib/screens/inbox/containers/ThreadsView.d.ts +8 -0
  13. package/lib/screens/index.d.ts +2 -0
  14. package/package.json +4 -4
  15. package/src/navigation/InboxNavigation.tsx +63 -0
  16. package/src/screens/inbox/DialogThreadMessages.tsx +90 -0
  17. package/src/screens/inbox/DialogThreads.tsx +107 -0
  18. package/src/screens/inbox/Inbox.tsx +5 -3
  19. package/src/screens/inbox/components/DialogsListItem.tsx +7 -3
  20. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +5 -5
  21. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +295 -0
  22. package/src/screens/inbox/components/ThreadsViewItem.tsx +236 -0
  23. package/src/screens/inbox/config/config.ts +4 -0
  24. package/src/screens/inbox/containers/ConversationView.tsx +440 -156
  25. package/src/screens/inbox/containers/Dialogs.tsx +2 -1
  26. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +119 -0
  27. package/src/screens/inbox/containers/ThreadConversationView.tsx +764 -0
  28. package/src/screens/inbox/containers/ThreadsView.tsx +205 -0
  29. package/src/screens/index.ts +3 -1
@@ -0,0 +1,295 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Text, Image, Pressable, HStack, Stack, Box, Avatar, View } from 'native-base';
3
+ import { format, isToday, isYesterday } from 'date-fns';
4
+ import { useFocusEffect } from '@react-navigation/native';
5
+ import {
6
+ IChannel,
7
+ IUserAccount,
8
+ useThreadMessagesQuery,
9
+ useMessagesQuery,
10
+ useUserAccountQuery,
11
+ } from '@messenger-box/platform-client';
12
+ import { startCase } from 'lodash';
13
+
14
+ const createdAtText = (value: string) => {
15
+ if (!value) return '';
16
+ let date = new Date(value);
17
+ if (isToday(date)) return 'Today';
18
+ if (isYesterday(date)) return 'Yesterday';
19
+ return format(new Date(value), 'MMM dd, yyyy');
20
+ };
21
+
22
+ export interface IDialogListChannel extends IChannel {
23
+ users: IUserAccount[];
24
+ }
25
+
26
+ export interface IDialogListItemProps {
27
+ currentUser?: any;
28
+ users?: any;
29
+ selectedChannelId?: any;
30
+ channel?: any;
31
+ onOpen: (id: any, title: any, postParentId?: any) => void;
32
+ refreshing: boolean;
33
+ role:any;
34
+ }
35
+
36
+ /**
37
+ * TODO:
38
+ * - Get Reservation info: reservation date, status
39
+ * - Add ability to get property information: name, logo
40
+ */
41
+ export const SupportServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
42
+ currentUser,
43
+ // users,
44
+ selectedChannelId,
45
+ channel,
46
+ onOpen,
47
+ refreshing,
48
+ role,
49
+ }) {
50
+ const {
51
+ data: threadMessages,
52
+ loading: threadMessageLoading,
53
+ error,
54
+ refetch: refetchThreadMessages,
55
+ } = useThreadMessagesQuery({
56
+ variables: {
57
+ channelId: channel?.id?.toString(),
58
+ role,
59
+ limit: 25,
60
+ },
61
+ fetchPolicy: 'cache-and-network',
62
+ });
63
+
64
+
65
+ // const {
66
+ // data: messagesQuery,
67
+ // loading: messageLoading,
68
+ // refetch: refetchMessages,
69
+ // } = useMessagesQuery({
70
+ // variables: {
71
+ // channelId: channel?.id?.toString(),
72
+ // limit: 25,
73
+ // },
74
+ // fetchPolicy: 'cache-and-network',
75
+ // });
76
+
77
+ useFocusEffect(
78
+ React.useCallback(() => {
79
+ // Do something when the screen is focused
80
+ // refetchMessages({ channelId: channel?.id?.toString(), limit: 25 });
81
+ refetchThreadMessages({ channelId: channel?.id?.toString(), limit: 25 });
82
+ return () => {
83
+ // Do something when the screen is unfocused
84
+ // Useful for cleanup functions
85
+ };
86
+ }, [refreshing]),
87
+ );
88
+
89
+ React.useEffect(() => {
90
+ if (refreshing) {
91
+ // refetchMessages({ channelId: channel?.id?.toString(), limit: 25 });
92
+ refetchThreadMessages({ channelId: channel?.id?.toString(), limit: 25 });
93
+ }
94
+ }, [refreshing]);
95
+
96
+ // const lastMessageCreatorAndMembers = useMemo(() => {
97
+ // const replyCount = threadMessages?.threadMessages?.data?.reduce((rc: any, t: any) => rc + t?.replyCount, 0);
98
+ // if (!messagesQuery?.messages?.data?.length || threadMessages?.threadMessages?.totalCount == 0) {
99
+ // return null;
100
+ // }
101
+ // const { data } = messagesQuery.messages;
102
+ // const filteredData = data?.filter((p: any) => p?.message !== '');
103
+ // if (replyCount == 0) {
104
+ // const post: any =
105
+ // threadMessages?.threadMessages?.data?.find((t: any) => {
106
+ // return t?.post?.message !== '';
107
+ // }) ??
108
+ // threadMessages?.threadMessages?.data?.find((t: any) => {
109
+ // return t?.post;
110
+ // }) ??
111
+ // null;
112
+
113
+ // return post ? post?.post : null;
114
+ // } else {
115
+ // return filteredData[0];
116
+ // }
117
+ // // return data[data.length - 1];
118
+ // }, [threadMessages, messagesQuery]);
119
+
120
+ // const lastMessage = useMemo(() => {
121
+ // if (!threadMessages?.threadMessages?.data?.length) {
122
+ // return null;
123
+ // }
124
+ // const { data }: any = threadMessages.threadMessages;
125
+ // const replies =
126
+ // data
127
+ // ?.map((t: any) => t?.replies)
128
+ // ?.flat(1)
129
+ // ?.filter((p: any) => p?.message !== '') ?? [];
130
+ // if (replies?.length) {
131
+ // return replies[0];
132
+ // // return replies[replies.length - 1];
133
+ // } else {
134
+ // const post =
135
+ // data?.find((t: any) => {
136
+ // return t?.post?.message !== '';
137
+ // }) ??
138
+ // data?.find((t: any) => {
139
+ // return t?.post;
140
+ // }) ??
141
+ // null;
142
+ // return post ? post?.post : null;
143
+ // }
144
+ // }, [threadMessages]);
145
+
146
+ const lastMessage = useMemo(() => {
147
+ if (!threadMessages?.threadMessages?.data?.length) {
148
+ return null;
149
+ }
150
+ const { data }: any = threadMessages.threadMessages;
151
+ const replies =
152
+ data
153
+ ?.map((t: any) => t?.replies)
154
+ ?.flat(1)
155
+ ?.filter((p: any) => p?.message !== '') ?? [];
156
+ if (replies?.length) {
157
+ return replies[0];
158
+ // return replies[replies.length - 1];
159
+ } else {
160
+ const post =
161
+ data?.find((t: any) => {
162
+ return t?.post?.message !== '';
163
+ }) ??
164
+ data?.find((t: any) => {
165
+ return t?.post;
166
+ }) ??
167
+ null;
168
+ return post ? post?.post : null;
169
+ }
170
+ }, [threadMessages]);
171
+
172
+ const creatorAndMembersId = React.useMemo(() => {
173
+ if (!channel?.members) return null;
174
+ const membersIds: any =
175
+ channel?.members?.filter((m: any) => m?.user?.id !== currentUser?.id)?.map((mu: any) => mu?.user?.id) ?? [];
176
+ const creatorId: any = channel?.creator?.id;
177
+ const mergedIds: any = [].concat(membersIds, creatorId) ?? [];
178
+ return mergedIds?.filter((m: any, pos: any) => mergedIds?.indexOf(m) === pos) ?? [];
179
+ }, [channel]);
180
+
181
+ const postParentId = React.useMemo(() => {
182
+ if (!creatorAndMembersId?.length) return null;
183
+
184
+ return creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
185
+ ? null
186
+ : lastMessage?.parentId
187
+ ? lastMessage?.parentId
188
+ : lastMessage?.id ?? 0;
189
+ }, [creatorAndMembersId, lastMessage]);
190
+
191
+ return (
192
+ <Pressable
193
+ onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id, channel?.title, postParentId)}
194
+ borderWidth={'1'}
195
+ borderRadius={10}
196
+ borderColor={'gray.200'}
197
+ flex={1}
198
+ _dark={{
199
+ borderColor: 'coolGray.600',
200
+ backgroundColor: 'gray.700',
201
+ }}
202
+ _web={{
203
+ shadow: 2,
204
+ borderWidth: 0,
205
+ }}
206
+ _light={{
207
+ backgroundColor: 'gray.50',
208
+ }}
209
+ >
210
+ <HStack
211
+ // px={2}
212
+ // pl={3}
213
+ py={3}
214
+ space={2}
215
+ w={'100%'}
216
+ flex={1}
217
+ direction={'row'}
218
+ justifyContent={'space-between'}
219
+ alignItems={'center'}
220
+ >
221
+ <Box flex={0.1} alignItems={'flex-start'} pl={3}>
222
+ <Avatar.Group
223
+ _avatar={{
224
+ size: 'sm',
225
+ bg: 'transparent',
226
+ }}
227
+ >
228
+ <Avatar
229
+ key={'service-channels-key'}
230
+ bg={'transparent'}
231
+ size={9}
232
+ top={0}
233
+ right={0}
234
+ zIndex={1}
235
+ _image={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
236
+ source={{
237
+ uri: channel?.creator?.picture,
238
+ }}
239
+ >
240
+ {startCase(channel?.creator?.username?.charAt(0))}
241
+ </Avatar>
242
+ </Avatar.Group>
243
+ </Box>
244
+ <Box flex={0.9}>
245
+ <HStack space={1} flex={1} direction={'row'} justifyContent={'center'} alignItems={'center'}>
246
+ <Box flex={0.8}>
247
+ <Text color="gray.600" fontSize="lg" flexWrap={'wrap'} fontWeight="semibold">
248
+ {channel?.title}
249
+ </Text>
250
+ <Text color="gray.600" noOfLines={1}>
251
+ {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id)
252
+ ? lastMessageCreatorAndMembers?.message ?? ''
253
+ : lastMessage?.message ?? ''} */}
254
+ {lastMessage?.message ?? ''}
255
+ </Text>
256
+ </Box>
257
+
258
+ <Box flex={0.2}>
259
+ {/* {creatorAndMembersId?.length && creatorAndMembersId?.includes(currentUser?.id) ? (
260
+ <Text color="gray.500">
261
+ {lastMessageCreatorAndMembers
262
+ ? createdAtText(lastMessageCreatorAndMembers?.createdAt)
263
+ : ''}
264
+ </Text>
265
+ ) : (
266
+ <Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
267
+ )} */}
268
+ <Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
269
+ </Box>
270
+ </HStack>
271
+ {/* <Text
272
+ flex={1}
273
+ color="gray.600"
274
+ p={0}
275
+ m={0}
276
+ w={'100%'}
277
+ justifyContent={''}
278
+ fontSize="lg"
279
+ fontWeight="semibold"
280
+ >
281
+ {title}
282
+ </Text> */}
283
+ {/* <Text flex={0.1} color="gray.600">
284
+ {lastMessage?.message ?? ''}
285
+ </Text> */}
286
+ </Box>
287
+ {/* <Text flex={0.2} color="gray.500">
288
+ {lastMessage ? createdAtText(lastMessage?.createdAt) : ''}
289
+ </Text> */}
290
+ </HStack>
291
+ </Pressable>
292
+ );
293
+ };
294
+
295
+ export const SupportServiceDialogsListItem = React.memo(SupportServiceDialogsListItemComponent);
@@ -0,0 +1,236 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Text, Image, Pressable, VStack, HStack, Stack, Box, Avatar, View, Button } from 'native-base';
3
+ import { format, isToday, isYesterday } from 'date-fns';
4
+ import { useFocusEffect } from '@react-navigation/native';
5
+ import {
6
+ IChannel,
7
+ IUserAccount,
8
+ useThreadMessagesQuery,
9
+ useMessagesQuery,
10
+ useUserAccountQuery,
11
+ } from '@messenger-box/platform-client';
12
+ import { startCase } from 'lodash';
13
+
14
+ const createdAtText = (value: string) => {
15
+ if (!value) return '';
16
+ let date = new Date(value);
17
+ if (isToday(date)) return 'Today';
18
+ if (isYesterday(date)) return 'Yesterday';
19
+ return format(new Date(value), 'MMM dd, yyyy');
20
+ };
21
+
22
+ export interface IDialogListChannel extends IChannel {
23
+ users: IUserAccount[];
24
+ }
25
+
26
+ export interface IDialogListItemProps {
27
+ currentUser?: any;
28
+ users?: any;
29
+ thread?: any;
30
+ onOpen: (id: any, title: any, postParentId?: any) => void;
31
+ }
32
+
33
+ /**
34
+ * TODO:
35
+ * - Get Reservation info: reservation date, status
36
+ * - Add ability to get property information: name, logo
37
+ */
38
+ export const ThreadViewItemComponent: React.FC<IDialogListItemProps> = function DialogsListItem({
39
+ currentUser,
40
+ // users,
41
+ thread,
42
+ onOpen,
43
+ }) {
44
+ useFocusEffect(
45
+ React.useCallback(() => {
46
+ // Do something when the screen is focused
47
+ return () => {
48
+ // Do something when the screen is unfocused
49
+ // Useful for cleanup functions
50
+ };
51
+ }, []),
52
+ );
53
+
54
+ const lastMessage = useMemo(() => {
55
+ if (!thread) {
56
+ return null;
57
+ }
58
+ const replies = thread?.replies?.filter((p: any) => p?.message !== '') ?? [];
59
+ if (replies?.length) {
60
+ return replies[0];
61
+ // return replies[replies.length - 1];
62
+ } else {
63
+ const post = thread?.post ?? null;
64
+ return post ? post?.post : null;
65
+ }
66
+ }, [thread]);
67
+
68
+ const participants: any = React.useMemo(() => {
69
+ if (!thread?.participants?.length) return null;
70
+ return thread?.participants?.filter((u: any) => u?.user?.id !== currentUser?.id) ?? [];
71
+ }, [thread]);
72
+
73
+ const allParticipantsNames: any = React.useMemo(() => {
74
+ if (!participants?.length) return null;
75
+ return (
76
+ participants
77
+ ?.map((p: any) => {
78
+ return p?.user?.givenName + ' ' + p?.user?.familyName ?? '';
79
+ })
80
+ ?.join(', ') ?? ''
81
+ );
82
+ }, [participants]);
83
+
84
+ return (
85
+ <VStack
86
+ space={1}
87
+ py={2}
88
+ px={2}
89
+ borderWidth={'1'}
90
+ borderRadius={10}
91
+ borderColor={'gray.200'}
92
+ flex={1}
93
+ _dark={{
94
+ borderColor: 'white',
95
+ backgroundColor: 'white',
96
+ }}
97
+ _web={{
98
+ shadow: 2,
99
+ borderWidth: 0,
100
+ }}
101
+ _light={{
102
+ backgroundColor: 'white',
103
+ }}
104
+ >
105
+ <HStack
106
+ // px={2}
107
+ // pl={3}
108
+ py={2}
109
+ space={2}
110
+ w={'100%'}
111
+ flex={1}
112
+ direction={'row'}
113
+ justifyContent={'space-between'}
114
+ alignItems={'center'}
115
+ >
116
+ <Box flex={1}>
117
+ <HStack flex={1} space={5} py={2} alignItems={'baseline'}>
118
+ <Box>
119
+ <Avatar.Badge size={4} left={0} zIndex={1} bg="green.800" />
120
+ </Box>
121
+ <Box>
122
+ <Text color="gray.600" fontSize="lg" flexWrap={'wrap'} fontWeight="semibold">
123
+ {allParticipantsNames || ''}
124
+ </Text>
125
+ </Box>
126
+ </HStack>
127
+ <HStack space={1} flex={1} direction={'row'} justifyContent={'center'} alignItems={'center'}>
128
+ <Box flex={1}>
129
+ <HStack space={2} py={2}>
130
+ <Box>
131
+ <Avatar
132
+ bg={'transparent'}
133
+ size={8}
134
+ _image={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
135
+ source={{
136
+ uri: thread?.post?.author?.picture,
137
+ }}
138
+ >
139
+ {startCase(thread?.post?.author?.username?.charAt(0))}
140
+ </Avatar>
141
+ </Box>
142
+ <Box>
143
+ <HStack space={4}>
144
+ <Text>
145
+ {thread?.post?.author?.givenName + ' ' + thread?.post?.author?.familyName ??
146
+ ''}
147
+ </Text>
148
+ <Text color="gray.500">
149
+ {thread?.post ? createdAtText(thread?.post?.createdAt) : ''}
150
+ </Text>
151
+ </HStack>
152
+ <Text color="gray.600" noOfLines={2}>
153
+ {thread?.post?.message ?? ''}
154
+ </Text>
155
+ {!thread?.replies?.length && (
156
+ <Button
157
+ size={'xs'}
158
+ w={150}
159
+ variant={'outline'}
160
+ _text={{ fontSize: 12, color: '#000' }}
161
+ onPress={() =>
162
+ onOpen(thread?.channel?.id, thread?.channel?.title, thread?.post?.id)
163
+ }
164
+ >
165
+ Reply
166
+ </Button>
167
+ )}
168
+ </Box>
169
+ </HStack>
170
+ {thread?.replies?.length > 0 && (
171
+ <HStack space={2} pb={2} pt={1}>
172
+ <Box>
173
+ <Avatar
174
+ bg={'transparent'}
175
+ size={8}
176
+ _image={{ borderRadius: 6, borderWidth: 2, borderColor: '#fff' }}
177
+ source={{
178
+ uri: lastMessage?.author?.picture,
179
+ }}
180
+ >
181
+ {startCase(lastMessage?.author?.username?.charAt(0))}
182
+ </Avatar>
183
+ </Box>
184
+ <Box>
185
+ <HStack space={4}>
186
+ <Text>
187
+ {lastMessage?.author?.givenName +
188
+ ' ' +
189
+ lastMessage?.author?.familyName ?? ''}
190
+ </Text>
191
+ <Text color="gray.500">
192
+ {lastMessage ? createdAtText(lastMessage?.createdAt) : ''}
193
+ </Text>
194
+ </HStack>
195
+ <Text color="gray.600" noOfLines={2}>
196
+ {/* {lastMessage?.message ?? ''} */}
197
+ {lastMessage?.message
198
+ ? lastMessage?.message.length < 70
199
+ ? `${lastMessage?.message}`
200
+ : `${lastMessage?.message.substring(0, 68)}....`
201
+ : ''}
202
+ </Text>
203
+ <Button
204
+ size={'xs'}
205
+ w={150}
206
+ variant={'outline'}
207
+ _text={{ fontSize: 12, color: '#000' }}
208
+ onPress={() =>
209
+ onOpen(thread?.channel?.id, thread?.channel?.title, thread?.post?.id)
210
+ }
211
+ >
212
+ Reply
213
+ </Button>
214
+ </Box>
215
+ </HStack>
216
+ )}
217
+ </Box>
218
+ </HStack>
219
+ </Box>
220
+ </HStack>
221
+ {/* <HStack>
222
+ <Box flex={0.06} alignItems={'flex-start'}></Box>
223
+ <Button
224
+ size={'xs'}
225
+ variant={'outline'}
226
+ _text={{ fontSize: 12, color: '#000' }}
227
+ onPress={() => onOpen(thread?.channel?.id, thread?.channel?.title, postParentId)}
228
+ >
229
+ Reply
230
+ </Button>
231
+ </HStack> */}
232
+ </VStack>
233
+ );
234
+ };
235
+
236
+ export const ThreadViewItem = React.memo(ThreadViewItemComponent);
@@ -4,6 +4,10 @@ export const config = cleanEnv(process['APP_ENV'] || process.env, {
4
4
  MESSAGES_PER_PAGE: num({ devDefault: 10, default: 20 }),
5
5
  FILES_PER_MESSAGE: num({ default: 10 }),
6
6
  INBOX_MESSEGE_PATH: str({ default: 'MainStack.Message' }),
7
+ // THREAD_MESSEGE_PATH: str({ default: 'MainStack.Thread' }),
8
+ // THREADS_PATH: str({ default: 'MainStack.ThreadMessage' }),
9
+ THREAD_MESSEGE_PATH: str({ default: 'MainStack.ThreadMessage' }),
10
+ THREADS_PATH: str({ default: 'MainStack.Thread' }),
7
11
  CALL_TO_ACTION_PATH: str({ default: 'MainStack.MyReservationDetails' }),
8
12
  CALL_TO_ACTION_BOX_BGCOLOR: str({ default: '#0084ff' }),
9
13
  CALL_TO_ACTION_BUTTON_BORDERCOLOR: str({ default: '#fff' }),