@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.
Files changed (71) hide show
  1. package/index.js +2 -0
  2. package/package.json +2 -1
  3. package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
  4. package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
  5. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
  6. package/src/commons/Dashboard/MyUnit/index.js +40 -32
  7. package/src/commons/ModalAlert/index.js +51 -0
  8. package/src/commons/ModalAlert/styles.js +54 -0
  9. package/src/commons/SubUnit/ShortDetail.js +20 -4
  10. package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
  11. package/src/configs/API.js +8 -0
  12. package/src/configs/AccessibilityLabel.js +3 -0
  13. package/src/configs/Constants.js +7 -0
  14. package/src/configs/SCConfig.js +6 -0
  15. package/src/context/SCContext.tsx +12 -1
  16. package/src/context/SCStore.ts +14 -0
  17. package/src/context/actionType.ts +10 -0
  18. package/src/context/mockStore.ts +30 -1
  19. package/src/context/reducer.ts +35 -0
  20. package/src/hooks/IoT/useRemoteControl.js +4 -1
  21. package/src/hooks/IoT/useWatchSharedChips.js +130 -0
  22. package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
  23. package/src/hooks/Review/useInAppReview.js +70 -0
  24. package/src/hooks/useMqtt.js +78 -27
  25. package/src/iot/Monitor.js +149 -26
  26. package/src/iot/UpdateStates.js +60 -0
  27. package/src/iot/mqtt.js +177 -22
  28. package/src/navigations/UnitStack.js +16 -0
  29. package/src/screens/ActivityLog/ItemLog.js +1 -0
  30. package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
  31. package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
  32. package/src/screens/Automate/AddNewAction/ReceiverSelect.js +210 -0
  33. package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
  34. package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
  35. package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
  36. package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
  37. package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
  38. package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
  39. package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
  40. package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
  41. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
  42. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
  43. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
  44. package/src/screens/Automate/Components/InputName.js +5 -1
  45. package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +4 -3
  46. package/src/screens/Automate/EditActionsList/UpdateReceiverSmsScript.js +5 -4
  47. package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
  48. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +1 -1
  49. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +116 -2
  50. package/src/screens/Automate/ScriptDetail/index.js +47 -9
  51. package/src/screens/CreatePassword/__test__/index.test.js +133 -0
  52. package/src/screens/CreatePassword/index.js +134 -0
  53. package/src/screens/CreatePassword/styles.js +45 -0
  54. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
  55. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
  56. package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
  57. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
  58. package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
  59. package/src/screens/Device/__test__/detail.test.js +61 -3
  60. package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
  61. package/src/screens/Device/detail.js +14 -6
  62. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
  63. package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
  64. package/src/screens/EnterPassword/index.js +34 -4
  65. package/src/screens/EnterPassword/styles.js +1 -1
  66. package/src/utils/FactoryGateway.js +597 -0
  67. package/src/utils/I18n/translations/en.js +11 -0
  68. package/src/utils/I18n/translations/vi.js +11 -0
  69. package/src/utils/Route/index.js +3 -1
  70. package/src/utils/Validation.js +5 -0
  71. 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.27",
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 { SCContext, useSCContextSelector } from '../../../context';
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
- import { useTranslations } from '../../../hooks/Common/useTranslations';
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
- useWatchConfigs(configsNeedWatching);
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(1);
144
- expect(mock.history.get[0].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
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(mock.history.get).toHaveLength(1);
174
- expect(mock.history.get[0].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
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(mock.history.get).toHaveLength(2);
182
- expect(mock.history.get[1].url).toEqual(API.UNIT_V2.MY_UNITS(2, 10));
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(mock.history.get).toHaveLength(3);
190
- expect(mock.history.get[2].url).toEqual(API.UNIT_V2.MY_UNITS(1, 10));
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 { SCContext, useSCContextSelector } from '../../../context';
14
- import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
15
- import { useBluetoothConnection, useWatchConfigs } from '../../../hooks/IoT';
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
- import { BleManager } from 'react-native-ble-plx';
24
- import Carousel from 'react-native-new-snap-carousel';
25
- import FImage from '../../FImage';
26
- import SearchMenu from '../../../Images/Common/search-menu.svg';
27
- import MyUnitDevice from '../../../screens/Unit/components/MyUnitDevice';
28
- import NetInfo from '@react-native-community/netinfo';
29
- import { PAGE_SIZE } from '../../../configs/Constants';
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
- useUnitConnectRemoteDevices(myUnits[slideIndex]);
147
+ const myUnitDetail = useMemo(
148
+ () => myUnits[slideIndex],
149
+ [myUnits, slideIndex]
150
+ );
141
151
 
142
- const configsNeedWatching = useMemo(() => {
143
- const configIds = [];
144
- myUnits.forEach((unit) => {
145
- (unit?.abstract_devices || []).forEach((device) => {
146
- if (
147
- device?.quick_action?.config_id &&
148
- device?.device_type !== DEVICE_TYPE.GOOGLE_HOME
149
- ) {
150
- configIds.push(device.quick_action.config_id);
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
- useWatchConfigs(configsNeedWatching);
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, {