@eohjsc/react-native-smart-city 0.2.61 → 0.2.65

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 (62) hide show
  1. package/README.md +115 -68
  2. package/package.json +2 -2
  3. package/src/commons/ActionGroup/CurtainButtonTemplate.js +10 -2
  4. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +1 -1
  5. package/src/commons/ActionGroup/__test__/MenuActionAddSchedule.test.js +71 -0
  6. package/src/commons/ActionGroup/hooks/AccessScheduleDetailStyles.js +41 -0
  7. package/src/commons/ActionGroup/hooks/MenuActionAddSchedule.js +110 -0
  8. package/src/commons/ActionGroup/hooks/MenuActionAddScheduleStyle.js +69 -0
  9. package/src/commons/ActionGroup/hooks/RecurringDetail.js +97 -0
  10. package/src/commons/DateTimeRangeChange/DateTimeButton.js +6 -1
  11. package/src/commons/Device/HistoryChart.js +2 -1
  12. package/src/commons/Device/HorizontalBarChart.js +2 -1
  13. package/src/commons/Device/LinearChart.js +28 -1
  14. package/src/commons/Form/CurrencyInput.js +1 -0
  15. package/src/commons/SubUnit/OneTap/OneTapStyles.js +20 -1
  16. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +151 -40
  17. package/src/commons/SubUnit/OneTap/index.js +64 -12
  18. package/src/configs/Constants.js +9 -0
  19. package/src/iot/RemoteControl/Bluetooth.js +6 -3
  20. package/src/iot/RemoteControl/GoogleHome.js +5 -2
  21. package/src/iot/RemoteControl/Internet.js +1 -0
  22. package/src/iot/RemoteControl/LG.js +2 -1
  23. package/src/iot/RemoteControl/index.js +13 -6
  24. package/src/navigations/SharedStack.js +8 -4
  25. package/src/navigations/UnitStack.js +10 -2
  26. package/src/screens/ActivityLog/hooks/index.js +1 -1
  27. package/src/screens/AddNewAction/SelectSensorDevices.js +18 -11
  28. package/src/screens/AddNewAction/Styles/SelectSensorDevicesStyles.js +5 -1
  29. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +6 -1
  30. package/src/screens/AddNewGateway/AddNewGatewayStyles.js +6 -1
  31. package/src/screens/AllCamera/index.js +27 -5
  32. package/src/screens/Automate/MultiUnits.js +7 -4
  33. package/src/screens/Automate/__test__/MultiUnits.test.js +1 -1
  34. package/src/screens/Automate/__test__/index.test.js +12 -0
  35. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +61 -0
  36. package/src/screens/ConfirmUnitDeletion/index.js +64 -0
  37. package/src/screens/ConfirmUnitDeletion/styles.js +37 -0
  38. package/src/screens/EmergencySetting/index.js +2 -0
  39. package/src/screens/EmergencySetting/styles.js +8 -2
  40. package/src/screens/ScriptDetail/Styles/indexStyles.js +3 -0
  41. package/src/screens/ScriptDetail/index.js +7 -1
  42. package/src/screens/SubUnit/AddSubUnit.js +13 -2
  43. package/src/screens/SubUnit/EditSubUnit.js +8 -1
  44. package/src/screens/SubUnit/EditSubUnitStyles.js +2 -3
  45. package/src/screens/SubUnit/__test__/AddSubUnit.test.js +2 -1
  46. package/src/screens/TDSGuide/index.js +1 -1
  47. package/src/screens/Unit/Detail.js +20 -7
  48. package/src/screens/Unit/ManageUnit.js +9 -12
  49. package/src/screens/Unit/SmartAccount.js +25 -41
  50. package/src/screens/Unit/SmartAccountItem.js +2 -1
  51. package/src/screens/Unit/SmartAccountStyles.js +0 -1
  52. package/src/screens/Unit/__test__/ManageUnit.test.js +0 -6
  53. package/src/screens/Unit/__test__/SmartAccount.test.js +24 -0
  54. package/src/screens/Unit/__test__/SmartAccountItem.test.js +72 -0
  55. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +2 -1
  56. package/src/screens/UnitSummary/components/PowerConsumption/index.js +1 -1
  57. package/src/screens/UnitSummary/components/Temperature/ItemTemperature/index.js +2 -2
  58. package/src/screens/WaterQualityGuide/index.js +2 -2
  59. package/src/utils/I18n/translations/en.json +15 -3
  60. package/src/utils/I18n/translations/vi.json +15 -3
  61. package/src/utils/Route/index.js +1 -0
  62. package/src/utils/Utils.js +4 -0
@@ -156,7 +156,8 @@ const HistoryChart = memo(
156
156
  return null;
157
157
  }
158
158
  const sum = datas[0].data.reduce((a, b) => a + b.y, 0);
159
- return sum * price;
159
+ const roundedSum = sum * price;
160
+ return roundedSum.toFixed();
160
161
  }, [configuration, datas, chartConfig]);
161
162
 
