@eohjsc/react-native-smart-city 0.3.92 → 0.3.93

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 (68) hide show
  1. package/package.json +5 -1
  2. package/src/commons/ActionGroup/SliderRangeTemplate.js +2 -2
  3. package/src/commons/AlertAction/index.js +5 -0
  4. package/src/commons/BottomButtonView/index.js +22 -4
  5. package/src/commons/Button/index.js +5 -0
  6. package/src/commons/Device/ConnectedViewHeader.js +0 -1
  7. package/src/commons/Device/Emergency/EmergencyDetail.js +4 -2
  8. package/src/commons/Device/Emergency/__test__/EmergencyDetail.test.js +4 -2
  9. package/src/commons/Device/ProgressBar/index.js +3 -1
  10. package/src/commons/Device/ProgressBar/styles.js +1 -4
  11. package/src/commons/Device/WindSpeed/Anemometer/index.js +1 -1
  12. package/src/commons/Header/HeaderCustom.js +8 -18
  13. package/src/commons/SubUnit/OneTap/ItemOneTap.js +5 -48
  14. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +6 -15
  15. package/src/commons/SubUnit/OneTap/index.js +3 -3
  16. package/src/commons/ViewButtonBottom/index.js +32 -4
  17. package/src/configs/API.js +3 -0
  18. package/src/configs/AccessibilityLabel.js +1 -0
  19. package/src/configs/BLE.js +1 -0
  20. package/src/context/actionType.ts +2 -1
  21. package/src/context/mockStore.ts +1 -0
  22. package/src/context/reducer.ts +12 -1
  23. package/src/hooks/Explore/useKeyboardAnimated.js +10 -4
  24. package/src/hooks/IoT/useBluetoothConnection.js +14 -26
  25. package/src/hooks/useMqtt.js +95 -0
  26. package/src/iot/Monitor.js +2 -1
  27. package/src/iot/RemoteControl/Bluetooth.js +56 -19
  28. package/src/iot/RemoteControl/__test__/Bluetooth.test.js +140 -0
  29. package/src/iot/mqtt.js +233 -0
  30. package/src/navigations/UnitStack.js +11 -3
  31. package/src/screens/AddLocationMaps/index.js +18 -16
  32. package/src/screens/AddLocationMaps/indexStyle.js +3 -0
  33. package/src/screens/Automate/AddNewAction/NewActionWrapper.js +3 -6
  34. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +29 -29
  35. package/src/screens/Automate/AddNewAction/__test__/SetupSensor.test.js +45 -39
  36. package/src/screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart.js +25 -0
  37. package/src/screens/{AddNewAutoSmart/index.js → Automate/AddNewAutoSmart/AddTypeSmart.js} +16 -51
  38. package/src/screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart.js +29 -0
  39. package/src/screens/{AddNewAutoSmart → Automate/AddNewAutoSmart}/__test__/AddNewAutoSmart.test.js +11 -11
  40. package/src/screens/{AddNewAutoSmart → Automate/AddNewAutoSmart}/styles/AddNewAutoSmartStyles.js +1 -1
  41. package/src/screens/Automate/Components/InputNameStyles.js +1 -1
  42. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +11 -25
  43. package/src/screens/Automate/EditActionsList/index.js +32 -33
  44. package/src/screens/Automate/MultiUnits.js +1 -1
  45. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +42 -3
  46. package/src/screens/Automate/ScriptDetail/index.js +21 -7
  47. package/src/screens/Automate/__test__/MultiUnits.test.js +1 -1
  48. package/src/screens/Automate/__test__/index.test.js +1 -1
  49. package/src/screens/Automate/index.js +1 -1
  50. package/src/screens/Device/__test__/detail.test.js +1 -1
  51. package/src/screens/Device/__test__/mqttDetail.test.js +599 -0
  52. package/src/screens/Device/components/SensorDisplayItem.js +1 -7
  53. package/src/screens/Device/detail.js +64 -30
  54. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +13 -3
  55. package/src/screens/SelectUnit/__test__/index.test.js +8 -13
  56. package/src/screens/SmartAccount/__test__/SmartAccount.test.js +8 -4
  57. package/src/screens/SmartAccount/index.js +8 -9
  58. package/src/screens/SmartAccount/style.js +8 -7
  59. package/src/screens/Unit/Detail.js +4 -19
  60. package/src/screens/Unit/Summaries.js +6 -17
  61. package/src/screens/Unit/__test__/Summaries.test.js +2 -2
  62. package/src/utils/FactoryGateway.js +525 -0
  63. package/src/utils/I18n/translations/en.json +5 -1
  64. package/src/utils/I18n/translations/vi.json +5 -2
  65. package/src/utils/Route/index.js +2 -1
  66. package/src/utils/Utils.js +11 -0
  67. package/src/commons/Device/SensorConnectedStatus.js +0 -56
  68. package/src/commons/Device/__test__/SensorConnectedStatus.test.js +0 -29
