stream-chat-react-native-core 5.36.1-beta.2 → 5.36.1-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 (50) hide show
  1. package/lib/commonjs/components/AttachmentPicker/components/AttachmentPickerItem.js.map +1 -1
  2. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +1 -0
  3. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  4. package/lib/commonjs/components/MessageInput/MessageInput.js +156 -84
  5. package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
  6. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecorder.js +1 -0
  7. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecorder.js.map +1 -1
  8. package/lib/commonjs/components/MessageInput/hooks/useAudioController.js +51 -50
  9. package/lib/commonjs/components/MessageInput/hooks/useAudioController.js.map +1 -1
  10. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +283 -226
  11. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  12. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +11 -5
  13. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  14. package/lib/commonjs/version.json +1 -1
  15. package/lib/module/components/AttachmentPicker/components/AttachmentPickerItem.js.map +1 -1
  16. package/lib/module/components/MessageInput/FileUploadPreview.js +1 -0
  17. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  18. package/lib/module/components/MessageInput/MessageInput.js +156 -84
  19. package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
  20. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecorder.js +1 -0
  21. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecorder.js.map +1 -1
  22. package/lib/module/components/MessageInput/hooks/useAudioController.js +51 -50
  23. package/lib/module/components/MessageInput/hooks/useAudioController.js.map +1 -1
  24. package/lib/module/contexts/messageInputContext/MessageInputContext.js +283 -226
  25. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  26. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +11 -5
  27. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  28. package/lib/module/version.json +1 -1
  29. package/lib/typescript/components/AttachmentPicker/components/AttachmentPickerItem.d.ts +1 -1
  30. package/lib/typescript/components/AttachmentPicker/components/AttachmentPickerItem.d.ts.map +1 -1
  31. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts.map +1 -1
  32. package/lib/typescript/components/MessageInput/MessageInput.d.ts +1 -1
  33. package/lib/typescript/components/MessageInput/MessageInput.d.ts.map +1 -1
  34. package/lib/typescript/components/MessageInput/hooks/useAudioController.d.ts.map +1 -1
  35. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  36. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +1 -2
  37. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts.map +1 -1
  38. package/lib/typescript/contexts/messageInputContext/hooks/useMessageDetailsForState.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx +1 -2
  41. package/src/components/MessageInput/FileUploadPreview.tsx +1 -0
  42. package/src/components/MessageInput/MessageInput.tsx +112 -84
  43. package/src/components/MessageInput/__tests__/MessageInput.test.js +60 -1
  44. package/src/components/MessageInput/components/AudioRecorder/AudioRecorder.tsx +1 -1
  45. package/src/components/MessageInput/hooks/useAudioController.tsx +15 -14
  46. package/src/contexts/messageInputContext/MessageInputContext.tsx +120 -91
  47. package/src/contexts/messageInputContext/__tests__/sendMessage.test.tsx +5 -0
  48. package/src/contexts/messageInputContext/__tests__/updateMessage.test.tsx +5 -0
  49. package/src/contexts/messageInputContext/hooks/useMessageDetailsForState.ts +8 -3
  50. package/src/version.json +1 -1
@@ -1,5 +1,12 @@
1
- import type { LegacyRef } from 'react';
2
- import React, { PropsWithChildren, useContext, useEffect, useRef, useState } from 'react';
1
+ import React, {
2
+ LegacyRef,
3
+ PropsWithChildren,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
3
10
  import { Alert, Keyboard, Linking, TextInput, TextInputProps } from 'react-native';
4
11
 
5
12
  import uniq from 'lodash/uniq';
@@ -46,7 +53,7 @@ import type { SendButtonProps } from '../../components/MessageInput/SendButton';
46
53
  import type { UploadProgressIndicatorProps } from '../../components/MessageInput/UploadProgressIndicator';
47
54
  import type { MessageType } from '../../components/MessageList/hooks/useMessageList';
48
55
  import type { Emoji } from '../../emoji-data';
49
- import { pickDocument, pickImage, takePhoto } from '../../native';
56
+ import { isImageMediaLibraryAvailable, pickDocument, pickImage, takePhoto } from '../../native';
50
57
  import {
51
58
  Asset,
52
59
  DefaultStreamChatGenerics,
@@ -657,7 +664,7 @@ export const MessageInputProvider = <
657
664
  );
658
665
  }
