@eohjsc/react-native-smart-city 0.3.20 → 0.3.23

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 (94) hide show
  1. package/index.js +2 -0
  2. package/package.json +2 -1
  3. package/src/Images/Common/buttonLeftCurtain.png +0 -0
  4. package/src/Images/Common/buttonLeftCurtain@2x.png +0 -0
  5. package/src/Images/Common/buttonLeftCurtain@3x.png +0 -0
  6. package/src/commons/Action/ItemQuickAction.js +1 -12
  7. package/src/commons/Action/__test__/ItemQuickAction.test.js +1 -1
  8. package/src/commons/ActionGroup/ColorPickerTemplate.js +2 -9
  9. package/src/commons/ActionGroup/CurtainButtonTemplate.js +5 -4
  10. package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +5 -0
  11. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +6 -16
  12. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +7 -4
  13. package/src/commons/ActionGroup/OnOffTemplate/index.js +6 -12
  14. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +5 -2
  15. package/src/commons/ActionGroup/SliderRangeTemplate.js +4 -9
  16. package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -10
  17. package/src/commons/ActionGroup/TimerActionTemplate.js +11 -4
  18. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +12 -15
  19. package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +37 -2
  20. package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +7 -0
  21. package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +15 -2
  22. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +8 -1
  23. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +8 -1
  24. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +7 -0
  25. package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +8 -1
  26. package/src/commons/ActionGroup/__test__/TimerActionTemplateWithutConfigValue.test.js +7 -0
  27. package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +7 -0
  28. package/src/commons/ActionGroup/__test__/index.test.js +8 -1
  29. package/src/commons/Device/ItemDevice.js +79 -35
  30. package/src/commons/MediaPlayerDetail/index.js +5 -0
  31. package/src/commons/RowItem/index.js +6 -2
  32. package/src/commons/RowItem/styles.js +1 -0
  33. package/src/commons/SubUnit/Favorites/index.js +24 -6
  34. package/src/commons/SubUnit/ShortDetail.js +19 -5
  35. package/src/commons/SubUnit/__test__/Favorites.test.js +1 -0
  36. package/src/commons/SubUnit/__test__/ShortDetail.test.js +1 -0
  37. package/src/configs/API.js +8 -3
  38. package/src/configs/Constants.js +8 -2
  39. package/src/configs/SCConfig.js +4 -0
  40. package/src/context/actionType.ts +6 -5
  41. package/src/context/mockStore.ts +10 -3
  42. package/src/context/reducer.ts +20 -15
  43. package/src/hoc/index.js +3 -0
  44. package/src/hoc/withRemoteControl.js +10 -0
  45. package/src/hooks/Common/index.js +2 -2
  46. package/src/hooks/Common/useDevicesStatus.js +57 -0
  47. package/src/hooks/Common/useGGHomeDeviceConnected.js +3 -3
  48. package/src/hooks/IoT/__test__/useGGHomeConnection.test.js +1 -2
  49. package/src/hooks/IoT/index.js +9 -1
  50. package/src/hooks/IoT/useGGHomeConnection.js +0 -1
  51. package/src/hooks/IoT/useUnwatchLGDeviceConfigControl.js +29 -0
  52. package/src/hooks/IoT/useValueEvaluation.js +17 -4
  53. package/src/hooks/IoT/useWatchConfigs.js +34 -0
  54. package/src/iot/Monitor.js +13 -20
  55. package/src/iot/RemoteControl/GoogleHome.js +12 -13
  56. package/src/iot/RemoteControl/LG.js +1 -0
  57. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +7 -2
  58. package/src/navigations/UnitStack.js +16 -3
  59. package/src/screens/AddNewAction/SelectAction.js +1 -1
  60. package/src/screens/AddNewAction/SetupSensor.js +4 -0
  61. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +44 -78
  62. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +15 -35
  63. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +2 -0
  64. package/src/screens/AllCamera/__test__/index.test.js +1 -1
  65. package/src/screens/Device/__test__/detail.test.js +1 -54
  66. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +18 -8
  67. package/src/screens/Device/detail.js +36 -23
  68. package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +102 -0
  69. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +20 -0
  70. package/src/screens/Device/utils/index.js +45 -0
  71. package/src/screens/Device/utils/index.test.js +111 -0
  72. package/src/screens/EmergencyContacts/EmergencyContactsAddNew.js +35 -22
  73. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +2 -1
  74. package/src/screens/EmergencyContacts/__test__/EmergencyContactAddNew.test.js +36 -2
  75. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +0 -2
  76. package/src/screens/Notification/__test__/NotificationItem.test.js +84 -19
  77. package/src/screens/Notification/components/NotificationItem.js +64 -31
  78. package/src/screens/ScriptDetail/hooks/useStarredScript.js +2 -2
  79. package/src/screens/SubUnit/AddSubUnit.js +2 -1
  80. package/src/screens/Unit/AddMenu.js +4 -0
  81. package/src/screens/Unit/{SelectFavoritesDevices.js → SelectAddToFavorites.js} +81 -26
  82. package/src/screens/Unit/{SelectFavoritesDevicesStyles.js → SelectAddToFavoritesStyles.js} +0 -0
  83. package/src/screens/Unit/__test__/CheckSendEmail.test.js +12 -0
  84. package/src/screens/Unit/__test__/Detail.test.js +2 -3
  85. package/src/screens/Unit/__test__/SelectAddToFavorites.test.js +267 -0
  86. package/src/screens/Unit/components/AutomateScript/index.js +65 -0
  87. package/src/screens/Unit/components/AutomateScript/styles.js +48 -0
  88. package/src/screens/Unit/components/MyUnitDevice/index.js +3 -2
  89. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +4 -2
  90. package/src/utils/I18n/translations/en.json +7 -2
  91. package/src/utils/I18n/translations/vi.json +6 -1
  92. package/src/utils/Route/index.js +1 -1
  93. package/src/hooks/Common/useSensorsStatus.js +0 -62
  94. package/src/screens/Unit/__test__/SelectFavoritesDevices.test.js +0 -110