162
163
  const renderChart = useCallback(() => {
@@ -5,6 +5,7 @@ import { isEmpty } from 'lodash';
5
5
 
6
6
  import { Colors } from '../../configs';
7
7
  import { getMaxValueIndex } from '../../utils/chartHelper/getMaxValueIndex';
8
+ import { arePropsEqual } from '../../utils/Utils';
8
9
 
9
10
  const HorizontalBarChart = memo(({ datas, config }) => {
10
11
  const [chartOptions, setChartOptions] = useState({
@@ -145,7 +146,7 @@ const HorizontalBarChart = memo(({ datas, config }) => {
145
146
  />
146
147
  </View>
147
148
  );
148
- });
149
+ }, arePropsEqual);
149
150
 
150
151
  export default HorizontalBarChart;
151
152
 
@@ -3,6 +3,7 @@ import { StyleSheet, View } from 'react-native';
3
3
  import HighchartsReactNative from '@highcharts/highcharts-react-native';
4
4
  import moment from 'moment';
5
5
  import { Colors } from '../../configs';
6
+ import { arePropsEqual } from '../../utils/Utils';
6
7
 
7
8
  const convertData = (data = []) => {
8
9
  let arr = [];
@@ -56,6 +57,32 @@ const chartOptions = {
56
57
  },
57
58
  minRange: 3600 * 24 * 1000,
58
59
  },
60
+ plotOptions: {
61
+ series: {
62
+ events: {
63
+ legendItemClick: function () {
64
+ const { index, visible } = this;
65
+ const isHiding = (serie, i) => {
66
+ if (i === index) {
67
+ return visible;
68
+ }
69
+ return !serie.visible;
70
+ };
71
+ if (this.chart.series.every(isHiding)) {
72
+ this.chart.yAxis[0].update({
73
+ min: 0,
74
+ max: 100,
75
+ });
76
+ } else {
77
+ this.chart.yAxis[0].update({
78
+ min: undefined,
79
+ max: undefined,
80
+ });
81
+ }
82
+ },
83
+ },
84
+ },
85
+ },
59
86
  };
60
87
 
61
88
  function LinearChart({ datas }) {
@@ -93,7 +120,7 @@ function LinearChart({ datas }) {
93
120
  );
94
121
  }
95
122
 
96
- export default memo(LinearChart);
123
+ export default memo(LinearChart, arePropsEqual);
97
124
 
98
125
  const styles = StyleSheet.create({
99
126
  container: {
@@ -136,6 +136,7 @@ const CurrencyInput = ({
136
136
  placeholder={placeholder}
137
137
  onSubmitEditing={onSubmitEditing}
138
138
  style={styles.input}
139
+ maxLength={10}
139
140
  />
140
141
  <Text
141
142
  semibold
@@ -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
  };
@@ -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',
@@ -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 () => {
@@ -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
  };
@@ -10,18 +10,24 @@ import { sendCommandOverLGThinq } from './LG';
10
10
 
11
11
  export const sendRemoteCommand = async (sensor, action, data) => {
12
12
  // No action, raise not authorized
13
+ let result = false;
13
14
  if (!action) {
14
15
  ToastBottomHelper.error(
15
16
  t('your_account_has_not_been_authorized_to_control')
16
17
  );
17
- return;
18
+ return result;
18
19
  }
19
20
  if (action.command_prefer_over_bluetooth) {
20
21
  try {
21
- await sendCommandOverBluetooth(sensor, action, data);
22
+ result = await sendCommandOverBluetooth(sensor, action, data);
22
23
  } catch (err) {
23
24
  if (err === SEND_COMMAND_OVER_BLUETOOTH_FAIL) {
24
- await sendCommandOverInternet(sensor, action, data, 'bluetooth');
25
+ result = await sendCommandOverInternet(
26
+ sensor,
27
+ action,
28
+ data,
29
+ 'bluetooth'
30
+ );
25
31
  } else {
26
32
  throw err;
27
33
  }
@@ -29,14 +35,15 @@ export const sendRemoteCommand = async (sensor, action, data) => {
29
35
  }
30
36
 
31
37
  if (action.command_prefer_over_internet) {
32
- await sendCommandOverInternet(sensor, action, data, 'internet');
38
+ result = await sendCommandOverInternet(sensor, action, data, 'internet');
33
39
  }
34
40
 
35
41
  if (action.command_prefer_over_googlehome) {
36
- await sendCommandOverGoogleHome(sensor, action, data);
42
+ result = await sendCommandOverGoogleHome(sensor, action, data);
37
43
  }
38
44
 
39
45
  if (action.command_prefer_over_lg) {
40
- await sendCommandOverLGThinq(sensor, action, data);
46
+ result = await sendCommandOverLGThinq(sensor, action, data);
41
47
  }
48
+ return result;
42
49
  };
@@ -1,7 +1,7 @@
1
1
  import React, { memo } from 'react';
2
2
  import { createStackNavigator } from '@react-navigation/stack';
3
3
  import { TouchableOpacity, StyleSheet } from 'react-native';
4
- import { useNavigation } from '@react-navigation/native';
4
+ import { useNavigation, useRoute } from '@react-navigation/native';
5
5
  import { Icon } from '@ant-design/react-native';
6
6
  import { useTranslations } from '../hooks/Common/useTranslations';
7
7
 
@@ -12,7 +12,8 @@ import Routes from '../utils/Route';
12
12
  const Stack = createStackNavigator();
13
13
  const SharedStack = memo(() => {
14
14
  const t = useTranslations();
15
- const navigation = useNavigation();
15
+ const { toggleDrawer, goBack } = useNavigation();
16
+ const { params } = useRoute();
16
17
  return (
17
18
  <Stack.Navigator>
18
19
  <Stack.Screen
@@ -23,9 +24,12 @@ const SharedStack = memo(() => {
23
24
  headerLeft: () => (
24
25
  <TouchableOpacity
25
26
  style={styles.btnMenu}
26
- onPress={() => navigation.toggleDrawer()}
27
+ onPress={() => (params?.isMainSource ? toggleDrawer() : goBack())}
27
28
  >
28
- <Icon name={'menu'} color={Colors.Black} />
29
+ <Icon
30
+ name={params?.isMainSource ? 'menu' : 'arrow-left'}
31
+ color={Colors.Black}
32
+ />
29
33
  </TouchableOpacity>
30
34
  ),
31
35
  headerTitleAlign: 'left',