@eohjsc/react-native-smart-city 0.3.48 → 0.3.50

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 (196) hide show
  1. package/package.json +4 -4
  2. package/src/Images/DevMode/file_copy.svg +3 -0
  3. package/src/Images/DevMode/inforCode.png +0 -0
  4. package/src/Images/DevMode/inforCode@2x.png +0 -0
  5. package/src/Images/DevMode/inforCode@3x.png +0 -0
  6. package/src/commons/Action/__test__/ItemQuickAction.test.js +0 -7
  7. package/src/commons/ActionGroup/OnOffTemplate/index.js +6 -8
  8. package/src/commons/ActionGroup/SliderRangeTemplate.js +7 -2
  9. package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +1 -8
  10. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +99 -1
  11. package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +28 -11
  12. package/src/commons/ActionTemplate/__test__/CurtainAction.test.js +64 -0
  13. package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +54 -0
  14. package/src/commons/ActionTemplate/__test__/index.test.js +0 -7
  15. package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +3 -3
  16. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +1 -1
  17. package/src/commons/Dashboard/MyUnit/index.js +30 -4
  18. package/src/commons/DevMode/Styles/ItemStyles.js +1 -1
  19. package/src/commons/Device/HorizontalBarChart.js +0 -1
  20. package/src/commons/Device/PMSensor/PMSensorIndicatior.js +4 -1
  21. package/src/commons/FourButtonFilterHistory/__test__/FourButtonFilterHistory.test.js +0 -7
  22. package/src/commons/Header/HeaderCustom.js +13 -6
  23. package/src/commons/MediaPlayer/__test__/index.test.js +0 -7
  24. package/src/commons/MediaPlayerDetail/__test__/MediaPlayerFull.test.js +0 -1
  25. package/src/commons/MenuActionMore/index.js +4 -1
  26. package/src/commons/NavBar/index.js +1 -1
  27. package/src/commons/OneTapTemplate/OptionsDropdownActionTemplate.js +1 -1
  28. package/src/commons/OneTapTemplate/__test__/NumberUpDownActionTemplate.test.js +0 -7
  29. package/src/commons/OneTapTemplate/__test__/OptionsDropdownActionTemplate.test.js +0 -7
  30. package/src/commons/OneTapTemplate/__test__/StatesGridActionTemplate.test.js +0 -7
  31. package/src/commons/Processing/styles.js +0 -2
  32. package/src/commons/RowItem/index.js +6 -1
  33. package/src/commons/SelectUnit/index.js +4 -1
  34. package/src/commons/Sharing/WrapHeaderScrollable.js +5 -4
  35. package/src/commons/StatusBox/styles.js +8 -3
  36. package/src/commons/SubUnit/__test__/Favorites.test.js +0 -7
  37. package/src/commons/SubUnit/__test__/ShortDetail.test.js +0 -7
  38. package/src/commons/Tabbar/__test__/index.test.js +0 -7
  39. package/src/commons/Unit/__test__/HeaderUnit.test.js +0 -5
  40. package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +9 -9
  41. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +41 -39
  42. package/src/configs/API.js +28 -0
  43. package/src/configs/AccessibilityLabel.js +13 -0
  44. package/src/configs/Colors.js +4 -0
  45. package/src/configs/Constants.js +8 -0
  46. package/src/configs/Images.js +1 -0
  47. package/src/configs/SCConfig.js +3 -0
  48. package/src/context/actionType.ts +8 -1
  49. package/src/context/mockStore.ts +8 -2
  50. package/src/context/reducer.ts +27 -4
  51. package/src/hooks/IoT/__test__/useWatchConfigs.test.js +46 -0
  52. package/src/hooks/IoT/useBluetoothConnection.js +78 -4
  53. package/src/hooks/IoT/useBluetoothDeviceConnected.js +1 -1
  54. package/src/iot/RemoteControl/Bluetooth.js +0 -16
  55. package/src/iot/RemoteControl/__test__/Bluetooth.test.js +0 -25
  56. package/src/navigations/AddDeviceStack.js +0 -5
  57. package/src/navigations/Main.js +39 -0
  58. package/src/navigations/UnitStack.js +23 -9
  59. package/src/screens/AQIGuide/index.js +2 -2
  60. package/src/screens/ActivityLog/__test__/FilterPopup.test.js +0 -7
  61. package/src/screens/ActivityLog/__test__/ItemLog.test.js +0 -7
  62. package/src/screens/ActivityLog/__test__/index.test.js +0 -7
  63. package/src/screens/ActivityLog/styles/itemLogStyles.js +1 -0
  64. package/src/screens/AddLocationMaps/__test__/index.test.js +0 -7
  65. package/src/screens/AddNewAction/SelectAction.js +22 -18
  66. package/src/screens/AddNewAction/__test__/SelectAction.test.js +35 -16
  67. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +0 -7
  68. package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +1 -5
  69. package/src/screens/AddNewGateway/ConnectingDevice.js +25 -3
  70. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +1 -1
  71. package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +10 -0
  72. package/src/screens/AddNewGateway/ConnectingZigbeeDevice.js +5 -6
  73. package/src/screens/AddNewGateway/ShareWifiPassword.js +2 -1
  74. package/src/screens/AddNewGateway/__test__/AddNewGateway.test.js +0 -4
  75. package/src/screens/AddNewGateway/__test__/ConnectingModbusDevice.test.js +0 -4
  76. package/src/screens/AddNewGateway/__test__/ConnectingWifiDevice.test.js +2 -5
  77. package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +29 -6
  78. package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +0 -7
  79. package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +0 -4
  80. package/src/screens/AddNewGateway/__test__/SelectModbusGateway.test.js +0 -4
  81. package/src/screens/AddNewGateway/__test__/SelectZigbeeGateway.test.js +0 -4
  82. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +0 -7
  83. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +0 -1
  84. package/src/screens/Device/EditDevice/__test__/EditDevice.test.js +0 -7
  85. package/src/screens/Device/__test__/detail.test.js +1 -1
  86. package/src/screens/Device/detail.js +12 -6
  87. package/src/screens/Device/hooks/useDisconnectedDevice.js +26 -7
  88. package/src/screens/EmergencyContacts/__test__/hooks.test.js +79 -0
  89. package/src/screens/Gateway/DetailConfigActionModbus/__test__/index.test.js +138 -0
  90. package/src/screens/Gateway/DetailConfigActionModbus/index.js +180 -0
  91. package/src/screens/Gateway/DetailConfigActionModbus/styles.js +9 -0
  92. package/src/screens/Gateway/DetailConfigActionZigbee/__test__/index.test.js +73 -0
  93. package/src/screens/Gateway/DetailConfigActionZigbee/index.js +62 -0
  94. package/src/screens/Gateway/DetailConfigActionZigbee/styles.js +9 -0
  95. package/src/screens/Gateway/DeviceGatewayInfo/__test__/index.test.js +73 -0
  96. package/src/screens/Gateway/DeviceGatewayInfo/index.js +96 -0
  97. package/src/screens/Gateway/DeviceGatewayInfo/styles.js +9 -0
  98. package/src/screens/Gateway/DeviceModbusDetail/__test__/index.test.js +393 -0
  99. package/src/screens/Gateway/DeviceModbusDetail/index.js +176 -0
  100. package/src/screens/Gateway/DeviceModbusDetail/styles.js +12 -0
  101. package/src/screens/Gateway/DeviceZigbeeDetail/__test__/index.test.js +265 -0
  102. package/src/screens/Gateway/DeviceZigbeeDetail/index.js +148 -0
  103. package/src/screens/Gateway/DeviceZigbeeDetail/styles.js +12 -0
  104. package/src/screens/Gateway/GatewayConnectionMethods/__test__/index.test.js +37 -0
  105. package/src/screens/Gateway/GatewayConnectionMethods/index.js +73 -0
  106. package/src/screens/Gateway/GatewayConnectionMethods/styles.js +45 -0
  107. package/src/screens/Gateway/GatewayDetail/__test__/index.test.js +298 -0
  108. package/src/screens/Gateway/GatewayDetail/index.js +148 -0
  109. package/src/screens/Gateway/GatewayDetail/styles.js +12 -0
  110. package/src/screens/Gateway/GatewayInfo/__test__/index.test.js +137 -0
  111. package/src/screens/Gateway/GatewayInfo/index.js +115 -0
  112. package/src/screens/Gateway/GatewayInfo/styles.js +9 -0
  113. package/src/screens/Gateway/__test__/index.test.js +58 -0
  114. package/src/screens/Gateway/components/Detail/__test__/index.test.js +46 -0
  115. package/src/screens/Gateway/components/Detail/index.js +62 -0
  116. package/src/screens/Gateway/components/Detail/styles.js +27 -0
  117. package/src/screens/Gateway/components/DetailActionModbus/__test__/index.test.js +49 -0
  118. package/src/screens/Gateway/components/DetailActionModbus/index.js +52 -0
  119. package/src/screens/Gateway/components/DetailActionModbus/styles.js +32 -0
  120. package/src/screens/Gateway/components/DetailConfigAction/__test__/index.test.js +59 -0
  121. package/src/screens/Gateway/components/DetailConfigAction/index.js +69 -0
  122. package/src/screens/Gateway/components/DetailConfigAction/styles.js +21 -0
  123. package/src/screens/Gateway/components/GatewayItem/__test__/index.test.js +1 -1
  124. package/src/screens/Gateway/components/GatewayItem/styles.js +4 -33
  125. package/src/screens/Gateway/components/Information/__test__/index.test.js +70 -0
  126. package/src/screens/Gateway/components/Information/index.js +116 -0
  127. package/src/screens/Gateway/components/Information/styles.js +59 -0
  128. package/src/screens/Gateway/components/RowItem/__test__/index.test.js +67 -0
  129. package/src/screens/Gateway/components/RowItem/index.js +65 -0
  130. package/src/screens/Gateway/components/RowItem/styles.js +25 -0
  131. package/src/screens/Gateway/components/TabPaneCT/__test__/index.test.js +98 -0
  132. package/src/screens/Gateway/components/TabPaneCT/index.js +134 -0
  133. package/src/screens/Gateway/components/TabPaneCT/styles.js +58 -0
  134. package/src/screens/Gateway/hooks/__test__/index.test.js +93 -0
  135. package/src/screens/Gateway/hooks/useGateway.js +110 -16
  136. package/src/screens/Gateway/index.js +19 -3
  137. package/src/screens/Gateway/styles.js +6 -8
  138. package/src/screens/Gateway/utils/index.js +16 -0
  139. package/src/screens/GuestInfo/__test__/index.test.js +0 -7
  140. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +0 -7
  141. package/src/screens/HanetCamera/__test__/Detail.test.js +0 -7
  142. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +0 -7
  143. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +0 -7
  144. package/src/screens/ManageAccess/__test__/ManageAccess.test.js +0 -6
  145. package/src/screens/ManageAccess/hooks/__test__/useManageAccess.test.js +0 -7
  146. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +0 -7
  147. package/src/screens/Notification/__test__/Notification.test.js +0 -7
  148. package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
  149. package/src/screens/Notification/components/NotificationItem.js +16 -1
  150. package/src/screens/Notification/index.js +1 -0
  151. package/src/screens/Notification/styles/indexStyles.js +3 -0
  152. package/src/screens/PlayBackCamera/__test__/index.test.js +0 -1
  153. package/src/screens/ScriptDetail/__test__/index.test.js +0 -7
  154. package/src/screens/SelectUnit/__test__/index.test.js +0 -1
  155. package/src/screens/SetSchedule/__test__/index.test.js +0 -7
  156. package/src/screens/Sharing/Components/__test__/DeviceItem.test.js +0 -7
  157. package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +0 -7
  158. package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +0 -7
  159. package/src/screens/Sharing/SelectPermission.js +2 -2
  160. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +0 -6
  161. package/src/screens/Sharing/hooks/__test__/index.test.js +80 -0
  162. package/src/screens/SmartAccount/ListDevice/__test__/DeviceItem.test.js +0 -7
  163. package/src/screens/SmartAccount/SuccessfullyConnected/__test__/SuccessfullyConnected.test.js +26 -7
  164. package/src/screens/SmartAccount/SuccessfullyConnected/index.js +29 -11
  165. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +0 -6
  166. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +1 -6
  167. package/src/screens/SmartIr/__test__/SelectBrand.test.js +1 -6
  168. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +1 -6
  169. package/src/screens/SubUnit/AddSubUnit.js +1 -0
  170. package/src/screens/SubUnit/ManageSubUnit.js +4 -1
  171. package/src/screens/SubUnit/hooks/__test__/useEmergencyContacts.test.js +34 -0
  172. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +0 -7
  173. package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +1 -8
  174. package/src/screens/Template/__test__/GatewayList.test.js +1 -1
  175. package/src/screens/Template/__test__/Information.test.js +1 -1
  176. package/src/screens/Unit/Detail.js +24 -18
  177. package/src/screens/Unit/__test__/AddMenu.test.js +0 -7
  178. package/src/screens/Unit/__test__/CheckSendEmail.test.js +1 -1
  179. package/src/screens/Unit/__test__/ChooseLocation.test.js +0 -7
  180. package/src/screens/Unit/__test__/Detail.test.js +63 -26
  181. package/src/screens/Unit/__test__/SelectAddToFavorites.test.js +0 -7
  182. package/src/screens/Unit/__test__/SelectAddress.test.js +0 -7
  183. package/src/screens/Unit/__test__/SmartAccount.test.js +0 -7
  184. package/src/screens/Unit/__test__/SmartAccountItem.test.js +0 -7
  185. package/src/screens/Unit/__test__/Summaries.test.js +0 -7
  186. package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +4 -3
  187. package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +2 -2
  188. package/src/utils/Apis/axios.js +52 -36
  189. package/src/utils/I18n/translations/en.json +32 -0
  190. package/src/utils/I18n/translations/vi.json +33 -1
  191. package/src/utils/Route/index.js +8 -0
  192. package/src/utils/Storage.js +0 -4
  193. package/src/utils/Utils.js +1 -1
  194. package/src/utils/__test__/Utils.test.js +27 -3
  195. package/src/screens/AddNewDevice/ConnectingDevices.js +0 -62
  196. package/src/screens/AddNewDevice/__test__/ConnectingDevices.test.js +0 -110
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.3.48",
4
+ "version": "0.3.50",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -64,9 +64,9 @@
64
64
  "license": "MIT",
