stream-chat-react-native-core 4.9.0-beta.2 → 4.9.0
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/lib/commonjs/components/Attachment/Gallery.js +246 -190
- package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
- package/lib/commonjs/components/Attachment/VideoThumbnail.js +11 -5
- package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
- package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
- package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js +7 -6
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js +24 -18
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/commonjs/components/MessageInput/ImageUploadPreview.js +2 -2
- package/lib/commonjs/components/MessageInput/ImageUploadPreview.js.map +1 -1
- package/lib/commonjs/components/RTLComponents/WritingDirectionAwareText.js +43 -0
- package/lib/commonjs/components/RTLComponents/WritingDirectionAwareText.js.map +1 -0
- package/lib/commonjs/components/Reply/Reply.js +7 -2
- package/lib/commonjs/components/Reply/Reply.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +20 -27
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/commonjs/mock-builders/generator/attachment.js +3 -2
- package/lib/commonjs/mock-builders/generator/attachment.js.map +1 -1
- package/lib/commonjs/utils/getUrlOfImageAttachment.js +1 -1
- package/lib/commonjs/utils/getUrlOfImageAttachment.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Attachment/Gallery.js +246 -190
- package/lib/module/components/Attachment/Gallery.js.map +1 -1
- package/lib/module/components/Attachment/VideoThumbnail.js +11 -5
- package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
- package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
- package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
- package/lib/module/components/Message/Message.js +7 -6
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/MessageInput/FileUploadPreview.js +24 -18
- package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/module/components/MessageInput/ImageUploadPreview.js +2 -2
- package/lib/module/components/MessageInput/ImageUploadPreview.js.map +1 -1
- package/lib/module/components/RTLComponents/WritingDirectionAwareText.js +43 -0
- package/lib/module/components/RTLComponents/WritingDirectionAwareText.js.map +1 -0
- package/lib/module/components/Reply/Reply.js +7 -2
- package/lib/module/components/Reply/Reply.js.map +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.js +20 -27
- package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/module/mock-builders/generator/attachment.js +3 -2
- package/lib/module/mock-builders/generator/attachment.js.map +1 -1
- package/lib/module/utils/getUrlOfImageAttachment.js +1 -1
- package/lib/module/utils/getUrlOfImageAttachment.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Attachment/VideoThumbnail.d.ts +3 -1
- package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts +1 -0
- package/lib/typescript/components/RTLComponents/WritingDirectionAwareText.d.ts +4 -0
- package/lib/typescript/components/Reply/__tests__/Reply.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/MessageInputContext.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/isValidMessage.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/pickFile.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/removeFile.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/removeImage.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/sendMessage.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/sendMessageAsync.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/updateMessage.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/uploadFile.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/uploadImage.test.d.ts +1 -0
- package/lib/typescript/contexts/messageInputContext/__tests__/useMessageDetailsForState.test.d.ts +1 -0
- package/lib/typescript/mock-builders/api/getOrCreateChannel.d.ts +7 -0
- package/lib/typescript/mock-builders/api/useMockedApis.d.ts +1 -0
- package/lib/typescript/mock-builders/generator/attachment.d.ts +10 -0
- package/lib/typescript/mock-builders/generator/channel.d.ts +116 -0
- package/lib/typescript/mock-builders/generator/message.d.ts +38 -0
- package/lib/typescript/mock-builders/generator/user.d.ts +9 -9
- package/package.json +7 -5
- package/src/components/Attachment/Gallery.tsx +231 -140
- package/src/components/Attachment/VideoThumbnail.tsx +12 -5
- package/src/components/Attachment/__tests__/Attachment.test.js +12 -0
- package/src/components/Attachment/__tests__/Gallery.test.js +23 -1
- package/src/components/Attachment/utils/buildGallery/buildThumbnail.ts +1 -0
- package/src/components/Attachment/utils/buildGallery/types.ts +1 -0
- package/src/components/Message/Message.tsx +5 -1
- package/src/components/MessageInput/FileUploadPreview.tsx +7 -5
- package/src/components/MessageInput/ImageUploadPreview.tsx +2 -2
- package/src/components/RTLComponents/WritingDirectionAwareText.tsx +17 -0
- package/src/components/Reply/Reply.tsx +19 -3
- package/src/components/Reply/__tests__/Reply.test.tsx +48 -0
- package/src/contexts/messageInputContext/MessageInputContext.tsx +3 -4
- package/src/contexts/messageInputContext/__tests__/MessageInputContext.test.tsx +208 -0
- package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessage.test.tsx.snap +109 -0
- package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessageAsync.test.tsx.snap +33 -0
- package/src/contexts/messageInputContext/__tests__/isValidMessage.test.tsx +71 -0
- package/src/contexts/messageInputContext/__tests__/pickFile.test.tsx +67 -0
- package/src/contexts/messageInputContext/__tests__/removeFile.test.tsx +82 -0
- package/src/contexts/messageInputContext/__tests__/removeImage.test.tsx +80 -0
- package/src/contexts/messageInputContext/__tests__/sendMessage.test.tsx +286 -0
- package/src/contexts/messageInputContext/__tests__/sendMessageAsync.test.tsx +124 -0
- package/src/contexts/messageInputContext/__tests__/updateMessage.test.tsx +92 -0
- package/src/contexts/messageInputContext/__tests__/uploadFile.test.tsx +76 -0
- package/src/contexts/messageInputContext/__tests__/uploadImage.test.tsx +55 -0
- package/src/contexts/messageInputContext/__tests__/useMessageDetailsForState.test.tsx +62 -0
- package/src/mock-builders/generator/attachment.js +4 -2
- package/src/utils/getUrlOfImageAttachment.ts +1 -1
- package/src/version.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { StyleSheet, View, ViewProps } from 'react-native';
|
|
2
|
+
import { ImageBackground, StyleSheet, View, ViewProps } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
5
5
|
import { Play } from '../../icons';
|
|
@@ -24,7 +24,9 @@ const styles = StyleSheet.create({
|
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
export type VideoThumbnailProps = ViewProps
|
|
27
|
+
export type VideoThumbnailProps = ViewProps & {
|
|
28
|
+
thumb_url?: string;
|
|
29
|
+
};
|
|
28
30
|
|
|
29
31
|
export const VideoThumbnail: React.FC<VideoThumbnailProps> = (props) => {
|
|
30
32
|
const {
|
|
@@ -34,12 +36,17 @@ export const VideoThumbnail: React.FC<VideoThumbnailProps> = (props) => {
|
|
|
34
36
|
},
|
|
35
37
|
},
|
|
36
38
|
} = useTheme();
|
|
37
|
-
const { style, ...rest } = props;
|
|
39
|
+
const { style, thumb_url, ...rest } = props;
|
|
38
40
|
return (
|
|
39
|
-
<
|
|
41
|
+
<ImageBackground
|
|
42
|
+
accessibilityLabel='video-thumbnail'
|
|
43
|
+
source={{ uri: thumb_url }}
|
|
44
|
+
{...rest}
|
|
45
|
+
style={[styles.container, container, style]}
|
|
46
|
+
>
|
|
40
47
|
<View style={[styles.roundedView, roundedView]}>
|
|
41
48
|
<Play height={24} pathFill={'#000'} width={24} />
|
|
42
49
|
</View>
|
|
43
|
-
</
|
|
50
|
+
</ImageBackground>
|
|
44
51
|
);
|
|
45
52
|
};
|
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
generateAudioAttachment,
|
|
12
12
|
generateFileAttachment,
|
|
13
13
|
generateImageAttachment,
|
|
14
|
+
generateVideoAttachment,
|
|
14
15
|
} from '../../../mock-builders/generator/attachment';
|
|
15
16
|
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
17
|
+
import * as NativeUtils from '../../../native';
|
|
16
18
|
|
|
17
19
|
import { ImageLoadingFailedIndicator } from '../../Attachment/ImageLoadingFailedIndicator';
|
|
18
20
|
import { ImageLoadingIndicator } from '../../Attachment/ImageLoadingIndicator';
|
|
@@ -47,6 +49,16 @@ describe('Attachment', () => {
|
|
|
47
49
|
});
|
|
48
50
|
});
|
|
49
51
|
|
|
52
|
+
it('should render File component for "video" type attachment', async () => {
|
|
53
|
+
jest.spyOn(NativeUtils, 'isVideoPackageAvailable').mockImplementation(jest.fn(() => false));
|
|
54
|
+
const attachment = generateVideoAttachment();
|
|
55
|
+
const { getByTestId } = render(getAttachmentComponent({ attachment }));
|
|
56
|
+
|
|
57
|
+
await waitFor(() => {
|
|
58
|
+
expect(getByTestId('file-attachment')).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
50
62
|
it('should render File component for "file" type attachment', async () => {
|
|
51
63
|
const attachment = generateFileAttachment();
|
|
52
64
|
const { getByTestId } = render(getAttachmentComponent({ attachment }));
|
|
@@ -11,12 +11,16 @@ import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvide
|
|
|
11
11
|
|
|
12
12
|
import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel';
|
|
13
13
|
import { useMockedApis } from '../../../mock-builders/api/useMockedApis';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
generateImageAttachment,
|
|
16
|
+
generateVideoAttachment,
|
|
17
|
+
} from '../../../mock-builders/generator/attachment';
|
|
15
18
|
import { generateChannelResponse } from '../../../mock-builders/generator/channel';
|
|
16
19
|
import { generateMember } from '../../../mock-builders/generator/member';
|
|
17
20
|
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
18
21
|
import { generateUser } from '../../../mock-builders/generator/user';
|
|
19
22
|
import { getTestClientWithUser } from '../../../mock-builders/mock';
|
|
23
|
+
import * as NativeUtils from '../../../native';
|
|
20
24
|
import { Channel } from '../../Channel/Channel';
|
|
21
25
|
import { Chat } from '../../Chat/Chat';
|
|
22
26
|
import { MessageList } from '../../MessageList/MessageList';
|
|
@@ -75,6 +79,24 @@ describe('Gallery', () => {
|
|
|
75
79
|
});
|
|
76
80
|
});
|
|
77
81
|
|
|
82
|
+
it('should render one image and one video attachment', async () => {
|
|
83
|
+
jest.spyOn(NativeUtils, 'isVideoPackageAvailable').mockImplementation(jest.fn(() => true));
|
|
84
|
+
const attachment1 = generateImageAttachment({
|
|
85
|
+
original_height: 600,
|
|
86
|
+
original_width: 400,
|
|
87
|
+
});
|
|
88
|
+
const attachment2 = generateVideoAttachment();
|
|
89
|
+
const component = await getComponent([attachment1, attachment2]);
|
|
90
|
+
const { getAllByA11yLabel, queryAllByTestId } = render(component);
|
|
91
|
+
|
|
92
|
+
await waitFor(() => {
|
|
93
|
+
expect(queryAllByTestId('gallery-row-0').length).toBe(1);
|
|
94
|
+
|
|
95
|
+
expect(queryAllByTestId('gallery-row-0-item-0').length).toBe(1);
|
|
96
|
+
expect(getAllByA11yLabel('video-thumbnail').length).toBe(1);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
78
100
|
it('should render portrait and landscape image in two rows', async () => {
|
|
79
101
|
const attachment1 = generateImageAttachment({
|
|
80
102
|
original_height: 600,
|
|
@@ -36,6 +36,7 @@ export function buildThumbnail<
|
|
|
36
36
|
resizeMode: resizeMode
|
|
37
37
|
? resizeMode
|
|
38
38
|
: ((image.original_height && image.original_width ? 'contain' : 'cover') as ImageResizeMode),
|
|
39
|
+
thumb_url: image.thumb_url,
|
|
39
40
|
type: image.type,
|
|
40
41
|
url: shouldResize
|
|
41
42
|
? getResizedImageUrl({
|
|
@@ -333,7 +333,11 @@ const MessageWithContext = <
|
|
|
333
333
|
acc.files.push(cur);
|
|
334
334
|
acc.other = []; // remove other attachments if a file exists
|
|
335
335
|
} else if (cur.type === 'video' && !cur.og_scrape_url && isVideoPackageAvailable()) {
|
|
336
|
-
acc.videos.push({
|
|
336
|
+
acc.videos.push({
|
|
337
|
+
image_url: cur.asset_url,
|
|
338
|
+
thumb_url: cur.thumb_url,
|
|
339
|
+
type: 'video',
|
|
340
|
+
});
|
|
337
341
|
acc.other = [];
|
|
338
342
|
} else if (cur.type === 'video' && !cur.og_scrape_url) {
|
|
339
343
|
acc.files.push(cur);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { FlatList, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
2
|
+
import { FlatList, I18nManager, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { UploadProgressIndicator } from './UploadProgressIndicator';
|
|
5
5
|
|
|
@@ -19,6 +19,7 @@ import { Warning } from '../../icons/Warning';
|
|
|
19
19
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
20
20
|
import { getIndicatorTypeForFileState, ProgressIndicatorTypes } from '../../utils/utils';
|
|
21
21
|
import { getFileSizeDisplayText } from '../Attachment/FileAttachment';
|
|
22
|
+
import { WritingDirectionAwareText } from '../RTLComponents/WritingDirectionAwareText';
|
|
22
23
|
|
|
23
24
|
const FILE_PREVIEW_HEIGHT = 60;
|
|
24
25
|
const WARNING_ICON_SIZE = 16;
|
|
@@ -71,7 +72,7 @@ const styles = StyleSheet.create({
|
|
|
71
72
|
},
|
|
72
73
|
warningIconStyle: {
|
|
73
74
|
borderRadius: 24,
|
|
74
|
-
marginTop:
|
|
75
|
+
marginTop: 2,
|
|
75
76
|
},
|
|
76
77
|
});
|
|
77
78
|
|
|
@@ -105,9 +106,9 @@ const UnsupportedFileTypeOrFileSizeIndicator = ({
|
|
|
105
106
|
</Text>
|
|
106
107
|
</View>
|
|
107
108
|
) : (
|
|
108
|
-
<
|
|
109
|
-
{item.file.duration
|
|
110
|
-
</
|
|
109
|
+
<WritingDirectionAwareText style={[styles.fileSizeText, { color: grey }, fileSizeText]}>
|
|
110
|
+
{item.file.duration || getFileSizeDisplayText(item.file.size)}
|
|
111
|
+
</WritingDirectionAwareText>
|
|
111
112
|
);
|
|
112
113
|
};
|
|
113
114
|
|
|
@@ -188,6 +189,7 @@ const FileUploadPreviewWithContext = <
|
|
|
188
189
|
24 - // 24 = close icon size
|
|
189
190
|
24, // 24 = internal padding
|
|
190
191
|
},
|
|
192
|
+
I18nManager.isRTL ? { writingDirection: 'rtl' } : { writingDirection: 'ltr' },
|
|
191
193
|
filenameText,
|
|
192
194
|
]}
|
|
193
195
|
>
|
|
@@ -27,7 +27,7 @@ const styles = StyleSheet.create({
|
|
|
27
27
|
},
|
|
28
28
|
fileSizeText: {
|
|
29
29
|
fontSize: 12,
|
|
30
|
-
|
|
30
|
+
paddingHorizontal: 10,
|
|
31
31
|
},
|
|
32
32
|
flatList: { paddingBottom: 12 },
|
|
33
33
|
iconContainer: {
|
|
@@ -54,7 +54,7 @@ const styles = StyleSheet.create({
|
|
|
54
54
|
},
|
|
55
55
|
warningIconStyle: {
|
|
56
56
|
borderRadius: 24,
|
|
57
|
-
marginTop:
|
|
57
|
+
marginTop: 6,
|
|
58
58
|
},
|
|
59
59
|
warningText: {
|
|
60
60
|
alignItems: 'center',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { I18nManager, StyleSheet, Text, ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
defaultStyle: { writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr' },
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export type WritingDirectionAwareTextProps = ViewProps;
|
|
9
|
+
|
|
10
|
+
export const WritingDirectionAwareText: React.FC<WritingDirectionAwareTextProps> = (props) => {
|
|
11
|
+
const { children, style, ...rest } = props;
|
|
12
|
+
return (
|
|
13
|
+
<Text {...rest} style={[style, styles.defaultStyle]}>
|
|
14
|
+
{children}
|
|
15
|
+
</Text>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useContext, useState } from 'react';
|
|
2
2
|
import { Image, ImageStyle, StyleSheet, View, ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import merge from 'lodash/merge';
|
|
@@ -7,8 +7,8 @@ import type { Attachment } from 'stream-chat';
|
|
|
7
7
|
|
|
8
8
|
import { useMessageContext } from '../../contexts/messageContext/MessageContext';
|
|
9
9
|
import {
|
|
10
|
+
MessageInputContext,
|
|
10
11
|
MessageInputContextValue,
|
|
11
|
-
useMessageInputContext,
|
|
12
12
|
} from '../../contexts/messageInputContext/MessageInputContext';
|
|
13
13
|
import {
|
|
14
14
|
MessagesContextValue,
|
|
@@ -267,6 +267,22 @@ const ReplyWithContext = <
|
|
|
267
267
|
);
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* When a reply is rendered in a MessageSimple, it does
|
|
272
|
+
* not have a MessageInputContext. As this is deliberate,
|
|
273
|
+
* this function exists to avoid the error thrown when
|
|
274
|
+
* using a context outside of its provider.
|
|
275
|
+
* */
|
|
276
|
+
const useMessageInputContextIfAvailable = <
|
|
277
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
278
|
+
>() => {
|
|
279
|
+
const contextValue = useContext(
|
|
280
|
+
MessageInputContext,
|
|
281
|
+
) as unknown as MessageInputContextValue<StreamChatGenerics>;
|
|
282
|
+
|
|
283
|
+
return contextValue;
|
|
284
|
+
};
|
|
285
|
+
|
|
270
286
|
const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(
|
|
271
287
|
prevProps: ReplyPropsWithContext<StreamChatGenerics>,
|
|
272
288
|
nextProps: ReplyPropsWithContext<StreamChatGenerics>,
|
|
@@ -307,7 +323,7 @@ export const Reply = <
|
|
|
307
323
|
const { FileAttachmentIcon = FileIconDefault, MessageAvatar = MessageAvatarDefault } =
|
|
308
324
|
useMessagesContext<StreamChatGenerics>();
|
|
309
325
|
|
|
310
|
-
const { editing, quotedMessage } =
|
|
326
|
+
const { editing, quotedMessage } = useMessageInputContextIfAvailable<StreamChatGenerics>();
|
|
311
327
|
|
|
312
328
|
const quotedEditingMessage = (
|
|
313
329
|
typeof editing !== 'boolean' ? editing?.quoted_message || false : false
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { render, waitFor } from '@testing-library/react-native';
|
|
4
|
+
|
|
5
|
+
import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
|
|
6
|
+
import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel';
|
|
7
|
+
import { useMockedApis } from '../../../mock-builders/api/useMockedApis';
|
|
8
|
+
import { generateChannelResponse } from '../../../mock-builders/generator/channel';
|
|
9
|
+
import { getTestClientWithUser } from '../../../mock-builders/mock';
|
|
10
|
+
import { Channel } from '../../Channel/Channel';
|
|
11
|
+
import { Chat } from '../../Chat/Chat';
|
|
12
|
+
import { Reply } from '../Reply';
|
|
13
|
+
|
|
14
|
+
describe('<Reply/>', () => {
|
|
15
|
+
it('can be rendered outside of a MessageInputProvider', async () => {
|
|
16
|
+
const oldEnvironment = process.env;
|
|
17
|
+
process.env.NODE_ENV = 'not_test';
|
|
18
|
+
|
|
19
|
+
const chatClient = await getTestClientWithUser({ id: 'neil' });
|
|
20
|
+
|
|
21
|
+
const mockedChannel = generateChannelResponse();
|
|
22
|
+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
|
|
23
|
+
const channel = chatClient.channel('messaging', 'some-chat');
|
|
24
|
+
await channel.watch();
|
|
25
|
+
|
|
26
|
+
const TestComponent = () => (
|
|
27
|
+
<OverlayProvider>
|
|
28
|
+
<Chat client={chatClient}>
|
|
29
|
+
<Channel channel={channel} client={chatClient}>
|
|
30
|
+
<Reply />
|
|
31
|
+
</Channel>
|
|
32
|
+
</Chat>
|
|
33
|
+
</OverlayProvider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const { toJSON } = render(<TestComponent />);
|
|
38
|
+
|
|
39
|
+
await waitFor(() => {
|
|
40
|
+
expect(toJSON()).not.toBeNull();
|
|
41
|
+
});
|
|
42
|
+
} catch (error: unknown) {
|
|
43
|
+
throw new Error(`Error thrown while rendering Reply: ${error}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
process.env = oldEnvironment;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -62,6 +62,7 @@ export type FileUpload = {
|
|
|
62
62
|
file: File;
|
|
63
63
|
id: string;
|
|
64
64
|
state: FileStateValue;
|
|
65
|
+
thumb_url?: string;
|
|
65
66
|
url?: string;
|
|
66
67
|
};
|
|
67
68
|
|
|
@@ -710,6 +711,7 @@ export const MessageInputProvider = <
|
|
|
710
711
|
duration: file.file.duration,
|
|
711
712
|
file_size: file.file.size,
|
|
712
713
|
mime_type: file.file.type,
|
|
714
|
+
thumb_url: file.thumb_url,
|
|
713
715
|
title: file.file.name,
|
|
714
716
|
type: 'video',
|
|
715
717
|
} as Attachment<StreamChatGenerics>);
|
|
@@ -897,9 +899,6 @@ export const MessageInputProvider = <
|
|
|
897
899
|
};
|
|
898
900
|
|
|
899
901
|
const uploadFile = async ({ newFile }: { newFile: FileUpload }) => {
|
|
900
|
-
if (!newFile) {
|
|
901
|
-
return;
|
|
902
|
-
}
|
|
903
902
|
const { file, id } = newFile;
|
|
904
903
|
|
|
905
904
|
setFileUploads(getUploadSetStateAction(id, FileState.UPLOADING));
|
|
@@ -911,7 +910,7 @@ export const MessageInputProvider = <
|
|
|
911
910
|
} else if (channel && file.uri) {
|
|
912
911
|
response = await channel.sendFile(file.uri, file.name, file.type);
|
|
913
912
|
}
|
|
914
|
-
const extraData: Partial<FileUpload> = { url: response.file };
|
|
913
|
+
const extraData: Partial<FileUpload> = { thumb_url: response.thumb_url, url: response.file };
|
|
915
914
|
setFileUploads(getUploadSetStateAction(id, FileState.UPLOADED, extraData));
|
|
916
915
|
} catch (error: unknown) {
|
|
917
916
|
handleFileOrImageUploadError(error, false, id);
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { TextInput } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { act, renderHook } from '@testing-library/react-hooks';
|
|
6
|
+
|
|
7
|
+
import type { AppSettingsAPIResponse, StreamChat } from 'stream-chat';
|
|
8
|
+
|
|
9
|
+
import { ChatContextValue, ChatProvider } from '../../../contexts/chatContext/ChatContext';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
generateFileAttachment,
|
|
13
|
+
generateImageAttachment,
|
|
14
|
+
} from '../../../mock-builders/generator/attachment';
|
|
15
|
+
|
|
16
|
+
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
17
|
+
import { generateUser } from '../../../mock-builders/generator/user';
|
|
18
|
+
|
|
19
|
+
import * as NativeUtils from '../../../native';
|
|
20
|
+
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
21
|
+
import { FileState } from '../../../utils/utils';
|
|
22
|
+
import {
|
|
23
|
+
InputMessageInputContextValue,
|
|
24
|
+
MessageInputContextValue,
|
|
25
|
+
MessageInputProvider,
|
|
26
|
+
useMessageInputContext,
|
|
27
|
+
} from '../MessageInputContext';
|
|
28
|
+
|
|
29
|
+
type WrapperType<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
|
|
30
|
+
Partial<InputMessageInputContextValue<StreamChatGenerics>>;
|
|
31
|
+
|
|
32
|
+
afterEach(jest.clearAllMocks);
|
|
33
|
+
|
|
34
|
+
describe('MessageInputContext', () => {
|
|
35
|
+
const Wrapper = <
|
|
36
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
37
|
+
>({
|
|
38
|
+
children,
|
|
39
|
+
...rest
|
|
40
|
+
}: PropsWithChildren<WrapperType<StreamChatGenerics>>) => (
|
|
41
|
+
<ChatProvider
|
|
42
|
+
value={
|
|
43
|
+
{
|
|
44
|
+
appSettings: {
|
|
45
|
+
app: {
|
|
46
|
+
file_upload_config: {
|
|
47
|
+
blocked_file_extensions: ['.mp3'],
|
|
48
|
+
blocked_mime_types: ['video/mp4'],
|
|
49
|
+
},
|
|
50
|
+
image_upload_config: {
|
|
51
|
+
blocked_file_extensions: ['.png'],
|
|
52
|
+
blocked_mime_types: ['image/png'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
} as unknown as AppSettingsAPIResponse<StreamChatGenerics>,
|
|
56
|
+
client: {
|
|
57
|
+
updateMessage: jest.fn().mockResolvedValue({ message: generateMessage() }),
|
|
58
|
+
} as unknown as StreamChat<StreamChatGenerics>,
|
|
59
|
+
} as ChatContextValue<StreamChatGenerics>
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
<MessageInputProvider
|
|
63
|
+
value={
|
|
64
|
+
{
|
|
65
|
+
...rest,
|
|
66
|
+
} as MessageInputContextValue<StreamChatGenerics>
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</MessageInputProvider>
|
|
71
|
+
</ChatProvider>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
it('appendText works', () => {
|
|
75
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
76
|
+
initialProps: {
|
|
77
|
+
editing: true,
|
|
78
|
+
hasImagePicker: true,
|
|
79
|
+
},
|
|
80
|
+
wrapper: Wrapper,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
act(() => {
|
|
84
|
+
result.current.setFileUploads([]);
|
|
85
|
+
result.current.setImageUploads([]);
|
|
86
|
+
result.current.setMentionedUsers([]);
|
|
87
|
+
result.current.setText('dummy');
|
|
88
|
+
result.current.appendText('text');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(result.current.text).toBe('dummytext');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('uploadNewImage with blocked image extensions to be not supported', () => {
|
|
95
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
96
|
+
initialProps: {
|
|
97
|
+
editing: true,
|
|
98
|
+
maxNumberOfFiles: 2,
|
|
99
|
+
},
|
|
100
|
+
wrapper: Wrapper,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
act(() => {
|
|
104
|
+
result.current.uploadNewImage(
|
|
105
|
+
generateImageAttachment({
|
|
106
|
+
uri: 'https://www.bastiaanmulder.nl/wp-content/uploads/2013/11/dummy-image-square.png',
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(result.current.imageUploads[0].state).toBe(FileState.NOT_SUPPORTED);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('onSelectItem works', () => {
|
|
115
|
+
const mentioned_user = generateUser();
|
|
116
|
+
const initialUsers = [mentioned_user.id];
|
|
117
|
+
|
|
118
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
119
|
+
initialProps: {
|
|
120
|
+
editing: true,
|
|
121
|
+
hasImagePicker: true,
|
|
122
|
+
},
|
|
123
|
+
wrapper: Wrapper,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
act(() => {
|
|
127
|
+
result.current.setFileUploads([]);
|
|
128
|
+
result.current.setImageUploads([]);
|
|
129
|
+
result.current.setMentionedUsers(initialUsers);
|
|
130
|
+
result.current.onSelectItem(mentioned_user);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
expect(result.current.mentionedUsers.length).toBe(2);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('setInputBoxRef works', () => {
|
|
137
|
+
const setInputRefMock = jest.fn();
|
|
138
|
+
const inputRef = React.createRef<TextInput | null>();
|
|
139
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
140
|
+
initialProps: {
|
|
141
|
+
editing: true,
|
|
142
|
+
setInputRef: setInputRefMock,
|
|
143
|
+
},
|
|
144
|
+
wrapper: Wrapper,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
act(() => {
|
|
148
|
+
result.current.setInputBoxRef(inputRef.current);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(setInputRefMock).toHaveBeenCalled();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('openCommandsPicker works', () => {
|
|
155
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
156
|
+
initialProps: {
|
|
157
|
+
editing: true,
|
|
158
|
+
hasImagePicker: true,
|
|
159
|
+
},
|
|
160
|
+
wrapper: Wrapper,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
act(() => {
|
|
164
|
+
result.current.openCommandsPicker();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(result.current.text).toBe('/');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('openMentionPicker works', () => {
|
|
171
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
172
|
+
initialProps: {
|
|
173
|
+
editing: true,
|
|
174
|
+
hasImagePicker: true,
|
|
175
|
+
},
|
|
176
|
+
wrapper: Wrapper,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
act(() => {
|
|
180
|
+
result.current.openMentionsPicker();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(result.current.text).toBe('@');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('openAttachmentPicker works', async () => {
|
|
187
|
+
jest.spyOn(NativeUtils, 'pickDocument').mockImplementation(
|
|
188
|
+
jest.fn().mockResolvedValue({
|
|
189
|
+
cancelled: false,
|
|
190
|
+
docs: [generateFileAttachment(), generateImageAttachment()],
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
const { result } = renderHook(() => useMessageInputContext(), {
|
|
194
|
+
initialProps: {
|
|
195
|
+
editing: true,
|
|
196
|
+
hasFilePicker: true,
|
|
197
|
+
hasImagePicker: false,
|
|
198
|
+
},
|
|
199
|
+
wrapper: Wrapper,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
act(() => {
|
|
203
|
+
result.current.openAttachmentPicker();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(await result.current.pickFile()).toBe(undefined);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`MessageInputContext's sendMessage exit sendMessage when edit message is not boolean image upload status is uploaded successfully 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"attachments": Array [
|
|
6
|
+
Object {
|
|
7
|
+
"fallback": undefined,
|
|
8
|
+
"image_url": undefined,
|
|
9
|
+
"original_height": undefined,
|
|
10
|
+
"original_width": undefined,
|
|
11
|
+
"type": "image",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
"created_at": "Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)",
|
|
15
|
+
"html": "<p>regular</p>",
|
|
16
|
+
"id": "7a85f744-cc89-4f82-a1d4-5456432cc8bf",
|
|
17
|
+
"mentioned_users": Array [
|
|
18
|
+
"dummy1",
|
|
19
|
+
"dummy2",
|
|
20
|
+
],
|
|
21
|
+
"quoted_message": undefined,
|
|
22
|
+
"text": "",
|
|
23
|
+
"type": "regular",
|
|
24
|
+
"updated_at": "Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)",
|
|
25
|
+
"user": Object {
|
|
26
|
+
"banned": false,
|
|
27
|
+
"created_at": "2020-04-27T13:39:49.331742Z",
|
|
28
|
+
"id": "5d6f6322-567e-4e1e-af90-97ef1ed5cc23",
|
|
29
|
+
"image": "fc86ddcb-bac4-400c-9afd-b0c0a1c0cd33",
|
|
30
|
+
"name": "50cbdd0e-ca7e-4478-9e2c-be0f1ac6a995",
|
|
31
|
+
"online": false,
|
|
32
|
+
"role": "user",
|
|
33
|
+
"updated_at": "2020-04-27T13:39:49.332087Z",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
exports[`MessageInputContext's sendMessage exit sendMessage when file upload status is uploaded successfully 1`] = `
|
|
39
|
+
Object {
|
|
40
|
+
"attachments": Array [
|
|
41
|
+
Object {
|
|
42
|
+
"asset_url": undefined,
|
|
43
|
+
"file_size": undefined,
|
|
44
|
+
"mime_type": "file",
|
|
45
|
+
"title": "dummy.pdf",
|
|
46
|
+
"type": "file",
|
|
47
|
+
},
|
|
48
|
+
Object {
|
|
49
|
+
"asset_url": undefined,
|
|
50
|
+
"duration": undefined,
|
|
51
|
+
"file_size": undefined,
|
|
52
|
+
"mime_type": "video/mp4",
|
|
53
|
+
"thumb_url": undefined,
|
|
54
|
+
"title": "dummy.pdf",
|
|
55
|
+
"type": "video",
|
|
56
|
+
},
|
|
57
|
+
Object {
|
|
58
|
+
"asset_url": undefined,
|
|
59
|
+
"duration": undefined,
|
|
60
|
+
"file_size": undefined,
|
|
61
|
+
"mime_type": "audio/mp3",
|
|
62
|
+
"title": "dummy.pdf",
|
|
63
|
+
"type": "audio",
|
|
64
|
+
},
|
|
65
|
+
Object {
|
|
66
|
+
"fallback": "dummy.pdf",
|
|
67
|
+
"image_url": undefined,
|
|
68
|
+
"type": "image",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
"mentioned_users": Array [
|
|
72
|
+
"dummy1",
|
|
73
|
+
"dummy2",
|
|
74
|
+
],
|
|
75
|
+
"parent_id": undefined,
|
|
76
|
+
"quoted_message_id": undefined,
|
|
77
|
+
"show_in_channel": undefined,
|
|
78
|
+
"text": "",
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
exports[`MessageInputContext's sendMessage exit sendMessage when image upload status is uploaded successfully 1`] = `
|
|
83
|
+
Object {
|
|
84
|
+
"attachments": Array [
|
|
85
|
+
Object {
|
|
86
|
+
"fallback": undefined,
|
|
87
|
+
"image_url": undefined,
|
|
88
|
+
"original_height": undefined,
|
|
89
|
+
"original_width": undefined,
|
|
90
|
+
"type": "image",
|
|
91
|
+
},
|
|
92
|
+
Object {
|
|
93
|
+
"fallback": undefined,
|
|
94
|
+
"image_url": undefined,
|
|
95
|
+
"original_height": undefined,
|
|
96
|
+
"original_width": undefined,
|
|
97
|
+
"type": "image",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
"mentioned_users": Array [
|
|
101
|
+
"dummy1",
|
|
102
|
+
"dummy2",
|
|
103
|
+
],
|
|
104
|
+
"parent_id": undefined,
|
|
105
|
+
"quoted_message_id": undefined,
|
|
106
|
+
"show_in_channel": undefined,
|
|
107
|
+
"text": "",
|
|
108
|
+
}
|
|
109
|
+
`;
|