@messenger-box/platform-mobile 0.0.1-alpha.190 → 0.0.1-alpha.197

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 (35) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/index.d.ts +1 -0
  3. package/lib/index.js +508 -203
  4. package/lib/index.js.map +1 -1
  5. package/lib/navigation/InboxNavigation.d.ts +3 -1
  6. package/lib/screens/inbox/DialogMessages.d.ts +3 -1
  7. package/lib/screens/inbox/Inbox.d.ts +2 -0
  8. package/lib/screens/inbox/components/CommonMessage.d.ts +9 -0
  9. package/lib/screens/inbox/components/DialogsListItem.d.ts +5 -4
  10. package/lib/screens/inbox/components/FilesList.d.ts +13 -0
  11. package/lib/screens/inbox/components/MessageInput.d.ts +6 -1
  12. package/lib/screens/inbox/components/MessageItem.d.ts +5 -8
  13. package/lib/screens/inbox/components/PlainMessage.d.ts +6 -0
  14. package/lib/screens/inbox/config/config.d.ts +4 -0
  15. package/lib/screens/inbox/config/index.d.ts +1 -0
  16. package/lib/screens/inbox/containers/Dialogs.d.ts +5 -1
  17. package/lib/screens/index.d.ts +1 -0
  18. package/package.json +4 -4
  19. package/src/index.ts +1 -0
  20. package/src/navigation/InboxNavigation.tsx +9 -20
  21. package/src/screens/inbox/DialogMessages.tsx +2 -7
  22. package/src/screens/inbox/{DialogsList.tsx → Inbox.tsx} +4 -4
  23. package/src/screens/inbox/components/CommonMessage.tsx +52 -0
  24. package/src/screens/inbox/components/DialogsListItem.tsx +63 -44
  25. package/src/screens/inbox/components/FilesList.tsx +41 -0
  26. package/src/screens/inbox/components/MessageInput.tsx +24 -22
  27. package/src/screens/inbox/components/MessageItem.tsx +34 -55
  28. package/src/screens/inbox/components/PlainMessage.tsx +16 -0
  29. package/src/screens/inbox/config/config.ts +6 -0
  30. package/src/screens/inbox/config/index.ts +1 -0
  31. package/src/screens/inbox/containers/ConversationView.tsx +158 -83
  32. package/src/screens/inbox/containers/Dialogs.tsx +93 -48
  33. package/src/screens/index.ts +1 -0
  34. package/lib/screens/inbox/DialogsList.d.ts +0 -2
  35. package/lib/screens/inbox/components/DialogsHeader.d.ts +0 -8
@@ -1,8 +1,8 @@
1
- import { first } from 'lodash';
2
- import React, { useEffect, useMemo } from 'react';
3
- import { Text, Box, Image, Pressable, HStack, VStack } from 'native-base';
1
+ import React, { useMemo } from 'react';
2
+ import { Text, Image, Pressable, HStack, Box } from 'native-base';
4
3
  import { format, isToday, isYesterday } from 'date-fns';
5
- import { IChannel, IUserAccount, useGetMessagesQuery } from '@messenger-box/platform-client';
4
+
5
+ import { IChannel, IUserAccount, useMessagesQuery, useUserAccountQuery } from '@messenger-box/platform-client';
6
6
 
