@eohjsc/react-native-smart-city 0.2.96 → 0.2.99

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 (109) hide show
  1. package/README.md +35 -14
  2. package/package.json +16 -4
  3. package/src/commons/Action/ItemQuickAction.js +5 -2
  4. package/src/commons/ActionGroup/ColorPickerTemplate.js +1 -1
  5. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +12 -4
  6. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +7 -4
  7. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +1 -0
  8. package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplate.js +10 -10
  9. package/src/commons/ActionGroup/OnOffTemplate/index.js +18 -15
  10. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +8 -2
  11. package/src/commons/ActionGroup/SliderRangeTemplate.js +1 -1
  12. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +4 -1
  13. package/src/commons/ActionGroup/StatesGridActionTemplate.js +14 -4
  14. package/src/commons/ActionGroup/TimerActionTemplate.js +9 -1
  15. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +13 -9
  16. package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +14 -14
  17. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +53 -78
  18. package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +36 -20
  19. package/src/commons/Auth/AccountList.js +1 -1
  20. package/src/commons/{Connecting → Connecting}/__test__/Connecting.test.js +0 -0
  21. package/src/commons/{Connecting → Connecting}/index.js +0 -0
  22. package/src/commons/{Connecting → Connecting}/styles.js +0 -0
  23. package/src/commons/ConnectingProcess/index.js +1 -1
  24. package/src/commons/Device/HistoryChart.js +6 -2
  25. package/src/commons/Device/PMSensor/PMSensorIndicatior.js +16 -12
  26. package/src/commons/Device/PMSensor/PMSensorIndicatorStyles.js +3 -0
  27. package/src/commons/Device/WaterQualitySensor/ListQualityIndicator.js +1 -0
  28. package/src/commons/FieldTemplate/ChooseUserField/ChooseFieldStyles.js +25 -0
  29. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopup.js +96 -0
  30. package/src/commons/FieldTemplate/ChooseUserField/ChoosePopupStyles.js +39 -0
  31. package/src/commons/FieldTemplate/ChooseUserField/__test__/index.test.js +113 -0
  32. package/src/commons/FieldTemplate/ChooseUserField/index.js +62 -0
  33. package/src/commons/FieldTemplate/PasscodeField/PasscodeFieldStyles.js +30 -0
  34. package/src/commons/FieldTemplate/PasscodeField/__test__/index.test.js +93 -0
  35. package/src/commons/FieldTemplate/PasscodeField/index.js +43 -0
  36. package/src/commons/FieldTemplate/ScheduleField/ScheduleFieldStyles.js +13 -0
  37. package/src/commons/FieldTemplate/ScheduleField/__test__/index.test.js +182 -0
  38. package/src/commons/FieldTemplate/ScheduleField/index.js +176 -0
  39. package/src/commons/FullLoading/index.js +2 -1
  40. package/src/commons/MenuActionAddnew/index.js +1 -0
  41. package/src/commons/MenuActionList/index.js +1 -0
  42. package/src/commons/MenuActionMore/index.js +1 -1
  43. package/src/commons/PreventAccess/__test__/PreventAccess.test.js +62 -0
  44. package/src/commons/PreventAccess/index.js +67 -0
  45. package/src/commons/PreventAccess/styles.js +33 -0
  46. package/src/commons/WheelDateTimePicker/index.js +2 -1
  47. package/src/configs/API.js +3 -0
  48. package/src/configs/Constants.js +16 -1
  49. package/src/iot/RemoteControl/GoogleHome.js +24 -11
  50. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +32 -0
  51. package/src/navigations/UnitStack.js +8 -0
  52. package/src/screens/AQIGuide/index.js +1 -1
  53. package/src/screens/ActivityLog/FilterPopup.js +2 -0
  54. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  55. package/src/screens/AddCommon/SelectUnit.js +1 -0
  56. package/src/screens/AddLocationMaps/index.js +4 -1
  57. package/src/screens/AddNewAction/SelectSensorDevices.js +14 -3
  58. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +34 -92
  59. package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +3 -1
  60. package/src/screens/AddNewAutoSmart/index.js +5 -2
  61. package/src/screens/AddNewDevice/index.js +1 -0
  62. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +1 -1
  63. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +4 -1
  64. package/src/screens/AddNewGateway/SelectGateway.js +1 -0
  65. package/src/screens/AddNewGateway/SetupGatewayWifi.js +1 -0
  66. package/src/screens/AddNewGateway/index.js +1 -0
  67. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +1 -1
  68. package/src/screens/AddNewOneTap/index.js +3 -2
  69. package/src/screens/Automate/index.js +2 -0
  70. package/src/screens/Device/__test__/detail.test.js +4 -4
  71. package/src/screens/Device/detail.js +44 -6
  72. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +5 -2
  73. package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +14 -0
  74. package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +19 -1
  75. package/src/screens/EmergencySetting/index.js +4 -1
  76. package/src/screens/Explore/index.js +2 -0
  77. package/src/screens/GuestInfo/__test__/index.test.js +1 -1
  78. package/src/screens/GuestInfo/components/RecurringDetail.js +1 -0
  79. package/src/screens/GuestInfo/components/TemporaryDetail.js +2 -2
  80. package/src/screens/ManageAccess/index.js +1 -0
  81. package/src/screens/MoveToAnotherSubUnit/index.js +1 -1
  82. package/src/screens/ScanChipQR/components/QRScan/index.js +1 -0
  83. package/src/screens/ScriptDetail/index.js +3 -3
  84. package/src/screens/SelectUnit/__test__/index.test.js +1 -1
  85. package/src/screens/SelectUnit/index.js +5 -2
  86. package/src/screens/SetSchedule/index.js +6 -2
  87. package/src/screens/SharedUnit/index.js +2 -0
  88. package/src/screens/Sharing/MemberList.js +12 -11
  89. package/src/screens/Sharing/SelectPermission.js +1 -1
  90. package/src/screens/Sharing/hooks/index.js +3 -0
  91. package/src/screens/SideMenuDetail/SideMenuDetailStyles.js +28 -0
  92. package/src/screens/SideMenuDetail/__test__/index.test.js +165 -0
  93. package/src/screens/SideMenuDetail/index.js +149 -0
  94. package/src/screens/SmartIr/components/SelectBrand.js +1 -1
  95. package/src/screens/SubUnit/ManageSubUnit.js +1 -0
  96. package/src/screens/SyncLGDevice/AddLGDevice.js +1 -0
  97. package/src/screens/TDSGuide/index.js +4 -1
  98. package/src/screens/UVIndexGuide/index.js +1 -1
  99. package/src/screens/Unit/Detail.js +18 -5
  100. package/src/screens/Unit/SelectAddress.js +4 -1
  101. package/src/screens/Unit/Station/index.js +1 -0
  102. package/src/screens/Unit/Summaries.js +1 -1
  103. package/src/screens/Unit/__test__/Detail.test.js +25 -5
  104. package/src/screens/UnitSummary/__test__/index.test.js +32 -0
  105. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +1 -1
  106. package/src/screens/WaterQualityGuide/index.js +1 -1
  107. package/src/utils/I18n/translations/en.json +5 -1
  108. package/src/utils/I18n/translations/vi.json +5 -1
  109. package/src/utils/Route/index.js +1 -0
