@eohjsc/react-native-smart-city 0.7.24 → 0.7.26

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 (54) hide show
  1. package/index.js +2 -0
  2. package/package.json +1 -1
  3. package/src/Images/Common/search-menu.svg +7 -0
  4. package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplateStyle.js +2 -1
  5. package/src/commons/ActionGroup/OneBigButtonTemplateStyle.js +1 -2
  6. package/src/commons/ActionGroup/SliderRangeTemplate.js +1 -3
  7. package/src/commons/ActionGroup/TerminalBoxTemplate.js +1 -4
  8. package/src/commons/ActionGroup/TextBoxTemplate.js +1 -5
  9. package/src/commons/ActionGroup/ThreeButtonTemplate/components/ThreeButtonDefaultStyles.js +1 -1
  10. package/src/commons/ActionGroup/__test__/index.test.js +51 -0
  11. package/src/commons/ActionGroup/index.js +4 -0
  12. package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +171 -0
  13. package/src/commons/Dashboard/MyDashboardDevice/index.js +218 -0
  14. package/src/commons/Dashboard/MyDashboardDevice/styles.js +60 -0
  15. package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +0 -10
  16. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +114 -48
  17. package/src/commons/Dashboard/MyUnit/index.js +74 -27
  18. package/src/commons/Dashboard/MyUnit/styles.js +16 -1
  19. package/src/commons/DateTimeRangeChange/index.js +1 -1
  20. package/src/commons/Device/ItemDevice.js +12 -3
  21. package/src/commons/Device/ItemDeviceWrapper.js +10 -2
  22. package/src/commons/SelectUnit/index.js +19 -5
  23. package/src/commons/SelectUnit/styles.js +0 -1
  24. package/src/commons/SubUnit/DeviceTemplate/DeviceTemplate.js +8 -3
  25. package/src/commons/Widgets/IFrame/IFrameStyles.js +1 -0
  26. package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfigStyles.js +1 -0
  27. package/src/configs/API.js +11 -0
  28. package/src/configs/AccessibilityLabel.js +2 -0
  29. package/src/configs/Constants.js +3 -0
  30. package/src/context/actionType.ts +4 -0
  31. package/src/context/mockStore.ts +5 -0
  32. package/src/context/reducer.ts +30 -5
  33. package/src/iot/mqtt.js +163 -47
  34. package/src/navigations/UnitStack.js +22 -0
  35. package/src/screens/Device/__test__/detail.test.js +42 -1
  36. package/src/screens/Device/__test__/mqttDetail.test.js +411 -190
  37. package/src/screens/Device/__test__/sensorDisplayItem.test.js +27 -0
  38. package/src/screens/Device/components/DonutChart.js +5 -14
  39. package/src/screens/Device/components/SensorDisplayItem.js +92 -61
  40. package/src/screens/Device/components/VisualChart.js +0 -12
  41. package/src/screens/Device/detail.js +50 -14
  42. package/src/screens/Device/hooks/useDashboardDevice.js +34 -0
  43. package/src/screens/Device/styles.js +16 -0
  44. package/src/screens/SubUnit/AddSubUnit.js +18 -8
  45. package/src/screens/SubUnit/__test__/AddSubUnit.test.js +5 -3
  46. package/src/screens/Unit/GoToDetailUnit.js +30 -0
  47. package/src/screens/Unit/__test__/GoToDetailUnit.test.js +103 -0
  48. package/src/utils/FactoryGateway.js +105 -0
  49. package/src/utils/I18n/translations/en.js +4 -0
  50. package/src/utils/I18n/translations/vi.js +4 -0
  51. package/src/utils/Route/index.js +1 -0
  52. package/src/utils/Storage.js +18 -4
  53. package/src/utils/Utils.js +2 -1
  54. package/src/utils/Functions/preloadImages.js +0 -38