@@ -63,10 +63,11 @@ export const initialState = {
63
63
  },
64
64
  iot: {
65
65
  googlehome: {
66
- isFirstTimeConnect: true,
67
- isConnecting: false,
68
66
  connections: {},
69
67
  },
68
+ internet: {
69
+ statuses: {},
70
+ },
70
71
  },
71
72
  valueEvaluations: {},
72
73
  fetchedValueEvaluationUnits: [],
@@ -235,7 +236,7 @@ export const reducer = (currentState: ContextData, action: Action) => {
235
236
  starredScriptIds: payload,
236
237
  },
237
238
  };
238
- case Action.STAR_SCRIPT:
239
+ case Action.STAR_SCRIPTS:
239
240
  return {
240
241
  ...currentState,
241
242
  automate: {
@@ -245,13 +246,13 @@ export const reducer = (currentState: ContextData, action: Action) => {
245
246
  ),
246
247
  },
247
248
  };
248
- case Action.UNSTAR_SCRIPT:
249
+ case Action.UNSTAR_SCRIPTS:
249
250
  return {
250
251
  ...currentState,
251
252
  automate: {
252
253
  ...currentState.automate,
253
254
  starredScriptIds: currentState.automate.starredScriptIds.filter(
254
- (scriptId) => scriptId !== payload
255
+ (scriptId) => !payload.includes(scriptId)
255
256
  ),
256
257
  },
257
258
  };
@@ -263,8 +264,6 @@ export const reducer = (currentState: ContextData, action: Action) => {
263
264
  ...currentState.iot,
264
265
  googlehome: {
265
266
  ...currentState.iot.googlehome,
266
- isFirstTimeConnect: false,
267
- isConnecting: false,
268
267
  connections: payload,
269
268
  },
270
269
  },
