stream-chat-react-native-core 4.9.0-beta.1 → 4.9.0-beta.4

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 (110) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +11 -9
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/VideoThumbnail.js +11 -5
  4. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
  6. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  7. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteInput.js +3 -2
  8. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteInput.js.map +1 -1
  9. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteSuggestionItem.js +1 -1
  10. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteSuggestionItem.js.map +1 -1
  11. package/lib/commonjs/components/Message/Message.js +7 -6
  12. package/lib/commonjs/components/Message/Message.js.map +1 -1
  13. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +24 -18
  14. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  15. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js +2 -2
  16. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js.map +1 -1
  17. package/lib/commonjs/components/RTLComponents/WritingDirectionAwareText.js +43 -0
  18. package/lib/commonjs/components/RTLComponents/WritingDirectionAwareText.js.map +1 -0
  19. package/lib/commonjs/components/Reply/Reply.js +7 -2
  20. package/lib/commonjs/components/Reply/Reply.js.map +1 -1
  21. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +20 -27
  22. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  23. package/lib/commonjs/mock-builders/generator/attachment.js +3 -2
  24. package/lib/commonjs/mock-builders/generator/attachment.js.map +1 -1
  25. package/lib/commonjs/utils/getUrlOfImageAttachment.js +1 -1
  26. package/lib/commonjs/utils/getUrlOfImageAttachment.js.map +1 -1
  27. package/lib/commonjs/version.json +1 -1
  28. package/lib/module/components/Attachment/Gallery.js +11 -9
  29. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  30. package/lib/module/components/Attachment/VideoThumbnail.js +11 -5
  31. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  32. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
  33. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  34. package/lib/module/components/AutoCompleteInput/AutoCompleteInput.js +3 -2
  35. package/lib/module/components/AutoCompleteInput/AutoCompleteInput.js.map +1 -1
  36. package/lib/module/components/AutoCompleteInput/AutoCompleteSuggestionItem.js +1 -1
  37. package/lib/module/components/AutoCompleteInput/AutoCompleteSuggestionItem.js.map +1 -1
  38. package/lib/module/components/Message/Message.js +7 -6
  39. package/lib/module/components/Message/Message.js.map +1 -1
  40. package/lib/module/components/MessageInput/FileUploadPreview.js +24 -18
  41. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  42. package/lib/module/components/MessageInput/ImageUploadPreview.js +2 -2
  43. package/lib/module/components/MessageInput/ImageUploadPreview.js.map +1 -1
  44. package/lib/module/components/RTLComponents/WritingDirectionAwareText.js +43 -0
  45. package/lib/module/components/RTLComponents/WritingDirectionAwareText.js.map +1 -0
  46. package/lib/module/components/Reply/Reply.js +7 -2
  47. package/lib/module/components/Reply/Reply.js.map +1 -1
  48. package/lib/module/contexts/messageInputContext/MessageInputContext.js +20 -27
  49. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  50. package/lib/module/mock-builders/generator/attachment.js +3 -2
  51. package/lib/module/mock-builders/generator/attachment.js.map +1 -1
  52. package/lib/module/utils/getUrlOfImageAttachment.js +1 -1
  53. package/lib/module/utils/getUrlOfImageAttachment.js.map +1 -1
  54. package/lib/module/version.json +1 -1
  55. package/lib/typescript/components/Attachment/VideoThumbnail.d.ts +3 -1
  56. package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts +1 -0
  57. package/lib/typescript/components/RTLComponents/WritingDirectionAwareText.d.ts +4 -0
  58. package/lib/typescript/components/Reply/__tests__/Reply.test.d.ts +1 -0
  59. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +1 -0
  60. package/lib/typescript/contexts/messageInputContext/__tests__/MessageInputContext.test.d.ts +1 -0
  61. package/lib/typescript/contexts/messageInputContext/__tests__/isValidMessage.test.d.ts +1 -0
  62. package/lib/typescript/contexts/messageInputContext/__tests__/pickFile.test.d.ts +1 -0
  63. package/lib/typescript/contexts/messageInputContext/__tests__/removeFile.test.d.ts +1 -0
  64. package/lib/typescript/contexts/messageInputContext/__tests__/removeImage.test.d.ts +1 -0
  65. package/lib/typescript/contexts/messageInputContext/__tests__/sendMessage.test.d.ts +1 -0
  66. package/lib/typescript/contexts/messageInputContext/__tests__/sendMessageAsync.test.d.ts +1 -0
  67. package/lib/typescript/contexts/messageInputContext/__tests__/updateMessage.test.d.ts +1 -0
  68. package/lib/typescript/contexts/messageInputContext/__tests__/uploadFile.test.d.ts +1 -0
  69. package/lib/typescript/contexts/messageInputContext/__tests__/uploadImage.test.d.ts +1 -0
  70. package/lib/typescript/contexts/messageInputContext/__tests__/useMessageDetailsForState.test.d.ts +1 -0
  71. package/lib/typescript/mock-builders/api/getOrCreateChannel.d.ts +7 -0
  72. package/lib/typescript/mock-builders/api/useMockedApis.d.ts +1 -0
  73. package/lib/typescript/mock-builders/generator/attachment.d.ts +10 -0
  74. package/lib/typescript/mock-builders/generator/channel.d.ts +116 -0
  75. package/lib/typescript/mock-builders/generator/message.d.ts +38 -0
  76. package/lib/typescript/mock-builders/generator/user.d.ts +9 -9
  77. package/package.json +7 -5
  78. package/src/components/Attachment/Gallery.tsx +2 -1
  79. package/src/components/Attachment/VideoThumbnail.tsx +12 -5
  80. package/src/components/Attachment/__tests__/Attachment.test.js +12 -0
  81. package/src/components/Attachment/__tests__/Gallery.test.js +23 -1
  82. package/src/components/Attachment/utils/buildGallery/buildThumbnail.ts +1 -0
  83. package/src/components/Attachment/utils/buildGallery/types.ts +1 -0
  84. package/src/components/AutoCompleteInput/AutoCompleteInput.tsx +2 -1
  85. package/src/components/AutoCompleteInput/AutoCompleteSuggestionItem.tsx +1 -1
  86. package/src/components/Message/Message.tsx +5 -1
  87. package/src/components/MessageInput/FileUploadPreview.tsx +7 -5
  88. package/src/components/MessageInput/ImageUploadPreview.tsx +2 -2
  89. package/src/components/MessageInput/__tests__/__snapshots__/MessageInput.test.js.snap +1 -0
  90. package/src/components/RTLComponents/WritingDirectionAwareText.tsx +17 -0
  91. package/src/components/Reply/Reply.tsx +19 -3
  92. package/src/components/Reply/__tests__/Reply.test.tsx +48 -0
  93. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +1 -0
  94. package/src/contexts/messageInputContext/MessageInputContext.tsx +3 -4
  95. package/src/contexts/messageInputContext/__tests__/MessageInputContext.test.tsx +208 -0
  96. package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessage.test.tsx.snap +109 -0
  97. package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessageAsync.test.tsx.snap +33 -0
  98. package/src/contexts/messageInputContext/__tests__/isValidMessage.test.tsx +71 -0
  99. package/src/contexts/messageInputContext/__tests__/pickFile.test.tsx +67 -0
  100. package/src/contexts/messageInputContext/__tests__/removeFile.test.tsx +82 -0
  101. package/src/contexts/messageInputContext/__tests__/removeImage.test.tsx +80 -0
  102. package/src/contexts/messageInputContext/__tests__/sendMessage.test.tsx +286 -0
  103. package/src/contexts/messageInputContext/__tests__/sendMessageAsync.test.tsx +124 -0
  104. package/src/contexts/messageInputContext/__tests__/updateMessage.test.tsx +92 -0
  105. package/src/contexts/messageInputContext/__tests__/uploadFile.test.tsx +76 -0
  106. package/src/contexts/messageInputContext/__tests__/uploadImage.test.tsx +55 -0
  107. package/src/contexts/messageInputContext/__tests__/useMessageDetailsForState.test.tsx +62 -0
  108. package/src/mock-builders/generator/attachment.js +4 -2
  109. package/src/utils/getUrlOfImageAttachment.ts +1 -1
  110. package/src/version.json +1 -1
