stream-chat-react-native-core 5.6.0-beta.0 → 5.6.0-beta.2

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 (171) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +21 -16
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/GalleryImage.js +3 -3
  4. package/lib/commonjs/components/Attachment/GalleryImage.js.map +1 -1
  5. package/lib/commonjs/components/Channel/Channel.js +43 -33
  6. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  7. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +5 -1
  8. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  9. package/lib/commonjs/components/Chat/Chat.js +1 -1
  10. package/lib/commonjs/components/Chat/Chat.js.map +1 -1
  11. package/lib/commonjs/components/Chat/hooks/useAppSettings.js +51 -22
  12. package/lib/commonjs/components/Chat/hooks/useAppSettings.js.map +1 -1
  13. package/lib/commonjs/components/Chat/hooks/useIsOnline.js +1 -1
  14. package/lib/commonjs/components/Chat/hooks/useIsOnline.js.map +1 -1
  15. package/lib/commonjs/components/Message/hooks/useMessageActions.js +2 -2
  16. package/lib/commonjs/components/Message/hooks/useMessageActions.js.map +1 -1
  17. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +18 -21
  18. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  19. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js +7 -32
  20. package/lib/commonjs/components/MessageInput/ImageUploadPreview.js.map +1 -1
  21. package/lib/commonjs/components/index.js +1 -1
  22. package/lib/commonjs/components/index.js.map +1 -1
  23. package/lib/commonjs/contexts/chatContext/ChatContext.js.map +1 -1
  24. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +128 -89
  25. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  26. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +1 -0
  27. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  28. package/lib/commonjs/store/QuickSqliteClient.js +46 -1
  29. package/lib/commonjs/store/QuickSqliteClient.js.map +1 -1
  30. package/lib/commonjs/store/QuickSqliteClient_v4.js +112 -0
  31. package/lib/commonjs/store/QuickSqliteClient_v4.js.map +1 -0
  32. package/lib/commonjs/store/apis/getAppSettings.js +23 -0
  33. package/lib/commonjs/store/apis/getAppSettings.js.map +1 -0
  34. package/lib/commonjs/store/apis/getPendingTasks.js.map +1 -1
  35. package/lib/commonjs/store/apis/index.js +26 -0
  36. package/lib/commonjs/store/apis/index.js.map +1 -1
  37. package/lib/commonjs/store/apis/queries/selectChannels.js.map +1 -1
  38. package/lib/commonjs/store/apis/queries/selectMembersForChannels.js.map +1 -1
  39. package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js.map +1 -1
  40. package/lib/commonjs/store/apis/queries/selectReactionsForMessages.js.map +1 -1
  41. package/lib/commonjs/store/apis/queries/selectReadsForChannels.js.map +1 -1
  42. package/lib/commonjs/store/apis/upsertAppSettings.js +26 -0
  43. package/lib/commonjs/store/apis/upsertAppSettings.js.map +1 -0
  44. package/lib/commonjs/store/schema.js +1 -0
  45. package/lib/commonjs/store/schema.js.map +1 -1
  46. package/lib/commonjs/utils/DBSyncManager.js +16 -16
  47. package/lib/commonjs/utils/DBSyncManager.js.map +1 -1
  48. package/lib/commonjs/{components/Message/utils → utils}/removeReservedFields.js +1 -1
  49. package/lib/commonjs/utils/removeReservedFields.js.map +1 -0
  50. package/lib/commonjs/utils/utils.js +2 -2
  51. package/lib/commonjs/utils/utils.js.map +1 -1
  52. package/lib/commonjs/version.json +1 -1
  53. package/lib/module/components/Attachment/Gallery.js +21 -16
  54. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  55. package/lib/module/components/Attachment/GalleryImage.js +3 -3
  56. package/lib/module/components/Attachment/GalleryImage.js.map +1 -1
  57. package/lib/module/components/Channel/Channel.js +43 -33
  58. package/lib/module/components/Channel/Channel.js.map +1 -1
  59. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +5 -1
  60. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  61. package/lib/module/components/Chat/Chat.js +1 -1
  62. package/lib/module/components/Chat/Chat.js.map +1 -1
  63. package/lib/module/components/Chat/hooks/useAppSettings.js +51 -22
  64. package/lib/module/components/Chat/hooks/useAppSettings.js.map +1 -1
  65. package/lib/module/components/Chat/hooks/useIsOnline.js +1 -1
  66. package/lib/module/components/Chat/hooks/useIsOnline.js.map +1 -1
  67. package/lib/module/components/Message/hooks/useMessageActions.js +2 -2
  68. package/lib/module/components/Message/hooks/useMessageActions.js.map +1 -1
  69. package/lib/module/components/MessageInput/FileUploadPreview.js +18 -21
  70. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  71. package/lib/module/components/MessageInput/ImageUploadPreview.js +7 -32
  72. package/lib/module/components/MessageInput/ImageUploadPreview.js.map +1 -1
  73. package/lib/module/components/index.js +1 -1
  74. package/lib/module/components/index.js.map +1 -1
  75. package/lib/module/contexts/chatContext/ChatContext.js.map +1 -1
  76. package/lib/module/contexts/messageInputContext/MessageInputContext.js +128 -89
  77. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  78. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +1 -0
  79. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  80. package/lib/module/store/QuickSqliteClient.js +46 -1
  81. package/lib/module/store/QuickSqliteClient.js.map +1 -1
  82. package/lib/module/store/QuickSqliteClient_v4.js +112 -0
  83. package/lib/module/store/QuickSqliteClient_v4.js.map +1 -0
  84. package/lib/module/store/apis/getAppSettings.js +23 -0
  85. package/lib/module/store/apis/getAppSettings.js.map +1 -0
  86. package/lib/module/store/apis/getPendingTasks.js.map +1 -1
  87. package/lib/module/store/apis/index.js +26 -0
  88. package/lib/module/store/apis/index.js.map +1 -1
  89. package/lib/module/store/apis/queries/selectChannels.js.map +1 -1
  90. package/lib/module/store/apis/queries/selectMembersForChannels.js.map +1 -1
  91. package/lib/module/store/apis/queries/selectMessagesForChannels.js.map +1 -1
  92. package/lib/module/store/apis/queries/selectReactionsForMessages.js.map +1 -1
  93. package/lib/module/store/apis/queries/selectReadsForChannels.js.map +1 -1
  94. package/lib/module/store/apis/upsertAppSettings.js +26 -0
  95. package/lib/module/store/apis/upsertAppSettings.js.map +1 -0
  96. package/lib/module/store/schema.js +1 -0
  97. package/lib/module/store/schema.js.map +1 -1
  98. package/lib/module/utils/DBSyncManager.js +16 -16
  99. package/lib/module/utils/DBSyncManager.js.map +1 -1
  100. package/lib/module/{components/Message/utils → utils}/removeReservedFields.js +1 -1
  101. package/lib/module/utils/removeReservedFields.js.map +1 -0
  102. package/lib/module/utils/utils.js +2 -2
  103. package/lib/module/utils/utils.js.map +1 -1
  104. package/lib/module/version.json +1 -1
  105. package/lib/typescript/components/Chat/hooks/useAppSettings.d.ts +2 -2
  106. package/lib/typescript/components/Chat/hooks/useIsOnline.d.ts +1 -1
  107. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +1 -1
  108. package/lib/typescript/components/MessageInput/ImageUploadPreview.d.ts +1 -1
  109. package/lib/typescript/components/index.d.ts +1 -1
  110. package/lib/typescript/contexts/chatContext/ChatContext.d.ts +1 -1
  111. package/lib/typescript/store/QuickSqliteClient.d.ts +4 -1
  112. package/lib/typescript/store/QuickSqliteClient_v4.d.ts +12 -0
  113. package/lib/typescript/store/apis/getAppSettings.d.ts +4 -0
  114. package/lib/typescript/store/apis/getPendingTasks.d.ts +1 -1
  115. package/lib/typescript/store/apis/index.d.ts +2 -0
  116. package/lib/typescript/store/apis/upsertAppSettings.d.ts +6 -0
  117. package/lib/typescript/store/mappers/mapTaskToStorable.d.ts +0 -8
  118. package/lib/typescript/store/schema.d.ts +1 -0
  119. package/lib/typescript/store/types.d.ts +0 -4
  120. package/lib/typescript/utils/DBSyncManager.d.ts +1 -1
  121. package/lib/typescript/{components/Message/utils → utils}/removeReservedFields.d.ts +2 -2
  122. package/lib/typescript/utils/utils.d.ts +1 -1
  123. package/package.json +1 -1
  124. package/src/components/Attachment/Gallery.tsx +5 -1
  125. package/src/components/Attachment/GalleryImage.tsx +2 -0
  126. package/src/components/Attachment/__tests__/Gallery.test.js +9 -2
  127. package/src/components/Attachment/__tests__/Giphy.test.js +9 -5
  128. package/src/components/Channel/Channel.tsx +20 -12
  129. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +6 -4
  130. package/src/components/Chat/Chat.tsx +1 -1
  131. package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx +1 -0
  132. package/src/components/Chat/hooks/useAppSettings.ts +19 -6
  133. package/src/components/Chat/hooks/useIsOnline.ts +1 -1
  134. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +29 -15
  135. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +12 -6
  136. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +9 -4
  137. package/src/components/Message/hooks/useMessageActions.tsx +1 -1
  138. package/src/components/MessageInput/FileUploadPreview.tsx +4 -5
  139. package/src/components/MessageInput/ImageUploadPreview.tsx +10 -35
  140. package/src/components/index.ts +1 -1
  141. package/src/contexts/chatContext/ChatContext.tsx +1 -1
  142. package/src/contexts/messageInputContext/MessageInputContext.tsx +94 -75
  143. package/src/contexts/messageInputContext/__tests__/MessageInputContext.test.tsx +8 -3
  144. package/src/contexts/messageInputContext/__tests__/__snapshots__/sendMessage.test.tsx.snap +0 -3
  145. package/src/contexts/messageInputContext/__tests__/uploadFile.test.tsx +16 -6
  146. package/src/contexts/messageInputContext/hooks/useMessageDetailsForState.ts +1 -0
  147. package/src/store/QuickSqliteClient.ts +49 -5
  148. package/src/store/QuickSqliteClient_v4.ts +98 -0
  149. package/src/store/apis/getAppSettings.ts +19 -0
  150. package/src/store/apis/getPendingTasks.ts +2 -1
  151. package/src/store/apis/index.ts +2 -0
  152. package/src/store/apis/queries/selectChannels.ts +4 -1
  153. package/src/store/apis/queries/selectMembersForChannels.ts +1 -1
  154. package/src/store/apis/queries/selectMessagesForChannels.ts +1 -1
  155. package/src/store/apis/queries/selectReactionsForMessages.ts +1 -1
  156. package/src/store/apis/queries/selectReadsForChannels.ts +1 -1
  157. package/src/store/apis/upsertAppSettings.ts +23 -0
  158. package/src/store/schema.ts +2 -0
  159. package/src/store/types.ts +0 -5
  160. package/src/utils/DBSyncManager.ts +1 -1
  161. package/src/{components/Message/utils → utils}/removeReservedFields.ts +7 -3
  162. package/src/utils/utils.ts +7 -6
  163. package/src/version.json +1 -1
  164. package/lib/commonjs/components/Message/utils/removeReservedFields.js.map +0 -1
  165. package/lib/commonjs/utils/pendingTaskUtils.js +0 -302
  166. package/lib/commonjs/utils/pendingTaskUtils.js.map +0 -1
  167. package/lib/module/components/Message/utils/removeReservedFields.js.map +0 -1
  168. package/lib/module/utils/pendingTaskUtils.js +0 -302
  169. package/lib/module/utils/pendingTaskUtils.js.map +0 -1
  170. package/lib/typescript/utils/pendingTaskUtils.d.ts +0 -13
  171. package/src/utils/pendingTaskUtils.ts +0 -131
