@eohjsc/react-native-smart-city 0.2.59 → 0.2.63

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 (101) hide show
  1. package/README.md +115 -68
  2. package/assets/images/Map/MarkerGeolocation.svg +4 -0
  3. package/package.json +3 -3
  4. package/src/commons/ActionGroup/CurtainButtonTemplate.js +10 -2
  5. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +1 -1
  6. package/src/commons/ActionGroup/__test__/MenuActionAddSchedule.test.js +71 -0
  7. package/src/commons/ActionGroup/hooks/AccessScheduleDetailStyles.js +41 -0
  8. package/src/commons/ActionGroup/hooks/MenuActionAddSchedule.js +110 -0
  9. package/src/commons/ActionGroup/hooks/MenuActionAddScheduleStyle.js +69 -0
  10. package/src/commons/ActionGroup/hooks/RecurringDetail.js +97 -0
  11. package/src/commons/DateTimeRangeChange/DateTimeButton.js +7 -2
  12. package/src/commons/Device/HistoryChart.js +80 -81
  13. package/src/commons/Device/HorizontalBarChart.js +48 -31
  14. package/src/commons/Device/LinearChart.js +28 -1
  15. package/src/commons/Form/CurrencyInput.js +1 -0
  16. package/src/commons/FourButtonFilterHistory/__test__/FourButtonFilterHistory.test.js +48 -0
  17. package/src/commons/FourButtonFilterHistory/index.js +72 -0
  18. package/src/commons/FourButtonFilterHistory/styles.js +22 -0
  19. package/src/commons/ImagePicker/index.js +27 -33
  20. package/src/commons/MediaPlayerDetail/Styles/MediaPlayerDetailStyles.js +11 -1
  21. package/src/commons/MediaPlayerDetail/index.js +14 -5
  22. package/src/commons/SubUnit/OneTap/OneTapStyles.js +20 -1
  23. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +151 -40
  24. package/src/commons/SubUnit/OneTap/index.js +64 -12
  25. package/src/commons/UnitSummary/AirQuality/index.js +9 -7
  26. package/src/commons/UnitSummary/ConfigHistoryChart.js +2 -1
  27. package/src/configs/API.js +3 -0
  28. package/src/configs/Constants.js +15 -0
  29. package/src/iot/RemoteControl/Bluetooth.js +6 -3
  30. package/src/iot/RemoteControl/GoogleHome.js +6 -3
  31. package/src/iot/RemoteControl/Internet.js +1 -0
  32. package/src/iot/RemoteControl/LG.js +2 -1
  33. package/src/iot/RemoteControl/index.js +13 -6
  34. package/src/navigations/SharedStack.js +11 -9
  35. package/src/navigations/UnitStack.js +26 -2
  36. package/src/screens/ActivityLog/ItemLog.js +3 -3
  37. package/src/screens/ActivityLog/__test__/ItemLog.test.js +5 -2
  38. package/src/screens/ActivityLog/hooks/index.js +2 -1
  39. package/src/screens/ActivityLog/index.js +0 -1
  40. package/src/screens/AddLocationMaps/index.js +4 -2
  41. package/src/screens/AddNewAction/SelectSensorDevices.js +18 -11
  42. package/src/screens/AddNewAction/Styles/SelectSensorDevicesStyles.js +5 -1
  43. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +6 -1
  44. package/src/screens/Automate/MultiUnits.js +7 -4
  45. package/src/screens/Automate/__test__/MultiUnits.test.js +1 -1
  46. package/src/screens/Automate/__test__/index.test.js +12 -0
  47. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +61 -0
  48. package/src/screens/ConfirmUnitDeletion/index.js +64 -0
  49. package/src/screens/ConfirmUnitDeletion/styles.js +37 -0
  50. package/src/screens/Device/__test__/detail.test.js +3 -2
  51. package/src/screens/Device/detail.js +48 -15
  52. package/src/screens/Device/hooks/useDisconnectedDevice.js +2 -1
  53. package/src/screens/Device/styles.js +3 -3
  54. package/src/screens/EmergencySetting/__test__/DropDownItem.test.js +59 -0
  55. package/src/screens/EmergencySetting/__test__/index.test.js +27 -0
  56. package/src/screens/EmergencySetting/components/DropDownItem.js +54 -0
  57. package/src/screens/EmergencySetting/index.js +92 -0
  58. package/src/screens/EmergencySetting/styles/DropDownItem.js +38 -0
  59. package/src/screens/EmergencySetting/styles.js +25 -0
  60. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +126 -0
  61. package/src/screens/MoveToAnotherSubUnit/index.js +88 -0
  62. package/src/screens/MoveToAnotherSubUnit/styles/MoveToAnotherSubUnitStyles.js +50 -0
  63. package/src/screens/ScriptDetail/Styles/indexStyles.js +0 -1
  64. package/src/screens/ScriptDetail/index.js +1 -0
  65. package/src/screens/SubUnit/AddSubUnit.js +3 -3
  66. package/src/screens/SubUnit/AddSubUnitStyles.js +0 -2
  67. package/src/screens/SubUnit/EditSubUnit.js +16 -7
  68. package/src/screens/SubUnit/EditSubUnitStyles.js +2 -3
  69. package/src/screens/SubUnit/__test__/EditSubUnit.test.js +2 -2
  70. package/src/screens/TDSGuide/index.js +1 -1
  71. package/src/screens/Unit/ChooseLocation.js +3 -7
  72. package/src/screens/Unit/ChooseLocationStyles.js +5 -8
  73. package/src/screens/Unit/Detail.js +16 -6
  74. package/src/screens/Unit/ManageUnit.js +20 -26
  75. package/src/screens/Unit/SmartAccount.js +25 -41
  76. package/src/screens/Unit/SmartAccountItem.js +2 -1
  77. package/src/screens/Unit/SmartAccountStyles.js +0 -1
  78. package/src/screens/Unit/__test__/ManageUnit.test.js +0 -6
  79. package/src/screens/Unit/__test__/SmartAccount.test.js +24 -0
  80. package/src/screens/Unit/__test__/SmartAccountItem.test.js +72 -0
  81. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +58 -59
  82. package/src/screens/UnitSummary/components/PowerConsumption/index.js +26 -22
  83. package/src/screens/UnitSummary/components/Temperature/ItemTemperature/index.js +2 -2
  84. package/src/screens/UnitSummary/components/Temperature/index.js +15 -14
  85. package/src/screens/UnitSummary/components/UvIndex/index.js +6 -5
  86. package/src/screens/UnitSummary/components/WaterQuality/index.js +9 -7
  87. package/src/screens/UnitSummary/index.js +11 -7
  88. package/src/screens/WaterQualityGuide/index.js +1 -0
  89. package/src/utils/Apis/axios.js +4 -4
  90. package/src/utils/I18n/translations/en.json +20 -2
  91. package/src/utils/I18n/translations/vi.json +21 -2
  92. package/src/utils/Route/index.js +3 -0
  93. package/src/utils/Utils.js +4 -0
  94. package/src/commons/ThreeButtonHistory/CalendarHeader.js +0 -35
  95. package/src/commons/ThreeButtonHistory/CalendarHeaderStyles.js +0 -17
  96. package/src/commons/ThreeButtonHistory/SelectMonth.js +0 -53
  97. package/src/commons/ThreeButtonHistory/SelectMonthStyles.js +0 -29
  98. package/src/commons/ThreeButtonHistory/__test__/SelectMonth.test.js +0 -37
  99. package/src/commons/ThreeButtonHistory/__test__/ThreeButtonHistory.test.js +0 -240
  100. package/src/commons/ThreeButtonHistory/index.js +0 -310
  101. package/src/commons/ThreeButtonHistory/styles.js +0 -65