659
666
  if (!photo.cancelled) {
660
- setSelectedImages((images) => [...images, photo]);
667
+ await uploadNewImage(photo);
661
668
  }
662
669
  };
663
670
 
@@ -677,14 +684,11 @@ export const MessageInputProvider = <
677
684
  );
678
685
  }
679
686
  if (result.assets && result.assets.length > 0) {
680
- result.assets.forEach((asset) => {
687
+ result.assets.forEach(async (asset) => {
681
688
  if (asset.type.includes('image')) {
682
- setSelectedImages((prevImages) => [...prevImages, asset]);
689
+ await uploadNewImage(asset);
683
690
  } else {
684
- setSelectedFiles((prevFiles) => [
685
- ...prevFiles,
686
- { ...asset, mimeType: asset.type, type: FileTypes.Video },
687
- ]);
691
+ await uploadNewFile({ ...asset, mimeType: asset.type, type: FileTypes.Video });
688
692
  }
689
693
  });
690
694
  }
@@ -693,30 +697,30 @@ export const MessageInputProvider = <
693
697
  /**
694
698
  * Function to open the attachment picker if the MediaLibary is installed.
695
699
  */
696
- const openAttachmentPicker = () => {
700
+ const openAttachmentPicker = useCallback(() => {
697
701
  Keyboard.dismiss();
698
702
  setSelectedPicker('images');
699
703
  openPicker();
700
- };
704
+ }, [openPicker, setSelectedPicker]);
701
705
 
702
706
  /**
703
707
  * Function to close the attachment picker if the MediaLibrary is installed.
704
708
  */
705
- const closeAttachmentPicker = () => {
709
+ const closeAttachmentPicker = useCallback(() => {
706
710
  setSelectedPicker(undefined);
707
711
  closePicker();
708
- };
712
+ }, [closePicker, setSelectedPicker]);
709
713
 
710
714
  /**
711
715
  * Function to toggle the attachment picker if the MediaLibrary is installed.
712
716
  */
713
- const toggleAttachmentPicker = () => {
717
+ const toggleAttachmentPicker = useCallback(() => {
714
718
  if (selectedPicker) {
715
719
  closeAttachmentPicker();
716
720
  } else {
717
721
  openAttachmentPicker();
718
722
  }
719
- };
723
+ }, [closeAttachmentPicker, openAttachmentPicker, selectedPicker]);
720
724
 
721
725
  const onSelectItem = (item: UserResponse<StreamChatGenerics>) => {
722
726
  setMentionedUsers((prevMentionedUsers) => [...prevMentionedUsers, item.id]);
@@ -740,7 +744,7 @@ export const MessageInputProvider = <
740
744
  });
741
745
 
742
746
  if (!result.cancelled && result.assets) {
743
- result.assets.forEach((asset) => {
747
+ result.assets.forEach(async (asset) => {
744
748
  /**
745
749
  * TODO: The current tight coupling of images to the image
746
750
  * picker does not allow images picked from the file picker
@@ -748,26 +752,40 @@ export const MessageInputProvider = <
748
752
  * This should be updated alongside allowing image a file
749
753
  * uploads together.
750
754
  */
751
- uploadNewFile(asset);
755
+ await uploadNewFile(asset);
752
756
  });
753
757
  }
754
758
  };
755
759
 
756
- const removeFile = (id: string) => {
757
- if (fileUploads.some((file) => file.id === id)) {
758
- setFileUploads((prevFileUploads) => prevFileUploads.filter((file) => file.id !== id));
759
- setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads - 1);
760
- }
761
- };
760
+ const removeFile = useCallback(
761
+ (id: string) => {
762
+ if (fileUploads.some((file) => file.id === id)) {
763
+ setFileUploads((prevFileUploads) => prevFileUploads.filter((file) => file.id !== id));
764
+ setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads - 1);
765
+ }
766
+ },
767
+ [fileUploads, setFileUploads, setNumberOfUploads],
768
+ );
762
769
 