@@ -38,6 +38,7 @@ import type { UploadProgressIndicatorProps } from '../../components/MessageInput
38
38
  import type { MessageType } from '../../components/MessageList/hooks/useMessageList';
39
39
  import { compressImage, getLocalAssetUri, pickDocument } from '../../native';
40
40
  import type { Asset, DefaultStreamChatGenerics, File, UnknownType } from '../../types/types';
41
+ import { removeReservedFields } from '../../utils/removeReservedFields';
41
42
  import {
42
43
  ACITriggerSettings,
43
44
  ACITriggerSettingsParams,
@@ -490,21 +491,20 @@ export const MessageInputProvider = <
490
491
  return true;
491
492
  }
492
493
 
493
- for (const image of imageUploads) {
494
- if ((!image || image.state === FileState.UPLOAD_FAILED) && !enableOfflineSupport) {
495
- continue;
496
- }
497
-
498
- if (image.state === FileState.UPLOADING) {
499
- // TODO: show error to user that they should wait until image is uploaded
500
- return false;
494
+ const imagesAndFiles = [...imageUploads, ...fileUploads];
495
+ if (enableOfflineSupport) {
496
+ // Allow only if none of the attachments have unsupported status
497
+ for (const file of imagesAndFiles) {
498
+ if (file.state === FileState.NOT_SUPPORTED) {
499
+ return false;
500
+ }
501
501
  }
502
502
 
503
503
  return true;
504
504
  }
505
505
 
506
- for (const file of fileUploads) {
507
- if ((!file || file.state === FileState.UPLOAD_FAILED) && !enableOfflineSupport) {
506
+ for (const file of imagesAndFiles) {
507
+ if (!file || file.state === FileState.UPLOAD_FAILED) {
508
508
  continue;
509
509
  }
510
510
  if (file.state === FileState.UPLOADING) {
@@ -623,6 +623,62 @@ export const MessageInputProvider = <
623
623
  setText('');
624
624
  };
625
625
 
626
+ const mapImageUploadToAttachment = (image: ImageUpload) => {
627
+ const mime_type: string | boolean = lookup(image.file.filename as string);
628
+ return {
629
+ fallback: image.file.name,
630
+ image_url: image.url,
631
+ mime_type: mime_type ? mime_type : undefined,
632
+ original_height: image.height,
633
+ original_width: image.width,
634
+ originalFile: image.file,
635
+ type: 'image',
636
+ } as Attachment;
637
+ };
638
+
639
+ const mapFileUploadToAttachment = (file: FileUpload) => {
640
+ const mime_type: string | boolean = lookup(file.file.name as string);
641
+ if (file.file.type?.startsWith('image/')) {
642
+ return {
643
+ fallback: file.file.name,
644
+ image_url: file.url,
645
+ mime_type: mime_type ? mime_type : undefined,
646
+ originalFile: file.file,
647
+ type: 'image',
648
+ };
649
+ } else if (file.file.type?.startsWith('audio/')) {
650
+ return {
651
+ asset_url: file.url || file.file.uri,
652
+ duration: file.file.duration,
653
+ file_size: file.file.size,
654
+ mime_type: file.file.type,
655
+ originalFile: file.file,
656
+ title: file.file.name,
657
+ type: 'audio',
658
+ };
659
+ } else if (file.file.type?.startsWith('video/')) {
660
+ return {
661
+ asset_url: file.url || file.file.uri,
662
+ duration: file.file.duration,
663
+ file_size: file.file.size,
664
+ mime_type: file.file.type,
665
+ originalFile: file.file,
666
+ thumb_url: file.thumb_url,
667
+ title: file.file.name,
668
+ type: 'video',
669
+ };
670
+ } else {
671
+ return {
672
+ asset_url: file.url || file.file.uri,
673
+ file_size: file.file.size,
674
+ mime_type: file.file.type,
675
+ originalFile: file.file,
676
+ title: file.file.name,
677
+ type: 'file',
678
+ };
679
+ }
680
+ };
681
+
626
682
  // TODO: Figure out why this is async, as it doesn't await any promise.
627
683
  // eslint-disable-next-line require-await
628
684
  const sendMessage = async () => {
@@ -648,6 +704,14 @@ export const MessageInputProvider = <
648
704
 
649
705
  const attachments = [] as Attachment<StreamChatGenerics>[];
650
706
  for (const image of imageUploads) {
707
+ if (enableOfflineSupport) {
708
+ if (image.state === FileState.NOT_SUPPORTED) {
709
+ return;
710
+ }
711
+ attachments.push(mapImageUploadToAttachment(image));
712
+ continue;
713
+ }
714
+
651
715
  if ((!image || image.state === FileState.UPLOAD_FAILED) && !enableOfflineSupport) {
652
716
  continue;
653
717
  }
@@ -667,28 +731,21 @@ export const MessageInputProvider = <
667
731
  }
668
732
 
669
733
  // To get the mime type of the image from the file name and send it as an response for an image
670
- const mime_type: string | boolean = lookup(image.file.filename as string);
671
-
672
- if (
673
- image.state === FileState.UPLOADED ||
674
- image.state === FileState.FINISHED ||
675
- (enableOfflineSupport && image.state === FileState.UPLOAD_FAILED)
676
- ) {
677
- // @ts-ignore
678
- attachments.push({
679
- fallback: image.file.name,
680
- image_url: image.url,
681
- mime_type: mime_type ? mime_type : undefined,
682
- original_height: image.height,
683
- original_width: image.width,
684
- originalFile: image.file,
685
- type: 'image',
686
- });
734
+ if (image.state === FileState.UPLOADED || image.state === FileState.FINISHED) {
735
+ attachments.push(mapImageUploadToAttachment(image));
687
736
  }
688
737
  }
689
738
 
690
739
  for (const file of fileUploads) {
691
- if ((!file || file.state === FileState.UPLOAD_FAILED) && !enableOfflineSupport) {
740
+ if (enableOfflineSupport) {
741
+ if (file.state === FileState.NOT_SUPPORTED) {
742
+ return;
743
+ }
744
+ attachments.push(mapFileUploadToAttachment(file));
745
+ continue;
746
+ }
747
+
748
+ if (!file || file.state === FileState.UPLOAD_FAILED) {
692
749
  continue;
693
750
  }
694
751
 
@@ -697,52 +754,9 @@ export const MessageInputProvider = <
697
754
  sending.current = false;
698
755
  return;
699
756
  }
700
- const mime_type: string | boolean = lookup(file.file.name as string);
701
-
702
- if (
703
- file.state === FileState.UPLOADED ||
704
- file.state === FileState.FINISHED ||
705
- (enableOfflineSupport && file.state === FileState.UPLOAD_FAILED)
706
- ) {
707
- if (file.file.type?.startsWith('image/')) {
708
- attachments.push({
709
- fallback: file.file.name,
710
- image_url: file.url,
711
- mime_type: mime_type ? mime_type : undefined,
712
- originalFile: file.file,
713
- type: 'image',
714
- });
715
- } else if (file.file.type?.startsWith('audio/')) {
716
- attachments.push({
717
- asset_url: file.url || file.file.uri,
718
- duration: file.file.duration,
719
- file_size: file.file.size,
720
- mime_type: file.file.type,
721
- originalFile: file.file,
722
- title: file.file.name,
723
- type: 'audio',
724
- });
725
- } else if (file.file.type?.startsWith('video/')) {
726
- attachments.push({
727
- asset_url: file.url || file.file.uri,
728
- duration: file.file.duration,
729
- file_size: file.file.size,
730
- mime_type: file.file.type,
731
- originalFile: file.file,
732
- thumb_url: file.thumb_url,
733
- title: file.file.name,
734
- type: 'video',
735
- });
736
- } else {
737
- attachments.push({
738
- asset_url: file.url || file.file.uri,
739
- file_size: file.file.size,
740
- mime_type: file.file.type,
741
- originalFile: file.file,
742
- title: file.file.name,
743
- type: 'file',
744
- });
745
- }
757
+
758
+ if (file.state === FileState.UPLOADED || file.state === FileState.FINISHED) {
759
+ attachments.push(mapFileUploadToAttachment(file));
746
760
  }
747
761
  }
748
762
 
@@ -764,7 +778,12 @@ export const MessageInputProvider = <
764
778
  // TODO: Remove this line and show an error when submit fails
765
779
  value.clearEditingState();
766
780
 
767
- const updateMessagePromise = value.editMessage(updatedMessage).then(value.clearEditingState);
781
+ const updateMessagePromise = value
782
+ .editMessage(
783
+ // @ts-ignore
784
+ removeReservedFields(updatedMessage),
785
+ )
786
+ .then(value.clearEditingState);
768
787
  resetInput(attachments);
769
788
  logChatPromiseExecution(updateMessagePromise, 'update message');
770
789
 
@@ -4,6 +4,7 @@ import type { TextInput } from 'react-native';
4
4
 
5
5
  import { act, renderHook } from '@testing-library/react-hooks';
6
6
 
7
+ import { waitFor } from '@testing-library/react-native';
7
8
  import type { AppSettingsAPIResponse, StreamChat } from 'stream-chat';
8
9
 
9
10
  import { ChatContextValue, ChatProvider } from '../../../contexts/chatContext/ChatContext';
@@ -167,7 +168,7 @@ describe('MessageInputContext', () => {
167
168
  expect(result.current.text).toBe('/');
168
169
  });
169
170
 
170
- it('openMentionPicker works', () => {
171
+ it('openMentionPicker works', async () => {
171
172
  const { result } = renderHook(() => useMessageInputContext(), {
172
173
  initialProps: {
173
174
  editing: true,
@@ -180,7 +181,9 @@ describe('MessageInputContext', () => {
180
181
  result.current.openMentionsPicker();
181
182
  });
182
183
 
183
- expect(result.current.text).toBe('@');
184
+ await waitFor(() => {
185
+ expect(result.current.text).toBe('@');
186
+ });
184
187
  });
185
188
 
186
189
  it('openAttachmentPicker works', async () => {
@@ -203,6 +206,8 @@ describe('MessageInputContext', () => {
203
206
  result.current.openAttachmentPicker();
204
207
  });
205
208
 
206
- expect(await result.current.pickFile()).toBe(undefined);
209
+ await waitFor(async () => {
210
+ expect(await result.current.pickFile()).toBe(undefined);
211
+ });
207
212
  });
208
213
  });
@@ -15,7 +15,6 @@ Object {
15
15
  "type": "image",
16
16
  },
17
17
  ],
18
- "created_at": "Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)",
19
18
  "html": "<p>regular</p>",
20
19
  "id": "7a85f744-cc89-4f82-a1d4-5456432cc8bf",
21
20
  "mentioned_users": Array [
@@ -24,8 +23,6 @@ Object {
24
23
  ],
25
24
  "quoted_message": undefined,
26
25
  "text": "",
27
- "type": "regular",
28
- "updated_at": "Sat Jul 02 2022 23:55:13 GMT+0530 (India Standard Time)",
29
26
  "user": Object {
30
27
  "banned": false,
31
28
  "created_at": "2020-04-27T13:39:49.331742Z",
@@ -3,6 +3,8 @@ import { act } from 'react-test-renderer';
3
3
 
4
4
  import { renderHook } from '@testing-library/react-hooks';
5
5
 
6
+ import { waitFor } from '@testing-library/react-native';
7
+
6
8
  import { generateFileUploadPreview } from '../../../mock-builders/generator/attachment';
7
9
  import type { DefaultStreamChatGenerics } from '../../../types/types';
8
10
  import {
@@ -31,7 +33,7 @@ const Wrapper = <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultS
31
33
  );
32
34
 
33
35
  describe("MessageInputContext's uploadFile", () => {
34
- it('uploadFile works', () => {
36
+ it('uploadFile works', async () => {
35
37
  const doDocUploadRequestMock = jest.fn().mockResolvedValue({
36
38
  file: {
37
39
  url: '',
@@ -46,16 +48,20 @@ describe("MessageInputContext's uploadFile", () => {
46
48
  wrapper: Wrapper,
47
49
  });
48
50
 
49
- expect(result.current.fileUploads).toHaveLength(0);
51
+ await waitFor(() => {
52
+ expect(result.current.fileUploads).toHaveLength(0);
53
+ });
50
54
 
51
55
  act(() => {
52
56
  result.current.uploadFile({ newFile: generateFileUploadPreview({ state: '' }) });
53
57
  });
54
58
 
55
- expect(doDocUploadRequestMock).toHaveBeenCalled();
59
+ await waitFor(() => {
60
+ expect(doDocUploadRequestMock).toHaveBeenCalled();
61
+ });
56
62
  });
57
63
 
58
- it('uploadFile catch block gets executed', () => {
64
+ it('uploadFile catch block gets executed', async () => {
59
65
  const doDocUploadRequestMock = jest.fn().mockResolvedValue(new Error('This is an error'));
60
66
  const { result } = renderHook(() => useMessageInputContext(), {
61
67
  initialProps: {
@@ -65,12 +71,16 @@ describe("MessageInputContext's uploadFile", () => {
65
71
  wrapper: Wrapper,
66
72
  });
67
73
 
68
- expect(result.current.fileUploads).toHaveLength(0);
74
+ await waitFor(() => {
75
+ expect(result.current.fileUploads).toHaveLength(0);
76
+ });
69
77
 
70
78
  act(() => {
71
79
  result.current.uploadFile({ newFile: generateFileUploadPreview({ state: '' }) });
72
80
  });
73
81
 
74
- expect(result.current.fileUploads.length).toBe(0);
82
+ await waitFor(() => {
83
+ expect(result.current.fileUploads.length).toBe(0);
84
+ });
75
85
  });
76
86
  });
@@ -84,6 +84,7 @@ export const useMessageDetailsForState = <
84
84
  },
85
85
  id,
86
86
  state: 'finished',
87
+ thumb_url: attachment.thumb_url,
87
88
  url: attachment.asset_url,
88
89
  });
89
90
  }
@@ -11,6 +11,7 @@ try {
11
11
  }
12
12
 
13
13
  import { DB_LOCATION, DB_NAME } from './constants';
14
+ import { QuickSqliteClient_v4 } from './QuickSqliteClient_v4';
14
15
  import { tables } from './schema';
15
16
  import { createCreateTableQuery } from './sqlite-utils/createCreateTableQuery';
16
17
  import type { PreparedQueries, Table } from './types';
@@ -18,6 +19,8 @@ import type { PreparedQueries, Table } from './types';
18
19
  /**
19
20
  * QuickSqliteClient takes care of any direct interaction with sqlite.
20
21
  * This way usage react-native-quick-sqlite package is scoped to a single class/file.
22
+ *
23
+ * TODO: Drop the support for v4 of react-native-quick-sqlite in the next major release.
21
24
  */
22
25
  export class QuickSqliteClient {
23
26
  static dbVersion = 3;
@@ -29,7 +32,16 @@ export class QuickSqliteClient {
29
32
  // Force a specific db version. This is mainly useful for testsuit.
30
33
  static setDbVersion = (version: number) => (this.dbVersion = version);
31
34
 
35
+ // @ts-ignore
36
+ static isQuickSqliteV4 = sqlite.executeSql ? true : false;
37
+
38
+ // print if legacy version
32
39
  static openDB = () => {
40
+ if (this.isQuickSqliteV4) {
41
+ QuickSqliteClient_v4.openDB();
42
+ return;
43
+ }
44
+
33
45
  try {
34
46
  sqlite.open(this.dbName, this.dbLocation);
35
47
  sqlite.execute(this.dbName, `PRAGMA foreign_keys = ON`, []);
@@ -39,6 +51,11 @@ export class QuickSqliteClient {
39
51
  };
40
52
 
41
53
  static closeDB = () => {
54
+ if (this.isQuickSqliteV4) {
55
+ QuickSqliteClient_v4.closeDB();
56
+ return;
57
+ }
58
+
42
59
  try {
43
60
  sqlite.close(this.dbName);
44
61
  } catch (e) {
@@ -48,10 +65,16 @@ export class QuickSqliteClient {
48
65
 
49
66
  static executeSqlBatch = (queries: PreparedQueries[]) => {
50
67
  if (!queries || !queries.length) return;
51
- this.openDB();
52
68
 
69
+ if (this.isQuickSqliteV4) {
70
+ QuickSqliteClient_v4.executeSqlBatch(queries);
71
+ return;
72
+ }
73
+
74
+ this.openDB();
53
75
  try {
54
76
  sqlite.executeBatch(DB_NAME, queries);
77
+
55
78
  this.closeDB();
56
79
  } catch (e) {
57
80
  this.closeDB();
@@ -60,9 +83,12 @@ export class QuickSqliteClient {
60
83
  };
61
84
 
62
85
  static executeSql = (query: string, params?: string[]) => {
63
- this.openDB();
86
+ if (this.isQuickSqliteV4) {
87
+ return QuickSqliteClient_v4.executeSql(query, params);
88
+ }
64
89
 
65
90
  try {
91
+ this.openDB();
66
92
  const { rows } = sqlite.execute(DB_NAME, query, params);
67
93
  this.closeDB();
68
94
 
@@ -83,6 +109,10 @@ export class QuickSqliteClient {
83
109
  };
84
110
 
85
111
  static deleteDatabase = () => {
112
+ if (this.isQuickSqliteV4) {
113
+ return QuickSqliteClient_v4.deleteDatabase();
114
+ }
115
+
86
116
  try {
87
117
  sqlite.delete(this.dbName, this.dbLocation);
88
118
  } catch (e) {
@@ -100,6 +130,14 @@ export class QuickSqliteClient {
100
130
  );
101
131
  }
102
132
 
133
+ if (this.isQuickSqliteV4) {
134
+ console.warn(
135
+ 'You seem to be using an older version of "react-native-quick-sqlite" dependency,',
136
+ 'and we are going to drop support for it in the next major release.',
137
+ 'Please upgrade to the version v5 of "react-native-quick-sqlite" to avoid any issues.',
138
+ );
139
+ }
140
+
103
141
  const version = this.getUserPragmaVersion();
104
142
 
105
143
  if (version !== this.dbVersion) {
@@ -118,16 +156,22 @@ export class QuickSqliteClient {
118
156
  };
119
157
 
120
158
  static updateUserPragmaVersion = (version: number) => {
121
- this.openDB();
159
+ if (this.isQuickSqliteV4) {
160
+ QuickSqliteClient_v4.updateUserPragmaVersion(version);
161
+ return;
162
+ }
122
163
 
164
+ this.openDB();
123
165
  sqlite.execute(DB_NAME, `PRAGMA user_version = ${version}`, []);
124
-
125
166
  this.closeDB();
126
167
  };
127
168
 
128
169
  static getUserPragmaVersion = () => {
129
- this.openDB();
170
+ if (this.isQuickSqliteV4) {
171
+ return QuickSqliteClient_v4.getUserPragmaVersion();
172
+ }
130
173
 
174
+ this.openDB();
131
175
  try {
132
176
  const { rows } = sqlite.execute(DB_NAME, `PRAGMA user_version`, []);
133
177
  const result = rows ? rows._array : [];
@@ -0,0 +1,98 @@
1
+ // We are going to disable type checks for this file, since this QuickSqliteClient is for legacy version of sqlite but
2
+ // dev-dependency "react-native-quick-sqlite" is not available for legacy version of sqlite.
3
+ /* eslint-disable no-underscore-dangle */
4
+ // @ts-nocheck
5
+
6
+ import type { QuickSQLite } from 'react-native-quick-sqlite';
7
+ let sqlite: typeof QuickSQLite;
8
+
9
+ try {
10
+ sqlite = require('react-native-quick-sqlite').QuickSQLite;
11
+ } catch (e) {
12
+ // Failed for one of the reason
13
+ // 1. Running on expo, where we don't support offline storage yet.
14
+ // 2. Offline support is disabled, in which case this library is not installed.
15
+ }
16
+ import { DB_LOCATION, DB_NAME, DB_STATUS_ERROR } from './constants';
17
+ import type { PreparedQueries } from './types';
18
+
19
+ // QuickSqliteClient takes care of any direct interaction with sqlite for v4 of react-native-quick-sqlite.
20
+ // This is to avoid any breaking changes for users using v4 of react-native-quick-sqlite.
21
+ export class QuickSqliteClient_v4 {
22
+ static dbName = DB_NAME;
23
+ static dbLocation = DB_LOCATION;
24
+
25
+ static openDB = () => {
26
+ const { message, status } = sqlite.open(this.dbName, this.dbLocation);
27
+ sqlite.executeSql(this.dbName, `PRAGMA foreign_keys = ON`, []);
28
+
29
+ if (status === DB_STATUS_ERROR) {
30
+ console.error(`Error opening database ${this.dbName}: ${message}`);
31
+ }
32
+ };
33
+
34
+ static closeDB = () => {
35
+ const { message, status } = sqlite.close(this.dbName);
36
+
37
+ if (status === DB_STATUS_ERROR) {
38
+ console.error(`Error closing database ${this.dbName}: ${message}`);
39
+ }
40
+ };
41
+
42
+ static executeSqlBatch = (queries: PreparedQueries[]) => {
43
+ this.openDB();
44
+
45
+ const res = sqlite.executeSqlBatch(DB_NAME, queries);
46
+
47
+ if (res.status === 1) {
48
+ console.error(`Query/queries failed: ${res.message} ${JSON.stringify(res)}`);
49
+ }
50
+
51
+ this.closeDB();
52
+ };
53
+
54
+ static executeSql = (query: string, params?: string[]) => {
55
+ this.openDB();
56
+
57
+ const { message, rows, status } = sqlite.executeSql(DB_NAME, query, params);
58
+
59
+ this.closeDB();
60
+
61
+ if (status === 1) {
62
+ console.error(`Query/queries failed: ${message}: `, query);
63
+ }
64
+
65
+ return rows ? rows._array : [];
66
+ };
67
+
68
+ static deleteDatabase = () => {
69
+ const { message, status } = sqlite.delete(this.dbName, this.dbLocation);
70
+ if (status === DB_STATUS_ERROR) {
71
+ throw new Error(`Error deleting DB: ${message}`);
72
+ }
73
+
74
+ return true;
75
+ };
76
+
77
+ static updateUserPragmaVersion = (version: number) => {
78
+ this.openDB();
79
+
80
+ sqlite.executeSql(DB_NAME, `PRAGMA user_version = ${version}`, []);
81
+
82
+ this.closeDB();
83
+ };
84
+
85
+ static getUserPragmaVersion = () => {
86
+ this.openDB();
87
+
88
+ const { message, rows, status } = sqlite.executeSql(DB_NAME, `PRAGMA user_version`, []);
89
+
90
+ this.closeDB();
91
+ if (status === 1) {
92
+ console.error(`Querying for user_version failed: ${message}`);
93
+ }
94
+
95
+ const result = rows ? rows._array : [];
96
+ return result[0].user_version as number;
97
+ };
98
+ }
@@ -0,0 +1,19 @@
1
+ import type { AppSettingsAPIResponse } from 'stream-chat';
2
+
3
+ import { QuickSqliteClient } from '../QuickSqliteClient';
4
+ import { createSelectQuery } from '../sqlite-utils/createSelectQuery';
5
+
6
+ export const getAppSettings = ({
7
+ currentUserId,
8
+ }: {
9
+ currentUserId: string;
10
+ }): AppSettingsAPIResponse => {
11
+ const result = QuickSqliteClient.executeSql.apply(
12
+ null,
13
+ createSelectQuery('userSyncStatus', ['*'], {
14
+ userId: currentUserId,
15
+ }),
16
+ );
17
+
18
+ return result[0]?.appSettings ? JSON.parse(result[0].appSettings) : null;
19
+ };
@@ -1,6 +1,7 @@
1
1
  import { mapStorableToTask } from '../mappers/mapStorableToTask';
2
2
  import { QuickSqliteClient } from '../QuickSqliteClient';
3
3
  import { createSelectQuery } from '../sqlite-utils/createSelectQuery';
4
+ import type { TableRowJoinedUser } from '../types';
4
5
 
5
6
  export const getPendingTasks = (conditions: { messageId?: string } = {}) => {
6
7
  const query = createSelectQuery('pendingTasks', ['*'], conditions, {
@@ -9,5 +10,5 @@ export const getPendingTasks = (conditions: { messageId?: string } = {}) => {
9
10
 
10
11
  const result = QuickSqliteClient.executeSql.apply(null, query);
11
12
 
12
- return result.map((r) => mapStorableToTask(r));
13
+ return result.map((r: TableRowJoinedUser<'pendingTasks'>) => mapStorableToTask(r));
13
14
  };
@@ -4,6 +4,7 @@ export * from './deleteMessage';
4
4
  export * from './deleteMessagesForChannel';
5
5
  export * from './deleteReactions';
6
6
  export * from './getAllChannelIds';
7
+ export * from './getAppSettings';
7
8
  export * from './getChannelMessages';
8
9
  export * from './getChannels';
9
10
  export * from './getChannelsForFilterSort';
@@ -12,6 +13,7 @@ export * from './getMembers';
12
13
  export * from './getReads';
13
14
  export * from './updateMessage';
14
15
  export * from './updateReaction';
16
+ export * from './upsertAppSettings';
15
17
  export * from './upsertChannelData';
16
18
  export * from './upsertChannels';
17
19
  export * from './upsertCidsForQuery';
@@ -18,7 +18,10 @@ export const selectChannels = ({
18
18
  const result = QuickSqliteClient.executeSql.apply(null, query);
19
19
 
20
20
  if (channelIds) {
21
- return result.sort((a, b) => channelIds.indexOf(a.cid) - channelIds.indexOf(b.cid));
21
+ return result.sort(
22
+ (a: { cid: string }, b: { cid: string }) =>
23
+ channelIds.indexOf(a.cid) - channelIds.indexOf(b.cid),
24
+ );
22
25
  } else {
23
26
  return result;
24
27
  }
@@ -28,5 +28,5 @@ export const selectMembersForChannels = (cids: string[]): TableRowJoinedUser<'me
28
28
  cids,
29
29
  );
30
30
 
31
- return result.map((r) => JSON.parse(r.value));
31
+ return result.map((r: { value: string }) => JSON.parse(r.value));
32
32
  };
@@ -36,5 +36,5 @@ export const selectMessagesForChannels = (cids: string[]): TableRowJoinedUser<'m
36
36
  cids,
37
37
  );
38
38
 
39
- return result.map((r) => JSON.parse(r.value));
39
+ return result.map((r: { value: string }) => JSON.parse(r.value));
40
40
  };
@@ -29,5 +29,5 @@ export const selectReactionsForMessages = (
29
29
  messageIds,
30
30
  );
31
31
 
32
- return result.map((r) => JSON.parse(r.value));
32
+ return result.map((r: { value: string }) => JSON.parse(r.value));
33
33
  };
@@ -26,5 +26,5 @@ export const selectReadsForChannels = (cids: string[]): TableRowJoinedUser<'read
26
26
  cids,
27
27
  );
28
28
 
29
- return result.map((r) => JSON.parse(r.value));
29
+ return result.map((r: { value: string }) => JSON.parse(r.value));
30
30
  };