@@ -28,6 +28,7 @@ const SelectSensorDevices = memo(({ route }) => {
28
28
  isAutomateTab,
29
29
  isCreateNewAction,
30
30
  isMultiUnits,
31
+ oldType,
31
32
  } = route.params;
32
33
 
33
34
  const [listStation, setListStation] = useState([]);
@@ -37,6 +38,7 @@ const SelectSensorDevices = memo(({ route }) => {
37
38
  const [selectedDevice, setSelectedDevice] = useState();
38
39
  const { navigate, dispatch, goBack } = useNavigation();
39
40
  const isSelectSensor = title === AUTOMATE_SELECT.SELECT_SENSOR;
41
+ const [loading, setLoading] = useState(true);
40
42
 
41
43
  const onSnapToItem = useCallback(
42
44
  (item, index) => {
@@ -83,6 +85,7 @@ const SelectSensorDevices = memo(({ route }) => {
83
85
  }
84
86
  }
85
87
  );
88
+ setLoading(false);
86
89
  }, [automate.sensor_id, isSelectSensor, unit]);
87
90
 
88
91
  useEffect(() => {
@@ -135,7 +138,7 @@ const SelectSensorDevices = memo(({ route }) => {
135
138
  navigate(Routes.ScriptDetail, {
136
139
  id: automateId,
137
140
  name: scriptName,
138
- type: type,
141
+ type: oldType,
139
142
  havePermission: true,
140
143
  unit,
141
144
  isMultiUnits,
@@ -162,6 +165,9 @@ const SelectSensorDevices = memo(({ route }) => {
162
165
  // eslint-disable-next-line react-hooks/exhaustive-deps
163
166
  [route.params]
164
167
  );
168
+ if (loading) {
169
+ return null;
170
+ }
165
171
 
166
172
  return (
167
173
  <View style={styles.wrap}>
@@ -170,12 +176,13 @@ const SelectSensorDevices = memo(({ route }) => {
170
176
  <ScrollView
171
177
  style={styles.wrap}
172
178
  contentContainerStyle={styles.contentContainerStyle}
179
+ scrollIndicatorInsets={{ right: 1 }}
173
180
  >
174
181
  <Text bold type="H2" style={styles.title}>
175
182
  {t(title)}
176
183
  </Text>
177
184
 
178
- {listStation ? (
185
+ {listStation.length ? (
179
186
  <NavBar
180
187
  listStation={listStation}
181
188
  listMenuItem={listMenuItem}
@@ -211,7 +218,11 @@ const SelectSensorDevices = memo(({ route }) => {
211
218
  style={styles.bottomButtonView}
212
219
  mainTitle={t('continue')}
213
220
  onPressMain={onPressContinue}
214
- typeMain={selectedDevice ? 'primary' : 'disabled'}
221
+ typeMain={
222
+ Object.keys(selectedDevice || {}).length === 0
223
+ ? 'disabled'
224
+ : 'primary'
225
+ }
215
226
  />
216
227
  </View>
217
228
  );
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import renderer, { act } from 'react-test-renderer';
3
3
  import axios from 'axios';
4
4
 
@@ -25,12 +25,10 @@ jest.mock('@react-navigation/native', () => {
25
25
  };
26
26
  });
27
27
 
28
- const mockSetState = jest.fn();
29
28
  jest.mock('react', () => {
30
29
  return {
31
30
  ...jest.requireActual('react'),
32
31
  memo: (x) => x,
33
- useState: jest.fn((init) => [init, mockSetState]),
34
32
  };
35
33
  });
36
34
 
@@ -49,28 +47,27 @@ describe('Test SelectSensorDevices', () => {
49
47
  scriptName: 'scriptName test',
50
48
  },
51
49
  };
50
+ const response = {
51
+ status: 200,
52
+ success: true,
53
+ data: [
54
+ {
55
+ id: 1,
56
+ name: 'Device 1',
57
+ sensors: [
58
+ { id: 1, name: 'sensor' },
59
+ { id: 2, name: 'sensor' },
60
+ ],
61
+ },
62
+ ],
63
+ };
52
64
 
53
65
  beforeEach(() => {
54
66
  axios.get.mockClear();
55
67
  mockedNavigate.mockClear();
56
- mockSetState.mockClear();
57
68
  });
58
69
 
59
70
  test('fetch Device success', async () => {
60
- const response = {
61
- status: 200,
62
- success: true,
63
- data: [
64
- {
65
- id: 1,
66
- name: 'Device 1',
67
- sensors: [
68
- { id: 1, name: 'sensor' },
69
- { id: 2, name: 'sensor' },
70
- ],
71
- },
72
- ],
73
- };
74
71
  axios.get.mockImplementation(async () => {
75
72
  return response;
76
73
  });
@@ -78,12 +75,17 @@ describe('Test SelectSensorDevices', () => {
78
75
  await act(async () => {
79
76
  tree = renderer.create(wrapComponent(route));
80
77
  });
78
+ const instance = tree.root;
79
+ const navBar = instance.findByType(NavBar);
81
80
 
82
81
  expect(axios.get).toHaveBeenCalledWith(API.UNIT.DEVICE_CONTROL(1), {});
83
- expect(mockSetState).toHaveBeenCalledTimes(3);
82
+ expect(navBar.props.listStation).toHaveLength(1);
84
83
  });
85
84
 
86
85
  test('onPress continue', async () => {
86
+ axios.get.mockImplementation(async () => {
87
+ return response;
88
+ });
87
89
  await act(async () => {
88
90
  tree = renderer.create(wrapComponent(route));
89
91
  });
@@ -97,23 +99,9 @@ describe('Test SelectSensorDevices', () => {
97
99
  });
98
100
 
99
101
  test('test onPressDevice', async () => {
100
- const data = [
101
- {
102
- id: 1,
103
- name: 'Device 1',
104
- sensors: [
105
- { id: 1, name: 'sensor' },
106
- { id: 2, name: 'sensor' },
107
- ],
108
- },
109
- ];
110
- const mockSetSelectedDevice = jest.fn();
111
- useState.mockImplementationOnce((init) => [init, mockSetState]);
112
- useState.mockImplementationOnce((init) => [init, mockSetState]);
113
- useState.mockImplementationOnce((init) => [init, mockSetState]);
114
- useState.mockImplementationOnce((init) => [data, mockSetState]);
115
- useState.mockImplementationOnce((init) => [false, mockSetSelectedDevice]);
116
-
102
+ axios.get.mockImplementation(async () => {
103
+ return response;
104
+ });
117
105
  await act(async () => {
118
106
  tree = renderer.create(wrapComponent(route));
119
107
  });
@@ -124,67 +112,18 @@ describe('Test SelectSensorDevices', () => {
124
112
  act(() => {
125
113
  device[0].props.onPress({ id: 1, name: 'sensor' });
126
114
  });
127
- expect(mockSetSelectedDevice).toHaveBeenCalledWith({
128
- id: 1,
129
- name: 'sensor',
130
- });
131
- });
132
-
133
- test('test onPressDevice false', async () => {
134
- const data = [
135
- {
136
- id: 1,
137
- name: 'Device 1',
138
- sensors: [
139
- { id: 1, name: 'sensor' },
140
- { id: 2, name: 'sensor' },
141
- ],
142
- },
143
- ];
144
- const mockSetSelectedDevice = jest.fn();
145
- useState.mockImplementationOnce((init) => [init, mockSetState]);
146
- useState.mockImplementationOnce((init) => [init, mockSetState]);
147
- useState.mockImplementationOnce((init) => [init, mockSetState]);
148
- useState.mockImplementationOnce((init) => [data, mockSetState]);
149
- useState.mockImplementationOnce((init) => [
150
- { id: 1, name: 'sensor' },
151
- mockSetSelectedDevice,
152
- ]);
153
-
154
- await act(async () => {
155
- tree = renderer.create(wrapComponent(route));
156
- });
157
- const instance = tree.root;
158
- const device = instance.findAllByType(Device);
159
- expect(device).toHaveLength(2);
115
+ expect(device[0].props.isSelectDevice).toEqual(true);
160
116
 
161
117
  act(() => {
162
118
  device[0].props.onPress({ id: 1, name: 'sensor' });
163
119
  });
164
- expect(mockSetSelectedDevice).toHaveBeenCalledWith(false);
120
+ expect(device[0].props.isSelectDevice).toEqual(false);
165
121
  });
166
122
 
167
123
  test('test onSnapItem', async () => {
168
- const data = [
169
- {
170
- id: 1,
171
- name: 'Device 1',
172
- sensors: [
173
- { id: 1, name: 'sensor' },
174
- { id: 2, name: 'sensor' },
175
- ],
176
- },
177
- ];
178
- const listMenu = data.map((item, index) => ({
179
- text: item.name,
180
- station: item,
181
- index: index,
182
- }));
183
- const mockSetIndexStation = jest.fn();
184
- useState.mockImplementationOnce((init) => [listMenu, mockSetState]);
185
- useState.mockImplementationOnce((init) => [init, mockSetState]);
186
- useState.mockImplementationOnce((init) => [init, mockSetIndexStation]);
187
- useState.mockImplementationOnce((init) => [data, mockSetState]);
124
+ axios.get.mockImplementation(async () => {
125
+ return response;
126
+ });
188
127
 
189
128
  await act(async () => {
190
129
  tree = renderer.create(wrapComponent(route));
@@ -195,10 +134,13 @@ describe('Test SelectSensorDevices', () => {
195
134
  act(() => {
196
135
  navBar.props.onSnapToItem({ id: 1, name: 'sensor' }, 0);
197
136
  });
198
-
199
- expect(mockSetIndexStation).toBeCalledWith(0);
137
+ expect(navBar.props.indexStation).toEqual(0);
200
138
  });
139
+
201
140
  test('test onPressClose user already has an automateId', async () => {
141
+ axios.get.mockImplementation(async () => {
142
+ return response;
143
+ });
202
144
  await act(async () => {
203
145
  tree = renderer.create(wrapComponent(route));
204
146
  });
@@ -69,12 +69,13 @@ describe('test AddNewAutoSmart', () => {
69
69
  automate: {},
70
70
  automateId: undefined,
71
71
  title: 'select_sensor',
72
- type: 'value_change',
72
+ oldType: 'value_change',
73
73
  scriptName: undefined,
74
74
  unit: { id: 1 },
75
75
  isAutomateTab: undefined,
76
76
  isMultiUnits: undefined,
77
77
  routeName: 'SelectSensorDevices',
78
+ type: 'value_change',
78
79
  });
79
80
  });
80
81
 
@@ -102,6 +103,7 @@ describe('test AddNewAutoSmart', () => {
102
103
  automate: {},
103
104
  automateId: undefined,
104
105
  type: 'schedule',
106
+ oldType: 'value_change',
105
107
  routeName: 'SetSchedule',
106
108
  scriptName: undefined,
107
109
  unit: route.params.unit,
@@ -25,6 +25,7 @@ const AddNewAutoSmart = memo(({ route }) => {
25
25
  automate = {},
26
26
  scriptName,
27
27
  } = route.params;
28
+
28
29
  const typeAutoSmart = {
29
30
  [AUTOMATE_TYPE.AUTOMATE]: [
30
31
  {
@@ -96,6 +97,7 @@ const AddNewAutoSmart = memo(({ route }) => {
96
97
  routeName: dataAutomate?.route,
97
98
  automate,
98
99
  scriptName,
100
+ oldType: type,
99
101
  };
100
102
 
101
103
  if (
@@ -107,14 +109,15 @@ const AddNewAutoSmart = memo(({ route }) => {
107
109
  navigate(dataAutomate.route, params);
108
110
  }
109
111
  }, [
110
- navigate,
111
- selectedIndex,
112
112
  data,
113
+ selectedIndex,
113
114
  unit,
114
115
  isAutomateTab,
115
116
  isMultiUnits,
116
117
  automate,
117
118
  scriptName,
119
+ type,
120
+ navigate,
118
121
  ]);
119
122
 
120
123
  const handleSelectIndex = (index) => {
@@ -90,6 +90,7 @@ const AddNewDevice = memo(({ route }) => {
90
90
  <ScrollView
91
91
  style={styles.scrollContainer}
92
92
  showsVerticalScrollIndicator={false}
93
+ scrollIndicatorInsets={{ right: 1 }}
93
94
  >
94
95
  <Section type={'border'}>
95
96
  <GroupCheckBox data={stations} onSelect={handleOnSelect} />
@@ -26,7 +26,7 @@ import Routes from '../../../utils/Route';
26
26
  import { SCContext } from '../../../context';
27
27
  import { Action } from '../../../context/actionType';
28
28
  import { TESTID } from '../../../configs/Constants';
29
- import Connecting from '../../../commons/Connecting ';
29
+ import Connecting from '../../../commons/Connecting';
30
30
 
31
31
  const isIos = Platform.OS === 'ios';
32
32
  const isAndroid = Platform.OS === 'android';
@@ -224,7 +224,10 @@ const GatewayWifiList = memo(({ route }) => {
224
224
  {t('select_wifi')}
225
225
  </Text>
226
226
 
227
- <ScrollView style={styles.listContainer}>
227
+ <ScrollView
228
+ style={styles.listContainer}
229
+ scrollIndicatorInsets={{ right: 1 }}
230
+ >
228
231
  {!!list_wifi.length &&
229
232
  list_wifi.map((item, index) => (
230
233
  <TouchableOpacity
@@ -91,6 +91,7 @@ const AddNewGatewaySelectGateway = ({ route }) => {
91
91
  <ScrollView
92
92
  style={styles.scrollContainer}
93
93
  showsVerticalScrollIndicator={false}
94
+ scrollIndicatorInsets={{ right: 1 }}
94
95
  >
95
96
  <Section type={'border'}>
96
97
  {gateways.map((item, index) => (
@@ -147,6 +147,7 @@ const SetupGatewayWifi = memo(({ route }) => {
147
147
  <ScrollView
148
148
  style={styles.scrollContainer}
149
149
  showsVerticalScrollIndicator={false}
150
+ scrollIndicatorInsets={{ right: 1 }}
150
151
  >
151
152
  <Section type={'border'}>
152
153
  <Text style={styles.textWifi} bold color={Colors.Primary}>
@@ -75,6 +75,7 @@ const AddNewGateway = memo(({ route }) => {
75
75
  <ScrollView
76
76
  style={styles.scrollContainer}
77
77
  showsVerticalScrollIndicator={false}
78
+ scrollIndicatorInsets={{ right: 1 }}
78
79
  >
79
80
  <Section type={'border'}>
80
81
  {!wifiName && (
@@ -165,7 +165,7 @@ describe('test AddNewOneTap', () => {
165
165
  expect(mockedNavigate).toHaveBeenCalledWith(Routes.ScriptDetail, {
166
166
  id: 1,
167
167
  name: 'script test',
168
- type: 'one_tap',
168
+ type: undefined,
169
169
  havePermission: true,
170
170
  unit: { id: 1 },
171
171
  isMultiUnits: false,
@@ -25,6 +25,7 @@ const AddNewOneTap = memo(({ route }) => {
25
25
  isMultiUnits,
26
26
  automateId,
27
27
  scriptName,
28
+ oldType,
28
29
  } = route.params;
29
30
  const t = useTranslations();
30
31
  const { navigate, dispatch, goBack } = useNavigation();
@@ -91,7 +92,7 @@ const AddNewOneTap = memo(({ route }) => {
91
92
  navigate(Routes.ScriptDetail, {
92
93
  id: automateId,
93
94
  name: scriptName,
94
- type: type,
95
+ type: oldType,
95
96
  havePermission: true,
96
97
  unit,
97
98
  isMultiUnits,
@@ -120,7 +121,7 @@ const AddNewOneTap = memo(({ route }) => {
120
121
  }
121
122
  >
122
123
  <HeaderCustom isShowClose onClose={onClose} />
123
- <ScrollView>
124
+ <ScrollView scrollIndicatorInsets={{ right: 1 }}>
124
125
  <Text
125
126
  testID={TESTID.ADD_NEW_DEVICE_ADD}
126
127
  semibold
@@ -147,6 +147,7 @@ const Automate = () => {
147
147
  showsHorizontalScrollIndicator={false}
148
148
  contentContainerStyle={styles.contentContainerStyle2}
149
149
  ListFooterComponent={renderListFooterComponent(type, unit_id)}
150
+ scrollIndicatorInsets={{ right: 1 }}
150
151
  />
151
152
  </View>
152
153
  );
@@ -189,6 +190,7 @@ const Automate = () => {
189
190
  contentContainerStyle={styles.contentContainerStyle}
190
191
  refreshing={false}
191
192
  onRefresh={getAutomates}
193
+ scrollIndicatorInsets={{ right: 1 }}
192
194
  />
193
195
  </View>
194
196
  );
@@ -192,6 +192,7 @@ describe('test DeviceDetail', () => {
192
192
  type: 'action',
193
193
  },
194
194
  ],
195
+ side_menu_items: [{ id: 1, order: 1, name: 'Setup generate passcode' }],
195
196
  };
196
197
  test('render DeviceDetail render SensorDisplayItem', async () => {
197
198
  const responseDisplay = {
@@ -227,10 +228,9 @@ describe('test DeviceDetail', () => {
227
228
  const instance = tree.root;
228
229
  expect(axios.get).toHaveBeenCalledTimes(4);
229
230
  expect(axios.get).toHaveBeenCalledWith(API.SENSOR.DISPLAY(1), {});
230
- expect(axios.get).toHaveBeenCalledWith(
231
- API.SENSOR.REMOTE_CONTROL_OPTIONS(1),
232
- {}
233
- );
231
+ expect(axios.get).toHaveBeenCalledWith(API.SENSOR.DISPLAY_VALUES_V2(1), {
232
+ params: new URLSearchParams(),
233
+ });
234
234
  const sensorDisplayItem = instance.findAll(
235
235
  (el) => el.props.testID === TESTID.SENSOR_DISPLAY_ITEM
236
236
  );
@@ -12,7 +12,7 @@ import { get } from 'lodash';
12
12
  import { useSelector } from 'react-redux';
13
13
  import { IconFill, IconOutline } from '@ant-design/icons-react-native';
14
14
  import { Icon } from '@ant-design/react-native';
15
-
15
+ import Routes from '../../utils/Route';
16
16
  import { useCountUp } from './hooks/useCountUp';
17
17
  import { getData as getLocalData } from '../../utils/Storage';
18
18
  import { API, Colors } from '../../configs';
@@ -35,7 +35,7 @@ import Text from '../../commons/Text';
35
35
  import { transformDatetime } from '../../utils/Converter/time';
36
36
  import { AlertAction, ButtonPopup, MenuActionMore } from '../../commons';
37
37
  import { TESTID } from '../../configs/Constants';
38
- import Routes from '../../utils/Route';
38
+
39
39
  import { usePopover } from '../../hooks/Common';
40
40
  import { useConfigGlobalState } from '../../iot/states';
41
41
  import { useNavigation } from '@react-navigation/native';
@@ -47,6 +47,7 @@ import { EmergencyCountdown } from './components/EmergencyCountdown';
47
47
  import { SensorConnectStatusViewHeader } from './components/SensorConnectStatusViewHeader';
48
48
  import { useDisconnectedDevice } from './hooks/useDisconnectedDevice';
49
49
  import { Card } from '../../commons/CardShadow';
50
+ import PreventAccess from '../../commons/PreventAccess';
50
51
 
51
52
  const DeviceDetail = ({ route }) => {
52
53
  const t = useTranslations();
@@ -73,13 +74,15 @@ const DeviceDetail = ({ route }) => {
73
74
  const { isOwner } = useIsOwnerOfUnit(unit?.user_id);
74
75
  const [sensorName, setSensorName] = useState(sensor?.name);
75
76
  const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
77
+ const [showPreventAccess, setShowPreventAccess, setHidePreventAccess] =
78
+ useBoolean(false);
76
79
  const [showWindDirection, setShowWindDirection] = useState(false);
77
80
  const [loading, setLoading] = useState({
78
81
  isConnected: true,
79
82
  displayTemplate: true,
80
83
  });
81
84
  const [serverDown, setServerDown] = useState(false);
82
-
85
+ const [sideMenu, setSideMenu] = useState([]);
83
86
  const isNetworkConnected = useSCContextSelector(
84
87
  (state) => state.app.isNetworkConnected
85
88
  );
@@ -142,7 +145,9 @@ const DeviceDetail = ({ route }) => {
142
145
  }, [currentUserId, unit]);
143
146
 
144
147
  const fetchUnitDetail = useCallback(async () => {
145
- const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unitId));
148
+ const { success, data } = await axiosGet(API.UNIT.UNIT_DETAIL(unitId), {
149
+ headers: { 'Cache-Control': 'no-cache' },
150
+ });
146
151
  if (success) {
147
152
  setUnit(data);
148
153
  }
@@ -155,15 +160,17 @@ const DeviceDetail = ({ route }) => {
155
160
  }, [fetchUnitDetail, unitId, unitData]);
156
161
 
157
162
  const fetchSensorDetail = useCallback(async () => {
158
- const { success, data } = await axiosGet(
163
+ const { success, data, resp_status } = await axiosGet(
159
164
  API.SENSOR.SENSOR_DETAIL(sensorId)
160
165
  );
161
166
  if (success) {
162
167
  setSensor(data);
163
168
  setSensorName(data.name);
164
169
  setStation(data.station);
170
+ } else if (resp_status === 404) {
171
+ setShowPreventAccess();
165
172
  }
166
- }, [sensorId]);
173
+ }, [sensorId, setShowPreventAccess]);
167
174
 
168
175
  useEffect(() => {
169
176
  if (sensorId && !sensorData) {
@@ -184,6 +191,7 @@ const DeviceDetail = ({ route }) => {
184
191
  {},
185
192
  true
186
193
  );
194
+
187
195
  if (success) {
188
196
  setDisplay(data);
189
197
  setServerDown(false);
@@ -203,6 +211,9 @@ const DeviceDetail = ({ route }) => {
203
211
  }
204
212
  }
205
213
  }
214
+ if (data.side_menu_items.length) {
215
+ setSideMenu(data.side_menu_items);
216
+ }
206
217
  }
207
218
  setLoading((preState) => ({ ...preState, displayTemplate: false }));
208
219
 
@@ -298,6 +309,19 @@ const DeviceDetail = ({ route }) => {
298
309
  text: t('activity_log'),
299
310
  });
300
311
  }
312
+
313
+ sideMenu.forEach((el) => {
314
+ menuItems.push({
315
+ route: Routes.SideMenuDetail,
316
+ data: {
317
+ unit,
318
+ sensor,
319
+ side_menu: el,
320
+ },
321
+ text: el.name,
322
+ });
323
+ });
324
+
301
325
  menuItems.push({
302
326
  route: Routes.DeviceInfo,
303
327
  text: t('device_info'),
@@ -314,6 +338,13 @@ const DeviceDetail = ({ route }) => {
314
338
  text: t('auto_lock'),
315
339
  });
316
340
  }
341
+ menuItems.push({
342
+ route: Routes.SmartLockStack,
343
+ data: {
344
+ screen: Routes.SetupGeneratePasscode,
345
+ },
346
+ text: t('setup_generate_passcode'),
347
+ });
317
348
  if (isOwner && isShowSetUpSmartLock) {
318
349
  menuItems.push({
319
350
  route: Routes.SmartLockStack,
@@ -354,6 +385,7 @@ const DeviceDetail = ({ route }) => {
354
385
  sensor,
355
386
  unit,
356
387
  sensorName,
388
+ sideMenu,
357
389
  station,
358
390
  emergencyDeviceId,
359
391
  addToFavorites,
@@ -500,6 +532,7 @@ const DeviceDetail = ({ route }) => {
500
532
  return isFlag;
501
533
  }, [display]);
502
534
  // replace isConnected=True to see template
535
+
503
536
  const renderSensorConnected = () => {
504
537
  return (
505
538
  <SensorConnectStatusViewHeader
@@ -691,6 +724,11 @@ const DeviceDetail = ({ route }) => {
691
724
  unit={unit}
692
725
  station={sensor?.station}
693
726
  />
727
+ <PreventAccess
728
+ visible={showPreventAccess}
729
+ hidePreventAccess={setHidePreventAccess}
730
+ headerBodyText={'device'}
731
+ />
694
732
  </WrapHeaderScrollable>
695
733
  {isShowEmergencyResolve && (
696
734
  <BottomButtonView
@@ -1,5 +1,5 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
- import { SafeAreaView, StyleSheet, View } from 'react-native';
2
+ import { SafeAreaView, StyleSheet, View, Platform } from 'react-native';
3
3
  import { IconOutline } from '@ant-design/icons-react-native';
4
4
  import { useNavigation } from '@react-navigation/native';
5
5
  import { useTranslations } from '../../hooks/Common/useTranslations';
@@ -71,7 +71,7 @@ export const EmergencyContactsSelectContacts = ({ route }) => {
71
71
  return (
72
72
  <SafeAreaView style={styles.container}>
73
73
  <WrapHeaderScrollable title={t('select_contacts')} loading={loading}>
74
- <Section type={'border'}>
74
+ <Section type={'border'} style={styles.section}>
75
75
  {dataContact.map((contact, index) => (
76
76
  <RowUser
77
77
  key={contact.id.toString()}
@@ -116,6 +116,9 @@ const styles = StyleSheet.create({
116
116
  flex: 1,
117
117
  backgroundColor: Colors.Gray2,
118
118
  },
119
+ section: {
120
+ marginTop: Platform.OS === 'ios' ? 40 : 0,
121
+ },
119
122
  buttonRemove: {
120
123
  height: 40,
121
124
  width: 40,
@@ -2,6 +2,9 @@ import React from 'react';
2
2
  import { TouchableOpacity } from 'react-native';
3
3
  import { act, create } from 'react-test-renderer';
4
4
  import Routes from '../../../utils/Route';
5
+ import axios from 'axios';
6
+ import { API } from '../../../configs';
7
+
5
8
  import { AlertAction } from '../../../commons';
6
9
  import { EmergencyContactsList } from '../EmergencyContactsList';
7
10
  import { TESTID } from '../../../configs/Constants';
@@ -27,6 +30,8 @@ jest.mock('@react-navigation/native', () => {
27
30
  };
28
31
  });
29
32
 
33
+ jest.mock('axios');
34
+
30
35
  describe('test EmergencyContactList', () => {
31
36
  let route;
32
37
 
@@ -37,6 +42,7 @@ describe('test EmergencyContactList', () => {
37
42
  group: 1,
38
43
  },
39
44
  };
45
+ axios.delete.mockClear();
40
46
  });
41
47
  let tree;
42
48
 
@@ -51,11 +57,19 @@ describe('test EmergencyContactList', () => {
51
57
  const instance = tree.root;
52
58
  const alertAction = instance.findByType(AlertAction);
53
59
 
60
+ const response = { status: 204 };
61
+ axios.delete.mockImplementation(async () => {
62
+ return response;
63
+ });
64
+
54
65
  act(() => {
55
66
  alertAction.props.rightButtonClick();
56
67
  });
57
68
 
58
69
  expect(alertAction.props.visible).toBe(false);
70
+ expect(axios.delete).toHaveBeenCalledWith(
71
+ API.EMERGENCY_BUTTON.REMOVE_CONTACTS()
72
+ );
59
73
  });
60
74
 
61
75
  test('onAddNew', async () => {