@eohjsc/react-native-smart-city 0.7.27 → 0.7.31
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/index.js +2 -0
- package/package.json +2 -1
- package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
- package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
- package/src/commons/Dashboard/MyUnit/index.js +40 -32
- package/src/commons/ModalAlert/index.js +51 -0
- package/src/commons/ModalAlert/styles.js +54 -0
- package/src/commons/SubUnit/ShortDetail.js +20 -4
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
- package/src/configs/API.js +8 -0
- package/src/configs/AccessibilityLabel.js +3 -0
- package/src/configs/Constants.js +7 -0
- package/src/configs/SCConfig.js +6 -0
- package/src/context/SCContext.tsx +12 -1
- package/src/context/SCStore.ts +14 -0
- package/src/context/actionType.ts +10 -0
- package/src/context/mockStore.ts +30 -1
- package/src/context/reducer.ts +35 -0
- package/src/hooks/IoT/useRemoteControl.js +4 -1
- package/src/hooks/IoT/useWatchSharedChips.js +130 -0
- package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
- package/src/hooks/Review/useInAppReview.js +70 -0
- package/src/hooks/useMqtt.js +78 -27
- package/src/iot/Monitor.js +149 -26
- package/src/iot/UpdateStates.js +60 -0
- package/src/iot/mqtt.js +177 -22
- package/src/navigations/UnitStack.js +16 -0
- package/src/screens/ActivityLog/ItemLog.js +1 -0
- package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
- package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
- package/src/screens/Automate/AddNewAction/ReceiverSelect.js +210 -0
- package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
- package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
- package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
- package/src/screens/Automate/Components/InputName.js +5 -1
- package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +4 -3
- package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +5 -4
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -1
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +116 -2
- package/src/screens/Automate/ScriptDetail/index.js +47 -9
- package/src/screens/CreatePassword/__test__/index.test.js +133 -0
- package/src/screens/CreatePassword/index.js +134 -0
- package/src/screens/CreatePassword/styles.js +45 -0
- package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
- package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
- package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
- package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
- package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
- package/src/screens/Device/__test__/detail.test.js +61 -3
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
- package/src/screens/Device/detail.js +14 -6
- package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
- package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
- package/src/screens/EnterPassword/index.js +34 -4
- package/src/screens/EnterPassword/styles.js +1 -1
- package/src/utils/FactoryGateway.js +597 -0
- package/src/utils/I18n/translations/en.js +11 -0
- package/src/utils/I18n/translations/vi.js +11 -0
- package/src/utils/Route/index.js +3 -1
- package/src/utils/Validation.js +5 -0
- package/src/utils/store.js +5 -0
package/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { withRemoteControl } from './src/hoc';
|
|
|
22
22
|
// import DevModeStack from './src/navigations/Main';
|
|
23
23
|
import { SmartAccountStack } from './src/navigations/SmartAccountStack';
|
|
24
24
|
import { AllGatewayStack } from './src/navigations/AllGatewayStack';
|
|
25
|
+
import useInAppReview from './src/hooks/Review/useInAppReview';
|
|
25
26
|
|
|
26
27
|
export {
|
|
27
28
|
AddSubUnitStack,
|
|
@@ -50,4 +51,5 @@ export {
|
|
|
50
51
|
// DevModeStack,
|
|
51
52
|
SmartAccountStack,
|
|
52
53
|
AllGatewayStack,
|
|
54
|
+
useInAppReview,
|
|
53
55
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eohjsc/react-native-smart-city",
|
|
3
3
|
"title": "React Native Smart Home",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.31",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -158,6 +158,7 @@
|
|
|
158
158
|
"react-native-get-location": "^2.0.0",
|
|
159
159
|
"react-native-image-crop-picker": "0.41.2",
|
|
160
160
|
"react-native-image-resizer": "^1.4.5",
|
|
161
|
+
"react-native-in-app-review": "^4.4.2",
|
|
161
162
|
"react-native-input-credit-card": "^0.5.5",
|
|
162
163
|
"react-native-iphone-x-helper": "^1.2.1",
|
|
163
164
|
"react-native-linear-gradient": "^2.5.6",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import MockAdapter from 'axios-mock-adapter';
|
|
2
|
+
import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
|
|
2
3
|
import React, { useContext } from 'react';
|
|
3
4
|
import renderer, { act } from 'react-test-renderer';
|
|
4
5
|
|
|
@@ -7,15 +8,28 @@ import { API } from '../../../../configs';
|
|
|
7
8
|
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
8
9
|
import { SCProvider } from '../../../../context';
|
|
9
10
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
11
|
+
import {
|
|
12
|
+
watchMultiConfigs,
|
|
13
|
+
watchMultiDataChips,
|
|
14
|
+
} from '../../../../iot/Monitor';
|
|
10
15
|
import { Section } from '../../../Section';
|
|
11
16
|
import ItemDevice from '../../../Device/ItemDevice';
|
|
12
17
|
import { DeviceTemplate } from '../../../SubUnit/DeviceTemplate/DeviceTemplate';
|
|
18
|
+
import { gatewayDataFactory } from '../../../../utils/FactoryGateway';
|
|
13
19
|
import api from '../../../../utils/Apis/axios';
|
|
14
20
|
import Routes from '../../../../utils/Route';
|
|
15
21
|
import MyDashboardDevice from '..';
|
|
16
22
|
|
|
17
23
|
const mock = new MockAdapter(api.axiosInstance);
|
|
18
24
|
|
|
25
|
+
jest.mock('../../../../iot/Monitor', () => {
|
|
26
|
+
return {
|
|
27
|
+
...jest.requireActual('../../../../iot/Monitor'),
|
|
28
|
+
watchMultiConfigs: jest.fn(),
|
|
29
|
+
watchMultiDataChips: jest.fn(),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
19
33
|
const wrapComponent = () => (
|
|
20
34
|
<SCProvider initState={mockSCStore({})}>
|
|
21
35
|
<MyDashboardDevice refreshing={true} />
|
|
@@ -32,6 +46,7 @@ describe('Test MyDashboardDevice', () => {
|
|
|
32
46
|
{
|
|
33
47
|
id: 1,
|
|
34
48
|
name: 'LED',
|
|
49
|
+
chip_id: 7689,
|
|
35
50
|
is_managed_by_backend: true,
|
|
36
51
|
device_type: '',
|
|
37
52
|
station: {
|
|
@@ -45,6 +60,7 @@ describe('Test MyDashboardDevice', () => {
|
|
|
45
60
|
{
|
|
46
61
|
id: 2,
|
|
47
62
|
name: 'Presence',
|
|
63
|
+
chip_id: 7690,
|
|
48
64
|
is_managed_by_backend: true,
|
|
49
65
|
device_type: '',
|
|
50
66
|
station: {
|
|
@@ -62,6 +78,7 @@ describe('Test MyDashboardDevice', () => {
|
|
|
62
78
|
{
|
|
63
79
|
id: 3,
|
|
64
80
|
name: 'Switch',
|
|
81
|
+
chip_id: 7691,
|
|
65
82
|
is_managed_by_backend: false,
|
|
66
83
|
device_type: 'GOOGLE_HOME',
|
|
67
84
|
station: {
|
|
@@ -83,6 +100,8 @@ describe('Test MyDashboardDevice', () => {
|
|
|
83
100
|
setAction: mockSetAction,
|
|
84
101
|
});
|
|
85
102
|
mockSetAction.mockClear();
|
|
103
|
+
watchMultiConfigs.mockClear();
|
|
104
|
+
watchMultiDataChips.mockClear();
|
|
86
105
|
});
|
|
87
106
|
|
|
88
107
|
it('Test dashboard no device', async () => {
|
|
@@ -168,4 +187,53 @@ describe('Test MyDashboardDevice', () => {
|
|
|
168
187
|
data[0].devices
|
|
169
188
|
);
|
|
170
189
|
});
|
|
190
|
+
|
|
191
|
+
it('Test dashboard with devices connect mqtt, pusher', async () => {
|
|
192
|
+
jest.useFakeTimers();
|
|
193
|
+
|
|
194
|
+
mock.onGet(API.UNIT.MY_DASHBOARD_DEVICES()).reply(200, data);
|
|
195
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [
|
|
196
|
+
gatewayDataFactory,
|
|
197
|
+
{
|
|
198
|
+
...gatewayDataFactory,
|
|
199
|
+
code: 'xxx',
|
|
200
|
+
id: 7695,
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, [
|
|
204
|
+
{
|
|
205
|
+
...gatewayDataFactory,
|
|
206
|
+
id: 7690,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
...gatewayDataFactory,
|
|
210
|
+
id: 7696,
|
|
211
|
+
},
|
|
212
|
+
]);
|
|
213
|
+
await act(async () => {
|
|
214
|
+
tree = await renderer.create(wrapComponent());
|
|
215
|
+
});
|
|
216
|
+
const instance = tree.root;
|
|
217
|
+
const devices = instance.findAllByType(ItemDevice);
|
|
218
|
+
expect(devices).toHaveLength(2);
|
|
219
|
+
const deviceTemplates = instance.findAllByType(DeviceTemplate);
|
|
220
|
+
expect(deviceTemplates).toHaveLength(1);
|
|
221
|
+
|
|
222
|
+
const client = mqtt.connect();
|
|
223
|
+
await act(async () => {
|
|
224
|
+
client.trigger('connect');
|
|
225
|
+
});
|
|
226
|
+
expect(client.subscribe).toHaveBeenCalledWith(
|
|
227
|
+
`eoh/chip/${gatewayDataFactory.code}/#`
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
await act(async () => {
|
|
231
|
+
jest.advanceTimersByTime(500);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(watchMultiConfigs).toHaveBeenCalledWith([1, 2]);
|
|
235
|
+
expect(watchMultiDataChips).toHaveBeenCalledWith([7690]);
|
|
236
|
+
|
|
237
|
+
jest.useRealTimers();
|
|
238
|
+
});
|
|
171
239
|
});
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { API, Colors, Images } from '../../../configs';
|
|
2
|
-
import { AccessibilityLabel, DEVICE_TYPE } from '../../../configs/Constants';
|
|
3
|
-
import { Image, FlatList, TouchableOpacity, View } from 'react-native';
|
|
4
1
|
import React, {
|
|
5
2
|
memo,
|
|
6
3
|
useCallback,
|
|
@@ -9,19 +6,31 @@ import React, {
|
|
|
9
6
|
useEffect,
|
|
10
7
|
useState,
|
|
11
8
|
} from 'react';
|
|
12
|
-
import {
|
|
13
|
-
import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
|
|
14
|
-
import { useWatchConfigs } from '../../../hooks/IoT';
|
|
9
|
+
import { Image, FlatList, TouchableOpacity, View } from 'react-native';
|
|
15
10
|
import { useIsFocused, useNavigation } from '@react-navigation/native';
|
|
16
11
|
|
|
12
|
+
import { API, Colors, Images } from '../../../configs';
|
|
13
|
+
import { AccessibilityLabel, DEVICE_TYPE } from '../../../configs/Constants';
|
|
14
|
+
|
|
15
|
+
import { SCContext, useSCContextSelector } from '../../../context';
|
|
17
16
|
import { Action } from '../../../context/actionType';
|
|
17
|
+
|
|
18
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
19
|
+
import { useWatchConfigs } from '../../../hooks/IoT';
|
|
20
|
+
import useWatchSharedChips from '../../../hooks/IoT/useWatchSharedChips';
|
|
21
|
+
import useChipJsonConfiguration, {
|
|
22
|
+
useConnectChipMqtt,
|
|
23
|
+
} from '../../../hooks/useMqtt';
|
|
24
|
+
|
|
25
|
+
import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
|
|
26
|
+
import { keyExtractor } from '../../../utils/Utils';
|
|
18
27
|
import Routes from '../../../utils/Route';
|
|
28
|
+
|
|
19
29
|
import { Section } from '../../Section';
|
|
20
30
|
import Text from '../../Text';
|
|
21
|
-
import { keyExtractor } from '../../../utils/Utils';
|
|
22
31
|
import ItemDevice from '../../Device/ItemDevice';
|
|
23
32
|
import { DeviceTemplate } from '../../SubUnit/DeviceTemplate/DeviceTemplate';
|
|
24
|
-
|
|
33
|
+
|
|
25
34
|
import styles from './styles';
|
|
26
35
|
|
|
27
36
|
const MyDashboardDevice = ({ refreshing }) => {
|
|
@@ -34,6 +43,22 @@ const MyDashboardDevice = ({ refreshing }) => {
|
|
|
34
43
|
);
|
|
35
44
|
const [myDashboardDevices, setMyDashboardDevices] = useState([]);
|
|
36
45
|
|
|
46
|
+
const listChipDashboard = useMemo(() => {
|
|
47
|
+
return myDashboardDevices.flatMap((dashboard) =>
|
|
48
|
+
dashboard.devices.map((device) => device.chip_id)
|
|
49
|
+
);
|
|
50
|
+
}, [myDashboardDevices]);
|
|
51
|
+
|
|
52
|
+
const { chips, isFetching } = useChipJsonConfiguration({
|
|
53
|
+
ready: !!listChipDashboard.length,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const listChipsMqtt = useMemo(() => {
|
|
57
|
+
return chips.filter((chip) => listChipDashboard.includes(chip.id));
|
|
58
|
+
}, [chips, listChipDashboard]);
|
|
59
|
+
|
|
60
|
+
const { mqttConfigs } = useConnectChipMqtt(listChipsMqtt);
|
|
61
|
+
|
|
37
62
|
const configsNeedWatching = useMemo(() => {
|
|
38
63
|
const configIds = [];
|
|
39
64
|
|
|
@@ -51,10 +76,20 @@ const MyDashboardDevice = ({ refreshing }) => {
|
|
|
51
76
|
});
|
|
52
77
|
});
|
|
53
78
|
|
|
54
|
-
return configIds;
|
|
55
|
-
}, [myDashboardDevices]);
|
|
79
|
+
return configIds.filter((id) => !mqttConfigs[id]);
|
|
80
|
+
}, [myDashboardDevices, mqttConfigs]);
|
|
81
|
+
|
|
82
|
+
useWatchConfigs(isFetching ? [] : configsNeedWatching);
|
|
83
|
+
|
|
84
|
+
const listSharedChips = useMemo(() => {
|
|
85
|
+
const chipMqttIds = listChipsMqtt.map((chip) => chip.id);
|
|
86
|
+
return listChipDashboard.filter((id) => !chipMqttIds.includes(id));
|
|
87
|
+
}, [listChipsMqtt, listChipDashboard]);
|
|
56
88
|
|
|
57
|
-
|
|
89
|
+
useWatchSharedChips({
|
|
90
|
+
filterChipIds: listSharedChips,
|
|
91
|
+
ready: !!listSharedChips.length,
|
|
92
|
+
});
|
|
58
93
|
|
|
59
94
|
const fetchMyDashboardDevices = useCallback(async () => {
|
|
60
95
|
if (isNeedUpdateCache) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import MockAdapter from 'axios-mock-adapter';
|
|
2
|
+
import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import renderer, { act } from 'react-test-renderer';
|
|
4
|
-
|
|
5
5
|
import Carousel from 'react-native-new-snap-carousel';
|
|
6
|
+
|
|
6
7
|
import MyUnit from '..';
|
|
7
8
|
import { API } from '../../../../configs';
|
|
8
9
|
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
@@ -10,6 +11,7 @@ import { SCProvider } from '../../../../context';
|
|
|
10
11
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
11
12
|
import { flushPromises } from '../../../../screens/AllGateway/test-utils';
|
|
12
13
|
import MyUnitDevice from '../../../../screens/Unit/components/MyUnitDevice';
|
|
14
|
+
import { gatewayDataFactory } from '../../../../utils/FactoryGateway';
|
|
13
15
|
import api from '../../../../utils/Apis/axios';
|
|
14
16
|
import Routes from '../../../../utils/Route';
|
|
15
17
|
|
|
@@ -39,6 +41,7 @@ describe('Test MyUnit', () => {
|
|
|
39
41
|
{
|
|
40
42
|
id: 1,
|
|
41
43
|
name: 'device',
|
|
44
|
+
chip_id: 7689,
|
|
42
45
|
is_managed_by_backend: true,
|
|
43
46
|
device_type: 'GOOGLE_HOME',
|
|
44
47
|
station_name: 'name',
|
|
@@ -46,6 +49,7 @@ describe('Test MyUnit', () => {
|
|
|
46
49
|
{
|
|
47
50
|
id: 2,
|
|
48
51
|
name: 'device',
|
|
52
|
+
chip_id: 7690,
|
|
49
53
|
is_managed_by_backend: true,
|
|
50
54
|
device_type: '',
|
|
51
55
|
station_name: 'name',
|
|
@@ -65,6 +69,14 @@ describe('Test MyUnit', () => {
|
|
|
65
69
|
|
|
66
70
|
beforeEach(async () => {
|
|
67
71
|
mock.resetHistory();
|
|
72
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [
|
|
73
|
+
gatewayDataFactory,
|
|
74
|
+
{
|
|
75
|
+
...gatewayDataFactory,
|
|
76
|
+
code: 'xxx',
|
|
77
|
+
id: 7695,
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
68
80
|
});
|
|
69
81
|
|
|
70
82
|
const getElement = (instance) => {
|
|
@@ -99,6 +111,18 @@ describe('Test MyUnit', () => {
|
|
|
99
111
|
const devices = instance.findAllByType(MyUnitDevice);
|
|
100
112
|
expect(devices).toHaveLength(2);
|
|
101
113
|
|
|
114
|
+
const client = mqtt.connect();
|
|
115
|
+
await act(async () => {
|
|
116
|
+
client.trigger('connect');
|
|
117
|
+
});
|
|
118
|
+
expect(client.subscribe).toHaveBeenCalledWith(
|
|
119
|
+
`eoh/chip/${gatewayDataFactory.code}/#`
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(mock.history.get).toHaveLength(2);
|
|
123
|
+
expect(mock.history.get[0].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
|
|
124
|
+
expect(mock.history.get[1].url).toEqual(API.CHIP.JSON_CONFIGURATION);
|
|
125
|
+
|
|
102
126
|
const button = instance.findByProps({
|
|
103
127
|
accessibilityLabel: `${AccessibilityLabel.MY_UNIT_GO_TO_DETAIL}-0`,
|
|
104
128
|
});
|
|
@@ -109,8 +133,6 @@ describe('Test MyUnit', () => {
|
|
|
109
133
|
params: { unitId: 1 },
|
|
110
134
|
screen: Routes.UnitDetail,
|
|
111
135
|
});
|
|
112
|
-
expect(mock.history.get).toHaveLength(1);
|
|
113
|
-
expect(mock.history.get[0].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
|
|
114
136
|
});
|
|
115
137
|
|
|
116
138
|
it('Test isNeedUpdateCache = false', async () => {
|
|
@@ -140,8 +162,9 @@ describe('Test MyUnit', () => {
|
|
|
140
162
|
wrapComponent({ app: { isNeedUpdateCache: false } }, false)
|
|
141
163
|
);
|
|
142
164
|
});
|
|
143
|
-
expect(mock.history.get).toHaveLength(
|
|
144
|
-
expect(mock.history.get[0].url).toEqual(API.
|
|
165
|
+
expect(mock.history.get).toHaveLength(2);
|
|
166
|
+
expect(mock.history.get[0].url).toEqual(API.CHIP.JSON_CONFIGURATION);
|
|
167
|
+
expect(mock.history.get[1].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
|
|
145
168
|
});
|
|
146
169
|
|
|
147
170
|
it('Test fetch unit data when snap to item', async () => {
|
|
@@ -170,24 +193,33 @@ describe('Test MyUnit', () => {
|
|
|
170
193
|
await act(() => {
|
|
171
194
|
carousel.props.onSnapToItem(4);
|
|
172
195
|
});
|
|
173
|
-
expect(
|
|
174
|
-
|
|
196
|
+
expect(
|
|
197
|
+
mock.history.get.filter((req) => req.url === API.UNIT_V2.MY_UNITS(1, 10))
|
|
198
|
+
).toHaveLength(1);
|
|
175
199
|
await act(() => {
|
|
176
200
|
carousel.props.onSnapToItem(5);
|
|
177
201
|
});
|
|
178
202
|
await act(() => {
|
|
179
203
|
carousel.props.onSnapToItem(6);
|
|
180
204
|
});
|
|
181
|
-
expect(
|
|
182
|
-
|
|
205
|
+
expect(
|
|
206
|
+
mock.history.get.filter((req) => req.url === API.UNIT_V2.MY_UNITS(1, 10))
|
|
207
|
+
).toHaveLength(1);
|
|
208
|
+
expect(
|
|
209
|
+
mock.history.get.filter((req) => req.url === API.UNIT_V2.MY_UNITS(2, 10))
|
|
210
|
+
).toHaveLength(1);
|
|
183
211
|
await act(() => {
|
|
184
212
|
carousel.props.onSnapToItem(4);
|
|
185
213
|
});
|
|
186
214
|
await act(() => {
|
|
187
215
|
carousel.props.onSnapToItem(3);
|
|
188
216
|
});
|
|
189
|
-
expect(
|
|
190
|
-
|
|
217
|
+
expect(
|
|
218
|
+
mock.history.get.filter((req) => req.url === API.UNIT_V2.MY_UNITS(1, 10))
|
|
219
|
+
).toHaveLength(2);
|
|
220
|
+
expect(
|
|
221
|
+
mock.history.get.filter((req) => req.url === API.UNIT_V2.MY_UNITS(2, 10))
|
|
222
|
+
).toHaveLength(1);
|
|
191
223
|
});
|
|
192
224
|
|
|
193
225
|
it('Test navigation select unit', async () => {
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { API, Colors, Images, SCConfig } from '../../../configs';
|
|
2
|
-
import { AccessibilityLabel, DEVICE_TYPE } from '../../../configs/Constants';
|
|
3
|
-
import { Dimensions, TouchableOpacity, View } from 'react-native';
|
|
4
1
|
import React, {
|
|
5
2
|
memo,
|
|
6
3
|
useCallback,
|
|
@@ -10,30 +7,40 @@ import React, {
|
|
|
10
7
|
useRef,
|
|
11
8
|
useState,
|
|
12
9
|
} from 'react';
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
10
|
+
import { Dimensions, TouchableOpacity, View } from 'react-native';
|
|
11
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
12
|
+
import { BleManager } from 'react-native-ble-plx';
|
|
13
|
+
import Carousel from 'react-native-new-snap-carousel';
|
|
16
14
|
import {
|
|
17
15
|
useFocusEffect,
|
|
18
16
|
useIsFocused,
|
|
19
17
|
useNavigation,
|
|
20
18
|
} from '@react-navigation/native';
|
|
21
19
|
|
|
20
|
+
import { API, Colors, Images, SCConfig } from '../../../configs';
|
|
21
|
+
import { AccessibilityLabel, PAGE_SIZE } from '../../../configs/Constants';
|
|
22
|
+
|
|
23
|
+
import { SCContext, useSCContextSelector } from '../../../context';
|
|
22
24
|
import { Action } from '../../../context/actionType';
|
|
23
|
-
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
|
|
26
|
+
import { usePrevious } from '../../../hooks';
|
|
27
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
28
|
+
import { useBluetoothConnection } from '../../../hooks/IoT';
|
|
29
|
+
import useChipJsonConfiguration, {
|
|
30
|
+
useConnectChipMqtt,
|
|
31
|
+
} from '../../../hooks/useMqtt';
|
|
32
|
+
import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
|
|
33
|
+
|
|
34
|
+
import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
|
|
30
35
|
import Routes from '../../../utils/Route';
|
|
36
|
+
|
|
37
|
+
import FImage from '../../FImage';
|
|
31
38
|
import { Section } from '../../Section';
|
|
32
39
|
import Text from '../../Text';
|
|
40
|
+
import SearchMenu from '../../../Images/Common/search-menu.svg';
|
|
41
|
+
import MyUnitDevice from '../../../screens/Unit/components/MyUnitDevice';
|
|
42
|
+
|
|
33
43
|
import styles from './styles';
|
|
34
|
-
import { usePrevious } from '../../../hooks';
|
|
35
|
-
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
36
|
-
import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
|
|
37
44
|
|
|
38
45
|
let screenWidth = Dimensions.get('window').width;
|
|
39
46
|
|
|
@@ -137,24 +144,25 @@ const MyUnit = ({ refreshing }) => {
|
|
|
137
144
|
}, [])
|
|
138
145
|
);
|
|
139
146
|
|
|
140
|
-
|
|
147
|
+
const myUnitDetail = useMemo(
|
|
148
|
+
() => myUnits[slideIndex],
|
|
149
|
+
[myUnits, slideIndex]
|
|
150
|
+
);
|
|
141
151
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return configIds;
|
|
155
|
-
}, [myUnits]);
|
|
152
|
+
useUnitConnectRemoteDevices(myUnitDetail);
|
|
153
|
+
|
|
154
|
+
const { chips } = useChipJsonConfiguration({
|
|
155
|
+
dashboardId: myUnitDetail?.id,
|
|
156
|
+
ready: !!myUnitDetail?.id,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const listChipsMqtt = useMemo(() => {
|
|
160
|
+
const listChipUnit =
|
|
161
|
+
myUnitDetail?.abstract_devices.map((device) => device.chip_id) ?? [];
|
|
162
|
+
return chips.filter((chip) => listChipUnit.includes(chip.id));
|
|
163
|
+
}, [chips, myUnitDetail]);
|
|
156
164
|
|
|
157
|
-
|
|
165
|
+
useConnectChipMqtt(listChipsMqtt);
|
|
158
166
|
|
|
159
167
|
const goToDetail = useCallback(
|
|
160
168
|
(item) => () => {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, TouchableOpacity } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Colors } from '../../configs';
|
|
5
|
+
import { ModalCustom } from '../Modal';
|
|
6
|
+
import Text from '../Text';
|
|
7
|
+
|
|
8
|
+
import styles from './styles';
|
|
9
|
+
|
|
10
|
+
const ModalAlert = ({
|
|
11
|
+
isVisible,
|
|
12
|
+
title,
|
|
13
|
+
description,
|
|
14
|
+
leftText,
|
|
15
|
+
rightText,
|
|
16
|
+
leftColor = Colors.Gray7,
|
|
17
|
+
rightColor = Colors.Primary,
|
|
18
|
+
onLeft,
|
|
19
|
+
onRight,
|
|
20
|
+
}) => {
|
|
21
|
+
return (
|
|
22
|
+
<ModalCustom isVisible={isVisible} style={styles.wrap}>
|
|
23
|
+
<View style={styles.wrapContent}>
|
|
24
|
+
<View style={styles.wrapText}>
|
|
25
|
+
<Text bold type={'H4'} style={styles.title}>
|
|
26
|
+
{title}
|
|
27
|
+
</Text>
|
|
28
|
+
<Text>{description}</Text>
|
|
29
|
+
</View>
|
|
30
|
+
<View style={styles.line} />
|
|
31
|
+
<View style={styles.wrapButton}>
|
|
32
|
+
<TouchableOpacity onPress={onLeft} style={styles.buttonStyle}>
|
|
33
|
+
<Text bold type={'H4'} color={leftColor}>
|
|
34
|
+
{leftText}
|
|
35
|
+
</Text>
|
|
36
|
+
</TouchableOpacity>
|
|
37
|
+
<TouchableOpacity
|
|
38
|
+
onPress={onRight}
|
|
39
|
+
style={[styles.buttonStyle, styles.buttonRightStyle]}
|
|
40
|
+
>
|
|
41
|
+
<Text bold type={'H4'} color={rightColor}>
|
|
42
|
+
{rightText}
|
|
43
|
+
</Text>
|
|
44
|
+
</TouchableOpacity>
|
|
45
|
+
</View>
|
|
46
|
+
</View>
|
|
47
|
+
</ModalCustom>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default ModalAlert;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors } from '../../configs';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
wrap: {
|
|
6
|
+
flex: 1,
|
|
7
|
+
justifyContent: 'center',
|
|
8
|
+
alignItems: 'center',
|
|
9
|
+
backgroundColor: Colors.TextTransparent,
|
|
10
|
+
padding: 16,
|
|
11
|
+
margin: 0,
|
|
12
|
+
},
|
|
13
|
+
wrapContent: {
|
|
14
|
+
height: 186,
|
|
15
|
+
backgroundColor: Colors.White,
|
|
16
|
+
width: '100%',
|
|
17
|
+
borderRadius: 10,
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
},
|
|
20
|
+
title: {
|
|
21
|
+
marginTop: 8,
|
|
22
|
+
marginBottom: 16,
|
|
23
|
+
},
|
|
24
|
+
wrapButton: {
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
paddingHorizontal: 16,
|
|
28
|
+
marginTop: 24,
|
|
29
|
+
},
|
|
30
|
+
buttonStyle: {
|
|
31
|
+
flex: 1,
|
|
32
|
+
height: 42,
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
borderRadius: 30,
|
|
35
|
+
borderWidth: 0,
|
|
36
|
+
},
|
|
37
|
+
buttonRightStyle: {
|
|
38
|
+
marginLeft: 8,
|
|
39
|
+
borderWidth: 0,
|
|
40
|
+
},
|
|
41
|
+
line: {
|
|
42
|
+
borderTopWidth: 1,
|
|
43
|
+
borderTopColor: Colors.Neutral.Neutral3,
|
|
44
|
+
width: '90%',
|
|
45
|
+
alignSelf: 'center',
|
|
46
|
+
},
|
|
47
|
+
wrapText: {
|
|
48
|
+
paddingHorizontal: 24,
|
|
49
|
+
paddingVertical: 16,
|
|
50
|
+
flex: 1,
|
|
51
|
+
flexDirection: 'column',
|
|
52
|
+
alignItems: 'flex-start',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import FastImage from 'react-native-fast-image';
|
|
3
4
|
import { useNavigation } from '@react-navigation/native';
|
|
4
5
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
6
|
import { useDevicesStatus } from '../../hooks/Common';
|
|
@@ -12,9 +13,12 @@ import Text from '../Text';
|
|
|
12
13
|
import ItemDevice from '../Device/ItemDevice';
|
|
13
14
|
import ItemHanetDevice from '../Device/Hanet/ItemHanetDevice';
|
|
14
15
|
import ItemAddNew from '../Device/ItemAddNew';
|
|
16
|
+
import useChipJsonConfiguration, {
|
|
17
|
+
useConnectChipMqtt,
|
|
18
|
+
} from '../../hooks/useMqtt';
|
|
19
|
+
import useWatchSharedChips from '../../hooks/IoT/useWatchSharedChips';
|
|
15
20
|
import { standardizeCameraScreenSize } from '../../utils/Utils';
|
|
16
21
|
import Routes from '../../utils/Route';
|
|
17
|
-
import FastImage from 'react-native-fast-image';
|
|
18
22
|
import MediaPlayerDetail from '../MediaPlayerDetail';
|
|
19
23
|
import { DeviceTemplate } from './DeviceTemplate/DeviceTemplate';
|
|
20
24
|
|
|
@@ -28,6 +32,17 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
|
|
|
28
32
|
|
|
29
33
|
useDevicesStatus(unit, station?.devices);
|
|
30
34
|
|
|
35
|
+
const { chips, isFetching } = useChipJsonConfiguration({
|
|
36
|
+
dashboardId: unit?.id,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const listChipsMqtt = useMemo(() => {
|
|
40
|
+
const stationChipIds = station?.devices?.map((device) => device.chip_id);
|
|
41
|
+
return chips?.filter((chip) => stationChipIds?.includes(chip.id));
|
|
42
|
+
}, [chips, station?.devices]);
|
|
43
|
+
|
|
44
|
+
const { mqttConfigs } = useConnectChipMqtt(listChipsMqtt);
|
|
45
|
+
|
|
31
46
|
const configsNeedWatching = useMemo(() => {
|
|
32
47
|
const configIds = (station?.devices || []).flatMap((device) => {
|
|
33
48
|
const ids = [];
|
|
@@ -45,10 +60,11 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
|
|
|
45
60
|
return ids;
|
|
46
61
|
});
|
|
47
62
|
|
|
48
|
-
return configIds;
|
|
49
|
-
}, [station]);
|
|
63
|
+
return configIds.filter((id) => !mqttConfigs[id]);
|
|
64
|
+
}, [station, mqttConfigs]);
|
|
50
65
|
|
|
51
|
-
useWatchConfigs(configsNeedWatching);
|
|
66
|
+
useWatchConfigs(isFetching ? [] : configsNeedWatching);
|
|
67
|
+
useWatchSharedChips({ dashboardId: unit?.id });
|
|
52
68
|
|
|
53
69
|
const goToPlayBack = useCallback(() => {
|
|
54
70
|
navigate(Routes.PlaybackCamera, {
|