@@ -0,0 +1,116 @@
1
+ export function generateChannel(customValues: any): {
2
+ _client: {};
3
+ data: {
4
+ cid: string;
5
+ config: {
6
+ name: string;
7
+ type: string;
8
+ automod: string;
9
+ automod_behavior: string;
10
+ commands: {
11
+ args: string;
12
+ description: string;
13
+ name: string;
14
+ set: string;
15
+ }[];
16
+ connect_events: boolean;
17
+ created_at: string;
18
+ max_message_length: number;
19
+ message_retention: string;
20
+ mutes: boolean;
21
+ reactions: boolean;
22
+ read_events: boolean;
23
+ replies: boolean;
24
+ search: boolean;
25
+ typing_events: boolean;
26
+ updated_at: string;
27
+ uploads: boolean;
28
+ url_enrichment: boolean;
29
+ };
30
+ created_at: string;
31
+ created_by: {
32
+ banned: boolean;
33
+ created_at: string;
34
+ id: string;
35
+ image: string;
36
+ name: string;
37
+ online: boolean;
38
+ role: string;
39
+ updated_at: string;
40
+ };
41
+ frozen: boolean;
42
+ id: string;
43
+ own_capabilities: string[];
44
+ type: string;
45
+ updated_at: string;
46
+ };
47
+ id: string;
48
+ state: {
49
+ members: {};
50
+ messages: never[];
51
+ setIsUpToDate: jest.Mock<any, any>;
52
+ };
53
+ type: string;
54
+ };
55
+ export function generateChannelResponse(customValues?: {
56
+ channel: {};
57
+ id: string;
58
+ type: string;
59
+ }): {
60
+ channel: {
61
+ id: string;
62
+ type: string;
63
+ user: {
64
+ banned: boolean;
65
+ created_at: string;
66
+ id: string;
67
+ image: string;
68
+ name: string;
69
+ online: boolean;
70
+ role: string;
71
+ updated_at: string;
72
+ };
73
+ cid: string;
74
+ config: {
75
+ name: string;
76
+ type: string;
77
+ automod: string;
78
+ automod_behavior: string;
79
+ commands: {
80
+ args: string;
81
+ description: string;
82
+ name: string;
83
+ set: string;
84
+ }[];
85
+ connect_events: boolean;
86
+ created_at: string;
87
+ max_message_length: number;
88
+ message_retention: string;
89
+ mutes: boolean;
90
+ reactions: boolean;
91
+ read_events: boolean;
92
+ replies: boolean;
93
+ search: boolean;
94
+ typing_events: boolean;
95
+ updated_at: string;
96
+ uploads: boolean;
97
+ url_enrichment: boolean;
98
+ };
99
+ created_at: string;
100
+ created_by: {
101
+ banned: boolean;
102
+ created_at: string;
103
+ id: string;
104
+ image: string;
105
+ name: string;
106
+ online: boolean;
107
+ role: string;
108
+ updated_at: string;
109
+ };
110
+ frozen: boolean;
111
+ own_capabilities: string[];
112
+ updated_at: string;
113
+ };
114
+ members: never[];
115
+ messages: never[];
116
+ };
@@ -0,0 +1,38 @@
1
+ export function generateMessage(options?: {}): {
2
+ attachments: never[];
3
+ created_at: any;
4
+ html: string;
5
+ id: string;
6
+ text: string;
7
+ type: string;
8
+ updated_at: any;
9
+ user: {
10
+ banned: boolean;
11
+ created_at: string;
12
+ id: string;
13
+ image: string;
14
+ name: string;
15
+ online: boolean;
16
+ role: string;
17
+ updated_at: string;
18
+ };
19
+ };
20
+ export function generateStaticMessage(seed: any, options: any, date: any): {
21
+ attachments: never[];
22
+ created_at: any;
23
+ html: string;
24
+ id: string;
25
+ text: string;
26
+ type: string;
27
+ updated_at: any;
28
+ user: {
29
+ banned: boolean;
30
+ created_at: string;
31
+ id: string;
32
+ image: string;
33
+ name: string;
34
+ online: boolean;
35
+ role: string;
36
+ updated_at: string;
37
+ };
38
+ };
@@ -1,9 +1,9 @@
1
1
  export function getUserDefaults(): {
2
2
  banned: boolean;
3
3
  created_at: string;
4
- id: any;
5
- image: any;
6
- name: any;
4
+ id: string;
5
+ image: string;
6
+ name: string;
7
7
  online: boolean;
8
8
  role: string;
9
9
  updated_at: string;
@@ -11,9 +11,9 @@ export function getUserDefaults(): {
11
11
  export function generateUser(options?: {}): {
12
12
  banned: boolean;
13
13
  created_at: string;
14
- id: any;
15
- image: any;
16
- name: any;
14
+ id: string;
15
+ image: string;
16
+ name: string;
17
17
  online: boolean;
18
18
  role: string;
19
19
  updated_at: string;
@@ -21,9 +21,9 @@ export function generateUser(options?: {}): {
21
21
  export function generateStaticUser(userNumber: any): {
22
22
  banned: boolean;
23
23
  created_at: string;
24
- id: any;
25
- image: any;
26
- name: any;
24
+ id: string;
25
+ image: string;
26
+ name: string;
27
27
  online: boolean;
28
28
  role: string;
29
29
  updated_at: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stream-chat-react-native-core",
3
3
  "description": "The official React Native and Expo components for Stream Chat, a service for building chat applications",
4
- "version": "4.9.0-beta.1",
4
+ "version": "4.9.0-beta.4",
5
5
  "author": {
6
6
  "company": "Stream.io Inc",
7
7
  "name": "Stream.io Inc"
@@ -34,7 +34,8 @@
34
34
  "prepare-distribution": "cd examples/SampleApp && npm version patch && react-native-version && git add ./ && git commit -m 'Bump build version' --no-verify",
35
35
  "prettier": "prettier --list-different '**/*.{js,ts,tsx,md,json}' .eslintrc.json ../.prettierrc .babelrc",
36
36
  "prettier-fix": "prettier --write '**/*.{js,ts,tsx,md,json}' .eslintrc.json ../.prettierrc .babelrc",
37
- "test:unit": "TZ=UTC jest --coverage",
37
+ "test:coverage": "yarn test:unit --coverage",
38
+ "test:unit": "TZ=UTC jest",
38
39
  "validate-translations": "node bin/validate-translations.js",
39
40
  "get-version": "echo $npm_package_version",
40
41
  "version": "bash ./bin/before-tag.sh",
@@ -79,7 +80,7 @@
79
80
  "react-art": "^17.0.2",
80
81
  "react-native-markdown-package": "1.8.1",
81
82
  "react-native-url-polyfill": "^1.3.0",
82
- "stream-chat": "6.2.0"
83
+ "stream-chat": "6.7.0"
83
84
  },
84
85
  "peerDependencies": {
85
86
  "react-native-svg": "^12.1.0"
@@ -87,18 +88,18 @@
87
88
  "devDependencies": {
88
89
  "@babel/cli": "^7.12.17",
89
90
  "@babel/core": "^7.12.9",
90
- "@babel/runtime": "^7.12.5",
91
91
  "@babel/plugin-proposal-object-rest-spread": "7.13.8",
92
92
  "@babel/plugin-transform-runtime": "7.13.10",
93
93
  "@babel/polyfill": "7.12.1",
94
94
  "@babel/preset-env": "7.13.12",
95
95
  "@babel/preset-typescript": "7.13.0",
96
+ "@babel/runtime": "^7.12.5",
96
97
  "@react-native-community/eslint-config": "2.0.0",
97
98
  "@react-native-community/eslint-plugin": "1.1.0",
98
99
  "@react-native-community/netinfo": "6.0.0",
99
100
  "@testing-library/jest-native": "4.0.4",
100
- "@testing-library/react-native": "9.0.0",
101
101
  "@testing-library/react-hooks": "7.0.2",
102
+ "@testing-library/react-native": "9.0.0",
102
103
  "@types/eslint": "7.2.10",
103
104
  "@types/jest": "26.0.23",
104
105
  "@types/lodash": "4.14.169",
@@ -106,6 +107,7 @@
106
107
  "@types/react": "17.0.5",
107
108
  "@types/react-native": "0.67.3",
108
109
  "@types/react-test-renderer": "17.0.1",
110
+ "@types/uuid": "^8.3.4",
109
111
  "@typescript-eslint/eslint-plugin": "^5.7.0",
110
112
  "@typescript-eslint/parser": "^5.7.0",
111
113
  "babel-eslint": "10.1.0",
@@ -212,7 +212,7 @@ const GalleryWithContext = <
212
212
  ]}
213
213
  testID={`gallery-${invertedDirections ? 'row' : 'column'}-${colIndex}`}
214
214
  >
215
- {rows.map(({ height, resizeMode, type, url, width }, rowIndex) => {
215
+ {rows.map(({ height, resizeMode, thumb_url, type, url, width }, rowIndex) => {
216
216
  const openImageViewer = () => {
217
217
  if (!legacyImageViewerSwipeBehaviour && message) {
218
218
  // Added if-else to keep the logic readable, instead of DRY.
@@ -307,6 +307,7 @@ const GalleryWithContext = <
307
307
  width: width - 1,
308
308
  },
309
309
  ]}
310
+ thumb_url={thumb_url}
310
311
  />
311
312
  ) : (
312
313
  <View style={styles.imageContainerStyle}>
@@ -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
- <View {...rest} style={[styles.container, container, style]}>
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
- </View>
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 { generateImageAttachment } from '../../../mock-builders/generator/attachment';
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({
@@ -6,6 +6,7 @@ export type Thumbnail = {
6
6
  url: string;
7
7
  width: number;
8
8
  id?: string;
9
+ thumb_url?: string;
9
10
  type?: string;
10
11
  };
11
12
 
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
- import { StyleSheet, TextInput, TextInputProps } from 'react-native';
2
+ import { I18nManager, StyleSheet, TextInput, TextInputProps } from 'react-native';
3
3
 
4
4
  import throttle from 'lodash/throttle';
5
5
 
@@ -417,6 +417,7 @@ const AutoCompleteInputWithContext = <
417
417
  {
418
418
  color: black,
419
419
  maxHeight: (textHeight || 17) * numberOfLines,
420
+ textAlign: I18nManager.isRTL ? 'right' : 'left',
420
421
  },
421
422
  inputBox,
422
423
  ]}
@@ -51,7 +51,7 @@ const styles = StyleSheet.create({
51
51
  title: {
52
52
  fontSize: 14,
53
53
  fontWeight: 'bold',
54
- paddingRight: 8,
54
+ paddingHorizontal: 8,
55
55
  },
56
56
  });
57
57
 
@@ -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({ image_url: cur.asset_url, type: 'video' });
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: 3,
75
+ marginTop: 2,
75
76
  },
76
77
  });
77
78
 
@@ -105,9 +106,9 @@ const UnsupportedFileTypeOrFileSizeIndicator = ({
105
106
  </Text>
106
107
  </View>
107
108
  ) : (
108
- <Text style={[styles.fileSizeText, { color: grey }, fileSizeText]}>
109
- {item.file.duration ? item.file.duration : getFileSizeDisplayText(item.file.size)}
110
- </Text>
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
- paddingLeft: 10,
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: 4,
57
+ marginTop: 6,
58
58
  },
59
59
  warningText: {
60
60
  alignItems: 'center',
@@ -286,6 +286,7 @@ Array [
286
286
  Object {
287
287
  "color": "#000000",
288
288
  "maxHeight": 85,
289
+ "textAlign": "left",
289
290
  },
290
291
  Object {},
291
292
  ]
@@ -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 } = useMessageInputContext<StreamChatGenerics>();
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
+ });
@@ -1623,6 +1623,7 @@ exports[`Thread should match thread snapshot 1`] = `
1623
1623
  Object {
1624
1624
  "color": "#000000",
1625
1625
  "maxHeight": 85,
1626
+ "textAlign": "left",
1626
1627
  },
1627
1628
  Object {},
1628
1629
  ]
@@ -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);