@messenger-box/chakra-ui-inbox 0.0.1-alpha.168
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.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/jest.config.js +9 -0
- package/lib/components/InboxMessage/ConversationItem.d.ts +11 -0
- package/lib/components/InboxMessage/ConversationItem.d.ts.map +1 -0
- package/lib/components/InboxMessage/ConversationItem.js +50 -0
- package/lib/components/InboxMessage/ConversationItem.js.map +1 -0
- package/lib/components/InboxMessage/LeftSidebar.d.ts +17 -0
- package/lib/components/InboxMessage/LeftSidebar.d.ts.map +1 -0
- package/lib/components/InboxMessage/LeftSidebar.js +107 -0
- package/lib/components/InboxMessage/LeftSidebar.js.map +1 -0
- package/lib/components/InboxMessage/MessageInput.d.ts +8 -0
- package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -0
- package/lib/components/InboxMessage/MessageInput.js +45 -0
- package/lib/components/InboxMessage/MessageInput.js.map +1 -0
- package/lib/components/InboxMessage/Messages.d.ts +10 -0
- package/lib/components/InboxMessage/Messages.d.ts.map +1 -0
- package/lib/components/InboxMessage/Messages.js +42 -0
- package/lib/components/InboxMessage/Messages.js.map +1 -0
- package/lib/components/InboxMessage/Popover.d.ts +3 -0
- package/lib/components/InboxMessage/Popover.d.ts.map +1 -0
- package/lib/components/InboxMessage/UserModalContent.d.ts +3 -0
- package/lib/components/InboxMessage/UserModalContent.d.ts.map +1 -0
- package/lib/components/InboxMessage/index.d.ts +4 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -0
- package/lib/components/inbox/FilesList.d.ts +12 -0
- package/lib/components/inbox/FilesList.d.ts.map +1 -0
- package/lib/components/inbox/FilesList.js +7 -0
- package/lib/components/inbox/FilesList.js.map +1 -0
- package/lib/components/inbox/MessageItem.d.ts +17 -0
- package/lib/components/inbox/MessageItem.d.ts.map +1 -0
- package/lib/compute.d.ts +8 -0
- package/lib/compute.d.ts.map +1 -0
- package/lib/compute.js +19 -0
- package/lib/compute.js.map +1 -0
- package/lib/constants/index.d.ts +2 -0
- package/lib/constants/index.d.ts.map +1 -0
- package/lib/constants/index.js +5 -0
- package/lib/constants/index.js.map +1 -0
- package/lib/container/Inbox.d.ts +4 -0
- package/lib/container/Inbox.d.ts.map +1 -0
- package/lib/container/Inbox.js +169 -0
- package/lib/container/Inbox.js.map +1 -0
- package/lib/container/index.d.ts +3 -0
- package/lib/container/index.d.ts.map +1 -0
- package/lib/hooks/upload-file.d.ts +27 -0
- package/lib/hooks/upload-file.d.ts.map +1 -0
- package/lib/hooks/upload-file.js +56 -0
- package/lib/hooks/upload-file.js.map +1 -0
- package/lib/hooks/upload-filex.d.ts +11 -0
- package/lib/hooks/upload-filex.d.ts.map +1 -0
- package/lib/hooks/upload-filex.js +5 -0
- package/lib/hooks/upload-filex.js.map +1 -0
- package/lib/hooks/upload-msg-files.d.ts +3 -0
- package/lib/hooks/upload-msg-files.d.ts.map +1 -0
- package/lib/hooks/upload-msg-files.js +10 -0
- package/lib/hooks/upload-msg-files.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -0
- package/lib/module.d.ts +4 -0
- package/lib/module.d.ts.map +1 -0
- package/lib/module.js +5 -0
- package/lib/module.js.map +1 -0
- package/package.json +79 -0
- package/rollup.config.js +32 -0
- package/src/components/InboxMessage/ConversationItem.tsx +98 -0
- package/src/components/InboxMessage/LeftSidebar.tsx +250 -0
- package/src/components/InboxMessage/MessageInput.tsx +148 -0
- package/src/components/InboxMessage/Messages.tsx +137 -0
- package/src/components/InboxMessage/Popover.tsx +56 -0
- package/src/components/InboxMessage/UserModalContent.tsx +52 -0
- package/src/components/InboxMessage/index.ts +3 -0
- package/src/components/inbox/FilesList.tsx +17 -0
- package/src/components/inbox/MessageItem.tsx +56 -0
- package/src/compute.tsx +33 -0
- package/src/constants/index.ts +4 -0
- package/src/container/Inbox.tsx +283 -0
- package/src/container/index.ts +3 -0
- package/src/hooks/upload-file.tsx +92 -0
- package/src/hooks/upload-filex.tsx +22 -0
- package/src/hooks/upload-msg-files.tsx +14 -0
- package/src/index.ts +1 -0
- package/src/module.tsx +9 -0
- package/tsconfig.json +26 -0
- package/webpack.config.js +97 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { format } from 'date-fns';
|
|
3
|
+
import { BsFlag } from '@react-icons/all-files/bs/BsFlag';
|
|
4
|
+
import { Avatar, Box, Flex, Icon, Text } from '@chakra-ui/react';
|
|
5
|
+
|
|
6
|
+
export function MessageItem({ message }: { message: any }) {
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
MessageItem.Plain = function PlainMessageItem({ message, index }) {
|
|
11
|
+
return (
|
|
12
|
+
<Flex w="full" key={`msgList_${index}`} justifyContent={'center'} mb="7">
|
|
13
|
+
<Text fontSize="14px" color="gray.600" fontWeight={'bold'}>
|
|
14
|
+
{message}
|
|
15
|
+
</Text>
|
|
16
|
+
</Flex>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
MessageItem.Dialog = function DialogMessageItem({ message, currentUser, index, onOpen }) {
|
|
21
|
+
return (
|
|
22
|
+
<Flex w="full" key={`msgList_${index}`} justifyContent={'flex-start'} mb="7">
|
|
23
|
+
<Flex flexGrow={1}>
|
|
24
|
+
<Avatar
|
|
25
|
+
width="60px"
|
|
26
|
+
height="60px"
|
|
27
|
+
backgroundColor="grey"
|
|
28
|
+
borderRadius="50%"
|
|
29
|
+
src={message?.imageUrl ? message?.imageUrl : ''}
|
|
30
|
+
marginRight="15px"
|
|
31
|
+
onClick={onOpen}
|
|
32
|
+
></Avatar>
|
|
33
|
+
<Box flexGrow={1}>
|
|
34
|
+
<Flex flexGrow={1} mt="5px">
|
|
35
|
+
<Text fontSize="14px" color="gray.600" fontWeight={'bold'}>
|
|
36
|
+
{message?.author?.familyName && message?.author?.givenName
|
|
37
|
+
? message?.author?.givenName + ' ' + message?.author?.familyName
|
|
38
|
+
: message?.author?.username}
|
|
39
|
+
</Text>
|
|
40
|
+
<Text fontSize="14px" color="gray.500" ml="10px">
|
|
41
|
+
{format(new Date(message?.createdAt), 'MMM dd, yyyy hh:mm aaa')}
|
|
42
|
+
</Text>
|
|
43
|
+
</Flex>
|
|
44
|
+
<Text fontSize="14px" mt="5px" color="gray.600" whiteSpace={'pre-line'}>
|
|
45
|
+
{message?.message}
|
|
46
|
+
</Text>
|
|
47
|
+
</Box>
|
|
48
|
+
</Flex>
|
|
49
|
+
{currentUser?.id !== message?.author?.id && (
|
|
50
|
+
<Box ml="8px">
|
|
51
|
+
<Icon as={BsFlag} color="gray.600" width={'24px'} height={'24px'} />
|
|
52
|
+
</Box>
|
|
53
|
+
)}
|
|
54
|
+
</Flex>
|
|
55
|
+
);
|
|
56
|
+
};
|
package/src/compute.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { IPreDefineAccountPermissions } from '@adminide-stack/core';
|
|
3
|
+
import { IMenuPosition, IRouteData } from '@common-stack/client-react';
|
|
4
|
+
import {
|
|
5
|
+
getFilteredRoutes,
|
|
6
|
+
IPageStore,
|
|
7
|
+
} from '@adminide-stack/core';
|
|
8
|
+
import { AiOutlineInbox } from '@react-icons/all-files/ai/AiOutlineInbox';
|
|
9
|
+
import { Inbox } from './container';
|
|
10
|
+
|
|
11
|
+
export const messengerPageStore: IPageStore[] | { [key: string]: any } = [
|
|
12
|
+
{
|
|
13
|
+
exact: false,
|
|
14
|
+
icon: <AiOutlineInbox/>,
|
|
15
|
+
key: 'inbox',
|
|
16
|
+
component: Inbox,
|
|
17
|
+
tab: 'Chat App',
|
|
18
|
+
position: IMenuPosition.MIDDLE,
|
|
19
|
+
authority: [IPreDefineAccountPermissions.secureUser],
|
|
20
|
+
name: 'Inbox',
|
|
21
|
+
path: '//inbox/:id?',
|
|
22
|
+
// path: '/o/:orgName/inbox',
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// get only selected Routes to work
|
|
27
|
+
const selectedRoutes = [
|
|
28
|
+
'inbox',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const filteredRoutes: IRouteData[] = getFilteredRoutes(messengerPageStore, selectedRoutes);
|
|
32
|
+
|
|
33
|
+
export { filteredRoutes };
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { CHANGE_SETTINGS_ACTION } from '@admin-layout/client';
|
|
2
|
+
import { userSelector } from '@adminide-stack/user-auth0-client';
|
|
3
|
+
import { Box, Container, Spinner, useMenuState } from '@chakra-ui/react';
|
|
4
|
+
import {
|
|
5
|
+
useEditMessageMutation,
|
|
6
|
+
useGetAllChannelQuery,
|
|
7
|
+
useGetAllUsersQuery,
|
|
8
|
+
useGetChannelsByUserQuery,
|
|
9
|
+
useGetMessagesQuery,
|
|
10
|
+
useSendMessagesMutation,
|
|
11
|
+
} from '@messenger-box/platform-client';
|
|
12
|
+
// import { useSendMessagesMutation } from '@messenger-box/platform-client';
|
|
13
|
+
import { push } from 'connected-react-router';
|
|
14
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
16
|
+
import { useParams } from 'react-router-dom';
|
|
17
|
+
import { LeftSidebar, MessageInput, Messages } from '../components/InboxMessage';
|
|
18
|
+
import { useMsgUploadFiles } from '../hooks/upload-msg-files';
|
|
19
|
+
|
|
20
|
+
const MESSAGES_PER_PAGE = 10;
|
|
21
|
+
|
|
22
|
+
const Inbox = () => {
|
|
23
|
+
const path: any = useParams();
|
|
24
|
+
|
|
25
|
+
const { id: channelId } = path || {};
|
|
26
|
+
const dispatch = useDispatch();
|
|
27
|
+
const [count, setCount] = useState(0);
|
|
28
|
+
const [channelToTop, setChannelToTop] = useState(0);
|
|
29
|
+
// channels
|
|
30
|
+
const {
|
|
31
|
+
data: userChannels,
|
|
32
|
+
loading: userChannelsLoading,
|
|
33
|
+
refetch: getChannelsRefetch,
|
|
34
|
+
} = useGetChannelsByUserQuery();
|
|
35
|
+
const { data: allChannels, loading: allChannelsLoading } = useGetAllChannelQuery();
|
|
36
|
+
const [totalCount, setTotalCount] = useState(0);
|
|
37
|
+
const messageListRef = useRef(null);
|
|
38
|
+
const { startUploads } = useMsgUploadFiles();
|
|
39
|
+
const [editMessage, {}] = useEditMessageMutation({ });
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const footerElement: any = document.querySelector('#nav-footer');
|
|
43
|
+
if (footerElement) {
|
|
44
|
+
footerElement.style.display = 'none';
|
|
45
|
+
}
|
|
46
|
+
const nkqmc7: any = document.querySelector('.css-nkqmc7'); // temp, check paddingBottom needed
|
|
47
|
+
if (nkqmc7) {
|
|
48
|
+
nkqmc7.style.paddingBottom = '0px';
|
|
49
|
+
nkqmc7.style.minHeight = '0px';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
footerElement.style.display = 'block';
|
|
54
|
+
};
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
const {
|
|
58
|
+
data,
|
|
59
|
+
loading: messageLoading,
|
|
60
|
+
error,
|
|
61
|
+
refetch,
|
|
62
|
+
} = useGetMessagesQuery({
|
|
63
|
+
variables: {
|
|
64
|
+
channelId: channelId?.toString(),
|
|
65
|
+
// skip: count,
|
|
66
|
+
limit: MESSAGES_PER_PAGE,
|
|
67
|
+
},
|
|
68
|
+
skip: !channelId,
|
|
69
|
+
fetchPolicy: 'network-only',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const [sendMsg, {}] = useSendMessagesMutation({
|
|
73
|
+
context: {},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const [currentUser, setCurrentUser] = useState<any>(null);
|
|
77
|
+
const [channelMessages, setChannelMessages] = useState([]);
|
|
78
|
+
|
|
79
|
+
const [updateMsg, setUpdateMsg] = useState(true);
|
|
80
|
+
const currentUserAuth0Id = useSelector((state: any) => state.user.auth0UserId);
|
|
81
|
+
const auth = useSelector(userSelector);
|
|
82
|
+
|
|
83
|
+
const usersRes = useGetAllUsersQuery();
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
dispatch({
|
|
88
|
+
type: CHANGE_SETTINGS_ACTION,
|
|
89
|
+
payload: {
|
|
90
|
+
footerRender: false,
|
|
91
|
+
},
|
|
92
|
+
} as any);
|
|
93
|
+
}, 0);
|
|
94
|
+
return () => {
|
|
95
|
+
console.log('unmounted');
|
|
96
|
+
dispatch({
|
|
97
|
+
type: CHANGE_SETTINGS_ACTION,
|
|
98
|
+
payload: {
|
|
99
|
+
footerRender: true,
|
|
100
|
+
},
|
|
101
|
+
} as any);
|
|
102
|
+
};
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (updateMsg) {
|
|
107
|
+
refetch({ skip: channelMessages.length });
|
|
108
|
+
}
|
|
109
|
+
}, [updateMsg]);
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (data?.messages?.data && updateMsg) {
|
|
113
|
+
setChannelMessages([...data.messages.data.reverse(), ...channelMessages]);
|
|
114
|
+
setTotalCount(data?.messages?.totalCount);
|
|
115
|
+
setUpdateMsg(false);
|
|
116
|
+
}
|
|
117
|
+
}, [data]);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!usersRes.loading && usersRes.data) {
|
|
121
|
+
setCurrentUser(usersRes.data?.getUsers?.find((i) => i.alias[0] === currentUserAuth0Id));
|
|
122
|
+
}
|
|
123
|
+
}, [usersRes.loading, usersRes.data]);
|
|
124
|
+
|
|
125
|
+
const handleSelectChannel = (cId: any) => {
|
|
126
|
+
setChannelMessages([]);
|
|
127
|
+
dispatch(push(`/inbox/${cId}`));
|
|
128
|
+
setUpdateMsg(true);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const onFetchMore = () => {
|
|
132
|
+
if (totalCount > channelMessages.length) {
|
|
133
|
+
setUpdateMsg(true);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const onMessagesScroll = (e) => {
|
|
138
|
+
if (messageListRef.current) {
|
|
139
|
+
const { scrollTop, scrollHeight, clientHeight } = messageListRef.current;
|
|
140
|
+
console.log(scrollTop);
|
|
141
|
+
console.log(scrollHeight);
|
|
142
|
+
console.log(clientHeight);
|
|
143
|
+
if (clientHeight - scrollTop > scrollHeight - 50 && !messageLoading) {
|
|
144
|
+
onFetchMore();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const handleSend = async (message: string, files?: File[]) => {
|
|
150
|
+
if (message && channelId) {
|
|
151
|
+
const { data } = await sendMsg({
|
|
152
|
+
variables: {
|
|
153
|
+
channelId,
|
|
154
|
+
content: message,
|
|
155
|
+
// files: [], // files: uploadedFiles.map(i => i.data.id)
|
|
156
|
+
},
|
|
157
|
+
update: (cache, { data, errors }) => {
|
|
158
|
+
if (!data || errors) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
setChannelMessages([...channelMessages, { ...data?.sendMessage }]);
|
|
162
|
+
setTotalCount(channelMessages.length + 1);
|
|
163
|
+
setChannelToTop(channelToTop + 1);
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if(files?.length) {
|
|
168
|
+
const uploadedFiles = await startUploads({
|
|
169
|
+
files,
|
|
170
|
+
refName: 'postId',
|
|
171
|
+
ref: data.sendMessage.id,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await editMessage({
|
|
175
|
+
variables: {
|
|
176
|
+
channelId,
|
|
177
|
+
content: message,
|
|
178
|
+
messageId: data.sendMessage.id,
|
|
179
|
+
files: uploadedFiles.map(i => i.data.id),
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const clearMessages = () => {
|
|
187
|
+
setChannelMessages([]);
|
|
188
|
+
setTotalCount(0);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<Container
|
|
193
|
+
maxW="full"
|
|
194
|
+
h={'calc(100vh - 82px)'}
|
|
195
|
+
p="0"
|
|
196
|
+
borderTopWidth="1px"
|
|
197
|
+
borderTopColor="gray.300"
|
|
198
|
+
display="flex"
|
|
199
|
+
>
|
|
200
|
+
<Box
|
|
201
|
+
top="82px"
|
|
202
|
+
w={{ base: '100%', md: '320px', lg: '420px' }}
|
|
203
|
+
h={{ base: 'calc(100vh - 100px)', md: 'calc(100vh - 82px)' }}
|
|
204
|
+
display="flex"
|
|
205
|
+
flexDirection="row"
|
|
206
|
+
>
|
|
207
|
+
<LeftSidebar
|
|
208
|
+
currentUser={currentUser}
|
|
209
|
+
allChannels={allChannels}
|
|
210
|
+
allChannelsLoading={allChannelsLoading}
|
|
211
|
+
userChannels={userChannels}
|
|
212
|
+
userChannelsLoading={userChannelsLoading}
|
|
213
|
+
users={usersRes?.data?.getUsers}
|
|
214
|
+
handleSelectChannel={handleSelectChannel}
|
|
215
|
+
clearMessages={clearMessages}
|
|
216
|
+
selectedChannelId={channelId}
|
|
217
|
+
channelToTop={channelToTop}
|
|
218
|
+
getChannelsRefetch={getChannelsRefetch}
|
|
219
|
+
/>
|
|
220
|
+
</Box>
|
|
221
|
+
<Box
|
|
222
|
+
d="flex"
|
|
223
|
+
flexDirection={'column'}
|
|
224
|
+
w={{ base: '100%', md: 'calc(100% - 320px)', lg: 'calc(100% - 420px)' }}
|
|
225
|
+
h={'100%'}
|
|
226
|
+
>
|
|
227
|
+
{messageLoading && (
|
|
228
|
+
<Box
|
|
229
|
+
d="flex"
|
|
230
|
+
flexDirection="column"
|
|
231
|
+
w="100%"
|
|
232
|
+
flexGrow={1}
|
|
233
|
+
flexBasis={0}
|
|
234
|
+
justifyContent={'center'}
|
|
235
|
+
alignItems="center"
|
|
236
|
+
padding="10px"
|
|
237
|
+
>
|
|
238
|
+
<Spinner thickness="4px" speed="0.65s" emptyColor="gray.200" color="blue.500" size="xl" />
|
|
239
|
+
</Box>
|
|
240
|
+
)}
|
|
241
|
+
{channelId && (
|
|
242
|
+
<React.Fragment>
|
|
243
|
+
<Box
|
|
244
|
+
ref={messageListRef}
|
|
245
|
+
d="flex"
|
|
246
|
+
flexDirection="column-reverse"
|
|
247
|
+
flexGrow={1}
|
|
248
|
+
flexShrink={1}
|
|
249
|
+
overflowY={'auto'}
|
|
250
|
+
onScroll={onMessagesScroll}
|
|
251
|
+
p={4}
|
|
252
|
+
px={{ base: 0, md: '80px', lg: '150px' }}
|
|
253
|
+
>
|
|
254
|
+
<Messages
|
|
255
|
+
channelId={channelId}
|
|
256
|
+
currentUser={currentUser}
|
|
257
|
+
channelMessages={channelMessages}
|
|
258
|
+
totalCount={totalCount}
|
|
259
|
+
/>
|
|
260
|
+
</Box>
|
|
261
|
+
<MessageInput channelId={channelId} handleSend={handleSend} />
|
|
262
|
+
</React.Fragment>
|
|
263
|
+
)}
|
|
264
|
+
</Box>
|
|
265
|
+
</Container>
|
|
266
|
+
);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export default Inbox;
|
|
270
|
+
|
|
271
|
+
// const VerticalSeparator = ({ loc }) => {
|
|
272
|
+
// return (
|
|
273
|
+
// <Center pos="absolute" w="full" h="full" x="0" y="0" zIndex="-1">
|
|
274
|
+
// <Flex w="full" h="80%" justifyContent={loc === 'right' ? 'flex-end' : 'flex-start'}>
|
|
275
|
+
// <Box
|
|
276
|
+
// w="1px"
|
|
277
|
+
// h="full"
|
|
278
|
+
// bg="linear-gradient(0deg, rgba(224, 225, 226, 0) 0%, #E0E1E2 49.52%, rgba(224, 225, 226, 0) 100%)"
|
|
279
|
+
// ></Box>
|
|
280
|
+
// </Flex>
|
|
281
|
+
// </Center>
|
|
282
|
+
// );
|
|
283
|
+
// };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { IFileInfo } from '@messenger-box/core';
|
|
2
|
+
import { imageSize } from '@container-stack/file-info-client';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { ApolloError } from '@apollo/client';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
import { GraphQLError } from 'graphql';
|
|
7
|
+
|
|
8
|
+
export interface IMutationOptions {
|
|
9
|
+
name: string;
|
|
10
|
+
mutation: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface IUseUploadFileOptions {
|
|
14
|
+
createUploadLink: IMutationOptions;
|
|
15
|
+
saveUploadedFile: IMutationOptions;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface IStartUploadOptions {
|
|
19
|
+
file: File;
|
|
20
|
+
ref: string;
|
|
21
|
+
refName: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IStartUploadResponse {
|
|
25
|
+
data?: Omit<IFileInfo, 'createdAt' | 'updatedAt'>;
|
|
26
|
+
error: GraphQLError;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface IUseUploadFileResponse {
|
|
30
|
+
startUpload: (options: IStartUploadOptions) => Promise<IStartUploadResponse>;
|
|
31
|
+
loading: boolean;
|
|
32
|
+
error: ApolloError;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isFileImage(file: File): boolean {
|
|
36
|
+
return file && file.type?.split('/')[0] === 'image';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const useUploadFile = (options: IUseUploadFileOptions): IUseUploadFileResponse => {
|
|
40
|
+
const { createUploadLink: createLink, saveUploadedFile } = options;
|
|
41
|
+
const [createUploadLink, { loading: linkLoading, error: linkError }] = createLink.mutation();
|
|
42
|
+
const [attachFile, { loading: fileSaving, error: fileSaveError }] = saveUploadedFile.mutation();
|
|
43
|
+
|
|
44
|
+
const startUpload = useCallback(async (options: IStartUploadOptions): Promise<IStartUploadResponse> => {
|
|
45
|
+
try {
|
|
46
|
+
const { file, ref, refName } = options;
|
|
47
|
+
const { data: link, errors: linkErrors } = await createUploadLink({
|
|
48
|
+
variables: {
|
|
49
|
+
filename: file.name,
|
|
50
|
+
[refName]: ref,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
if (linkErrors) {
|
|
54
|
+
return { error: linkErrors[0] };
|
|
55
|
+
}
|
|
56
|
+
const { width, height } = isFileImage
|
|
57
|
+
? await imageSize(await file.arrayBuffer())
|
|
58
|
+
: { width: null, height: null };
|
|
59
|
+
const url = link[createLink.name];
|
|
60
|
+
const { status } = await axios.put(url, file);
|
|
61
|
+
if (status !== 200) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const { data: attachedFile, errors: attachFileErrors } = await attachFile({
|
|
65
|
+
variables: {
|
|
66
|
+
[refName]: ref,
|
|
67
|
+
file: {
|
|
68
|
+
name: file.name,
|
|
69
|
+
size: file.size,
|
|
70
|
+
mimeType: file.type,
|
|
71
|
+
url,
|
|
72
|
+
width,
|
|
73
|
+
height,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
data: attachedFile[saveUploadedFile.name],
|
|
80
|
+
error: attachFileErrors ? attachFileErrors[0] : null,
|
|
81
|
+
};
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.error(e);
|
|
84
|
+
}
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
startUpload,
|
|
89
|
+
loading: linkLoading || fileSaving,
|
|
90
|
+
error: linkError || fileSaveError,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IStartUploadResponse, IUseUploadFileOptions, useUploadFile } from "./upload-file";
|
|
2
|
+
|
|
3
|
+
export interface IStartUploadsOptions {
|
|
4
|
+
files: File[];
|
|
5
|
+
ref: string;
|
|
6
|
+
refName: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface IUseUploadFilesHookResponse extends Omit<ReturnType<typeof useUploadFile>, 'startUpload'> {
|
|
10
|
+
startUploads: (options: IStartUploadsOptions) => Promise<IStartUploadResponse[]>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useUploadFiles = (options: IUseUploadFileOptions): IUseUploadFilesHookResponse => {
|
|
14
|
+
const { startUpload: startUploadSingle, ...rest } = useUploadFile(options);
|
|
15
|
+
const startUploads = async ({ files, ref, refName }: IStartUploadsOptions): Promise<IStartUploadResponse[]> =>
|
|
16
|
+
Promise.all(files.map((file) => startUploadSingle({ file, ref, refName })));
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
...rest,
|
|
20
|
+
startUploads,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useAttachUploadedFileToMessageMutation, useCreateMessageFileUploadLinkMutation } from '@messenger-box/core';
|
|
2
|
+
import { useUploadFiles } from './upload-filex';
|
|
3
|
+
|
|
4
|
+
export const useMsgUploadFiles = (): ReturnType<typeof useUploadFiles> =>
|
|
5
|
+
useUploadFiles({
|
|
6
|
+
createUploadLink: {
|
|
7
|
+
name: 'createMessageFileUploadLink',
|
|
8
|
+
mutation: useCreateMessageFileUploadLinkMutation,
|
|
9
|
+
},
|
|
10
|
+
saveUploadedFile: {
|
|
11
|
+
name: 'attachUploadedFileToMessage',
|
|
12
|
+
mutation: useAttachUploadedFileToMessageMutation,
|
|
13
|
+
},
|
|
14
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './module';
|
package/src/module.tsx
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Feature } from '@common-stack/client-react';
|
|
2
|
+
import { schema, typePolicies, dataIdFromObject } from '@messenger-box/platform-client';
|
|
3
|
+
import { filteredRoutes } from './compute';
|
|
4
|
+
|
|
5
|
+
export default new Feature({
|
|
6
|
+
routeConfig: filteredRoutes,
|
|
7
|
+
dataIdFromObject,
|
|
8
|
+
clientStateParams: { typeDefs: schema, typePolicies },
|
|
9
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowSyntheticDefaultImports": true,
|
|
5
|
+
"experimentalDecorators": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"outDir": "lib",
|
|
10
|
+
"declarationDir": "lib",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true
|
|
13
|
+
},
|
|
14
|
+
"exclude": [
|
|
15
|
+
"../../../node_modules",
|
|
16
|
+
"node_modules",
|
|
17
|
+
"lib",
|
|
18
|
+
"dist",
|
|
19
|
+
"webpack.config.js",
|
|
20
|
+
"rollup.config.js"
|
|
21
|
+
],
|
|
22
|
+
"include": [
|
|
23
|
+
"src",
|
|
24
|
+
"./typings/*.d.ts"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
const nodeExternals = require('webpack-node-externals');
|
|
3
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
4
|
+
const webpack = require('webpack');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const webpackOpts = {
|
|
8
|
+
mode: 'development',
|
|
9
|
+
entry: {
|
|
10
|
+
index: './src/index.ts',
|
|
11
|
+
},
|
|
12
|
+
target: 'node',
|
|
13
|
+
output: {
|
|
14
|
+
path: path.join(__dirname, 'lib'),
|
|
15
|
+
filename: '[name].js',
|
|
16
|
+
libraryTarget: 'commonjs2',
|
|
17
|
+
},
|
|
18
|
+
resolve: {
|
|
19
|
+
extensions: [
|
|
20
|
+
'.js',
|
|
21
|
+
'.jsx',
|
|
22
|
+
'.ts',
|
|
23
|
+
'.tsx',
|
|
24
|
+
'.graphql',
|
|
25
|
+
'.graphqls',
|
|
26
|
+
'.gql',
|
|
27
|
+
'.native.tsx',
|
|
28
|
+
'.native.ts',
|
|
29
|
+
'.json',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
plugins: [
|
|
33
|
+
new webpack.LoaderOptionsPlugin({
|
|
34
|
+
options: {
|
|
35
|
+
test: /\.tsx?$/,
|
|
36
|
+
ts: {
|
|
37
|
+
compiler: 'typescript',
|
|
38
|
+
configFile: 'tsconfig.json',
|
|
39
|
+
},
|
|
40
|
+
tslint: {
|
|
41
|
+
emitErrors: true,
|
|
42
|
+
failOnHint: true,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
devtool: 'source-map',
|
|
48
|
+
module: {
|
|
49
|
+
rules: [
|
|
50
|
+
{
|
|
51
|
+
test: /\.(tsx)?$/,
|
|
52
|
+
loaders: 'ts-loader',
|
|
53
|
+
options: {
|
|
54
|
+
compilerOptions: {
|
|
55
|
+
outDir: path.join(),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
test: /\.mjs$/,
|
|
61
|
+
include: /node_modules/,
|
|
62
|
+
type: 'javascript/auto',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
test: /\.(gql)$/,
|
|
66
|
+
exclude: /node_modules/,
|
|
67
|
+
use: ['graphql-tag/loader'],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
test: /\.graphql?/,
|
|
71
|
+
exclude: /node_modules/,
|
|
72
|
+
use: 'raw-loader',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
test: /\.(png|jpg|gif|webp)$/i,
|
|
76
|
+
use: {
|
|
77
|
+
loader: 'url-loader',
|
|
78
|
+
options: {
|
|
79
|
+
limit: 8192,
|
|
80
|
+
name: 'static/media/[name].[hash:8].[ext]',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
test: /\.svg$/,
|
|
86
|
+
use: ['@svgr/webpack'],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
test: /\.json$/,
|
|
90
|
+
loader: 'json-loader',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
externals: [nodeExternals({ modulesDir: '../../../node_modules' }), nodeExternals()],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = webpackOpts;
|