65
65
  "licenseFilename": "LICENSE",
66
66
  "peerDependencies": {
67
- "@react-native-community/clipboard": "*",
68
67
  "react": "*",
69
- "react-native": "*"
68
+ "react-native": "*",
69
+ "@react-native-community/clipboard": "*"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@babel/core": "^7.12.9",
@@ -183,7 +183,7 @@
183
183
  "react-native-pager-view": "^5.4.1",
184
184
  "react-native-parallax-scroll-view": "^0.21.3",
185
185
  "react-native-parsed-text": "^0.0.22",
186
- "react-native-permissions": "3.0.3",
186
+ "react-native-permissions": "3.4.0",
187
187
  "react-native-popover-view": "^4.0.3",
188
188
  "react-native-progress": "^5.0.0",
189
189
  "react-native-reanimated": "1.10.1",
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M16 1.59863H4C2.9 1.59863 2 2.49863 2 3.59863V17.5986H4V3.59863H16V1.59863ZM15 5.59863H8C6.9 5.59863 6.01 6.49863 6.01 7.59863L6 21.5986C6 22.6986 6.89 23.5986 7.99 23.5986H19C20.1 23.5986 21 22.6986 21 21.5986V11.5986L15 5.59863ZM8 21.5986V7.59863H14V12.5986H19V21.5986H8Z" fill="#808080"/>
3
+ </svg>
Binary file
@@ -12,13 +12,6 @@ class Sensor {}
12
12
 
13
13
  factory.define('Sensor', Sensor, {});
14
14
 
15
- jest.mock('react', () => {
16
- return {
17
- ...jest.requireActual('react'),
18
- memo: (x) => x,
19
- };
20
- });
21
-
22
15
  const mockSendRemoteControl = jest.fn();
23
16
  jest.mock('../../../hooks/IoT', () => {
24
17
  return {
@@ -75,9 +75,8 @@ const OnOffTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
75
75
  break;
76
76
  case DEVICE_TYPE.LG_THINQ:
77
77
  setTempIsOn((prev) => !prev);
78
- if (action_data) {
79
- await doAction(action_data, JSON.stringify({ value: !isOn }));
80
- }
78
+ action_data &&
79
+ (await doAction(action_data, JSON.stringify({ value: !isOn })));
81
80
  break;
82
81
  default:
83
82
  if (action_data) {
@@ -97,11 +96,10 @@ const OnOffTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
97
96
  break;
98
97
  }
99
98
  updateStatusFromPusher();
100
- if (sensor?.is_managed_by_backend) {
101
- if (config && sensor.device_type === DEVICE_TYPE.LG_THINQ) {
102
- watchMultiConfigs([config]);
103
- }
104
- }
99
+ sensor?.is_managed_by_backend &&
100
+ config &&
101
+ sensor.device_type === DEVICE_TYPE.LG_THINQ &&
102
+ watchMultiConfigs([config]);
105
103
  }, [
106
104
  allow_config_store_value,
107
105
  config,
@@ -30,14 +30,19 @@ const SliderRangeTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
30
30
  const [valueBrightness, setValueBrightness] = useState(getPercent());
31
31
  const [isFirstTime, setIsFirstTime] = useState(true);
32
32
 
33
+ // TODO Thinh: remove action_brightness_data
33
34
  const onChangeBrightness = useCallback(
34
35
  async (value) => {
35
36
  await doAction(
36
- configuration?.action_brightness_data,
37
+ configuration?.action_brightness_data || configuration?.action_data,
37
38
  JSON.stringify({ value_brness: value })
38
39
  );
39
40
  },
40
- [configuration?.action_brightness_data, doAction]
41
+ [
42
+ configuration?.action_brightness_data,
43
+ configuration?.action_data,
44
+ doAction,
45
+ ]
41
46
  );
42
47
 
43
48
  useEffect(() => {
@@ -12,14 +12,7 @@ const mockDoAction = jest.fn();
12
12
  jest.mock('../../../iot/states', () => ({
13
13
  useConfigGlobalState: jest.fn(),
14
14
  }));
15
- const mockSetState = jest.fn();
16
- jest.mock('react', () => {
17
- return {
18
- ...jest.requireActual('react'),
19
- useState: jest.fn((init) => [init, mockSetState]),
20
- memo: (x) => x,
21
- };
22
- });
15
+
23
16
  const wrapComponent = (actionGroup, doAction, sensor) => (
24
17
  <SCProvider initState={mockSCStore({})}>
25
18
  <ColorPickerTemplate
@@ -118,7 +118,7 @@ describe('Test OnOffTemplate', () => {
118
118
  });
119
119
  const instance = tree.root;
120
120
  const template = instance.findAllByType(OnOffButtonTemplate);
121
- expect(template).toHaveLength(0);
121
+ expect(template).toHaveLength(1);
122
122
  });
123
123
 
124
124
  it('render with wrong template', async () => {
@@ -227,6 +227,7 @@ describe('Test OnOffTemplate', () => {
227
227
  });
228
228
 
229
229
  it('render with template OnOffSimpleActionTemplate with just action_data lg_thinq', async () => {
230
+ jest.useFakeTimers();
230
231
  actionGroup = {
231
232
  template: 'OnOffSimpleActionTemplate',
232
233
  configuration: {
@@ -242,6 +243,7 @@ describe('Test OnOffTemplate', () => {
242
243
  tree = await create(
243
244
  wrapComponent(actionGroup, mockDoAction, {
244
245
  device_type: DEVICE_TYPE.LG_THINQ,
246
+ is_managed_by_backend: true,
245
247
  })
246
248
  );
247
249
  });
@@ -253,12 +255,108 @@ describe('Test OnOffTemplate', () => {
253
255
  await act(async () => {
254
256
  await template[0].props.triggerAction();
255
257
  });
258
+ jest.runAllTimers();
256
259
  expect(mockDoAction).toHaveBeenCalledWith(
257
260
  action_data,
258
261
  JSON.stringify({ value: false })
259
262
  );
260
263
  });
261
264
 
265
+ it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger off', async () => {
266
+ actionGroup = {
267
+ template: 'OnOffSimpleActionTemplate',
268
+ configuration: {
269
+ config: 5,
270
+ action_on_data: action_on_data,
271
+ action_off_data: action_off_data,
272
+ icon: 'up',
273
+ is_on_value: [2],
274
+ allow_config_store_value: true,
275
+ },
276
+ title: 'Turn on / off',
277
+ };
278
+ const mockDoAction = jest.fn();
279
+ await act(async () => {
280
+ tree = await create(
281
+ wrapComponent(actionGroup, mockDoAction, {
282
+ device_type: DEVICE_TYPE.ZIGBEE,
283
+ })
284
+ );
285
+ });
286
+ const instance = tree.root;
287
+ const template = instance.findAllByType(OnOffSimpleTemplate);
288
+
289
+ await act(async () => {
290
+ await template[0].props.triggerAction();
291
+ });
292
+ expect(mockDoAction).toHaveBeenCalledWith(
293
+ action_off_data,
294
+ JSON.stringify({ state: 0, config_id: 5, config_value: 0 })
295
+ );
296
+ });
297
+
298
+ it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger on', async () => {
299
+ actionGroup = {
300
+ template: 'OnOffSimpleActionTemplate',
301
+ configuration: {
302
+ config: 5,
303
+ action_on_data: action_on_data,
304
+ action_off_data: action_off_data,
305
+ icon: 'up',
306
+ is_on_value: [1],
307
+ allow_config_store_value: true,
308
+ },
309
+ title: 'Turn on / off',
310
+ };
311
+ const mockDoAction = jest.fn();
312
+ await act(async () => {
313
+ tree = await create(
314
+ wrapComponent(actionGroup, mockDoAction, {
315
+ device_type: DEVICE_TYPE.ZIGBEE,
316
+ })
317
+ );
318
+ });
319
+ const instance = tree.root;
320
+ const template = instance.findAllByType(OnOffSimpleTemplate);
321
+
322
+ await act(async () => {
323
+ await template[0].props.triggerAction();
324
+ });
325
+ expect(mockDoAction).toHaveBeenCalledWith(
326
+ action_on_data,
327
+ JSON.stringify({ state: 1, config_id: 5, config_value: 1 })
328
+ );
329
+ });
330
+
331
+ it('render with template OnOffSimpleActionTemplate with zigbee device wrong action_data', async () => {
332
+ actionGroup = {
333
+ template: 'OnOffSimpleActionTemplate',
334
+ configuration: {
335
+ config: 5,
336
+ action_data: action_data,
337
+ icon: 'up',
338
+ is_on_value: [2],
339
+ allow_config_store_value: true,
340
+ },
341
+ title: 'Turn on / off',
342
+ };
343
+ const mockDoAction = jest.fn();
344
+ await act(async () => {
345
+ tree = await create(
346
+ wrapComponent(actionGroup, mockDoAction, {
347
+ device_type: DEVICE_TYPE.ZIGBEE,
348
+ })
349
+ );
350
+ });
351
+ const instance = tree.root;
352
+ const template = instance.findAllByType(OnOffSimpleTemplate);
353
+
354
+ await act(async () => {
355
+ await template[0].props.triggerAction();
356
+ });
357
+ expect(mockDoAction).not.toHaveBeenCalled();
358
+ });
359
+
262
360
  it('render with template OnOffSimpleActionTemplate disabled', async () => {
263
361
  actionGroup = {
264
362
  template: 'OnOffSimpleActionTemplate',
@@ -12,14 +12,7 @@ const mockDoAction = jest.fn();
12
12
  jest.mock('../../../iot/states', () => ({
13
13
  useConfigGlobalState: jest.fn(),
14
14
  }));
15
- const mockSetState = jest.fn();
16
- jest.mock('react', () => {
17
- return {
18
- ...jest.requireActual('react'),
19
- useState: jest.fn((init) => [init, mockSetState]),
20
- memo: (x) => x,
21
- };
22
- });
15
+
23
16
  const wrapComponent = (actionGroup, doAction, sensor) => (
24
17
  <SCProvider initState={mockSCStore({})}>
25
18
  <SliderRangeTemplate
@@ -34,7 +27,7 @@ describe('Test SliderRangeTemplate', () => {
34
27
  let wrapper;
35
28
  let actionGroup;
36
29
 
37
- const action_brightness_data = {
30
+ const action_data = {
38
31
  color: '#00979D',
39
32
  command_prefer_over_bluetooth: false,
40
33
  command_prefer_over_googlehome: false,
@@ -49,7 +42,7 @@ describe('Test SliderRangeTemplate', () => {
49
42
  template: 'ColorPickerTemplate',
50
43
  configuration: {
51
44
  config: 5,
52
- action_brightness_data: action_brightness_data,
45
+ action_data,
53
46
  },
54
47
  title: '',
55
48
  };
@@ -65,7 +58,31 @@ describe('Test SliderRangeTemplate', () => {
65
58
  const silderRange = instance.findAllByType(SliderRange);
66
59
  expect(silderRange).toHaveLength(1);
67
60
  await act(async () => {
68
- await silderRange[0].props.onSlidingComplete();
61
+ await silderRange[0].props.onSlidingComplete(50);
62
+ });
63
+ expect(mockDoAction).toHaveBeenCalledWith(
64
+ action_data,
65
+ JSON.stringify({ value_brness: 50 })
66
+ );
67
+ });
68
+
69
+ it('render template SliderRangeTemplate with data backward compatible', async () => {
70
+ actionGroup.configuration.action_data = undefined;
71
+ actionGroup.configuration.action_brightness_data = action_data;
72
+ useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
73
+ const sensor = { is_managed_by_backend: true, name: 'Sensor' };
74
+ await act(async () => {
75
+ wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
76
+ });
77
+ const instance = wrapper.root;
78
+ const silderRange = instance.findAllByType(SliderRange);
79
+ expect(silderRange).toHaveLength(1);
80
+ await act(async () => {
81
+ await silderRange[0].props.onSlidingComplete(50);
69
82
  });
83
+ expect(mockDoAction).toHaveBeenCalledWith(
84
+ action_data,
85
+ JSON.stringify({ value_brness: 50 })
86
+ );
70
87
  });
71
88
  });
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import { TouchableOpacity } from 'react-native';
4
+
5
+ import CurtainAction from '../CurtainAction';
6
+ import { SCProvider } from '../../../context';
7
+ import { mockSCStore } from '../../../context/mockStore';
8
+
9
+ const wrapComponent = (configuration, onPress) => (
10
+ <SCProvider initState={mockSCStore({})}>
11
+ <CurtainAction configuration={configuration} onPress={onPress} />
12
+ </SCProvider>
13
+ );
14
+
15
+ describe('Test CurtainAction', () => {
16
+ let tree;
17
+
18
+ it('test onPress curtain action', async () => {
19
+ const configuration = {
20
+ open_action: 'a',
21
+ close_action: 'b',
22
+ stop_action: 'c',
23
+ text1: '1',
24
+ text2: '2',
25
+ text3: '3',
26
+ };
27
+ const mockFuntion = jest.fn();
28
+ await act(async () => {
29
+ tree = renderer.create(wrapComponent(configuration, mockFuntion));
30
+ });
31
+ const instance = tree.root;
32
+ const touchOpacity = instance.findAllByType(TouchableOpacity);
33
+
34
+ expect(touchOpacity).toHaveLength(3);
35
+ await act(async () => {
36
+ touchOpacity[0].props.onPress();
37
+ });
38
+ expect(mockFuntion).toHaveBeenCalledWith({
39
+ name: configuration.text1,
40
+ action: configuration.close_action,
41
+ template: undefined,
42
+ });
43
+
44
+ mockFuntion.mockClear();
45
+ await act(async () => {
46
+ touchOpacity[1].props.onPress();
47
+ });
48
+ expect(mockFuntion).toHaveBeenCalledWith({
49
+ name: configuration.text2,
50
+ action: configuration.stop_action,
51
+ template: undefined,
52
+ });
53
+
54
+ mockFuntion.mockClear();
55
+ await act(async () => {
56
+ touchOpacity[2].props.onPress();
57
+ });
58
+ expect(mockFuntion).toHaveBeenCalledWith({
59
+ name: configuration.text3,
60
+ action: configuration.open_action,
61
+ template: undefined,
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import { TouchableOpacity } from 'react-native';
4
+
5
+ import OnOffSmartLockAction from '../OnOffSmartLockAction';
6
+ import { SCProvider } from '../../../context';
7
+ import { mockSCStore } from '../../../context/mockStore';
8
+
9
+ const wrapComponent = (configuration, onPress) => (
10
+ <SCProvider initState={mockSCStore({})}>
11
+ <OnOffSmartLockAction configuration={configuration} onPress={onPress} />
12
+ </SCProvider>
13
+ );
14
+
15
+ describe('Test OnOffSmartLockAction', () => {
16
+ let tree;
17
+
18
+ it('test onPress smart lock action', async () => {
19
+ const configuration = {
20
+ action_on: 'a',
21
+ action_off: 'b',
22
+ text_on: 'on',
23
+ text_off: 'off',
24
+ };
25
+ const mockFuntion = jest.fn();
26
+ await act(async () => {
27
+ tree = renderer.create(wrapComponent(configuration, mockFuntion));
28
+ });
29
+ const instance = tree.root;
30
+ const touchOpacity = instance.findAllByType(TouchableOpacity);
31
+
32
+ expect(touchOpacity).toHaveLength(2);
33
+ await act(async () => {
34
+ touchOpacity[0].props.onPress();
35
+ });
36
+ expect(mockFuntion).toHaveBeenCalledWith({
37
+ ...configuration,
38
+ name: configuration.text_off,
39
+ action: configuration.action_off,
40
+ action_on: null,
41
+ });
42
+
43
+ mockFuntion.mockClear();
44
+ await act(async () => {
45
+ touchOpacity[1].props.onPress();
46
+ });
47
+ expect(mockFuntion).toHaveBeenCalledWith({
48
+ ...configuration,
49
+ name: configuration.text_on,
50
+ action: configuration.action_on,
51
+ action_off: null,
52
+ });
53
+ });
54
+ });
@@ -8,13 +8,6 @@ import SelectActionCard from '../../SelectActionCard';
8
8
  import Modal from 'react-native-modal';
9
9
  import ThreeButtonAction from '../ThreeButtonAction';
10
10
 
11
- jest.mock('react', () => {
12
- return {
13
- ...jest.requireActual('react'),
14
- memo: (x) => x,
15
- };
16
- });
17
-
18
11
  const mockOnSelectAction = jest.fn();
19
12
 
20
13
  const wrapComponent = (data) => (
@@ -12,7 +12,7 @@ import { useTranslations } from '../../../hooks/Common/useTranslations';
12
12
  import SharedUnit from '../../Unit/SharedUnit';
13
13
  import { fetchWithCache } from '../../../utils/Apis/axios';
14
14
 
15
- const MyPinnedSharedUnit = () => {
15
+ const MyPinnedSharedUnit = ({ refreshing }) => {
16
16
  const t = useTranslations();
17
17
  const isFocused = useIsFocused();
18
18
  const navigation = useNavigation();
@@ -35,10 +35,10 @@ const MyPinnedSharedUnit = () => {
35
35
  }, [setSharedUnits]);
36
36
 
37
37
  useEffect(() => {
38
- if (isFocused) {
38
+ if (isFocused || refreshing) {
39
39
  fetchSharedUnitDashboard();
40
40
  }
41
- }, [fetchSharedUnitDashboard, isFocused]);
41
+ }, [fetchSharedUnitDashboard, isFocused, refreshing]);
42
42
 
43
43
  return (
44
44
  <>
@@ -32,7 +32,7 @@ jest.mock('react-redux', () => ({
32
32
 
33
33
  const wrapComponent = () => (
34
34
  <SCProvider initState={mockSCStore({})}>
35
- <MyUnit />
35
+ <MyUnit refreshing={true} />
36
36
  </SCProvider>
37
37
  );
38
38
 
@@ -13,6 +13,7 @@ import {
13
13
  useFocusEffect,
14
14
  } from '@react-navigation/native';
15
15
  import NetInfo from '@react-native-community/netinfo';
16
+ import { BleManager } from 'react-native-ble-plx';
16
17
  import { API, Colors, Images } from '../../../configs';
17
18
  import Text from '../../Text';
18
19
  import { fetchWithCache } from '../../../utils/Apis/axios';
@@ -21,7 +22,7 @@ import styles from './styles';
21
22
  import { Section } from '../../Section';
22
23
  import { useTranslations } from '../../../hooks/Common/useTranslations';
23
24
  import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
24
- import { useWatchConfigs } from '../../../hooks/IoT';
25
+ import { useWatchConfigs, useBluetoothConnection } from '../../../hooks/IoT';
25
26
  import { SCContext } from '../../../context';
26
27
  import { Action } from '../../../context/actionType';
27
28
 
@@ -31,7 +32,10 @@ import Routes from '../../../utils/Route';
31
32
  import MyUnitDevice from '../../../screens/Unit/components/MyUnitDevice';
32
33
 
33
34
  let screenWidth = Dimensions.get('window').width;
34
- const MyUnit = () => {
35
+
36
+ const bleManager = new BleManager();
37
+
38
+ const MyUnit = ({ refreshing }) => {
35
39
  const t = useTranslations();
36
40
  const isFocused = useIsFocused();
37
41
  const navigation = useNavigation();
@@ -39,6 +43,15 @@ const MyUnit = () => {
39
43
  const [slideIndex, setSlideIndex] = useState(0);
40
44
  const { setAction } = useContext(SCContext);
41
45
 
46
+ const {
47
+ permissionsRequested: bluetoothPermRequested,
48
+ requestPerm: requestBluetoothPerm,
49
+ } = useBluetoothConnection();
50
+
51
+ useEffect(() => {
52
+ !bluetoothPermRequested && requestBluetoothPerm();
53
+ }, [bluetoothPermRequested, requestBluetoothPerm]);
54
+
42
55
  const fetchMyUnitDashboard = useCallback(async () => {
43
56
  await fetchWithCache(API.UNIT.MY_UNITS(), {}, (response) => {
44
57
  const { success, data } = response;
@@ -47,8 +60,10 @@ const MyUnit = () => {
47
60
  }, [setMyUnits]);
48
61
 
49
62
  useEffect(() => {
50
- isFocused && fetchMyUnitDashboard();
51
- }, [fetchMyUnitDashboard, isFocused]);
63
+ if (isFocused || refreshing) {
64
+ fetchMyUnitDashboard();
65
+ }
66
+ }, [fetchMyUnitDashboard, isFocused, refreshing]);
52
67
 
53
68
  useFocusEffect(
54
69
  useCallback(() => {
@@ -60,6 +75,17 @@ const MyUnit = () => {
60
75
  }, [])
61
76
  );
62
77
 
78
+ useFocusEffect(
79
+ useCallback(() => {
80
+ const subscription = bleManager.onStateChange((state) => {
81
+ const connected = state === 'PoweredOn';
82
+ setAction(Action.SET_BLUETOOTH_STATE, connected);
83
+ }, true);
84
+ return () => subscription.remove();
85
+ // eslint-disable-next-line react-hooks/exhaustive-deps
86
+ }, [])
87
+ );
88
+
63
89
  useUnitConnectRemoteDevices(myUnits[slideIndex]);
64
90
 
65
91
  const configsNeedWatching = useMemo(() => {
@@ -21,7 +21,7 @@ export default StyleSheet.create({
21
21
  },
22
22
  countItem: {
23
23
  fontSize: 12,
24
- fontWeight: 400,
24
+ fontWeight: '400',
25
25
  color: Colors.Neutral.Neutral5,
26
26
  },
27
27
  });
@@ -163,7 +163,6 @@ const styles = StyleSheet.create({
163
163
  backgroundColor: Colors.White,
164
164
  justifyContent: 'center',
165
165
  flex: 1,
166
- marginRight: 24,
167
166
  },
168
167
  chartStyle: {
169
168
  backgroundColor: Colors.White,
@@ -9,12 +9,15 @@ const keyExtractor = (item) => item.id.toString();
9
9
  const PMSensorIndicatior = memo(({ data = [], style }) => {
10
10
  const renderItem = useCallback(
11
11
  ({ item }) => {
12
+ const getValue = ['', null, undefined, NaN].includes(item?.value)
13
+ ? '--'
14
+ : item?.value;
12
15
  return (
13
16
  <QualityIndicatorItem
14
17
  key={item.id.toString()}
15
18
  color={item.color}
16
19
  standard={item.standard}
17
- value={item.value || '--'}
20
+ value={getValue}
18
21
  evaluate={item.evaluate}
19
22
  measure={item.measure}
20
23
  style={style}
@@ -11,13 +11,6 @@ const wrapComponent = (props) => (
11
11
  </SCProvider>
12
12
  );
13
13
 
14
- jest.mock('react', () => {
15
- return {
16
- ...jest.requireActual('react'),
17
- memo: (x) => x,
18
- };
19
- });
20
-
21
14
  it('test', async () => {
22
15
  const mockSetGroupBy = jest.fn();
23
16
  let tree;
@@ -7,6 +7,7 @@ import { useNavigation } from '@react-navigation/native';
7
7
  import styles from './Styles/HeaderCustomStyles';
8
8
  import { useTranslations } from '../../hooks/Common/useTranslations';
9
9
  import { notImplemented } from '../../utils/Utils';
10
+ import { AccessibilityLabel } from '../../configs/Constants';
10
11
 
11
12
  const HeaderCustom = ({
12
13
  title = '',
@@ -25,6 +26,7 @@ const HeaderCustom = ({
25
26
  wrapTitleStyle,
26
27
  iconBackStyle,
27
28
  isCanBack = true,
29
+ customTitle = false,
28
30
  }) => {
29
31
  const t = useTranslations();
30
32
  const { goBack } = useNavigation();
@@ -53,12 +55,16 @@ const HeaderCustom = ({
53
55
  </TouchableOpacity>
54
56
  )}
55
57
  <View style={[styles.wrapTitle, wrapTitleStyle]}>
56
- <Text
57
- style={[styles.title, titleStyles, !isShowRight && styles.title2]}
58
- numberOfLines={1}
59
- >
60
- {title}
61
- </Text>
58
+ {!customTitle ? (
59
+ <Text
60
+ style={[styles.title, titleStyles, !isShowRight && styles.title2]}
61
+ numberOfLines={1}
62
+ >
63
+ {title}
64
+ </Text>
65
+ ) : (
66
+ customTitle
67
+ )}
62
68
  </View>
63
69
 
64
70
  <View style={styles.viewRight}>
@@ -77,6 +83,7 @@ const HeaderCustom = ({
77
83
  style={styles.buttonBack}
78
84
  onPress={handleShowMenuAction}
79
85
  ref={refMenuAction}
86
+ accessibilityLabel={AccessibilityLabel.MENU_POPPER_MORE}
80
87
  >
81
88
  <Icon name={'more'} size={27} color={Colors.Black} />
82
89
  </TouchableOpacity>
@@ -5,13 +5,6 @@ import { mockSCStore } from '../../../context/mockStore';
5
5
  import { TouchableOpacity } from 'react-native';
6
6
  import MediaPlay from '../index';
7
7
 
8
- jest.mock('react', () => {
9
- return {
10
- ...jest.requireActual('react'),
11
- memo: (x) => x,
12
- };
13
- });
14
-
15
8
  const wrapComponent = (props) => (
16
9
  <SCProvider initState={mockSCStore({})}>
17
10
  <MediaPlay {...props} />