@@ -69,7 +69,17 @@ export default StyleSheet.create({
69
69
  bottom: 0,
70
70
  },
71
71
  firstOpenCamera: {
72
- zIndex: -10,
72
+ zIndex: -9999,
73
73
  position: 'absolute',
74
+ width: 1,
75
+ height: 1,
76
+ },
77
+ loading: {
78
+ position: 'absolute',
79
+ zIndex: 10,
80
+ width: '100%',
81
+ height: '100%',
82
+ justifyContent: 'center',
83
+ alignItems: 'center',
74
84
  },
75
85
  });
@@ -13,6 +13,7 @@ import {
13
13
  Text,
14
14
  TouchableOpacity,
15
15
  Platform,
16
+ ActivityIndicator,
16
17
  } from 'react-native';
17
18
  import { VLCPlayer } from 'react-native-vlc-media-player';
18
19
  import { useTranslations } from '../../hooks/Common/useTranslations';
@@ -46,9 +47,10 @@ const MediaPlayerDetail = ({
46
47
  );
47
48
  const t = useTranslations();
48
49
  const [paused, setPaused] = useState(isPaused);
50
+
49
51
  const onTapPause = useCallback(() => {
50
- setPaused(false);
51
- }, []);
52
+ !isFirstOpenCamera && setPaused(false);
53
+ }, [isFirstOpenCamera]);
52
54
 
