@messenger-box/platform-browser 0.0.1-alpha.134 → 0.0.1-alpha.137

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.
@@ -0,0 +1,2 @@
1
+ export * from './use-upload-file.hook';
2
+ export * from './use-upload-files.hook';
@@ -0,0 +1,26 @@
1
+ import { IFileInfo } from '@messenger-box/core';
2
+ import { ApolloError } from '@apollo/client';
3
+ import { GraphQLError } from 'graphql';
4
+ export interface IMutationOptions {
5
+ name: string;
6
+ mutation: any;
7
+ }
8
+ export interface IUseUploadFileOptions {
9
+ createUploadLink: IMutationOptions;
10
+ saveUploadedFile: IMutationOptions;
11
+ }
12
+ export interface IStartUploadOptions {
13
+ file: File;
14
+ ref: string;
15
+ refName: string;
16
+ }
17
+ export interface IStartUploadResponse {
18
+ data?: Omit<IFileInfo, 'createdAt' | 'updatedAt'>;
19
+ error: GraphQLError;
20
+ }
21
+ export interface IUseUploadFileResponse {
22
+ startUpload: (options: IStartUploadOptions) => Promise<IStartUploadResponse>;
23
+ loading: boolean;
24
+ error: ApolloError;
25
+ }
26
+ export declare const useUploadFile: (options: IUseUploadFileOptions) => IUseUploadFileResponse;
@@ -0,0 +1,10 @@
1
+ import { IStartUploadResponse, IUseUploadFileOptions, useUploadFile } from './use-upload-file.hook';
2
+ export interface IStartUploadsOptions {
3
+ files: File[];
4
+ ref: string;
5
+ refName: string;
6
+ }
7
+ export interface IUseUploadFilesHookResponse extends Omit<ReturnType<typeof useUploadFile>, 'startUpload'> {
8
+ startUploads: (options: IStartUploadsOptions) => Promise<IStartUploadResponse[]>;
9
+ }
10
+ export declare const useUploadFiles: (options: IUseUploadFileOptions) => IUseUploadFilesHookResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messenger-box/platform-browser",
3
- "version": "0.0.1-alpha.134",
3
+ "version": "0.0.1-alpha.137",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -21,10 +21,11 @@
21
21
  "dependencies": {
22
22
  "@chakra-ui/icons": "^1.0.16",
23
23
  "@chakra-ui/react": "~1.6.12",
24
+ "@container-stack/file-info-client": "^0.0.26-96",
24
25
  "@emotion/react": "^11",
25
26
  "@emotion/styled": "^11",
26
- "@messenger-box/core": "0.0.1-alpha.127",
27
- "@messenger-box/platform-client": "0.0.1-alpha.134",
27
+ "@messenger-box/core": "0.0.1-alpha.137",
28
+ "@messenger-box/platform-client": "0.0.1-alpha.137",
28
29
  "bootstrap": "3.4.1",
29
30
  "css-vars-ponyfill": "2.4.5",
30
31
  "dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#119db968c96643c7106d4d2c965f05b2e251bc83",
@@ -57,5 +58,5 @@
57
58
  "typescript": {
58
59
  "definition": "lib/index.d.ts"
59
60
  },
60
- "gitHead": "c573ab335ea48becde0a1efe8ffd3edac7848e72"
61
+ "gitHead": "9cac9c1317e3081e9cc4efd54be348c988f581b5"
61
62
  }
@@ -1,38 +1,30 @@
1
- import React, {FC, useCallback, useEffect, useRef, useState} from 'react';
2
- import {Col, Row, Input, Divider} from 'antd';
3
- // import { MessagesList, ThreadMessagesList } from './messagesList';
4
- import {MessagesList} from './messagesList';
1
+ import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
2
+ import { Col, Row, Input } from 'antd';
5
3
  import {
6
4
  useGetMessagesQuery,
7
5
  useSendMessagesMutation,
8
6
  useDeleteMessageMutation,
9
7
  useEditMessageMutation,
10
- useUploadImgMutation, Exact,
11
8
  } from '@messenger-box/core';
12
- import {messagesData} from './mock';
13
- import {IMessageList} from './types/message';
14
9
  import {
15
- BiDotsHorizontalRounded,
16
10
  HiOutlinePaperClip,
17
- IoIosClose,
18
- IoMdClose,
19
11
  MdOutlineEmojiEmotions,
20
12
  } from 'react-icons/all';
