stream-chat-react-native-core 5.6.0-beta.1 → 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.
- package/lib/commonjs/components/Channel/Channel.js +22 -16
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Chat/Chat.js +1 -1
- package/lib/commonjs/components/Chat/Chat.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/useAppSettings.js +51 -22
- package/lib/commonjs/components/Chat/hooks/useAppSettings.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/useIsOnline.js +1 -1
- package/lib/commonjs/components/Chat/hooks/useIsOnline.js.map +1 -1
- package/lib/commonjs/contexts/chatContext/ChatContext.js.map +1 -1
- package/lib/commonjs/store/QuickSqliteClient.js +46 -1
- package/lib/commonjs/store/QuickSqliteClient.js.map +1 -1
- package/lib/commonjs/store/QuickSqliteClient_v4.js +112 -0
- package/lib/commonjs/store/QuickSqliteClient_v4.js.map +1 -0
- package/lib/commonjs/store/apis/getAppSettings.js +23 -0
- package/lib/commonjs/store/apis/getAppSettings.js.map +1 -0
- package/lib/commonjs/store/apis/getPendingTasks.js.map +1 -1
- package/lib/commonjs/store/apis/index.js +26 -0
- package/lib/commonjs/store/apis/index.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectChannels.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectMembersForChannels.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectReactionsForMessages.js.map +1 -1
- package/lib/commonjs/store/apis/queries/selectReadsForChannels.js.map +1 -1
- package/lib/commonjs/store/apis/upsertAppSettings.js +26 -0
- package/lib/commonjs/store/apis/upsertAppSettings.js.map +1 -0
- package/lib/commonjs/store/schema.js +1 -0
- package/lib/commonjs/store/schema.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Channel/Channel.js +22 -16
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Chat/Chat.js +1 -1
- package/lib/module/components/Chat/Chat.js.map +1 -1
- package/lib/module/components/Chat/hooks/useAppSettings.js +51 -22
- package/lib/module/components/Chat/hooks/useAppSettings.js.map +1 -1
- package/lib/module/components/Chat/hooks/useIsOnline.js +1 -1
- package/lib/module/components/Chat/hooks/useIsOnline.js.map +1 -1
- package/lib/module/contexts/chatContext/ChatContext.js.map +1 -1
- package/lib/module/store/QuickSqliteClient.js +46 -1
- package/lib/module/store/QuickSqliteClient.js.map +1 -1
- package/lib/module/store/QuickSqliteClient_v4.js +112 -0
- package/lib/module/store/QuickSqliteClient_v4.js.map +1 -0
- package/lib/module/store/apis/getAppSettings.js +23 -0
- package/lib/module/store/apis/getAppSettings.js.map +1 -0
- package/lib/module/store/apis/getPendingTasks.js.map +1 -1
- package/lib/module/store/apis/index.js +26 -0
- package/lib/module/store/apis/index.js.map +1 -1
- package/lib/module/store/apis/queries/selectChannels.js.map +1 -1
- package/lib/module/store/apis/queries/selectMembersForChannels.js.map +1 -1
- package/lib/module/store/apis/queries/selectMessagesForChannels.js.map +1 -1
- package/lib/module/store/apis/queries/selectReactionsForMessages.js.map +1 -1
- package/lib/module/store/apis/queries/selectReadsForChannels.js.map +1 -1
- package/lib/module/store/apis/upsertAppSettings.js +26 -0
- package/lib/module/store/apis/upsertAppSettings.js.map +1 -0
- package/lib/module/store/schema.js +1 -0
- package/lib/module/store/schema.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Chat/hooks/useAppSettings.d.ts +2 -2
- package/lib/typescript/components/Chat/hooks/useIsOnline.d.ts +1 -1
- package/lib/typescript/contexts/chatContext/ChatContext.d.ts +1 -1
- package/lib/typescript/store/QuickSqliteClient.d.ts +4 -1
- package/lib/typescript/store/QuickSqliteClient_v4.d.ts +12 -0
- package/lib/typescript/store/apis/getAppSettings.d.ts +4 -0
- package/lib/typescript/store/apis/getPendingTasks.d.ts +1 -1
- package/lib/typescript/store/apis/index.d.ts +2 -0
- package/lib/typescript/store/apis/upsertAppSettings.d.ts +6 -0
- package/lib/typescript/store/schema.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/Attachment/__tests__/Gallery.test.js +9 -2
- package/src/components/Attachment/__tests__/Giphy.test.js +9 -5
- package/src/components/Channel/Channel.tsx +8 -1
- package/src/components/Chat/Chat.tsx +1 -1
- package/src/components/Chat/hooks/__tests__/useAppSettings.test.tsx +1 -0
- package/src/components/Chat/hooks/useAppSettings.ts +19 -6
- package/src/components/Chat/hooks/useIsOnline.ts +1 -1
- package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +29 -15
- package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +12 -6
- package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +9 -4
- package/src/contexts/chatContext/ChatContext.tsx +1 -1
- package/src/contexts/messageInputContext/__tests__/MessageInputContext.test.tsx +8 -3
- package/src/contexts/messageInputContext/__tests__/uploadFile.test.tsx +16 -6
- package/src/store/QuickSqliteClient.ts +49 -5
- package/src/store/QuickSqliteClient_v4.ts +98 -0
- package/src/store/apis/getAppSettings.ts +19 -0
- package/src/store/apis/getPendingTasks.ts +2 -1
- package/src/store/apis/index.ts +2 -0
- package/src/store/apis/queries/selectChannels.ts +4 -1
- package/src/store/apis/queries/selectMembersForChannels.ts +1 -1
- package/src/store/apis/queries/selectMessagesForChannels.ts +1 -1
- package/src/store/apis/queries/selectReactionsForMessages.ts +1 -1
- package/src/store/apis/queries/selectReadsForChannels.ts +1 -1
- package/src/store/apis/upsertAppSettings.ts +23 -0
- package/src/store/schema.ts +2 -0
- package/src/version.json +1 -1
|
@@ -4,7 +4,7 @@ import type { SharedValue } from 'react-native-reanimated';
|
|
|
4
4
|
|
|
5
5
|
import { act } from 'react-test-renderer';
|
|
6
6
|
|
|
7
|
-
import { fireEvent, render } from '@testing-library/react-native';
|
|
7
|
+
import { fireEvent, render, waitFor } from '@testing-library/react-native';
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
ImageGalleryContext,
|
|
@@ -45,7 +45,7 @@ const getComponent = (props: Partial<ImageGalleryContextValue>) => (
|
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
describe('ImageGallery', () => {
|
|
48
|
-
it('render image gallery component', () => {
|
|
48
|
+
it('render image gallery component', async () => {
|
|
49
49
|
const { queryAllByA11yLabel } = render(
|
|
50
50
|
getComponent({
|
|
51
51
|
messages: [
|
|
@@ -59,11 +59,14 @@ describe('ImageGallery', () => {
|
|
|
59
59
|
] as unknown as MessageType<DefaultStreamChatGenerics>[],
|
|
60
60
|
}),
|
|
61
61
|
);
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(queryAllByA11yLabel('Image Item')).toHaveLength(2);
|
|
65
|
+
expect(queryAllByA11yLabel('Image Gallery Video')).toHaveLength(1);
|
|
66
|
+
});
|
|
64
67
|
});
|
|
65
68
|
|
|
66
|
-
it('handle handleLoad function when video item present and payload duration is available', () => {
|
|
69
|
+
it('handle handleLoad function when video item present and payload duration is available', async () => {
|
|
67
70
|
const attachment = generateVideoAttachment({ type: 'video' });
|
|
68
71
|
const message = generateMessage({
|
|
69
72
|
attachments: [attachment],
|
|
@@ -86,10 +89,13 @@ describe('ImageGallery', () => {
|
|
|
86
89
|
});
|
|
87
90
|
|
|
88
91
|
const videoDurationComponent = getByA11yLabel('Video Duration');
|
|
89
|
-
|
|
92
|
+
|
|
93
|
+
await waitFor(() => {
|
|
94
|
+
expect(videoDurationComponent.children[0]).toBe('00:10');
|
|
95
|
+
});
|
|
90
96
|
});
|
|
91
97
|
|
|
92
|
-
it('handle handleLoad function when video item present and payload duration is undefined', () => {
|
|
98
|
+
it('handle handleLoad function when video item present and payload duration is undefined', async () => {
|
|
93
99
|
const { getByA11yLabel } = render(
|
|
94
100
|
getComponent({
|
|
95
101
|
messages: [
|
|
@@ -109,10 +115,12 @@ describe('ImageGallery', () => {
|
|
|
109
115
|
});
|
|
110
116
|
|
|
111
117
|
const videoDurationComponent = getByA11yLabel('Video Duration');
|
|
112
|
-
|
|
118
|
+
await waitFor(() => {
|
|
119
|
+
expect(videoDurationComponent.children[0]).toBe('00:00');
|
|
120
|
+
});
|
|
113
121
|
});
|
|
114
122
|
|
|
115
|
-
it('handle handleProgress function when video item present and payload is well defined', () => {
|
|
123
|
+
it('handle handleProgress function when video item present and payload is well defined', async () => {
|
|
116
124
|
const attachment = generateVideoAttachment({ type: 'video' });
|
|
117
125
|
const message = generateMessage({
|
|
118
126
|
attachments: [attachment],
|
|
@@ -143,10 +151,12 @@ describe('ImageGallery', () => {
|
|
|
143
151
|
|
|
144
152
|
const progressDurationComponent = getByA11yLabel('Progress Duration');
|
|
145
153
|
|
|
146
|
-
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
expect(progressDurationComponent.children[0]).toBe('00:03');
|
|
156
|
+
});
|
|
147
157
|
});
|
|
148
158
|
|
|
149
|
-
it('handle handleProgress function when video item present and payload is not defined', () => {
|
|
159
|
+
it('handle handleProgress function when video item present and payload is not defined', async () => {
|
|
150
160
|
const { getByA11yLabel } = render(
|
|
151
161
|
getComponent({
|
|
152
162
|
messages: [
|
|
@@ -171,10 +181,12 @@ describe('ImageGallery', () => {
|
|
|
171
181
|
|
|
172
182
|
const progressDurationComponent = getByA11yLabel('Progress Duration');
|
|
173
183
|
|
|
174
|
-
|
|
184
|
+
await waitFor(() => {
|
|
185
|
+
expect(progressDurationComponent.children[0]).toBe('00:00');
|
|
186
|
+
});
|
|
175
187
|
});
|
|
176
188
|
|
|
177
|
-
it('handle handleEnd function when video item present', () => {
|
|
189
|
+
it('handle handleEnd function when video item present', async () => {
|
|
178
190
|
const attachment = generateVideoAttachment({ type: 'video' });
|
|
179
191
|
const message = generateMessage({
|
|
180
192
|
attachments: [attachment],
|
|
@@ -198,7 +210,9 @@ describe('ImageGallery', () => {
|
|
|
198
210
|
});
|
|
199
211
|
|
|
200
212
|
const progressDurationComponent = getByA11yLabel('Progress Duration');
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
await waitFor(() => {
|
|
214
|
+
expect(getByA11yLabel('Play Icon')).not.toBeUndefined();
|
|
215
|
+
expect(progressDurationComponent.children[0]).toBe('00:10');
|
|
216
|
+
});
|
|
203
217
|
});
|
|
204
218
|
});
|
|
@@ -97,10 +97,13 @@ describe('ImageGalleryFooter', () => {
|
|
|
97
97
|
</ImageGalleryContext.Provider>
|
|
98
98
|
</OverlayProvider>,
|
|
99
99
|
);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
expect(queryAllByText('Left element')).toHaveLength(1);
|
|
103
|
+
expect(queryAllByText('Right element')).toHaveLength(1);
|
|
104
|
+
expect(queryAllByText('Center element')).toHaveLength(1);
|
|
105
|
+
expect(queryAllByText('Video Control element')).toHaveLength(1);
|
|
106
|
+
});
|
|
104
107
|
});
|
|
105
108
|
|
|
106
109
|
it('render image gallery footer component with custom component footer Grid Icon and Share Icon component', async () => {
|
|
@@ -147,8 +150,11 @@ describe('ImageGalleryFooter', () => {
|
|
|
147
150
|
</ImageGalleryContext.Provider>
|
|
148
151
|
</OverlayProvider>,
|
|
149
152
|
);
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
expect(queryAllByText('Share Icon element')).toHaveLength(1);
|
|
156
|
+
expect(queryAllByText('Grid Icon element')).toHaveLength(1);
|
|
157
|
+
});
|
|
152
158
|
});
|
|
153
159
|
|
|
154
160
|
it('should trigger the share button onPress Handler', async () => {
|
|
@@ -90,9 +90,12 @@ describe('ImageGalleryHeader', () => {
|
|
|
90
90
|
</ImageGalleryContext.Provider>
|
|
91
91
|
</OverlayProvider>,
|
|
92
92
|
);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
|
|
94
|
+
await waitFor(() => {
|
|
95
|
+
expect(queryAllByText('Left element')).toHaveLength(1);
|
|
96
|
+
expect(queryAllByText('Right element')).toHaveLength(1);
|
|
97
|
+
expect(queryAllByText('Center element')).toHaveLength(1);
|
|
98
|
+
});
|
|
96
99
|
});
|
|
97
100
|
|
|
98
101
|
it('render image gallery header component with custom Close Icon component', async () => {
|
|
@@ -132,7 +135,9 @@ describe('ImageGalleryHeader', () => {
|
|
|
132
135
|
</ImageGalleryContext.Provider>
|
|
133
136
|
</OverlayProvider>,
|
|
134
137
|
);
|
|
135
|
-
|
|
138
|
+
await waitFor(() => {
|
|
139
|
+
expect(queryAllByText('Close Icon element')).toHaveLength(1);
|
|
140
|
+
});
|
|
136
141
|
});
|
|
137
142
|
|
|
138
143
|
it('should trigger the hideOverlay function on button onPress', async () => {
|
|
@@ -36,7 +36,7 @@ export type ChatContextValue<
|
|
|
36
36
|
connectionRecovering: boolean;
|
|
37
37
|
enableOfflineSupport: boolean;
|
|
38
38
|
ImageComponent: React.ComponentType<ImageProps>;
|
|
39
|
-
isOnline: boolean;
|
|
39
|
+
isOnline: boolean | null;
|
|
40
40
|
mutedUsers: Mute<StreamChatGenerics>[];
|
|
41
41
|
/**
|
|
42
42
|
* @param newChannel Channel to set as active.
|
|
@@ -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
|
-
|
|
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
|
-
|
|
209
|
+
await waitFor(async () => {
|
|
210
|
+
expect(await result.current.pickFile()).toBe(undefined);
|
|
211
|
+
});
|
|
207
212
|
});
|
|
208
213
|
});
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
await waitFor(() => {
|
|
83
|
+
expect(result.current.fileUploads.length).toBe(0);
|
|
84
|
+
});
|
|
75
85
|
});
|
|
76
86
|
});
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
};
|
package/src/store/apis/index.ts
CHANGED
|
@@ -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(
|
|
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
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AppSettingsAPIResponse } from 'stream-chat';
|
|
2
|
+
|
|
3
|
+
import { QuickSqliteClient } from '../QuickSqliteClient';
|
|
4
|
+
import { createUpsertQuery } from '../sqlite-utils/createUpsertQuery';
|
|
5
|
+
|
|
6
|
+
export const upsertAppSettings = ({
|
|
7
|
+
appSettings,
|
|
8
|
+
currentUserId,
|
|
9
|
+
flush = true,
|
|
10
|
+
}: {
|
|
11
|
+
appSettings: AppSettingsAPIResponse;
|
|
12
|
+
currentUserId: string;
|
|
13
|
+
flush?: boolean;
|
|
14
|
+
}) => {
|
|
15
|
+
const query = createUpsertQuery('userSyncStatus', {
|
|
16
|
+
appSettings: JSON.stringify(appSettings),
|
|
17
|
+
userId: currentUserId,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (flush) {
|
|
21
|
+
QuickSqliteClient.executeSql.apply(null, query);
|
|
22
|
+
}
|
|
23
|
+
};
|
package/src/store/schema.ts
CHANGED
|
@@ -201,6 +201,7 @@ export const tables: Tables = {
|
|
|
201
201
|
},
|
|
202
202
|
userSyncStatus: {
|
|
203
203
|
columns: {
|
|
204
|
+
appSettings: 'TEXT',
|
|
204
205
|
lastSyncedAt: 'TEXT',
|
|
205
206
|
userId: 'TEXT',
|
|
206
207
|
},
|
|
@@ -302,6 +303,7 @@ export type Schema = {
|
|
|
302
303
|
updatedAt?: string;
|
|
303
304
|
};
|
|
304
305
|
userSyncStatus: {
|
|
306
|
+
appSettings: string;
|
|
305
307
|
lastSyncedAt: string;
|
|
306
308
|
userId: string;
|
|
307
309
|
};
|
package/src/version.json
CHANGED