@@ -276,8 +275,6 @@ export const reducer = (currentState: ContextData, action: Action) => {
276
275
  ...currentState.iot,
277
276
  googlehome: {
278
277
  ...currentState.iot.googlehome,
279
- isFirstTimeConnect: false,
280
- isConnecting: false,
281
278
  connections: {
282
279
  ...currentState.iot.googlehome.connections,
283
280
  [payload.option.chip_id]: payload.data,
@@ -285,16 +282,24 @@ export const reducer = (currentState: ContextData, action: Action) => {
285
282
  },
286
283
  },
287
284
  };
288
- case Action.CONNECTING_GOOGLE_HOME:
285
+
286
+ case Action.SET_DEVICES_STATUS:
287
+ // eslint-disable-next-line no-case-declarations
288
+ let newStatuses = currentState.iot.internet.statuses;
289
+ (payload || []).map(
290
+ (i) =>
291
+ (newStatuses[i.id] = {
292
+ ...(newStatuses[i.id] || {}),
293
+ isConnected: i.is_connected,
294
+ })
295
+ );
289
296
  return {
290
297
  ...currentState,
291
298
  iot: {
292
299
  ...currentState.iot,
293
- googlehome: {
294
- ...currentState.iot.googlehome,
295
- isConnecting: currentState.iot.googlehome.isFirstTimeConnect
296
- ? true
297
- : false,
300
+ internet: {
301
+ ...currentState.iot.internet,
302
+ statuses: newStatuses,
298
303
  },
299
304
  },
300
305
  };
@@ -0,0 +1,3 @@
1
+ import withRemoteControl from './withRemoteControl';
2
+
3
+ export { withRemoteControl };
@@ -0,0 +1,10 @@
1
+ import { useRemoteControl } from '../hooks/IoT';
2
+
3
+ function withRemoteControl(Component) {
4
+ return function WrappedComponent(props) {
5
+ const sendRemoteCommand = useRemoteControl();
6
+ return <Component {...props} sendRemoteCommand={sendRemoteCommand} />;
7
+ };
8
+ }
9
+
10
+ export default withRemoteControl;
@@ -4,7 +4,7 @@ import useForceUpdate from './useForceUpdate';
4
4
  import useKeyboardShow from './useKeyboardShow';
5
5
  import usePopover from './usePopover';
6
6
  import useTitleHeader from './useTitleHeader';
7
- import useSensorsStatus from './useSensorsStatus';
7
+ import useDevicesStatus from './useDevicesStatus';
8
8
  import useGGHomeDeviceConnected from './useGGHomeDeviceConnected';
9
9
  import { useBlockBackAndroid } from './useBlockBackAndroid';
10
10
  import { useIsOwnerOfUnit } from './useIsOwnerOfUnit';
@@ -22,6 +22,6 @@ export {
22
22
  useIsOwnerOfUnit,
23
23
  useStatusBar,
24
24
  useGetIdUser,
25
- useSensorsStatus,
25
+ useDevicesStatus,
26
26
  useGGHomeDeviceConnected,
27
27
  };
@@ -0,0 +1,57 @@
1
+ import { useCallback, useContext } from 'react';
2
+ import { useFocusEffect } from '@react-navigation/native';
3
+ import { SCContext, useSCContextSelector } from '../../context';
4
+ import { axiosGet } from '../../utils/Apis/axios';
5
+ import { API } from '../../configs';
6
+ import { Action } from '../../context/actionType';
7
+
8
+ let timeoutId;
9
+
10
+ const useDevicesStatus = (unit, devices) => {
11
+ const { setAction } = useContext(SCContext);
12
+ const isNetworkConnected = useSCContextSelector(
13
+ (state) => state.app.isNetworkConnected
14
+ );
15
+
16
+ const getDevicesStatus = useCallback(async (_unit, _devices) => {
17
+ const params = new URLSearchParams();
18
+ _devices.forEach((device) => {
19
+ params.append('sensors', device.id);
20
+ });
21
+ const { success, data } = await axiosGet(
22
+ API.UNIT.SENSORS_STATUS(_unit.id),
23
+ {
24
+ params: params,
25
+ }
26
+ );
27
+ if (success) {
28
+ setAction(Action.SET_DEVICES_STATUS, data);
29
+ }
30
+ timeoutId = setTimeout(() => getDevicesStatus(_unit, _devices), 5000);
31
+ // eslint-disable-next-line react-hooks/exhaustive-deps
32
+ }, []);
33
+
34
+ useFocusEffect(
35
+ useCallback(() => {
36
+ if (!devices?.length || !isNetworkConnected) {
37
+ return;
38
+ }
39
+
40
+ const managedDevices = devices.filter(
41
+ (device) => device?.is_managed_by_backend
42
+ );
43
+ if (!managedDevices.length) {
44
+ return;
45
+ }
46
+
47
+ timeoutId = setTimeout(() => getDevicesStatus(unit, managedDevices), 200);
48
+
49
+ return () => {
50
+ clearTimeout(timeoutId);
51
+ };
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
53
+ }, [unit, devices, isNetworkConnected])
54
+ );
55
+ };
56
+
57
+ export default useDevicesStatus;
@@ -1,9 +1,9 @@
1
1
  import { useSCContextSelector } from '../../context';
2
2
 
3
3
  const useGGHomeDeviceConnected = (device) => {
4
- const { connections, isConnecting } = useSCContextSelector(
5
- (state) => state.iot.googlehome
6
- );
4
+ const { connections } = useSCContextSelector((state) => state.iot.googlehome);
5
+
6
+ const isConnecting = !!device?.chip_id && !(device.chip_id in connections);
7
7
 
8
8
  const isConnected =
9
9
  !!device?.chip_id &&
@@ -167,8 +167,7 @@ describe('Test useGGHomeConnection', () => {
167
167
  await act(async () => {
168
168
  await result.current.connectGoogleHome(options);
169
169
  });
170
- expect(mockedSetAction).toBeCalledTimes(3);
171
- expect(mockedSetAction).toBeCalledWith(Action.CONNECTING_GOOGLE_HOME);
170
+ expect(mockedSetAction).toBeCalledTimes(2);
172
171
  expect(mockedSetAction).toBeCalledWith(
173
172
  Action.SET_GOOGLE_HOME_CONNECTIONS,
174
173
  conns
@@ -1,5 +1,13 @@
1
1
  import useGGHomeConnection from './useGGHomeConnection';
2
2
  import useRemoteControl from './useRemoteControl';
3
3
  import useValueEvaluations from './useValueEvaluation';
4
+ import useWatchConfigs from './useWatchConfigs';
5
+ import useUnwatchLGDeviceConfigControl from './useUnwatchLGDeviceConfigControl';
4
6
 
5
- export { useGGHomeConnection, useRemoteControl, useValueEvaluations };
7
+ export {
8
+ useGGHomeConnection,
9
+ useRemoteControl,
10
+ useValueEvaluations,
11
+ useWatchConfigs,
12
+ useUnwatchLGDeviceConfigControl,
13
+ };
@@ -63,7 +63,6 @@ const useGGHomeConnection = () => {
63
63
 
64
64
  const connectGoogleHome = useCallback(
65
65
  async (options) => {
66
- setAction(Action.CONNECTING_GOOGLE_HOME);
67
66
  await googleHomeConnect(
68
67
  connections,
69
68
  options,
@@ -0,0 +1,29 @@
1
+ import { useCallback } from 'react';
2
+ import { useFocusEffect } from '@react-navigation/native';
3
+ import { unwatchMultiConfigs } from '../../iot/Monitor';
4
+ import { DEVICE_TYPE } from '../../configs/Constants';
5
+
6
+ const useUnwatchLGDeviceConfigControl = (device, configs) => {
7
+ const unwatch = useCallback(
8
+ (_configs) => {
9
+ if (
10
+ device?.is_managed_by_backend &&
11
+ device?.device_type === DEVICE_TYPE.LG_THINQ
12
+ ) {
13
+ unwatchMultiConfigs(configs.map((config) => config));
14
+ }
15
+ },
16
+ [device, configs]
17
+ );
18
+
19
+ useFocusEffect(
20
+ useCallback(() => {
21
+ return () => {
22
+ unwatch();
23
+ };
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
25
+ }, [])
26
+ );
27
+ };
28
+
29
+ export default useUnwatchLGDeviceConfigControl;
@@ -1,4 +1,4 @@
1
- import { useCallback, useContext, useEffect } from 'react';
1
+ import { useCallback, useContext, useEffect, useState } from 'react';
2
2
  import { API } from '../../configs';
3
3
  import { SCContext, useSCContextSelector } from '../../context';
4
4
  import { Action } from '../../context/actionType';
@@ -6,12 +6,14 @@ import { axiosGet } from '../../utils/Apis/axios';
6
6
 
7
7
  const useValueEvaluations = (unitId) => {
8
8
  const { setAction } = useContext(SCContext);
9
+ const [fetching, setFetching] = useState(false);
9
10
 
10
11
  const fetchConfigValueEvaluations = useCallback(
11
12
  async (page = 1) => {
12
13
  if (!unitId) {
13
14
  return;
14
15
  }
16
+ setFetching(true);
15
17
  const params = new URLSearchParams();
16
18
  params.append('config__end_device__station__unit', unitId);
17
19
  params.append('page', page);
@@ -24,9 +26,15 @@ const useValueEvaluations = (unitId) => {
24
26
  data: data.results,
25
27
  });
26
28
  if (data.next) {
27
- await fetchConfigValueEvaluations(page + 1);
29
+ return await fetchConfigValueEvaluations(page + 1);
28
30
  }
31
+ } else {
32
+ setAction(Action.UPDATE_VALUE_EVALUATIONS, {
33
+ unitId,
34
+ data: [],
35
+ });
29
36
  }
37
+ setFetching(false);
30
38
  },
31
39
  [unitId, setAction]
32
40
  );
@@ -36,10 +44,15 @@ const useValueEvaluations = (unitId) => {
36
44
  });
37
45
 
38
46
  useEffect(() => {
39
- if (!(fetchedValueEvaluationUnits.indexOf(unitId) !== -1)) {
47
+ if (!fetching && !(fetchedValueEvaluationUnits.indexOf(unitId) !== -1)) {
40
48
  fetchConfigValueEvaluations();
41
49
  }
42
- }, [unitId, fetchConfigValueEvaluations, fetchedValueEvaluationUnits]);
50
+ }, [
51
+ unitId,
52
+ fetching,
53
+ fetchConfigValueEvaluations,
54
+ fetchedValueEvaluationUnits,
55
+ ]);
43
56
  };
44
57
 
45
58
  export default useValueEvaluations;
@@ -0,0 +1,34 @@
1
+ import { useCallback } from 'react';
2
+ import { useFocusEffect } from '@react-navigation/native';
3
+ import { useSCContextSelector } from '../../context';
4
+ import { watchMultiConfigs, unwatchMultiConfigs } from '../../iot/Monitor';
5
+ import { SCConfig } from '../../configs';
6
+
7
+ let intervalId;
8
+
9
+ const useWatchConfigs = (configIds) => {
10
+ const isNetworkConnected = useSCContextSelector(
11
+ (state) => state.app.isNetworkConnected
12
+ );
13
+
14
+ useFocusEffect(
15
+ useCallback(() => {
16
+ if (!configIds.length || !isNetworkConnected) {
17
+ return;
18
+ }
19
+
20
+ watchMultiConfigs(configIds);
21
+ clearInterval(intervalId);
22
+ intervalId = setInterval(() => {
23
+ watchMultiConfigs(configIds);
24
+ }, SCConfig.intervalWatchConfigTime);
25
+
26
+ return () => {
27
+ unwatchMultiConfigs(configIds);
28
+ clearInterval(intervalId);
29
+ };
30
+ }, [configIds, isNetworkConnected])
31
+ );
32
+ };
33
+
34
+ export default useWatchConfigs;
@@ -2,8 +2,10 @@ import { API } from '../configs';
2
2
  import { getConfigGlobalState, setConfigGlobalState } from './states';
3
3
  import _ from 'lodash';
4
4
  import Pusher from 'pusher-js/react-native';
5
+ import PusherBatchAuthorizer from 'pusher-js-auth';
5
6
  import { axiosPost } from '../utils/Apis/axios';
6
7
  import { SCConfig } from '../configs';
8
+ import api from '../utils/Apis/axios';
7
9
 
8
10
  Pusher.logToConsole = true;
9
11
  let pusher = null;
@@ -12,23 +14,14 @@ const getPusher = () => {
12
14
  if (!pusher) {
13
15
  pusher = new Pusher(SCConfig.pusherAppKey, {
14
16
  cluster: 'ap1',
15
- authorizer: function (channel, option) {
16
- return {
17
- // eslint-disable-next-line promise/prefer-await-to-callbacks
18
- authorize: async function (socketId, callback) {
19
- const { success, data } = await axiosPost(
20
- API.IOT.CHIP_MANAGER.PUSHER_AUTH(),
21
- {
22
- channel_name: channel.name,
23
- socket_id: socketId,
24
- }
25
- );
26
- if (success) {
27
- // eslint-disable-next-line promise/prefer-await-to-callbacks
28
- callback(null, data);
29
- }
30
- },
31
- };
17
+ authorizer: PusherBatchAuthorizer,
18
+ authEndpoint: SCConfig.apiRoot + API.IOT.CHIP_MANAGER.PUSHER_AUTH(),
19
+ authDelay: 300,
20
+ auth: {
21
+ headers: {
22
+ Accept: 'application/json',
23
+ Authorization: api.headers.Authorization,
24
+ },
32
25
  },
33
26
  });
34
27
  }
@@ -55,7 +48,7 @@ const watchConfig = (configId) => {
55
48
  return;
56
49
  }
57
50
  watchingConfigs[configId] = 1;
58
- const channel = getPusher().subscribe(`private-config-${configId}`);
51
+ const channel = getPusher().subscribe(`private-config_v2-${configId}`);
59
52
  channel.bind('new-value', updateGlobalValue.bind(channel, configId));
60
53
  };
61
54
 
@@ -66,7 +59,7 @@ const unwatchConfig = (configId) => {
66
59
  watchingConfigs[configId] -= 1;
67
60
  if (!watchingConfigs[configId]) {
68
61
  delete watchingConfigs[configId];
69
- getPusher().unsubscribe(`private-config-${configId}`);
62
+ getPusher().unsubscribe(`private-config_v2-${configId}`);
70
63
  if (_.isEmpty(watchingConfigs)) {
71
64
  destroyPusher();
72
65
  }
@@ -84,7 +77,7 @@ export const watchMultiConfigs = async (configIds) => {
84
77
  waitWatchConfigIds = [];
85
78
  clearTimeout(waitWatchConfigTimerId);
86
79
  waitWatchConfigTimerId = 0;
87
- }, 100);
80
+ }, 200);
88
81
  }
89
82
  };
90
83
 
@@ -48,10 +48,9 @@ async function stateChangeCallback(event) {
48
48
  isChanged = true;
49
49
  const [configId, type] = configMaps[entityId];
50
50
  const typeConverter = valueTypes[type] || keepValue;
51
- configValues[configId] = typeConverter(
52
- event.data.new_state.state,
53
- entityId
54
- );
51
+ configValues[configId] = {
52
+ value: typeConverter(event.data.new_state.state, entityId),
53
+ };
55
54
  }
56
55
 
57
56
  if (entityId in attributeMaps) {
@@ -66,10 +65,9 @@ async function stateChangeCallback(event) {
66
65
 
67
66
  const [configId, type] = attributeMap;
68
67
  const typeConverter = valueTypes[type] || keepValue;
69
- configValues[configId] = typeConverter(
70
- entity.attributes[attributeName],
71
- entityId
72
- );
68
+ configValues[configId] = {
69
+ value: typeConverter(entity.attributes[attributeName], entityId),
70
+ };
73
71
  }
74
72
  }
75
73
 
@@ -91,7 +89,9 @@ async function fetchConnectionEntities(connection) {
91
89
  const [configId, type] = configMaps[entityId];
92
90
  const typeConverter = valueTypes[type] || keepValue;
93
91
 
94
- configValues[configId] = typeConverter(entity.state, entityId);
92
+ configValues[configId] = {
93
+ value: typeConverter(entity.state, entityId),
94
+ };
95
95
  }
96
96
 
97
97
  if (Object.prototype.hasOwnProperty.call(attributeMaps, entityId)) {
@@ -105,10 +105,9 @@ async function fetchConnectionEntities(connection) {
105
105
 
106
106
  const [configId, type] = attributeMap;
107
107
  const typeConverter = valueTypes[type] || keepValue;
108
- configValues[configId] = typeConverter(
109
- entity.attributes[attributeName],
110
- entityId
111
- );
108
+ configValues[configId] = {
109
+ value: typeConverter(entity.attributes[attributeName], entityId),
110
+ };
112
111
  }
113
112
  }
114
113
  }
@@ -3,6 +3,7 @@ import { axiosGet } from '../../utils/Apis/axios';
3
3
  import { getConfigGlobalState, setConfigGlobalState } from '../states';
4
4
  import { sendCommandOverInternet } from './Internet';
5
5
 
6
+ // TODO update show config name of camelCase and snakeCase
6
7
  let deviceMaps = {};
7
8
  const propertyListMaps = {
8
9
  temperature: 'targetTemperature',
@@ -122,7 +122,12 @@ describe('Remote Control Google Home', () => {
122
122
  expect(getStates).toBeCalledTimes(1);
123
123
 
124
124
  configValues = getConfigGlobalState('configValues');
125
- expect(configValues).toEqual({ 1: true, 2: 50, 3: 10, 4: 123.4 });
125
+ expect(configValues).toEqual({
126
+ 1: { value: true },
127
+ 2: { value: 50 },
128
+ 3: { value: 10 },
129
+ 4: { value: 123.4 },
130
+ });
126
131
  });
127
132
 
128
133
  it('When state change, global config value also change', async () => {
@@ -162,7 +167,7 @@ describe('Remote Control Google Home', () => {
162
167
  );
163
168
 
164
169
  configValues = getConfigGlobalState('configValues');
165
- expect(configValues).toEqual({ 1: true });
170
+ expect(configValues).toEqual({ 1: { value: true } });
166
171
  });
167
172
 
168
173
  it('Connect to same google home will be skipped', async () => {
@@ -4,10 +4,12 @@ import { IconOutline } from '@ant-design/icons-react-native';
4
4
  import { createStackNavigator } from '@react-navigation/stack';
5
5
  import { BleManager } from 'react-native-ble-plx';
6
6
  import NetInfo from '@react-native-community/netinfo';
7
+ import { AppState } from 'react-native';
7
8
  import { get } from 'lodash';
8
9
 
9
10
  import Text from '../commons/Text';
10
11
  import { useTranslations } from '../hooks/Common/useTranslations';
12
+ import { unwatchAllConfigs } from '../iot/Monitor';
11
13
  import { Colors, Device } from '../configs';
12
14
  import Route from '../utils/Route';
13
15
  import ActivityLogScreen from '../screens/ActivityLog';
@@ -51,7 +53,7 @@ import EmergencySetting from '../screens/EmergencySetting';
51
53
  import ConfirmUnitDeletion from '../screens/ConfirmUnitDeletion';
52
54
  import InfoMemberUnit from '../screens/Sharing/InfoMemberUnit';
53
55
  import EnterPassword from '../screens/EnterPassword';
54
- import SelectFavoritesDevices from '../screens/Unit/SelectFavoritesDevices';
56
+ import SelectAddToFavorites from '../screens/Unit/SelectAddToFavorites';
55
57
  import { HanetCameraStack } from './HanetCameraStack';
56
58
  import { axiosGet } from '../utils/Apis/axios';
57
59
  import { API } from '../configs';
@@ -107,6 +109,17 @@ export const UnitStack = memo((props) => {
107
109
  // eslint-disable-next-line react-hooks/exhaustive-deps
108
110
  }, []);
109
111
 
112
+ useEffect(() => {
113
+ const subscription = AppState.addEventListener('change', (nextAppState) => {
114
+ if (nextAppState === 'background') {
115
+ unwatchAllConfigs();
116
+ }
117
+ });
118
+ return () => {
119
+ subscription?.remove();
120
+ };
121
+ }, []);
122
+
110
123
  return (
111
124
  <Stack.Navigator
112
125
  screenOptions={{
@@ -402,8 +415,8 @@ export const UnitStack = memo((props) => {
402
415
  }}
403
416
  />
404
417
  <Stack.Screen
405
- name={Route.SelectFavoritesDevices}
406
- component={SelectFavoritesDevices}
418
+ name={Route.SelectAddToFavorites}
419
+ component={SelectAddToFavorites}
407
420
  options={{
408
421
  headerShown: false,
409
422
  }}
@@ -349,7 +349,7 @@ const SelectAction = memo(({ route }) => {
349
349
  <LoadingSelectAction style={styles.container} />
350
350
  ) : (
351
351
  sensorData.map((item) => {
352
- const isHasValue = !!item?.value || item?.value === 0;
352
+ const isHasValue = !!item?.value;
353
353
  return (
354
354
  <View style={styles.wrapItem} key={item?.id}>
355
355
  <TitleCheckBox
@@ -149,6 +149,10 @@ const SetUpSensor = () => {
149
149
  // eslint-disable-next-line react-hooks/exhaustive-deps
150
150
  }, [minimum, maximum, value]);
151
151
 
152
+ useEffect(() => {
153
+ !isNumberValue && setValue(1);
154
+ }, [isNumberValue]);
155
+
152
156
  useEffect(() => {
153
157
  if (!isHasLimit && maximum - 150 <= value * 10) {
154
158
  setMaximum(maximum + 200);