53
55
  const onTapGoDetail = useCallback(() => {
54
56
  if (!paused) {
@@ -139,7 +141,7 @@ const MediaPlayerDetail = ({
139
141
  const to = setTimeout(() => {
140
142
  setAction(Action.IS_FIRST_OPEN_CAMERA, false);
141
143
  clearTimeout(to);
142
- }, 500);
144
+ }, 1000);
143
145
  }
144
146
  // eslint-disable-next-line react-hooks/exhaustive-deps
145
147
  }, [isFirstOpenCamera]);
@@ -147,7 +149,14 @@ const MediaPlayerDetail = ({
147
149
  const source = !thumbnail || !thumbnail.uri ? Images.BgDevice : thumbnail;
148
150
  return (
149
151
  <View style={[styles.wrap, wrapStyles]}>
150
- {isFirstOpenCamera && Platform.OS === 'ios' && renderCamera}
152
+ {isFirstOpenCamera && Platform.OS === 'ios' && (
153
+ <>
154
+ {renderCamera}
155
+ <View style={styles.loading}>
156
+ <ActivityIndicator size={'small'} color={Colors.Primary} />
157
+ </View>
158
+ </>
159
+ )}
151
160
  <View style={[styles.loadingWrap]}>
152
161
  <Text style={styles.loadingText}>{t('loading')}</Text>
153
162
  </View>
@@ -172,7 +181,7 @@ const MediaPlayerDetail = ({
172
181
  />
173
182
  </View>
174
183
  ) : (
175
- renderCamera
184
+ !isFirstOpenCamera && renderCamera
176
185
  )}
177
186
 
178
187
  <View style={styles.buttonView}>
@@ -1,4 +1,4 @@
1
- import { StyleSheet } from 'react-native';
1
+ import { Platform, StyleSheet } from 'react-native';
2
2
  import { Colors, Device } from '../../../configs';
3
3
 
4
4
  export default StyleSheet.create({
@@ -33,4 +33,23 @@ export default StyleSheet.create({
33
33
  alignItems: 'center',
34
34
  paddingBottom: 3,
35
35
  },
36
+ dropDown: {
37
+ width: 114,
38
+ height: 40,
39
+ borderRadius: 30,
40
+ backgroundColor: Colors.Gray3,
41
+ },
42
+ boxDropDown: {
43
+ justifyContent: 'center',
44
+ flexDirection: 'row',
45
+ alignItems: 'center',
46
+ padding: Platform.select({
47
+ ios: 10,
48
+ android: 6,
49
+ }),
50
+ },
51
+ textDropDown: {
52
+ color: Colors.Primary,
53
+ marginRight: 10,
54
+ },
36
55
  });
@@ -4,7 +4,7 @@ import { TouchableOpacity } from 'react-native';
4
4
  import Toast from 'react-native-toast-message';
5
5
  import { act, create } from 'react-test-renderer';
6
6
  import SubUnitAutomate from '..';
7
- import { TESTID } from '../../../../configs/Constants';
7
+ import { AUTOMATE_TYPE, TESTID } from '../../../../configs/Constants';
8
8
  import { SCProvider } from '../../../../context';
9
9
  import { mockSCStore } from '../../../../context/mockStore';
10
10
  import Routes from '../../../../utils/Route';
@@ -37,18 +37,23 @@ jest.mock('axios');
37
37
  let tree;
38
38
  let data = {
39
39
  isOwner: true,
40
- type: 'one_tap',
41
- automates: [
40
+ listAutomate: [
42
41
  {
43
- id: 1,
44
- user: 6,
45
- type: 'one_tap',
46
- activate_at: '2021-09-17T05:30:00Z',
47
- script: {
48
- name: 'Joshua Ray',
49
- icon: '',
50
- icon_kit: '',
51
- },
42
+ text: 'Scenario',
43
+ data: [
44
+ {
45
+ id: 1,
46
+ user: 6,
47
+ type: 'one_tap',
48
+ activate_at: '2021-09-17T05:30:00Z',
49
+ script: {
50
+ name: 'Joshua Ray',
51
+ icon: '',
52
+ icon_kit: '',
53
+ },
54
+ },
55
+ ],
56
+ type: AUTOMATE_TYPE.ONE_TAP,
52
57
  },
53
58
  ],
54
59
  };
@@ -58,7 +63,7 @@ describe('test Item', () => {
58
63
  axios.post.mockClear();
59
64
  mockedNavigate.mockClear();
60
65
  });
61
- test('render SubUnitAutomate isOwner', async () => {
66
+ test('render SubUnitAutomate isOwner and handleOnAddNew', async () => {
62
67
  const response = {
63
68
  status: 200,
64
69
  };
@@ -100,7 +105,7 @@ describe('test Item', () => {
100
105
  type: 'one_tap',
101
106
  unit: undefined,
102
107
  textCondition: null,
103
- automate: data.automates[0],
108
+ automate: data.listAutomate[0].data[0],
104
109
  });
105
110
 
106
111
  const handleScriptAction = instance.findAll(
@@ -154,20 +159,26 @@ describe('test Item', () => {
154
159
  test('render SubUnitAutomate script value_change', async () => {
155
160
  data.isOwner = false;
156
161
  data.type = 'value_change';
157
- data.automates = [
162
+ data.listAutomate = [
158
163
  {
159
- id: 1,
160
- user: 6,
161
- type: 'value_change',
162
- activate_at: null,
163
- condition: '>',
164
- config: 'Temperature',
165
- value: 29,
166
- script: {
167
- name: 'Rain',
168
- icon: '',
169
- icon_kit: 'https://www.figma.com/',
170
- },
164
+ text: AUTOMATE_TYPE.AUTOMATION,
165
+ type: AUTOMATE_TYPE.AUTOMATION,
166
+ data: [
167
+ {
168
+ id: 1,
169
+ user: 6,
170
+ type: 'value_change',
171
+ activate_at: null,
172
+ condition: '>',
173
+ config: 'Temperature',
174
+ value: 29,
175
+ script: {
176
+ name: 'Rain',
177
+ icon: '',
178
+ icon_kit: 'https://www.figma.com/',
179
+ },
180
+ },
181
+ ],
171
182
  },
172
183
  ];
173
184
  const response = {
@@ -197,30 +208,36 @@ describe('test Item', () => {
197
208
  type: 'value_change',
198
209
  unit: undefined,
199
210
  textCondition: 'Temperature higher than 29',
200
- automate: data.automates[0],
211
+ automate: data.listAutomate[0].data[0],
201
212
  });
202
213
  });
203
- test('render SubUnitAutomate script schedule', async () => {
214
+ test('render SubUnitAutomate script schedule and handleOnAddNew item automate', async () => {
204
215
  data.isOwner = false;
205
216
  data.type = 'schedule';
206
- data.automates = [
217
+ data.listAutomate = [
207
218
  {
208
- id: 1,
209
- user: 6,
210
- type: 'schedule',
211
- activate_at: null,
212
- script: {
213
- name: 'Rain',
214
- icon: '',
215
- icon_kit: '',
216
- },
219
+ text: AUTOMATE_TYPE.AUTOMATION,
220
+ type: AUTOMATE_TYPE.AUTOMATION,
221
+ data: [
222
+ {
223
+ id: 1,
224
+ user: 6,
225
+ type: 'schedule',
226
+ activate_at: null,
227
+ script: {
228
+ name: 'Rain',
229
+ icon: '',
230
+ icon_kit: '',
231
+ },
232
+ },
233
+ ],
217
234
  },
218
235
  ];
219
236
  const response = {
220
237
  status: 200,
221
238
  };
222
239
 
223
- axios.post.mockImplementation(async () => {
240
+ await axios.post.mockImplementation(async () => {
224
241
  return response;
225
242
  });
226
243
 
@@ -228,10 +245,104 @@ describe('test Item', () => {
228
245
  tree = await create(wrapComponent(data));
229
246
  });
230
247
 
248
+ const instance = tree.root;
249
+ const item = instance.findAll(
250
+ (el) => el.props.testID === TESTID.PLUS && el.type === TouchableOpacity
251
+ );
252
+
253
+ expect(item).toHaveLength(1);
254
+ await act(async () => {
255
+ await item[0].props.onPress();
256
+ });
257
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.AddNewAutoSmart, {
258
+ type: AUTOMATE_TYPE.VALUE_CHANGE,
259
+ unit: undefined,
260
+ });
261
+ mockedNavigate.mockClear();
262
+
231
263
  const goDetail = tree.root.findAll(
232
264
  (el) =>
233
265
  el.props.testID === TESTID.GO_DETAIL && el.type === TouchableOpacity
234
266
  );
235
267
  expect(goDetail).toHaveLength(1);
236
268
  });
269
+
270
+ test('render click select option filter by automation', async () => {
271
+ data.isOwner = false;
272
+ data.type = 'schedule';
273
+ data.listAutomate = [
274
+ {
275
+ text: AUTOMATE_TYPE.SCENARIO,
276
+ type: AUTOMATE_TYPE.ONE_TAP,
277
+ data: [
278
+ {
279
+ id: 1,
280
+ user: 6,
281
+ type: 'one_tap',
282
+ activate_at: null,
283
+ script: {
284
+ name: 'One-tap',
285
+ icon: '',
286
+ icon_kit: '',
287
+ },
288
+ },
289
+ ],
290
+ },
291
+ {
292
+ text: AUTOMATE_TYPE.AUTOMATION,
293
+ type: AUTOMATE_TYPE.AUTOMATION,
294
+ data: [
295
+ {
296
+ id: 2,
297
+ user: 6,
298
+ type: 'schedule',
299
+ activate_at: null,
300
+ script: {
301
+ name: 'Rain',
302
+ icon: '',
303
+ icon_kit: '',
304
+ },
305
+ },
306
+ ],
307
+ },
308
+ ];
309
+ const response = {
310
+ status: 200,
311
+ };
312
+
313
+ await axios.post.mockImplementation(async () => {
314
+ return response;
315
+ });
316
+
317
+ await act(async () => {
318
+ tree = await create(wrapComponent(data));
319
+ });
320
+
321
+ const instance = tree.root;
322
+ const menuDropDown = instance.find(
323
+ (el) =>
324
+ el.props.testID === TESTID.SUB_UNIT_SELECT_AUTOMATE_TYPE &&
325
+ el.type === TouchableOpacity
326
+ );
327
+ await act(async () => {
328
+ await menuDropDown.props.onPress();
329
+ });
330
+
331
+ const menu = instance.find(
332
+ (el) => el.props.testID === TESTID.NAVBAR_MENU_ACTION_MORE
333
+ );
334
+
335
+ expect(menu.props.isVisible).toBeTruthy();
336
+
337
+ const automation = menu.props.listMenuItem[1];
338
+
339
+ await act(async () => {
340
+ await menu.props.onItemClick(automation, 1);
341
+ });
342
+
343
+ const text = instance.find(
344
+ (el) => el.props.testID === TESTID.SUB_UNIT_TEXT_DROPDOWN
345
+ );
346
+ expect(text.props.children).toEqual(AUTOMATE_TYPE.AUTOMATION);
347
+ });
237
348
  });
@@ -1,33 +1,75 @@
1
- import React from 'react';
2
- import { View } from 'react-native';
3
- import styles from './OneTapStyles.js';
4
- import { Section } from '../..';
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import { Icon } from '@ant-design/react-native';
5
4
 
5
+ import { MenuActionMore, Section } from '../..';
6
6
  import ItemAddNew from '../../Device/ItemAddNew';
7
7
  import ItemOneTap from './ItemOneTap';
8
8
  import { useTranslations } from '../../../hooks/Common/useTranslations';
9
9
  import { useNavigation } from '@react-navigation/native';
10
10
  import Routes from '../../../utils/Route/index.js';
11
- import { AUTOMATE_TYPE } from '../../../configs/Constants';
11
+ import { AUTOMATE_TYPE, TESTID } from '../../../configs/Constants';
12
+ import { Colors } from '../../../configs/Colors.js';
13
+ import usePopover from '../../../hooks/Common/usePopover.js';
14
+ import Text from '../../Text/index.js';
15
+
16
+ import styles from './OneTapStyles.js';
12
17
 
13
- const SubUnitAutomate = ({ isOwner, type, automates, unit, wrapItemStyle }) => {
18
+ const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
14
19
  const t = useTranslations();
15
20
  const { navigate } = useNavigation();
21
+ const [automates, setAutomates] = useState(listAutomate[0]);
22
+ const [indexAutomate, setIndexAutomate] = useState(0);
16
23
  const handleOnAddNew = () => {
17
- switch (type) {
24
+ switch (automates.type) {
18
25
  case AUTOMATE_TYPE.ONE_TAP:
19
- navigate(Routes.AddNewOneTap, { type: type, unit });
26
+ navigate(Routes.AddNewOneTap, { type: AUTOMATE_TYPE.ONE_TAP, unit });
20
27
  break;
21
- case AUTOMATE_TYPE.VALUE_CHANGE:
22
- navigate(Routes.AddNewAutoSmart, { type, unit });
28
+ case AUTOMATE_TYPE.AUTOMATION:
29
+ navigate(Routes.AddNewAutoSmart, {
30
+ type: AUTOMATE_TYPE.VALUE_CHANGE,
31
+ unit,
32
+ });
23
33
  break;
24
34
  }
25
35
  };
36
+ const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
37
+ usePopover();
38
+
39
+ const refMenuAction = useRef();
40
+ const handleShowMenuAction = () => showPopoverWithRef(refMenuAction);
41
+
42
+ const onItemClick = useCallback((item, index) => {
43
+ setAutomates(item);
44
+ setIndexAutomate(index);
45
+ }, []);
46
+ useEffect(() => {
47
+ setAutomates(listAutomate[indexAutomate]);
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ }, [listAutomate]);
50
+
26
51
  return (
27
52
  <Section style={styles.noShadow}>
53
+ <TouchableOpacity
54
+ style={styles.dropDown}
55
+ onPress={handleShowMenuAction}
56
+ ref={refMenuAction}
57
+ testID={TESTID.SUB_UNIT_SELECT_AUTOMATE_TYPE}
58
+ >
59
+ <View style={styles.boxDropDown}>
60
+ <Text
61
+ testID={TESTID.SUB_UNIT_TEXT_DROPDOWN}
62
+ style={styles.textDropDown}
63
+ semibold
64
+ >
65
+ {automates?.text}
66
+ </Text>
67
+ <Icon name={'caret-down'} size={14} style={{ color: Colors.Gray8 }} />
68
+ </View>
69
+ </TouchableOpacity>
28
70
  <View style={styles.boxDevices}>
29
- {!!automates.length &&
30
- automates.map((item) => (
71
+ {automates?.data &&
72
+ automates.data.map((item) => (
31
73
  <ItemOneTap isOwner={isOwner} automate={item} unit={unit} />
32
74
  ))}
33
75
  <ItemAddNew
@@ -36,6 +78,16 @@ const SubUnitAutomate = ({ isOwner, type, automates, unit, wrapItemStyle }) => {
36
78
  wrapStyle={wrapItemStyle}
37
79
  />
38
80
  </View>
81
+ <MenuActionMore
82
+ isVisible={showingPopover}
83
+ hideMore={hidePopover}
84
+ listMenuItem={listAutomate}
85
+ childRef={childRef}
86
+ onItemClick={onItemClick}
87
+ isTextCenter={false}
88
+ testID={TESTID.NAVBAR_MENU_ACTION_MORE}
89
+ wrapStyle={styles.wrapStyle}
90
+ />
39
91
  </Section>
40
92
  );
41
93
  };
@@ -63,6 +63,14 @@ const AirQuality = memo(({ summaryDetail }) => {
63
63
  return outdoor_pm10_id || outdoor_pm2_5_id || outdoor_co_id ? true : false;
64
64
  }, [outdoor_pm10_id, outdoor_pm2_5_id, outdoor_co_id]);
65
65
 
66
+ const configs = useMemo(() => {
67
+ return [
68
+ { id: outdoor_pm2_5_id, title: 'PM2.5', color: 'red' },
69
+ { id: outdoor_pm10_id, title: 'PM10', color: 'blue' },
70
+ { id: outdoor_co_id, title: 'CO', color: 'orange' },
71
+ ];
72
+ }, [outdoor_pm10_id, outdoor_pm2_5_id, outdoor_co_id]);
73
+
66
74
  const [indexOutdoor, setIndexOutdoor] = useState(0);
67
75
  const onSelectOutdoor = useCallback((i) => {
68
76
  setIndexOutdoor(i);
@@ -154,13 +162,7 @@ const AirQuality = memo(({ summaryDetail }) => {
154
162
  )}
155
163
  {showBoxHistory && (
156
164
  <Section type={'border'}>
157
- <ConfigHistoryChart
158
- configs={[
159
- { id: outdoor_pm2_5_id, title: 'PM2.5', color: 'red' },
160
- { id: outdoor_pm10_id, title: 'PM10', color: 'blue' },
161
- { id: outdoor_co_id, title: 'CO', color: 'orange' },
162
- ]}
163
- />
165
+ <ConfigHistoryChart configs={configs} />
164
166
  </Section>
165
167
  )}
166
168
  </View>
@@ -45,7 +45,8 @@ const ConfigHistoryChart = memo(({ configs }) => {
45
45
  }
46
46
  };
47
47
  fetchData();
48
- }, [startDate, endDate, configs]);
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ }, [startDate, endDate]);
49
50
 
50
51
  if (!chartData.length) {
51
52
  return false;
@@ -82,6 +82,9 @@ const API = {
82
82
  SCConfig.apiRoot + `/property_manager/sensors/${id}/`,
83
83
  REMOVE_SENSOR: (id) =>
84
84
  SCConfig.apiRoot + `/property_manager/sensors/${id}/`,
85
+ CHANGE_SUB_UNIT: (unit_id, station_id, id) =>
86
+ SCConfig.apiRoot +
87
+ `/property_manager/${unit_id}/sub_units/${station_id}/devices/${id}/change_sub_unit/`,
85
88
  },
86
89
  SHARED_SENSOR: {
87
90
  ACCESS: (id) =>
@@ -93,6 +93,9 @@ export const AUTOMATE_TYPE = {
93
93
  SCHEDULE: 'schedule',
94
94
  ONE_TAP_ONLY: 'one_tap_only',
95
95
  AUTOMATE: 'automate',
96
+ AUTOMATION: 'automation',
97
+ ALL: 'all',
98
+ SCENARIO: 'scenario',
96
99
  };
97
100
 
98
101
  export const AUTOMATE_SELECT = {
@@ -138,6 +141,10 @@ export const TESTID = {
138
141
  DASHBOARD_VIEW_ALL_SHARED_UNITS: 'DASHBOARD_VIEW_ALL_SHARED_UNITS',
139
142
  DASHBOARD_HOME_SCROLL_VIEW: 'DASHBOARD_HOME_SCROLL_VIEW',
140
143
 
144
+ //SmartAccountItem
145
+ SMART_ACCOUNT_ITEM: 'SMART_ACCOUNT_ITEM',
146
+ SMART_ACCOUNT_ITEM_PRESSMORE: 'SMART_ACCOUNT_ITEM_PRESSMORE',
147
+
141
148
  // Login
142
149
  LOGIN_TITLE: 'LOGIN_TITLE',
143
150
  LOGIN_INPUT_PHONE_NUMBER: 'LOGIN_INPUT_PHONE_NUMBER',
@@ -179,6 +186,8 @@ export const TESTID = {
179
186
  SUB_UNIT_DEVICES: 'SUB_UNIT_DEVICES',
180
187
  SUB_UNIT_ICON_BARS: 'SUB_UNIT_ICON_BARS',
181
188
  SUB_UNIT_STATION: 'SUB_UNIT_STATION',
189
+ SUB_UNIT_SELECT_AUTOMATE_TYPE: 'SUB_UNIT_SELECT_AUTOMATE_TYPE',
190
+ SUB_UNIT_TEXT_DROPDOWN: 'SUB_UNIT_TEXT_DROPDOWN',
182
191
 
183
192
  // NavBar
184
193
  NAVBAR_ICON_BARS: 'NAVBAR_ICON_BARS',
@@ -573,9 +582,15 @@ export const TESTID = {
573
582
  HISTORY_BUTTON: 'HISTORY_BUTTON',
574
583
  HISTORY_CALENDAR: 'HISTORY_CALENDAR',
575
584
 
585
+ // DropDownPicker
586
+ DROP_DOWN_PICKER_ITEM: 'DROP_DOWN_PICKER_ITEM',
587
+
576
588
  // SelectAddress
577
589
  BUTTON_YOUR_LOCATION: 'BUTTON_YOUR_LOCATION',
578
590
  BUTTON_CHOOSE_ON_MAP: 'BUTTON_CHOOSE_ON_MAP',
591
+
592
+ // MoveToAnotherSubUnit
593
+ ROW_SUB_UNIT: 'ROW_SUB_UNIT',
579
594
  };
580
595
 
581
596
  export const NOTIFICATION_TYPES = {
@@ -94,12 +94,13 @@ export const sendCommandOverBluetooth = async (sensor, action, data) => {
94
94
  device = getDeviceByName(bluetooth.address);
95
95
  }
96
96
 
97
- await sendDataOverBluetooth(device, {
97
+ const result = await sendDataOverBluetooth(device, {
98
98
  type: 'command',
99
99
  command: action.key,
100
100
  password: bluetooth ? bluetooth.password : '',
101
101
  data,
102
102
  });
103
+ return result;
103
104
  };
104
105
 
105
106
  export const getDeviceByName = (name) => {
@@ -138,7 +139,7 @@ export const sendDataOverBluetooth = async (
138
139
 
139
140
  let connectedDevice = null;
140
141
  let fullDataDevice = null;
141
-
142
+ let result = false;
142
143
  try {
143
144
  connectedDevice = await device.connect();
144
145
  fullDataDevice =
@@ -149,16 +150,18 @@ export const sendDataOverBluetooth = async (
149
150
  base64.encode(JSON.stringify(data))
150
151
  );
151
152
  ToastBottomHelper.success(t('Command is sent to device via bluetooth'));
153
+ result = true;
152
154
  } catch (e) {
153
155
  ToastBottomHelper.error(t('Command is fail to send via bluetooth'));
154
156
  throw SEND_COMMAND_OVER_BLUETOOTH_FAIL;
155
157
  }
156
158
 
157
159
  if (keepConnect) {
158
- return;
160
+ return result;
159
161
  }
160
162
 
161
163
  await device.cancelConnection();
164
+ return result;
162
165
  };
163
166
 
164
167
  export const isBluetoothEnabled = async () => {
@@ -27,7 +27,7 @@ function numberType(value) {
27
27
 
28
28
  function textType(value, entityId) {
29
29
  const textMap = textMaps[entityId];
30
- return textMap[value];
30
+ return textMap ? textMap[value] : '';
31
31
  }
32
32
 
33
33
  function keepValue(value) {
@@ -224,9 +224,12 @@ export async function sendCommandOverGoogleHome(sensor, action, data) {
224
224
  await connection.sendMessagePromise(message);
225
225
  }
226
226
 
227
- await axiosPost(API.SENSOR.ACTIVITY_LOG(), {
227
+ const { success } = await axiosPost(API.SENSOR.ACTIVITY_LOG(), {
228
228
  action_id: action.id,
229
229
  message: 'Trigger by user action with google home',
230
230
  });
231
- ToastBottomHelper.success(t('command_send_success_googlehome'));
231
+ if (success) {
232
+ ToastBottomHelper.success(t('command_send_success_googlehome'));
233
+ }
234
+ return success;
232
235
  }
@@ -19,4 +19,5 @@ export const sendCommandOverInternet = async (sensor, action, data, source) => {
19
19
  if (success) {
20
20
  ToastBottomHelper.success(t('Command is sent to device via internet'));
21
21
  }
22
+ return success;
22
23
  };
@@ -167,11 +167,12 @@ export const sendCommandOverLGThinq = async (sensor, action, data) => {
167
167
  new_message[key] = new_property;
168
168
  }
169
169
 
170
- await sendCommandOverInternet(
170
+ const result = await sendCommandOverInternet(
171
171
  sensor,
172
172
  action,
173
173
  JSON.stringify(new_message),
174
174
  'lg_thinq'
175
175
  );
176
+ return result;
176
177
  }
177
178
  };