763
- const removeImage = (id: string) => {
764
- if (imageUploads.some((image) => image.id === id)) {
765
- setImageUploads((prevImageUploads) => prevImageUploads.filter((image) => image.id !== id));
766
- setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads - 1);
767
- }
768
- };
770
+ const removeImage = useCallback(
771
+ (id: string) => {
772
+ if (imageUploads.some((image) => image.id === id)) {
773
+ setImageUploads((prevImageUploads) => prevImageUploads.filter((image) => image.id !== id));
774
+ setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads - 1);
775
+ }
776
+ },
777
+ [imageUploads, setImageUploads, setNumberOfUploads],
778
+ );
769
779
 
770
780
  const resetInput = (pendingAttachments: Attachment<StreamChatGenerics>[] = []) => {
781
+ /**
782
+ * If the MediaLibrary is available, reset the selected files and images
783
+ */
784
+ if (isImageMediaLibraryAvailable()) {
785
+ setSelectedFiles([]);
786
+ setSelectedImages([]);
787
+ }
788
+
771
789
  setFileUploads([]);
772
790
  setGiphyActive(false);
773
791
  setShowMoreOptions(true);
@@ -1253,87 +1271,98 @@ export const MessageInputProvider = <
1253
1271
  };
1254
1272
 
1255
1273
  const uploadNewFile = async (file: File) => {
1256
- const id: string = generateRandomId();
1257
- const fileConfig = getFileUploadConfig();
1258
- const { size_limit } = fileConfig;
1274
+ try {
1275
+ const id: string = generateRandomId();
1276
+ const fileConfig = getFileUploadConfig();
1277
+ const { size_limit } = fileConfig;
1259
1278
 
1260
- const isAllowed = isUploadAllowed({ config: fileConfig, file });
1279
+ const isAllowed = isUploadAllowed({ config: fileConfig, file });
1261
1280
 
1262
- const sizeLimit = size_limit || MAX_FILE_SIZE_TO_UPLOAD;
1281
+ const sizeLimit = size_limit || MAX_FILE_SIZE_TO_UPLOAD;
1263
1282
 
1264
- if (file.size && file.size > sizeLimit) {
1265
- Alert.alert(
1266
- t('File is too large: {{ size }}, maximum upload size is {{ limit }}', {
1267
- limit: prettifyFileSize(sizeLimit),
1268
- size: prettifyFileSize(file.size),
1269
- }),
1270
- );
1271
- setSelectedFiles(selectedFiles.filter((selectedFile) => selectedFile.uri !== file.uri));
1272
- return;
1273
- }
1283
+ if (file.size && file.size > sizeLimit) {
1284
+ Alert.alert(
1285
+ t('File is too large: {{ size }}, maximum upload size is {{ limit }}', {
1286
+ limit: prettifyFileSize(sizeLimit),
1287
+ size: prettifyFileSize(file.size),
1288
+ }),
1289
+ );
1290
+ setSelectedFiles(selectedFiles.filter((selectedFile) => selectedFile.uri !== file.uri));
1291
+ return;
1292
+ }
1274
1293
 
1275
- const fileState = isAllowed ? FileState.UPLOADING : FileState.NOT_SUPPORTED;
1294
+ const fileState = isAllowed ? FileState.UPLOADING : FileState.NOT_SUPPORTED;
1276
1295
 
1277
- // If file type is explicitly provided while upload we use it, else we derive the file type.
1278
- const fileType = file.type || file.mimeType?.split('/')[0];
1296
+ // If file type is explicitly provided while upload we use it, else we derive the file type.
1297
+ const fileType = file.type || file.mimeType?.split('/')[0];
1279
1298
 
1280
- const newFile: FileUpload = {
1281
- duration: file.duration || 0,
1282
- file,
1283
- id: file.id || id,
1284
- state: fileState,
1285
- type: fileType,
1286
- };
1299
+ const newFile: FileUpload = {
1300
+ duration: file.duration || 0,
1301
+ file,
1302
+ id: file.id || id,
1303
+ state: fileState,
1304
+ type: fileType,
1305
+ url: file.uri,
1306
+ };
1287
1307
 
1288
- await Promise.all([
1289
- setFileUploads((prevFileUploads) => prevFileUploads.concat([newFile])),
1290
- setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads + 1),
1291
- ]);
1308
+ await Promise.all([
1309
+ setFileUploads((prevFileUploads) => prevFileUploads.concat([newFile])),
1310
+ setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads + 1),
1311
+ ]);
1292
1312
 