@@ -40,6 +40,7 @@ export default {
40
40
  MY_UNIT_GO_TO_DETAIL: 'MY_UNIT_GO_TO_DETAIL',
41
41
  MY_UNIT_NO_UNIT: 'MY_UNIT_NO_UNIT',
42
42
  ITEM_UNIT: 'ITEM_UNIT',
43
+ UNIT_GO_TO_DETAIL: 'UNIT_GO_TO_DETAIL',
43
44
 
44
45
  // ConfirmUnitDeletion
45
46
  CONFIRM_UNIT_DELETION_BUTTON: 'CONFIRM_UNIT_DELETION_BUTTON',
@@ -270,6 +271,7 @@ export default {
270
271
  PARKING_SPOT_TEXT_RESULT: 'PARKING_SPOT_TEXT_RESULT',
271
272
 
272
273
  // Header Device
274
+ HEADER_DEVICE_BUTTON_PIN: 'HEADER_DEVICE_BUTTON_PIN',
273
275
  HEADER_DEVICE_BUTTON_STAR: 'HEADER_DEVICE_BUTTON_STAR',
274
276
  HEADER_SCRIPT_DETAIL_BUTTON_STAR: 'HEADER_SCRIPT_DETAIL_BUTTON_STAR',
275
277
  HEADER_DEVICE_BUTTON_MORE: 'HEADER_DEVICE_BUTTON_MORE',
@@ -98,6 +98,9 @@ const marginItem = 12;
98
98
  const marginHorizontal = 16;
99
99
  const widthItem = (Constants.width - marginHorizontal * 2 - marginItem) / 2;
100
100
  const heightItem = (widthItem / 166) * 106;
101
+
102
+ export const PAGE_SIZE = 10;
103
+
101
104
  export const DEVICE_SIZE = {
102
105
  width: widthItem,
103
106
  height: heightItem,
@@ -12,6 +12,9 @@ export const Action = {
12
12
  SET_NETWORK_CONNECTED: 'SET_NETWORK_CONNECTED',
13
13
  CAMERA_STATUS_CHANGE: 'CAMERA_STATUS_CHANGE',
14
14
  CLOSE_ALL_CAMERA: 'CLOSE_ALL_CAMERA',
15
+ SET_DASHBOARD_DEVICES: 'SET_DASHBOARD_DEVICES',
16
+ ADD_DEVICES_TO_DASHBOARD: 'ADD_DEVICE_TO_DASHBOARD',
17
+ REMOVE_DEVICES_FROM_DASHBOARD: 'REMOVE_DEVICE_FROM_DASHBOARD',
15
18
  SET_FAVORITE_DEVICES: 'SET_FAVORITE_DEVICES',
16
19
  ADD_DEVICES_TO_FAVORITES: 'ADD_DEVICE_TO_FAVORITES',
17
20
  REMOVE_DEVICES_FROM_FAVORITES: 'REMOVE_DEVICE_FROM_FAVORITES',
@@ -78,6 +81,7 @@ export type ListAction = {
78
81
  }[];
79
82
 
80
83
  export type UnitType = {
84
+ dashboardDeviceIds: [];
81
85
  favoriteDeviceIds: [];
82
86
  };
83
87
 
@@ -27,6 +27,7 @@ export const mockDataStore: ContextData = {
27
27
  listAction: [],
28
28
  myUnits: [],
29
29
  unit: {
30
+ dashboardDeviceIds: [],
30
31
  favoriteDeviceIds: [],
31
32
  },
32
33
  automate: {
@@ -103,6 +104,10 @@ export const mockSCStore = (data: ContextData): ContextData => {
103
104
  },
104
105
  myUnits: [...mockDataStore.myUnits, ...(data?.myUnits || [])],
105
106
  unit: {
107
+ dashboardDeviceIds: [
108
+ ...mockDataStore.unit.dashboardDeviceIds,
109
+ ...(data?.unit?.dashboardDeviceIds || []),
110
+ ],
106
111
  favoriteDeviceIds: [
107
112
  ...mockDataStore.unit.favoriteDeviceIds,
108
113
  ...(data?.unit?.favoriteDeviceIds || []),
@@ -15,7 +15,6 @@ import {
15
15
  BluetoothType,
16
16
  } from './actionType';
17
17
  import _ from 'lodash';
18
- import { STORAGE_KEY, removeMultiple } from '../utils/Storage.js';
19
18
  import { AppState } from 'react-native';
20
19
 
21
20
  export type ContextData = {
@@ -57,6 +56,7 @@ export const initialState = {
57
56
  percent: 0,
58
57
  myUnits: [],
59
58
  unit: {
59
+ dashboardDeviceIds: [],
60
60
  favoriteDeviceIds: [],
61
61
  },
62
62
  automate: {
@@ -264,6 +264,35 @@ export const reducer = (currentState: ContextData, action: Action) => {
264
264
  },
265
265
  };
266
266
 
267
+ case Action.SET_DASHBOARD_DEVICES:
268
+ return {
269
+ ...currentState,
270
+ unit: {
271
+ ...currentState.unit,
272
+ dashboardDeviceIds: payload,
273
+ },
274
+ };
275
+ case Action.ADD_DEVICES_TO_DASHBOARD:
276
+ return {
277
+ ...currentState,
278
+ unit: {
279
+ ...currentState.unit,
280
+ dashboardDeviceIds: _.uniq(
281
+ currentState.unit.dashboardDeviceIds.concat(payload)
282
+ ),
283
+ },
284
+ };
285
+ case Action.REMOVE_DEVICES_FROM_DASHBOARD:
286
+ return {
287
+ ...currentState,
288
+ unit: {
289
+ ...currentState.unit,
290
+ dashboardDeviceIds: currentState.unit.dashboardDeviceIds.filter(
291
+ (deviceId) => !payload.includes(deviceId)
292
+ ),
293
+ },
294
+ };
295
+
267
296
  case Action.SET_FAVORITE_DEVICES:
268
297
  return {
269
298
  ...currentState,
@@ -552,10 +581,6 @@ export const reducer = (currentState: ContextData, action: Action) => {
552
581
  };
553
582
 
554
583
  case Action.LOGOUT:
555
- removeMultiple([
556
- STORAGE_KEY.IS_FIRST_TIME_LOAD_MY_UNITS,
557
- STORAGE_KEY.IS_FIRST_TIME_LOAD_MY_SHARE_UNIT,
558
- ]);
559
584
  return {
560
585
  ...currentState,
561
586
  };
package/src/iot/mqtt.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import moment from 'moment';
2
+ import { getObject, storeObject } from '../utils/Storage';
2
3
  import { updateGlobalValue } from './Monitor';
3
4
  import { Buffer } from 'buffer';
4
5
 
5
- const int_all = (bytes_str, config_data = null) => {
6
+ const struct = require('python-struct');
7
+
8
+ const int_all = (bytes_str) => {
6
9
  let val;
7
10
  val = Number.parseInt(bytes_str, 16);
8
11
 
@@ -13,44 +16,75 @@ const int_all = (bytes_str, config_data = null) => {
13
16
  return val;
14
17
  };
15
18
 
16
- const int_first4 = (bytes_str, config_data = null) => {
17
- return Number.parseInt(bytes_str.slice(0, 4), 16);
19
+ const int_first4 = (bytes_str) => {
20
+ return Number.parseInt(bytes_str?.slice(0, 4), 16);
18
21
  };
19
22
 
20
- const int_last4 = (bytes_str, config_data = null) => {
21
- return Number.parseInt(bytes_str.slice(4), 16);
23
+ const int_last4 = (bytes_str) => {
24
+ return Number.parseInt(bytes_str?.slice(4), 16);
22
25
  };
23
26
 
24
- const uint_32 = (bytes_str, config_data = null) => {
25
- let bits = 32;
26
- let value = Number.parseInt(bytes_str, 16);
27
-
28
- // eslint-disable-next-line no-bitwise
29
- if (value & (1 << (bits - 1))) {
30
- // eslint-disable-next-line no-bitwise
31
- value -= 1 << bits;
32
- }
33
-
34
- return value;
35
- };
36
-
37
- const float_convert = (bytes_str) => {
38
- const struct = require('python-struct');
27
+ const value_unpacked = (format, bytes_str) => {
39
28
  let value = null;
40
29
  try {
41
- value = struct.unpack('>f', Buffer.from(bytes_str, 'hex'))[0];
30
+ value = struct.unpack(format, Buffer.from(bytes_str, 'hex'))[0];
42
31
  // eslint-disable-next-line no-empty
43
32
  } catch {}
44
33
  return value;
45
34
  };
46
35
 
47
- const float_cdba = (bytes_str, config_data = null) => {
48
- const bytes_cdba = bytes_str?.slice(4) + bytes_str?.slice(0, 4);
49
- return float_convert(bytes_cdba);
36
+ const uint_32_abcd = (bytes_str) => {
37
+ return value_unpacked('>I', bytes_str?.slice(0, 8));
38
+ };
39
+
40
+ const uint_32_dcba = (bytes_str) => {
41
+ return value_unpacked('<I', bytes_str?.slice(0, 8));
42
+ };
43
+
44
+ const uint_32_badc = (bytes_str) => {
45
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
46
+ return value_unpacked('<I', swapped);
47
+ };
48
+
49
+ const uint_32_cdab = (bytes_str) => {
50
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
51
+ return value_unpacked('>I', swapped);
52
+ };
53
+
54
+ const int_32_abcd = (bytes_str) => {
55
+ return value_unpacked('>i', bytes_str?.slice(0, 8));
56
+ };
57
+
58
+ const int_32_dcba = (bytes_str) => {
59
+ return value_unpacked('<i', bytes_str?.slice(0, 8));
50
60
  };
51
61
 
52
- const float_abcd = (bytes_str, config_data = null) => {
53
- return float_convert(bytes_str);
62
+ const int_32_badc = (bytes_str) => {
63
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
64
+ return value_unpacked('<i', swapped);
65
+ };
66
+
67
+ const int_32_cdab = (bytes_str) => {
68
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
69
+ return value_unpacked('>i', swapped);
70
+ };
71
+
72
+ const float_abcd = (bytes_str) => {
73
+ return value_unpacked('>f', bytes_str?.slice(0, 8));
74
+ };
75
+
76
+ const float_dcba = (bytes_str) => {
77
+ return value_unpacked('<f', bytes_str?.slice(0, 8));
78
+ };
79
+
80
+ const float_badc = (bytes_str) => {
81
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
82
+ return value_unpacked('<f', swapped);
83
+ };
84
+
85
+ const float_cdab = (bytes_str) => {
86
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
87
+ return value_unpacked('>f', swapped);
54
88
  };
55
89
 
56
90
  const range_value_converting = (
@@ -84,12 +118,21 @@ const convert_ai = (bytes_str, config_data = null) => {
84
118
 
85
119
  const mappingTransformer = {
86
120
  int_all: int_all,
87
- int_first4: int_first4,
88
- int_last4: int_last4,
89
- uint_32: uint_32,
90
- float_cdba: float_cdba,
91
121
  float_abcd: float_abcd,
122
+ float_dcba: float_dcba,
123
+ float_badc: float_badc,
124
+ float_cdab: float_cdab,
125
+ uint_32_abcd: uint_32_abcd,
126
+ uint_32_dcba: uint_32_dcba,
127
+ uint_32_badc: uint_32_badc,
128
+ uint_32_cdab: uint_32_cdab,
129
+ int_32_abcd: int_32_abcd,
130
+ int_32_dcba: int_32_dcba,
131
+ int_32_badc: int_32_badc,
132
+ int_32_cdab: int_32_cdab,
92
133
  convert_ai: convert_ai,
134
+ int_first4: int_first4,
135
+ int_last4: int_last4,
93
136
  };
94
137
 
95
138
  const extract_config_value = (register, value_bytes) => {
@@ -135,19 +178,56 @@ const get_sensor_data = (sensor, data) => {
135
178
  };
136
179
 
137
180
  const get_scale_value = (value, config) => {
138
- if (!value || typeof value === 'string') {
181
+ if (!value) {
139
182
  return value;
140
183
  }
141
- const { decimal_behind, scale } = config;
142
- let scaledValue = value * (scale || 1);
184
+ const scale = config?.scale || 1;
185
+ return value * scale;
186
+ };
187
+
188
+ const get_decimal_value = (value, config) => {
189
+ if (config?.decimal_behind || config?.decimal_behind === 0) {
190
+ value = value.toFixed(config.decimal_behind);
191
+ }
192
+ return value;
193
+ };
143
194
 
144
- if (decimal_behind || decimal_behind === 0) {
145
- scaledValue = scaledValue.toFixed(decimal_behind);
195
+ const get_offset_sample_value = async (value, config) => {
196
+ const offset = parseFloat(config?.ai_trans_offset_value) || 0;
197
+ const sample = config?.ai_trans_average_sample || 1;
198
+ value += offset;
199
+ if (sample <= 1) {
200
+ return Number(get_decimal_value(value, config));
146
201
  }
147
- return Number(scaledValue);
202
+
203
+ const cacheKey = `last_values_${config?.id}`;
204
+ let values = await getObject(cacheKey, []);
205
+
206
+ values = [value, ...values];
207
+ values = values.slice(0, sample);
208
+
209
+ value = values.reduce((a, b) => a + b) / values.length;
210
+ value = Number(get_decimal_value(value, config));
211
+
212
+ values[0] = value;
213
+ await storeObject(cacheKey, values);
214
+ return value;
148
215
  };
149
216
 
150
- const updateGlobalValueMqtt = (config, value) => {
217
+ const check_filter = (value, config) => {
218
+ if (!config?.active_filter) {
219
+ return false;
220
+ }
221
+ if (config?.active_filter === 'zero') {
222
+ return !value;
223
+ }
224
+
225
+ const low = config?.low_level || 0;
226
+ const high = config?.high_level || 0;
227
+ return value < low || value > high;
228
+ };
229
+
230
+ const updateGlobalValueMqtt = async (config, value) => {
151
231
  if (!config?.id) {
152
232
  return;
153
233
  }
@@ -155,13 +235,20 @@ const updateGlobalValueMqtt = (config, value) => {
155
235
  return;
156
236
  }
157
237
 
158
- value = get_scale_value(value, config);
159
- updateGlobalValue(config.id, { value: value });
160
- };
238
+ const last_updated = moment().format('YYYY-MM-DDTHH:mm:ss.SSSSSS');
239
+ if (typeof value === 'string') {
240
+ updateGlobalValue(config.id, { value, last_updated });
241
+ return;
242
+ }
161
243
 
162
- const arduinoUpdateGlobalValueMqtt = (config, value, last_updated) => {
163
244
  value = get_scale_value(value, config);
164
- updateGlobalValue(config.id, { value: value, last_updated: last_updated });
245
+ value = await get_offset_sample_value(value, config);
246
+
247
+ if (check_filter(value, config)) {
248
+ return;
249
+ }
250
+
251
+ updateGlobalValue(config.id, { value, last_updated });
165
252
  };
166
253
 
167
254
  export const handleModbusData = (chip, configById, data) => {
@@ -188,11 +275,7 @@ export const handleModbusData = (chip, configById, data) => {
188
275
  };
189
276
 
190
277
  export const handleChipData = (configById, configId, data) => {
191
- arduinoUpdateGlobalValueMqtt(
192
- configById[configId],
193
- data?.v,
194
- moment().format('YYYY-MM-DDTHH:mm:ss.SSSSSS')
195
- );
278
+ updateGlobalValueMqtt(configById[configId], data?.v);
196
279
  };
197
280
 
198
281
  export const handleZigbeeData = (chip, configById, ieee_address, data) => {
@@ -217,6 +300,26 @@ export const handleZigbeeData = (chip, configById, ieee_address, data) => {
217
300
  }
218
301
  };
219
302
 
303
+ export const handleThirdPartyData = (chip, configById, device_uid, data) => {
304
+ const third_party_gateway = chip?.third_party_gateway;
305
+ if (!third_party_gateway) {
306
+ return;
307
+ }
308
+
309
+ const third_party_device_by_uid = {};
310
+
311
+ third_party_gateway?.sensors?.forEach((device) => {
312
+ third_party_device_by_uid[device.device_uid] = device;
313
+ });
314
+
315
+ const device = third_party_device_by_uid[device_uid];
316
+ device?.configs?.forEach((config_map) => {
317
+ const value = data[config_map?.key];
318
+ const configId = config_map?.config;
319
+ updateGlobalValueMqtt(configById[configId], value);
320
+ });
321
+ };
322
+
220
323
  export const handleMqttMessage = (
221
324
  topic,
222
325
  payloadData,
@@ -246,4 +349,17 @@ export const handleMqttMessage = (
246
349
  // payload: {zigbee_data: 'aaa', 'data': {state: 1, state_0: 0}}
247
350
  handleZigbeeData(chip, configById, matchZigbeeConfigValue[1], payloadData);
248
351
  }
352
+
353
+ const matchThirdPartyConfigValue = topic.match(/third_party\/(.+)\/data/);
354
+ if (matchThirdPartyConfigValue) {
355
+ // ThirdParty
356
+ // topic: eoh/chip/code-123/third_party/UID-123/data
357
+ // payload: {state: 1, temperature: 27.6}
358
+ handleThirdPartyData(
359
+ chip,
360
+ configById,
361
+ matchThirdPartyConfigValue[1],
362
+ payloadData
363
+ );
364
+ }
249
365
  };
@@ -60,6 +60,7 @@ import TDSGuide from '../screens/TDSGuide';
60
60
  import ChooseLocation from '../screens/Unit/ChooseLocation';
61
61
  import UnitDetail from '../screens/Unit/Detail';
62
62
  import ManageUnit from '../screens/Unit/ManageUnit';
63
+ import GoToDetailUnit from '../screens/Unit/GoToDetailUnit';
63
64
  import SelectAddress from '../screens/Unit/SelectAddress';
64
65
  import SelectAddToFavorites from '../screens/Unit/SelectAddToFavorites';
65
66
  import ListSmartAccount from '../screens/Unit/SmartAccount';
@@ -124,6 +125,19 @@ export const UnitStack = memo((props) => {
124
125
  }, [isBluetoothEnabled, bluetoothPermGranted, onDeviceFound]);
125
126
 
126
127
  useEffect(() => {
128
+ const fetchDashboardDevices = async () => {
129
+ const id = unitId || unitData?.id;
130
+ if (!id) {
131
+ return;
132
+ }
133
+ await fetchWithCache(
134
+ API.UNIT.DASHBOARD_DEVICES(id),
135
+ {},
136
+ ({ success, data }) => {
137
+ success && setAction(Action.SET_DASHBOARD_DEVICES, data);
138
+ }
139
+ );
140
+ };
127
141
  const fetchFavoriteDevices = async () => {
128
142
  const id = unitId || unitData?.id;
129
143
  if (!id) {
@@ -137,6 +151,7 @@ export const UnitStack = memo((props) => {
137
151
  }
138
152
  );
139
153
  };
154
+ fetchDashboardDevices();
140
155
  fetchFavoriteDevices();
141
156
  // eslint-disable-next-line react-hooks/exhaustive-deps
142
157
  }, []);
@@ -209,6 +224,13 @@ export const UnitStack = memo((props) => {
209
224
  headerShown: false,
210
225
  }}
211
226
  />
227
+ <Stack.Screen
228
+ name={Route.GoToDetailUnit}
229
+ component={GoToDetailUnit}
230
+ options={{
231
+ headerShown: false,
232
+ }}
233
+ />
212
234
  <Stack.Screen
213
235
  name={Route.ListSmartAccount}
214
236
  component={ListSmartAccount}
@@ -661,6 +661,47 @@ describe('test DeviceDetail', () => {
661
661
  expect(menu.props.isVisible).toBe(true);
662
662
  });
663
663
 
664
+ it('Add device to Dashboard', async () => {
665
+ const sensor = route?.params?.sensorData;
666
+ mock.onPost(API.DEVICE.ADD_TO_DASHBOARD(sensor.id)).reply(200);
667
+
668
+ await act(async () => {
669
+ tree = await create(wrapComponent(store, account, route));
670
+ });
671
+ const instance = tree.root;
672
+ const buttonPin = instance.find(
673
+ (el) =>
674
+ el.props.accessibilityLabel ===
675
+ AccessibilityLabel.HEADER_DEVICE_BUTTON_PIN
676
+ );
677
+ await act(async () => {
678
+ await buttonPin.props.onPress();
679
+ });
680
+ const urls = mock.history.post.map(({ url }) => url);
681
+ expect(urls).toContain(API.DEVICE.ADD_TO_DASHBOARD(sensor.id));
682
+ });
683
+
684
+ it('Remove device from Dashboard', async () => {
685
+ const sensor = route?.params?.sensorData;
686
+ store.unit.dashboardDeviceIds = [sensor.id];
687
+ mock.onPost(API.DEVICE.REMOVE_FROM_DASHBOARD(sensor.id)).reply(200);
688
+
689
+ await act(async () => {
690
+ tree = await create(wrapComponent(store, account, route));
691
+ });
692
+ const instance = tree.root;
693
+ const buttonPin = instance.find(
694
+ (el) =>
695
+ el.props.accessibilityLabel ===
696
+ AccessibilityLabel.HEADER_DEVICE_BUTTON_PIN
697
+ );
698
+ await act(async () => {
699
+ await buttonPin.props.onPress();
700
+ });
701
+ const urls = mock.history.post.map(({ url }) => url);
702
+ expect(urls).toContain(API.DEVICE.REMOVE_FROM_DASHBOARD(sensor.id));
703
+ });
704
+
664
705
  it('Add device to Favourites', async () => {
665
706
  const sensor = route?.params?.sensorData;
666
707
  sensor.is_favourite = false;
@@ -733,7 +774,7 @@ describe('test DeviceDetail', () => {
733
774
  });
734
775
  const instance = tree.root;
735
776
  const menu = instance.findByType(MenuActionMore);
736
- const gotoActivityLog = menu.props.listMenuItem[1];
777
+ const gotoActivityLog = menu.props.listMenuItem[2];
737
778
 
738
779
  await act(async () => {
739
780
  await menu.props.onItemClick(gotoActivityLog);