21
- import {styleSheet3} from './messagesList/style';
22
- import {useFela} from 'react-fela';
23
- import {Picker} from 'emoji-mart';
13
+ import { useFela } from 'react-fela';
14
+ import { Picker } from 'emoji-mart';
24
15
  import 'emoji-mart/css/emoji-mart.css';
25
- import Moment from 'moment';
26
- import {Button, Modal} from 'react-bootstrap';
16
+ import { useUploadFiles } from '../../hooks';
17
+ import { styleSheet3 } from './messagesList/style';
18
+ import { MessagesList } from './messagesList';
27
19
 
28
20
  interface PropsTypes {
29
21
  channel: any;
30
22
  currentUsrId: string;
31
23
  }
32
24
 
33
- export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
25
+ export const MessengerComponent: FC<PropsTypes> = ({ channel, currentUsrId }) => {
34
26
  document.getElementsByClassName('demo')[0].setAttribute('style', `{{overflow: 'hidden'}}`);
35
- const {css} = useFela();
27
+ const { css } = useFela();
36
28
  const [enterValue, setEnterValue] = useState<string>('');
37
29
  const [showThread, setShowThread] = useState<boolean>(false);
38
30
  const [flag, setFlag] = useState<boolean>(false);
@@ -42,16 +34,17 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
42
34
  const [day, setDay] = useState<string>('Today');
43
35
  const [threadEmoji, setThreadEmoji] = useState(false);
44
36
  const [files, setFiles] = useState([])
37
+ const { startUploads } = useUploadFiles();
45
38
 
46
39
  // let token;
47
40
  // useEffect(() => {
48
41
  // token = window.localStorage.getItem('access_token');
49
42
  // }, []);
50
- const {data, loading, error, refetch} = useGetMessagesQuery({
43
+ const { data, loading, error, refetch } = useGetMessagesQuery({
51
44
  variables: {
52
45
  channelId: channel.id,
53
46
  },
54
- fetchPolicy: "cache-first"
47
+ fetchPolicy: 'cache-first'
55
48
  });
56
49
  // useEffect(() => {
57
50
  // if (isRefetch) {
@@ -71,8 +64,8 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
71
64
  setFiles([])
72
65
  cache.modify({
73
66
  fields: {
74
- messages(existingMessages, {toReference}) {
75
- return {...existingMessages, data: toReference(mutationResult.data.sendMessage)}
67
+ messages(existingMessages, { toReference }) {
68
+ return { ...existingMessages, data: toReference(mutationResult.data.sendMessage) }
76
69
  }
77
70
  }
78
71
  })
@@ -80,20 +73,36 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
80
73
  // context: {headers: {Authorization: token}},
81
74
  // refetchQueries: ['GetMessages']
82
75
  });
83
- const handleEnterButton = (e) => {
84
- if (enterValue) {
85
- sendMsg({
86
- variables: {
87
- channelId: channel.id,
88
- content: enterValue,
89
- files: files
90
- },
91
- })
92
- setEnterValue('');
93
- scrollToBottom();
94
- setFlag(true);
76
+
77
+ const handleEnterButton = useCallback(async (e) => {
78
+ if (!enterValue) {
79
+ return;
95
80
  }
96
- };
81
+ const { data } = await sendMsg({
82
+ variables: {
83
+ channelId: channel.id,
84
+ content: enterValue,
85
+ files: []
86
+ },
87
+ });
88
+ const uploadedFiles = await startUploads({
89
+ files,
90
+ ref: data.sendMessage.id,
91
+ refName: 'postId'
92
+ });
93
+ await editMessage({
94
+ variables: {
95
+ channelId: channel.id,
96
+ messageId: data.sendMessage.id,
97
+ files: uploadedFiles.map(i => i.data.id),
98
+ content: enterValue
99
+ }
100
+ })
101
+ setEnterValue('');
102
+ scrollToBottom();
103
+ setFlag(true);
104
+ }, [channel, files, enterValue]);
105
+
97
106
  const [deleteMsg, {}] = useDeleteMessageMutation({
98
107
  // context: {headers: {Authorization: token}},
99
108
  // refetchQueries: ['GetMessages']
@@ -146,7 +155,7 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
146
155
  };
147
156
  const messagesEndRef = useRef(null);
148
157
  const scrollToBottom = () => {
149
- messagesEndRef.current?.scrollIntoView({behavior: 'smooth'});
158
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
150
159
  };
151
160
 
152
161
  const fileUploader = useRef(null);
@@ -157,18 +166,22 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
157
166
  const handleShowSideBar = () => {
158
167
  setShowThread(!showThread);
159
168
  };
160
- const handleEditMessage = (id, msg) => {
161
- editMessage({
169
+ const handleEditMessage = useCallback(async (id, msg) => {
170
+ const uploadedFiles = await startUploads({
171
+ files,
172
+ ref: id,
173
+ refName: 'postId'
174
+ });
175
+ return editMessage({
162
176
  variables: {
163
177
  channelId: channel.id,
164
178
  messageId: id,
165
179
  content: msg,
166
- files: files
180
+ files: uploadedFiles.map(i => i.data.id),
167
181
  },
168
182
  })
169
- };
183
+ }, [files, channel]);
170
184
 
171
- const [fileUpload, uploadedRes] = useUploadImgMutation()
172
185
  const handleFileChange = (e) => {
173
186
  let inputFiles: any = []
174
187
  Object.keys(e.target.files).map((key) => inputFiles.push(e.target.files[key]));
@@ -182,14 +195,14 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
182
195
  let imgs = document.getElementById('preview_img')
183
196
  imgs.innerHTML = ''
184
197
  files.forEach((f, index) => {
185
- let childDiv = document.createElement("div")
186
- childDiv.className = "child_div"
187
- let childImg = document.createElement("img")
198
+ let childDiv = document.createElement('div')
199
+ childDiv.className = 'child_div'
200
+ let childImg = document.createElement('img')
188
201
  childImg.src = URL.createObjectURL(f)
189
- let childClose = document.createElement("i")
190
- childClose.className = "fa fa-times"
202
+ let childClose = document.createElement('i')
203
+ childClose.className = 'fa fa-times'
191
204
  let overLayDiv = document.createElement('div')
192
- overLayDiv.className = "overlay"
205
+ overLayDiv.className = 'overlay'
193
206
  childClose.onclick = () => previewClose(f)
194
207
  childDiv.appendChild(overLayDiv)
195
208
  childDiv.appendChild(childImg)
@@ -240,7 +253,7 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
240
253
  ''
241
254
  )}
242
255
  <div className="input_msg">
243
- <div style={{display: 'flex', position: 'relative'}}>
256
+ <div style={{ display: 'flex', position: 'relative' }}>
244
257
  <Input
245
258
  value={enterValue}
246
259
  onChange={(e: any) => setEnterValue(e?.target?.value)}
@@ -251,13 +264,13 @@ export const MessengerComponent: FC<PropsTypes> = ({channel, currentUsrId}) => {
251
264
  <div className="icon_box">
252
265
  <div className="icon_style">
253
266
  <input type="file" onChange={handleFileChange} ref={fileUploader}
254
- style={{display: 'none'}} multiple={true}/>
255
- <button style={{border: '0px'}} onClick={fileClick}>
267
+ style={{ display: 'none' }} multiple={true}/>
268
+ <button style={{ border: '0px' }} onClick={fileClick}>
256
269
  <HiOutlinePaperClip/>
257
270
  </button>
258
271
  </div>
259
272
  <div className="icon_style">
260
- <button style={{border: '0px'}} onClick={(e) => emojiClick('main')}>
273
+ <button style={{ border: '0px' }} onClick={(e) => emojiClick('main')}>
261
274
  <MdOutlineEmojiEmotions/>
262
275
  </button>
263
276
  </div>
@@ -0,0 +1,12 @@
1
+ fragment FileInfo on FileInfo{
2
+ id
3
+ name
4
+ extension
5
+ mimeType
6
+ width
7
+ height
8
+ url
9
+ ref
10
+ size
11
+ refType
12
+ }
@@ -1,7 +1,7 @@
1
1
  mutation SendMessages(
2
2
  $channelId:String!,
3
3
  $content:String!,
4
- $files:[Upload!]!
4
+ $files:[ID!]
5
5
  ){
6
6
  sendMessage(
7
7
  channelId: $channelId,
@@ -31,7 +31,7 @@ mutation EditMessage(
31
31
  $messageId:String!,
32
32
  $channelId:String!,
33
33
  $content:String!,
34
- $files:[Upload!]!
34
+ $files:[ID!]!
35
35
  ){
36
36
  editMessage(
37
37
  messageId: {
@@ -47,10 +47,21 @@ mutation EditMessage(
47
47
  }
48
48
  }
49
49
 
50
- mutation UploadImg($files:[Upload!]!, $postId: String!){
51
- uploadFile(files: $files, postId: $postId)
50
+ mutation CreateMessageFileUploadLink($filename:String!, $postId: ID!){
51
+ createMessageFileUploadLink(postId:$postId, filename: $filename )
52
52
  }
53
53
 
54
+ mutation AttachUploadedFileToMessage($postId:ID!, $file: UploadedFileInput!){
55
+ attachUploadedFileToMessage(postId: $postId, file: $file){
56
+ ...FileInfo
57
+ }
58
+ }
59
+
60
+ mutation DeleteMessageFile($url:String!){
61
+ deleteMessageFile(url:$url)
62
+ }
63
+
64
+
54
65
  #mutation PinMessage($messageId:String! , $messageInput:String! , $content:String!) {
55
66
  # pinMessage(
56
67
  # messageId: {
@@ -0,0 +1,2 @@
1
+ export * from './use-upload-file.hook';
2
+ export * from './use-upload-files.hook';
@@ -0,0 +1,14 @@
1
+ import { useCreateMessageFileUploadLinkMutation, useAttachUploadedFileToMessageMutation } from '@messenger-box/core';
2
+ import { useUploadFile as useBaseUploadFile } from '../temp';
3
+
4
+ export const useUploadFile = (): ReturnType<typeof useBaseUploadFile> =>
5
+ useBaseUploadFile({
6
+ createUploadLink: {
7
+ name: 'createMessageFileUploadLink',
8
+ mutation: useCreateMessageFileUploadLinkMutation,
9
+ },
10
+ saveUploadedFile: {
11
+ name: 'attachUploadedFileToMessage',
12
+ mutation: useAttachUploadedFileToMessageMutation,
13
+ },
14
+ });
@@ -0,0 +1,14 @@
1
+ import { useAttachUploadedFileToMessageMutation, useCreateMessageFileUploadLinkMutation } from '@messenger-box/core';
2
+ import { useUploadFiles as useBaseUploadFiles } from '../temp';
3
+
4
+ export const useUploadFiles = (): ReturnType<typeof useBaseUploadFiles> =>
5
+ useBaseUploadFiles({
6
+ createUploadLink: {
7
+ name: 'createMessageFileUploadLink',
8
+ mutation: useCreateMessageFileUploadLinkMutation,
9
+ },
10
+ saveUploadedFile: {
11
+ name: 'attachUploadedFileToMessage',
12
+ mutation: useAttachUploadedFileToMessageMutation,
13
+ },
14
+ });
@@ -0,0 +1,2 @@
1
+ export * from './use-upload-file.hook';
2
+ export * from './use-upload-files.hook';
@@ -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 './use-upload-file.hook';
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
+ };
@@ -1,50 +0,0 @@
1
- export declare const messagesData: ({
2
- id: number;
3
- loginUser: boolean;
4
- message: string;
5
- time: string;
6
- timeIsToday: boolean;
7
- isReply: boolean;
8
- thread: {
9
- threadId: number;
10
- message: string;
11
- time: string;
12
- timeIsToday: boolean;
13
- loginUser: boolean;
14
- }[];
15
- } | {
16
- id: number;
17
- loginUser: boolean;
18
- message: string;
19
- time: string;
20
- timeIsToday: boolean;
21
- isReply: boolean;
22
- thread?: undefined;
23
- })[];
24
- export declare const userProfile: ({
25
- displayName: string;
26
- isBusy: boolean;
27
- user: {
28
- username: string;
29
- };
30
- isShared: boolean;
31
- disablePopover: boolean;
32
- url: string;
33
- displayUsername: boolean;
34
- hasMention: boolean;
35
- message: any[];
36
- hideStatus: boolean;
37
- } | {
38
- displayName: string;
39
- isBusy: boolean;
40
- user: {
41
- username: string;
42
- };
43
- isShared: boolean;
44
- disablePopover: boolean;
45
- url: string;
46
- displayUsername: boolean;
47
- hasMention: boolean;
48
- hideStatus: boolean;
49
- message?: undefined;
50
- })[];
@@ -1,15 +0,0 @@
1
- export interface IMessageList {
2
- id: number;
3
- loginUser: boolean;
4
- message: string;
5
- timeIsToday: boolean;
6
- isReply: boolean;
7
- thread?: IMessageReplyList[];
8
- isPin?: boolean;
9
- }
10
- export interface IMessageReplyList {
11
- threadId: number;
12
- message: string;
13
- time: string;
14
- timeIsToday: boolean;
15
- }