1293
- if (isAllowed) {
1294
- uploadFile({ newFile });
1313
+ if (isAllowed) {
1314
+ await uploadFile({ newFile });
1315
+ }
1316
+ } catch (error) {
1317
+ console.log('Error uploading file', error);
1295
1318
  }
1296
1319
  };
1297
1320
 
1298
1321
  const uploadNewImage = async (image: Partial<Asset>) => {
1299
- const id = generateRandomId();
1300
- const imageUploadConfig = getImageUploadConfig();
1322
+ try {
1323
+ const id = generateRandomId();
1324
+ const imageUploadConfig = getImageUploadConfig();
1301
1325
 
1302
- const { size_limit } = imageUploadConfig;
1326
+ const { size_limit } = imageUploadConfig;
1303
1327
 
1304
- const isAllowed = isUploadAllowed({ config: imageUploadConfig, file: image });
1328
+ const isAllowed = isUploadAllowed({ config: imageUploadConfig, file: image });
1305
1329
 
1306
- const sizeLimit = size_limit || MAX_FILE_SIZE_TO_UPLOAD;
1330
+ const sizeLimit = size_limit || MAX_FILE_SIZE_TO_UPLOAD;
1307
1331
 
1308
- if (image.size && image?.size > sizeLimit) {
1309
- Alert.alert(
1310
- t('File is too large: {{ size }}, maximum upload size is {{ limit }}', {
1311
- limit: prettifyFileSize(sizeLimit),
1312
- size: prettifyFileSize(image.size),
1313
- }),
1314
- );
1315
- setSelectedImages(selectedImages.filter((selectedImage) => selectedImage.uri !== image.uri));
1316
- return;
1317
- }
1332
+ if (image.size && image?.size > sizeLimit) {
1333
+ Alert.alert(
1334
+ t('File is too large: {{ size }}, maximum upload size is {{ limit }}', {
1335
+ limit: prettifyFileSize(sizeLimit),
1336
+ size: prettifyFileSize(image.size),
1337
+ }),
1338
+ );
1339
+ setSelectedImages(
1340
+ selectedImages.filter((selectedImage) => selectedImage.uri !== image.uri),
1341
+ );
1342
+ return;
1343
+ }
1318
1344
 
1319
- const imageState = isAllowed ? FileState.UPLOADING : FileState.NOT_SUPPORTED;
1345
+ const imageState = isAllowed ? FileState.UPLOADING : FileState.NOT_SUPPORTED;
1320
1346
 
1321
- const newImage: ImageUpload = {
1322
- file: image,
1323
- height: image.height,
1324
- id,
1325
- state: imageState,
1326
- url: image.uri,
1327
- width: image.width,
1328
- };
1347
+ const newImage: ImageUpload = {
1348
+ file: image,
1349
+ height: image.height,
1350
+ id,
1351
+ state: imageState,
1352
+ url: image.uri,
1353
+ width: image.width,
1354
+ };
1329
1355
 
1330
- await Promise.all([
1331
- setImageUploads((prevImageUploads) => prevImageUploads.concat([newImage])),
1332
- setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads + 1),
1333
- ]);
1356
+ await Promise.all([
1357
+ setImageUploads((prevImageUploads) => prevImageUploads.concat([newImage])),
1358
+ setNumberOfUploads((prevNumberOfUploads) => prevNumberOfUploads + 1),
1359
+ ]);
1334
1360
 
1335
- if (isAllowed) {
1336
- uploadImage({ newImage });
1361
+ if (isAllowed) {
1362
+ await uploadImage({ newImage });
1363
+ }
1364
+ } catch (error) {
1365
+ console.log('Error uploading image', error);
1337
1366
  }
1338
1367
  };
1339
1368
 
@@ -12,6 +12,7 @@ import { generateMessage } from '../../../mock-builders/generator/message';
12
12
  import { generateUser } from '../../../mock-builders/generator/user';
13
13
  import type { DefaultStreamChatGenerics } from '../../../types/types';
14
14
  import { FileState } from '../../../utils/utils';