7
7
  const createdAtText = (value: string) => {
8
8
  if (!value) return '';
@@ -17,10 +17,11 @@ export interface IDialogListChannel extends IChannel {
17
17
  }
18
18
 
19
19
  export interface IDialogListItemProps {
20
- refreshKey?: number;
21
- currentUserId: string;
22
- channel: IDialogListChannel;
23
- onOpen: (channel: IChannel, options?: any) => void;
20
+ currentUser?: any;
21
+ users?: any;
22
+ selectedChannelId?: any;
23
+ channel?: any;
24
+ onOpen: (id: any) => void;
24
25
  }
25
26
 
26
27
  /**
@@ -29,61 +30,79 @@ export interface IDialogListItemProps {
29
30
  * - Add ability to get property information: name, logo
30
31
  */
31
32
  export const DialogsListItem: React.FC<IDialogListItemProps> = function DialogsListItem({
32
- refreshKey,
33
+ currentUser,
34
+ users,
35
+ selectedChannelId,
33
36
  channel,
34
- currentUserId,
35
37
  onOpen,
36
38
  }) {
37
- const message$ = useGetMessagesQuery({
38
- fetchPolicy: 'network-only',
39
- variables: { limit: 1, channelId: channel.id },
39
+ const { data: messagesQuery, loading: messageLoading } = useMessagesQuery({
40
+ variables: {
41
+ channelId: channel?.id?.toString(),
42
+ limit: 1,
43
+ },
44
+ fetchPolicy: 'cache-and-network',
40
45
  });
41
46
 
42
- // Workaround for messages refresh: update latest messages view after list refresh
43
- useEffect(() => {
44
- message$.refetch();
45
- }, [refreshKey]);
46
-
47
- const users = useMemo(() => channel.users.filter(({ alias }) => !alias?.includes(currentUserId)), [currentUserId]);
48
-
49
- const message = useMemo(() => first(message$.data?.messages.data), [message$.data?.messages]);
50
- const title = useMemo(
51
- () => users.map(({ givenName, familyName }) => `${givenName} ${familyName}`).join(','),
52
- [users],
47
+ const chatUser = useMemo(
48
+ () =>
49
+ users?.find(({ id }) => {
50
+ const isNotCurrentUser = id !== currentUser?.id;
51
+ if (isNotCurrentUser) {
52
+ return channel?.members?.find(({ user }: any) => user.id === id);
53
+ }
54
+ return isNotCurrentUser;
55
+ }),
56
+ [users, currentUser, channel],
53
57
  );
54
58
 
55
- const text = message?.message;
56
- const date = createdAtText(message?.createdAt);
59
+ const { data: userQuery } = useUserAccountQuery({
60
+ variables: {
61
+ userId: chatUser?.id,
62
+ },
63
+ skip: !chatUser?.id,
64
+ });
65
+
66
+ const lastMessage = useMemo(() => {
67
+ if (!messagesQuery?.messages?.data?.length) {
68
+ return null;
69
+ }
70
+ const { data } = messagesQuery.messages;
71
+ return data[data.length - 1];
72
+ }, [messagesQuery]);
57
73
 
58
- const onOpenChannel = () => onOpen(channel, { title, users });
74
+ const channelType = useMemo(() => {
75
+ return channel?.type;
76
+ }, [channel]);
59
77
 
60
78
  return (
61
- <Pressable onPress={onOpenChannel} borderWidth={'1'} borderRadius="md" borderColor={'gray.200'} shadow={'6'}>
62
- <HStack m={3} space={2} alignItems="center">
79
+ <Pressable
80
+ onPress={() => channel?.id !== selectedChannelId && onOpen(channel?.id)}
81
+ borderWidth={'1'}
82
+ borderRadius={10}
83
+ borderColor={'gray.200'}
84
+ shadow={'6'}
85
+ >
86
+ <HStack m={3} space={2}>
63
87
  <Image
64
88
  alt={'image'}
65
89
  width={16}
66
- borderRadius="full"
90
+ borderRadius={10}
67
91
  height={16}
68
- source={{ uri: 'https://picsum.photos/220' }}
92
+ source={{ uri: userQuery?.getUserAccount?.picture || 'https://picsum.photos/220' }}
69
93
  />
70
- <VStack space={1}>
94
+ <Box width={'80%'}>
71
95
  <HStack alignItems="center" justifyContent="space-between">
72
- {/* TODO: change to valid status */}
73
96
  <Text fontSize="xs" color="red.500">
74
- Request withdrawal
97
+ {channelType}
75
98
  </Text>
76
- <Text color="gray.500">{date}</Text>
99
+ <Text color="gray.500">{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
77
100
  </HStack>
78
- {title !== '' ? (
79
- <Text color="gray.600" fontSize="lg" fontWeight="semibold">
80
- {title}
81
- </Text>
82
- ) : null}
83
- <Text color="gray.600">{text}</Text>
84
- {/* TODO: change to valid reservation date */}
85
- <Text>Sep 12-16, 2019. Private room fully furnis...</Text>
86
- </VStack>
101
+ <Text color="gray.600" fontSize="lg" fontWeight="semibold">
102
+ {chatUser?.givenName + ' ' + chatUser?.familyName}
103
+ </Text>
104
+ <Text color="gray.600">{lastMessage?.message}</Text>
105
+ </Box>
87
106
  </HStack>
88
107
  </Pressable>
89
108
  );
@@ -0,0 +1,41 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Image, HStack, Box } from 'native-base';
3
+
4
+ interface FilesListProps {
5
+ files: any;
6
+ uploaded?: boolean;
7
+ }
8
+
9
+ export function FilesList({ files, uploaded = false }: FilesListProps) {
10
+ return (
11
+ <HStack space={2} mt={2}>
12
+ <FilesList.FilesView files={files} uploaded={uploaded} />
13
+ </HStack>
14
+ );
15
+ }
16
+
17
+ FilesList.FilesView = function MessageItemFiles({ files = [], uploaded }: { files: any[]; uploaded?: boolean }) {
18
+ if (!files.length) {
19
+ return null;
20
+ }
21
+
22
+ return (
23
+ <Box>
24
+ {files.map((file) => {
25
+ const url = useMemo(() => (uploaded ? file.url : URL.createObjectURL(file)), [file, uploaded]);
26
+ return (
27
+ <Image
28
+ alt={'image'}
29
+ mr={2}
30
+ height="16"
31
+ width="16"
32
+ source={{
33
+ uri: url,
34
+ scale: 0.2,
35
+ }}
36
+ />
37
+ );
38
+ })}
39
+ </Box>
40
+ );
41
+ };
@@ -1,23 +1,29 @@
1
- import { TextField, View, Image, Pressable, HStack, VStack } from 'native-base';
1
+ import { TextField, View, Image, Pressable, HStack, VStack, Toast } from 'native-base';
2
2
  import { FontAwesome } from '@expo/vector-icons';
3
3
  import * as ImagePicker from 'expo-image-picker';
4
- import React, { forwardRef, useImperativeHandle, useState } from 'react';
4
+ import React, { forwardRef, useImperativeHandle, useState, useCallback } from 'react';
5
+ import { FilesList } from './FilesList';
5
6
 
6
- export const MessageInput = forwardRef(function MessageInput({ onSend }: any, ref) {
7
- const [text, setText] = useState('');
8
- const [files, setFiles] = useState<string[]>([]);
7
+ type MessageInputProps = {
8
+ channelId?: string;
9
+ handleSend: (message: string, files: any) => Promise<void>;
10
+ };
9
11
 
10
- const reset = () => {
11
- setText('');
12
- setFiles([]);
13
- };
12
+ export const MessageInput = forwardRef(function MessageInput({ handleSend: handleSendProp }: MessageInputProps) {
13
+ const [message, setMessage] = useState('');
14
+ const [sending, setSending] = useState(false);
15
+ const [files, setFiles] = useState<File[]>([]);
14
16
 
15
- useImperativeHandle(ref, () => ({ reset, text, files }));
17
+ const handleSend = useCallback(() => {
18
+ setSending(true);
19
+ handleSendProp(message, files)
20
+ .then(() => {
21
+ setMessage('');
22
+ setFiles([]);
23
+ })
24
+ .finally(() => setSending(false));
25
+ }, [files, handleSendProp, message]);
16
26
 
17
- const onSendMessage = () => {
18
- onSend(text, files);
19
- };
20
- const onRemoveImage = (url: string) => setFiles((files) => files.filter((file) => file !== url));
21
27
  const onSelectImages = async () => {
22
28
  // No permissions request is necessary for launching the image library
23
29
  await ImagePicker.requestMediaLibraryPermissionsAsync();
@@ -38,23 +44,19 @@ export const MessageInput = forwardRef(function MessageInput({ onSend }: any, re
38
44
  <TextField
39
45
  placeholder="Message..."
40
46
  borderColor="gray.400"
41
- value={text}
42
- onChange={(e) => setText(e.nativeEvent.text)}
47
+ value={sending ? '' : message}
48
+ onChange={(e) => setMessage(e.nativeEvent.text)}
43
49
  fontSize={14}
44
50
  />
45
51
  </View>
46
52
  {files.length ? (
47
53
  <View mb={4} flexDirection="row">
48
- {files.map((file, index) => (
49
- <Pressable onPress={() => onRemoveImage(file)} key={index}>
50
- <Image alt={'image'} mr={2} height={10} width={10} source={{ uri: file }} />
51
- </Pressable>
52
- ))}
54
+ <FilesList files={files} />
53
55
  </View>
54
56
  ) : null}
55
57
  <HStack alignContent="center" justifyContent="space-between">
56
58
  <FontAwesome onPress={onSelectImages} size={20} style={{ marginRight: 5 }} name="file-image-o" />
57
- <FontAwesome onPress={onSendMessage} size={20} name="send" />
59
+ <FontAwesome onPress={handleSend} size={20} name="send" />
58
60
  </HStack>
59
61
  </VStack>
60
62
  );
@@ -1,62 +1,41 @@
1
- import React, { useMemo } from 'react';
2
- import { Text, Box, Image, HStack } from 'native-base';
3
- import { format, isToday, isYesterday } from 'date-fns';
4
- import { IFileInfo, IPost } from '@messenger-box/platform-client';
1
+ import React from 'react';
2
+ import { Box } from 'native-base';
3
+ import { IPost, IPostTypeEnum } from '@messenger-box/platform-client';
4
+ import { PlainMessage } from './PlainMessage';
5
+ import { CommonMessage } from './CommonMessage';
6
+ import { Slot } from '@common-stack/components-pro';
5
7
 
6
- const createdAtText = (value: string) => {
7
- if (!value) return '';
8
- let date = new Date(value);
9
- if (isToday(date)) return 'Today';
10
- if (isYesterday(date)) return 'Yesterday';
11
- return format(new Date(value), 'MMM dd, yyyy');
12
- };
8
+ export function MessageItem({
9
+ message,
10
+ channelId,
11
+ currentUser,
12
+ totalCount,
13
+ }: {
14
+ message: IPost;
15
+ channelId: number;
16
+ currentUser: any;
17
+ totalCount: number;
18
+ }) {
19
+ if (typeof message === 'string') {
20
+ return <PlainMessage message={message} />;
21
+ }
13
22
 
14
- export function MessageItem({ message, userId }: { message: IPost; userId: string }) {
15
- const isOwnMessage = useMemo(() => message.editedBy?.alias?.includes(userId) || false, [message.author, userId]);
16
- const author = useMemo(
17
- () => (message.author ? `${message.author?.givenName} ${message.author?.familyName}` : null),
18
- [message.author],
19
- );
23
+ const { type } = message;
20
24
 
21
- return (
22
- <HStack mb={4} alignItems="center">
23
- {isOwnMessage ? <Box flexGrow={1} /> : null}
24
- <Box borderRadius="md" backgroundColor="gray.200" paddingX={3} paddingY="1.5" flexGrow={3}>
25
- <Box flexDirection="row" alignContent="flex-start" mb={1}>
26
- <Text flexGrow={1} fontWeight="semibold">
27
- {author}
28
- </Text>
29
- <Text fontSize="xs" color="gray.500">
30
- {createdAtText(message.createdAt)}
31
- </Text>
32
- </Box>
33
- <Text flexGrow={1}>{message.message}</Text>
34
- <MessageItem.FilesView files={message.files?.data as IFileInfo[]} />
35
- </Box>
36
- {!isOwnMessage ? <Box flexGrow={1} /> : null}
37
- </HStack>
38
- );
39
- }
40
-
41
- MessageItem.FilesView = function MessageItemFiles({ files = [] }: { files: IFileInfo[] }) {
42
- if (!files.length) {
43
- return null;
25
+ if (!type || type === IPostTypeEnum.Simple) {
26
+ return <CommonMessage message={message} currentUser={currentUser} />;
44
27
  }
45
28
 
46
29
  return (
47
- <HStack space={2} mt={2}>
48
- {files.map((file) => (
49
- <Image
50
- alt={'image'}
51
- mr={2}
52
- height="16"
53
- width="16"
54
- source={{
55
- uri: 'https://preview.keenthemes.com/metronic-v4/theme/assets/pages/media/profile/profile_user.jpg',
56
- scale: 0.2,
57
- }}
58
- />
59
- ))}
60
- </HStack>
30
+ <Slot
31
+ name={(type as string)?.toLowerCase()}
32
+ fillProps={{
33
+ active: true,
34
+ message,
35
+ currentUser,
36
+ }}
37
+ >
38
+ {(item) => <Box>{item}</Box>}
39
+ </Slot>
61
40
  );
62
- };
41
+ }
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { Flex, Text } from 'native-base';
3
+
4
+ interface IPlainMessageProps {
5
+ message: string;
6
+ }
7
+
8
+ export const PlainMessage = ({ message }: IPlainMessageProps) => {
9
+ return (
10
+ <Flex w="full" justifyContent={'center'} mb="7">
11
+ <Text fontSize="14px" fontWeight={'bold'}>
12
+ {message}
13
+ </Text>
14
+ </Flex>
15
+ );
16
+ };
@@ -0,0 +1,6 @@
1
+ import { cleanEnv, num } from 'envalid';
2
+
3
+ export const config = cleanEnv(process.env, {
4
+ MESSAGES_PER_PAGE: num({ devDefault: 20, default: 50 }),
5
+ FILES_PER_MESSAGE: num({ default: 10 }),
6
+ });
@@ -0,0 +1 @@
1
+ export { config } from './config';