@@ -25,7 +25,7 @@ import {
25
25
  } from './hooks/useEmergencyButton';
26
26
  import { useFavoriteDevice } from './hooks/useFavoriteDevice';
27
27
  import { usePopover } from '../../hooks/Common';
28
- import { useConfigGlobalState } from '../../iot/states';
28
+ import { setConfigGlobalState, getConfigGlobalState } from '../../iot/states';
29
29
  import { useIsOwnerOfUnit, useBoolean } from '../../hooks/Common';
30
30
  import {
31
31
  useBluetoothConnection,
@@ -58,17 +58,24 @@ import { DEVICE_TYPE, AccessibilityLabel } from '../../configs/Constants';
58
58
  import { axiosGet } from '../../utils/Apis/axios';
59
59
  import { notImplemented } from '../../utils/Utils';
60
60
  import { useReceiveNotifications } from '../../hooks';
61
+ import useChipJsonConfiguration, {
62
+ useConnectChipMqtt,
63
+ } from '../../hooks/useMqtt';
64
+ import { realWatchMultiConfigs } from '../../iot/Monitor';
61
65
 
62
66
  const DeviceDetail = ({ route }) => {
67
+ const configIdsTemp = useRef([]);
68
+
63
69
  const t = useTranslations();
64
70
  const navigation = useNavigation();
65
71
  const token = useSCContextSelector((state) => state.auth.account.token);
66
- const { isLockWhenPickColor } = useSCContextSelector((state) => state.app);
72
+ const { isLockWhenPickColor, appState } = useSCContextSelector(
73
+ (state) => state.app
74
+ );
75
+
67
76
  const { setAction } = useContext(SCContext);
68
77
  const [offsetTitle, setOffsetTitle] = useState(1);
69
78
  const [display, setDisplay] = useState({ items: [] });
70
- // eslint-disable-next-line no-unused-vars
71
- const [configValues, setConfigValues] = useConfigGlobalState('configValues');
72
79
  const [displayValuesData, setDisplayValuesData] = useState({
73
80
  isConnected: false,
74
81
  lastUpdated: null,
@@ -140,7 +147,14 @@ const DeviceDetail = ({ route }) => {
140
147
 
141
148
  useDisconnectedDevice(sensorName, isDeviceHasBle, serverDown);
142
149
 
143
- useDeviceWatchConfigControl(sensor, display);
150
+ const { chips } = useChipJsonConfiguration(unit?.id);
151
+
152
+ const chipFiltered = useMemo(() => {
153
+ return chips?.filter((item) => item?.id === sensor?.chip_id);
154
+ }, [chips, sensor?.chip_id]);
155
+
156
+ const { mqttConfigs } = useConnectChipMqtt(chipFiltered);
157
+ useDeviceWatchConfigControl(sensor, display, mqttConfigs);
144
158
 
145
159
  const isShowSetupEmergencyContact = useMemo(
146
160
  () =>
@@ -150,7 +164,6 @@ const DeviceDetail = ({ route }) => {
150
164
  ).length > 0,
151
165
  [display.items]
152
166
  );
153
-
154
167
  const isShowSetUpSmartLock = useMemo(
155
168
  () =>
156
169
  display.items.filter(
@@ -488,20 +501,32 @@ const DeviceDetail = ({ route }) => {
488
501
  const configIds = [];
489
502
 
490
503
  display.items.map((item) => {
491
- if (item.type !== 'value') {
504
+ if (!item.configuration) {
492
505
  return;
493
506
  }
494
-
495
- if (!item.configuration) {
507
+ if (!['action', 'value'].includes(item.type)) {
496
508
  return;
497
509
  }
498
-
499
- item.configuration.configs.map((config) => {
500
- if (!configIds.includes(config.id)) {
501
- configIds.push(config.id);
510
+ if (item.type === 'action') {
511
+ if (
512
+ [
513
+ 'on_off_button_action_template',
514
+ 'one_button_action_template',
515
+ ].includes(item.configuration.template)
516
+ ) {
517
+ !configIds.includes(item.configuration.configuration.config) &&
518
+ configIds.push(item.configuration.configuration.config);
502
519
  }
503
- });
520
+ }
521
+ if (item.type === 'value') {
522
+ item.configuration.configs.map((config) => {
523
+ if (!configIds.includes(config.id)) {
524
+ configIds.push(config.id);
525
+ }
526
+ });
527
+ }
504
528
  });
529
+ configIdsTemp.current = configIds;
505
530
 
506
531
  configIds.map((id) => {
507
532
  params.append('config', id);
@@ -546,23 +571,28 @@ const DeviceDetail = ({ route }) => {
546
571
  lastUpdated: lastUpdated,
547
572
  };
548
573
  });
549
- setConfigValues((prev) => {
550
- let hasValueChange = false;
551
- data.configs.map((config) => {
552
- if (prev[config.id]?.value !== config.value) {
553
- hasValueChange = true;
554
- prev[config.id] = { ...prev[config.id], value: config.value };
555
- }
556
- setEvaluate((prevE) => ({
557
- ...prevE,
558
- [config?.id]: config?.evaluate,
559
- }));
560
- });
561
- if (hasValueChange) {
562
- return { ...prev };
574
+ const configsData = data.configs.filter(
575
+ (id) => !mqttConfigs.includes(id)
576
+ );
577
+ let configValues = getConfigGlobalState('configValues');
578
+ let hasValueChange = false;
579
+ configsData.map((config) => {
580
+ if (configValues[config.id]?.value !== config.value) {
581
+ hasValueChange = true;
582
+ configValues[config.id] = {
583
+ ...configValues[config.id],
584
+ value: config.value,
585
+ };
563
586
  }
564
- return prev;
587
+ setEvaluate((prev) => ({
588
+ ...prev,
589
+ [config?.id]: config?.evaluate,
590
+ }));
565
591
  });
592
+ if (hasValueChange) {
593
+ configValues = { ...configValues };
594
+ }
595
+ setConfigGlobalState('configValues', { ...configValues });
566
596
  } else if (resp_status >= 500) {
567
597
  setServerDown(true);
568
598
  }
@@ -580,7 +610,7 @@ const DeviceDetail = ({ route }) => {
580
610
  setLoading((preState) => ({ ...preState, isConnected: false }));
581
611
  }
582
612
  // eslint-disable-next-line react-hooks/exhaustive-deps
583
- }, [sensor, display, isNetworkConnected])
613
+ }, [display.items, isNetworkConnected, sensor, mqttConfigs])
584
614
  );
585
615
 
586
616
  const isShowEmergencyResolve =
@@ -687,6 +717,10 @@ const DeviceDetail = ({ route }) => {
687
717
  SCConfig.setCurrentSensorDisplay(sensor);
688
718
  }, [sensor]);
689
719
 
720
+ useEffect(() => {
721
+ appState === 'active' && realWatchMultiConfigs(configIdsTemp.current);
722
+ }, [appState]);
723
+
690
724
  const shouldRender =
691
725
  loading.displayTemplate === false &&
692
726
  loading.isConnected === false &&
@@ -3,7 +3,7 @@ import { DEVICE_TYPE } from '../../../configs/Constants';
3
3
  import { getConfigControlFromDeviceDisplay } from '../utils';
4
4
  import { useWatchConfigs } from '../../../hooks/IoT';
5
5
 
6
- export const useDeviceWatchConfigControl = (device, display) => {
6
+ export const useDeviceWatchConfigControl = (device, display, mqttConfigs) => {
7
7
  const configsNeedWatching = useMemo(() => {
8
8
  if (
9
9
  !device?.is_managed_by_backend ||
@@ -13,8 +13,18 @@ export const useDeviceWatchConfigControl = (device, display) => {
13
13
  ) {
14
14
  return [];
15
15
  }
16
- return getConfigControlFromDeviceDisplay(display);
17
- }, [device, display]);
16
+
17
+ const configsControl = getConfigControlFromDeviceDisplay(display);
18
+ if (mqttConfigs?.length) {
19
+ return configsControl.filter((id) => !mqttConfigs.includes(id));
20
+ }
21
+ return configsControl;
22
+ }, [
23
+ mqttConfigs,
24
+ device?.device_type,
25
+ device?.is_managed_by_backend,
26
+ display,
27
+ ]);
18
28
 
19
29
  useWatchConfigs(configsNeedWatching);
20
30
  };
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import { TouchableOpacity } from 'react-native';
3
3
  import { useRoute } from '@react-navigation/native';
4
4
  import { act, create } from 'react-test-renderer';
@@ -11,21 +11,14 @@ import { AccessibilityLabel } from '../../../configs/Constants';
11
11
  import Routes from '../../../utils/Route';
12
12
  import api from '../../../utils/Apis/axios';
13
13
  import { API } from '../../../configs';
14
+ import BottomButtonView from '../../../commons/BottomButtonView';
14
15
 
15
16
  const mock = new MockAdapter(api.axiosInstance);
16
17
 
17
- const mockSetState = jest.fn();
18
18
  const mockDispatch = jest.fn();
19
19
  const mockGoBack = jest.fn();
20
20
  const mockNavigate = jest.fn();
21
21
 
22
- jest.mock('react', () => {
23
- return {
24
- ...jest.requireActual('react'),
25
- useState: jest.fn((init) => [init, mockSetState]),
26
- };
27
- });
28
-
29
22
  jest.mock('@react-navigation/native', () => {
30
23
  return {
31
24
  ...jest.requireActual('@react-navigation/native'),
@@ -48,7 +41,6 @@ describe('Test Select unit screen', () => {
48
41
  let tree;
49
42
 
50
43
  beforeEach(() => {
51
- mockSetState.mockClear();
52
44
  mockNavigate.mockClear();
53
45
  });
54
46
 
@@ -74,18 +66,21 @@ describe('Test Select unit screen', () => {
74
66
  ],
75
67
  };
76
68
  mock.onGet(API.AUTOMATE.GET_ALL_UNITS()).reply(200, response.data);
77
- useState.mockImplementation((init) => [response.data, mockSetState]);
69
+
78
70
  await act(async () => {
79
71
  tree = await create(wrapComponent());
80
72
  });
81
73
  const instance = tree.root;
82
74
  const TouchableOpacities = instance.findAllByType(TouchableOpacity);
75
+ const bottomButtonView = instance.findByType(BottomButtonView);
76
+
77
+ expect(bottomButtonView.props.typeMain).toEqual('disabled');
83
78
  expect(TouchableOpacities).toHaveLength(4);
84
79
  await act(async () => {
85
80
  await TouchableOpacities[1].props.onPress();
86
81
  await TouchableOpacities[2].props.onPress(response.data[0]);
87
82
  });
88
- expect(mockSetState).toBeCalledWith(response.data[0]);
83
+ expect(bottomButtonView.props.typeMain).toEqual('primary');
89
84
  });
90
85
 
91
86
  it('Test SelectUnit getAllUnits fail', async () => {
@@ -106,7 +101,7 @@ describe('Test Select unit screen', () => {
106
101
 
107
102
  const instance = tree.root;
108
103
  const TouchableOpacities = instance.findAllByType(TouchableOpacity);
109
- expect(TouchableOpacities).toHaveLength(4);
104
+ expect(TouchableOpacities).toHaveLength(3);
110
105
  await act(async () => {
111
106
  await TouchableOpacities[1].props.onPress();
112
107
  await TouchableOpacities[2].props.onPress();
@@ -64,7 +64,8 @@ describe('Test SmartAccount', () => {
64
64
  const touchableOpacity = instance.find(
65
65
  (el) =>
66
66
  el.props.accessibilityLabel ===
67
- AccessibilityLabel.LOGIN_SMART_ACCOUNT && el.type === TouchableOpacity
67
+ `${AccessibilityLabel.LOGIN_SMART_ACCOUNT}${AccessibilityLabel.BOTTOM_VIEW_MAIN}` &&
68
+ el.type === TouchableOpacity
68
69
  );
69
70
  await act(async () => {
70
71
  touchableOpacity.props.onPress();
@@ -103,7 +104,8 @@ describe('Test SmartAccount', () => {
103
104
  const touchableOpacity = instance.find(
104
105
  (el) =>
105
106
  el.props.accessibilityLabel ===
106
- AccessibilityLabel.LOGIN_SMART_ACCOUNT && el.type === TouchableOpacity
107
+ `${AccessibilityLabel.LOGIN_SMART_ACCOUNT}${AccessibilityLabel.BOTTOM_VIEW_MAIN}` &&
108
+ el.type === TouchableOpacity
107
109
  );
108
110
  await act(async () => {
109
111
  await touchableOpacity.props.onPress();
@@ -156,7 +158,8 @@ describe('Test SmartAccount', () => {
156
158
  const touchableOpacity = instance.find(
157
159
  (el) =>
158
160
  el.props.accessibilityLabel ===
159
- AccessibilityLabel.LOGIN_SMART_ACCOUNT && el.type === TouchableOpacity
161
+ `${AccessibilityLabel.LOGIN_SMART_ACCOUNT}${AccessibilityLabel.BOTTOM_VIEW_MAIN}` &&
162
+ el.type === TouchableOpacity
160
163
  );
161
164
  await act(async () => {
162
165
  await touchableOpacity.props.onPress();
@@ -206,7 +209,8 @@ describe('Test SmartAccount', () => {
206
209
  const touchableOpacity = instance.find(
207
210
  (el) =>
208
211
  el.props.accessibilityLabel ===
209
- AccessibilityLabel.LOGIN_SMART_ACCOUNT && el.type === TouchableOpacity
212
+ `${AccessibilityLabel.LOGIN_SMART_ACCOUNT}${AccessibilityLabel.BOTTOM_VIEW_MAIN}` &&
213
+ el.type === TouchableOpacity
210
214
  );
211
215
  await act(async () => {
212
216
  await touchableOpacity.props.onPress();
@@ -13,7 +13,7 @@ import TextInput from '../../commons/Form/TextInput';
13
13
  import _TextInputPassword from '../../commons/Form/TextInputPassword';
14
14
  import { useTranslations } from '../../hooks/Common/useTranslations';
15
15
  import { useNavigation } from '@react-navigation/native';
16
- import { Button } from '../../commons';
16
+ import BottomButtonView from '../../commons/BottomButtonView';
17
17
  import { isValidPhoneNumberOrEmailAddress } from '../../utils/Validation';
18
18
  import { ToastBottomHelper } from '../../utils/Utils';
19
19
  import Routes from '../../utils/Route';
@@ -158,14 +158,13 @@ const SmartAccount = ({ route }) => {
158
158
  }
159
159
  />
160
160
  </ScrollView>
161
- <View style={[styles.buttonWrap]}>
162
- <Button
163
- type="primary"
164
- title={t('save')}
165
- onPress={validate}
166
- accessibilityLabel={AccessibilityLabel.LOGIN_SMART_ACCOUNT}
167
- />
168
- </View>
161
+ <BottomButtonView
162
+ style={styles.bottomButtonView}
163
+ mainTitle={t('save')}
164
+ onPressMain={validate}
165
+ typeMain={'primary'}
166
+ accessibilityLabelPrefix={AccessibilityLabel.LOGIN_SMART_ACCOUNT}
167
+ />
169
168
  </View>
170
169
  );
171
170
  };
@@ -47,13 +47,6 @@ export default StyleSheet.create({
47
47
  paddingHorizontal: 0,
48
48
  paddingLeft: 0,
49
49
  },
50
- buttonWrap: {
51
- marginHorizontal: 20,
52
- flexDirection: 'row',
53
- marginTop: 40,
54
- position: 'absolute',
55
- bottom: 32,
56
- },
57
50
  borderLogo: {
58
51
  borderColor: Colors.Primary,
59
52
  borderWidth: 1,
@@ -67,4 +60,12 @@ export default StyleSheet.create({
67
60
  ...borderCommonStyle,
68
61
  borderBottomColor: Colors.Red,
69
62
  },
63
+ bottomButtonView: {
64
+ paddingTop: 24,
65
+ paddingBottom: 32,
66
+
67
+ backgroundColor: Colors.White,
68
+ borderColor: Colors.ShadownTransparent,
69
+ borderTopWidth: 1,
70
+ },
70
71
  });
@@ -2,11 +2,10 @@ import React, {
2
2
  useCallback,
3
3
  useEffect,
4
4
  useState,
5
- useRef,
6
5
  useContext,
7
6
  useMemo,
8
7
  } from 'react';
9
- import { AppState, RefreshControl, View, Platform } from 'react-native';
8
+ import { RefreshControl, View, Platform } from 'react-native';
10
9
  import { useIsFocused } from '@react-navigation/native';
11
10
 
12
11
  import { useTranslations } from '../../hooks/Common/useTranslations';
@@ -219,7 +218,7 @@ const UnitDetail = ({ route }) => {
219
218
  isSuccessfullyConnected ? RouterHardware(Routes.Dashboard) : goBack
220
219
  );
221
220
  const user = useSCContextSelector((state) => state?.auth?.account?.user);
222
- const { isLavidaSource, isFirstOpenCamera } = useSCContextSelector(
221
+ const { isLavidaSource, isFirstOpenCamera, appState } = useSCContextSelector(
223
222
  (state) => state.app
224
223
  );
225
224
 
@@ -228,7 +227,6 @@ const UnitDetail = ({ route }) => {
228
227
  const [showAdd, setShowAdd, setHideAdd] = useBoolean();
229
228
  const [showPreventAccess, setShowPreventAccess, setHidePreventAccess] =
230
229
  useBoolean(false);
231
- const appState = useRef(AppState.currentState);
232
230
 
233
231
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
234
232
  usePopover();
@@ -306,21 +304,8 @@ const UnitDetail = ({ route }) => {
306
304
  );
307
305
 
308
306
  useEffect(() => {
309
- const handler = (nextAppState) => {
310
- if (
311
- appState.current.match(/inactive|background/) &&
312
- nextAppState === 'active'
313
- ) {
314
- fetchDetails();
315
- }
316
- appState.current = nextAppState;
317
- };
318
- const subscription = AppState.addEventListener('change', handler);
319
-
320
- return () => {
321
- subscription?.remove();
322
- };
323
- }, [fetchDetails]);
307
+ appState === 'active' && fetchDetails();
308
+ }, [appState, fetchDetails]);
324
309
 
325
310
  useValueEvaluations(unitId);
326
311
 
@@ -1,5 +1,5 @@
1
- import React, { memo, useCallback, useEffect, useState, useRef } from 'react';
2
- import { AppState, ScrollView } from 'react-native';
1
+ import React, { memo, useCallback, useEffect, useState } from 'react';
2
+ import { ScrollView } from 'react-native';
3
3
  import SummaryItem from '../../commons/SummaryItem';
4
4
  import Routes from '../../utils/Route';
5
5
  import { useIsFocused, useNavigation } from '@react-navigation/native';
@@ -7,6 +7,7 @@ import { axiosGet } from '../../utils/Apis/axios';
7
7
  import { API } from '../../configs';
8
8
  import { useReceiveNotifications } from '../../hooks';
9
9
  import { AccessibilityLabel } from '../../configs/Constants';
10
+ import { useSCContextSelector } from '../../context';
10
11
 
11
12
  let timeoutId;
12
13
 
@@ -14,7 +15,7 @@ const Summaries = memo(({ unit }) => {
14
15
  const [unitSummaries, setUnitSummaries] = useState([]);
15
16
  const isFocused = useIsFocused();
16
17
  const navigation = useNavigation();
17
- const appState = useRef(AppState.currentState);
18
+ const appState = useSCContextSelector((state) => state.app.appState);
18
19
 
19
20
  const fetchUnitSummary = useCallback(async () => {
20
21
  if (!unit.id) {
@@ -59,20 +60,8 @@ const Summaries = memo(({ unit }) => {
59
60
  }, [fetchUnitSummary]);
60
61
 
61
62
  useEffect(() => {
62
- const subscription = AppState.addEventListener('change', (nextAppState) => {
63
- if (
64
- appState.current.match(/inactive|background/) &&
65
- nextAppState === 'active'
66
- ) {
67
- fetchUnitSummary();
68
- }
69
- appState.current = nextAppState;
70
- });
71
-
72
- return () => {
73
- subscription?.remove();
74
- };
75
- }, [fetchUnitSummary]);
63
+ appState === 'active' && fetchUnitSummary();
64
+ }, [appState, fetchUnitSummary]);
76
65
 
77
66
  useEffect(() => {
78
67
  if (!isFocused) {
@@ -104,10 +104,10 @@ describe('Test Summaries', () => {
104
104
  await act(async () => {
105
105
  tree = await renderer.create(wrapComponent(props));
106
106
  });
107
- expect(mock.history.get).toHaveLength(1);
107
+ expect(mock.history.get).toHaveLength(2);
108
108
  await act(async () => {
109
109
  jest.runOnlyPendingTimers();
110
110
  });
111
- expect(mock.history.get).toHaveLength(2);
111
+ expect(mock.history.get).toHaveLength(3);
112
112
  });
113
113
  });