15
+ import * as AttachmentPickerContext from '../../attachmentPickerContext/AttachmentPickerContext';
15
16
  import {
16
17
  InputMessageInputContextValue,
17
18
  MessageInputContextValue,
@@ -39,6 +40,10 @@ const Wrapper = <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultS
39
40
 
40
41
  const newMessage = generateMessage({ id: 'new-id' });
41
42
  describe("MessageInputContext's sendMessage", () => {
43
+ jest.spyOn(AttachmentPickerContext, 'useAttachmentPickerContext').mockImplementation(() => ({
44
+ setSelectedFiles: jest.fn(),
45
+ setSelectedImages: jest.fn(),
46
+ }));
42
47
  const message: boolean | MessageType<DefaultStreamChatGenerics> = generateMessage({
43
48
  created_at: 'Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)',
44
49
  id: '7a85f744-cc89-4f82-a1d4-5456432cc8bf',
@@ -11,6 +11,7 @@ import { ChatContextValue, ChatProvider } from '../../../contexts/chatContext/Ch
11
11
  import { generateMessage } from '../../../mock-builders/generator/message';
12
12
  import { generateUser } from '../../../mock-builders/generator/user';
13
13
  import type { DefaultStreamChatGenerics } from '../../../types/types';
14
+ import * as AttachmentPickerContext from '../../attachmentPickerContext/AttachmentPickerContext';
14
15
  import {
15
16
  InputMessageInputContextValue,
16
17
  MessageInputContextValue,
@@ -49,6 +50,10 @@ const Wrapper = <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultS
49
50
  );
50
51
 
51
52
  describe("MessageInputContext's updateMessage", () => {
53
+ jest.spyOn(AttachmentPickerContext, 'useAttachmentPickerContext').mockImplementation(() => ({
54
+ setSelectedFiles: jest.fn(),
55
+ setSelectedImages: jest.fn(),
56
+ }));
52
57
  const clearEditingStateMock = jest.fn();
53
58
  const generatedMessage: boolean | MessageType<DefaultStreamChatGenerics> = generateMessage({
54
59
  created_at: 'Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)',
@@ -8,7 +8,7 @@ import {
8
8
  FileUpload,
9
9
  ImageUpload,
10
10
  } from '../../../types/types';
11
- import { generateRandomId } from '../../../utils/utils';
11
+ import { generateRandomId, stringifyMessage } from '../../../utils/utils';
12
12
 
13
13
  import type { MessageInputContextValue } from '../MessageInputContext';
14
14
 
@@ -37,8 +37,7 @@ export const useMessageDetailsForState = <
37
37
  // eslint-disable-next-line react-hooks/exhaustive-deps
38
38
  }, [text, imageUploads.length, fileUploads.length]);
39
39
 
40
- const messageValue =
41
- message === undefined ? '' : `${message.id}${message.text}${message.updated_at}`;
40
+ const messageValue = message ? stringifyMessage(message) : '';
42
41
 
43
42
  useEffect(() => {
44
43
  if (message && Array.isArray(message?.mentioned_users)) {
@@ -67,9 +66,11 @@ export const useMessageDetailsForState = <
67
66
  } else if (attachment.type === FileTypes.Video) {
68
67
  return {
69
68
  file: {
69
+ duration: attachment.duration,
70
70
  mimeType: attachment.mime_type,
71
71
  name: attachment.title || '',
72
72
  size: attachment.file_size,
73
+ uri: attachment.asset_url,
73
74
  },
74
75
  id,
75
76
  state: 'finished',
@@ -96,6 +97,7 @@ export const useMessageDetailsForState = <
96
97
  mimeType: attachment.mime_type,
97
98
  name: attachment.title || '',
98
99
  size: attachment.file_size,
100
+ uri: attachment.asset_url,
99
101
  },
100
102
  id,
101
103
  state: 'finished',
@@ -107,6 +109,7 @@ export const useMessageDetailsForState = <
107
109
  mimeType: attachment.mime_type,
108
110
  name: attachment.title || '',
109
111
  size: attachment.file_size,
112
+ uri: attachment.asset_url,
110
113
  },
111
114
  id,
112
115
  state: 'finished',
@@ -128,9 +131,11 @@ export const useMessageDetailsForState = <
128
131
  const id = generateRandomId();
129
132
  newImageUploads.push({
130
133
  file: {
134
+ height: attachment.original_height,
131
135
  name: attachment.fallback,
132
136
  size: attachment.file_size,
133
137
  type: attachment.type,
138
+ width: attachment.original_width,
134
139
  },
135
140
  id,
136
141
  state: 'finished',
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "5.36.1-beta.2"
2
+ "version": "5.36.1-beta.4"
3
3
  }