@eohjsc/react-native-smart-city 0.2.85 → 0.2.86

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 (42) hide show
  1. package/assets/images/Device/button-lock.svg +3 -0
  2. package/assets/images/Device/button-unlock.svg +3 -0
  3. package/package.json +1 -1
  4. package/src/commons/ActionGroup/OnOffSmartLock.js +48 -0
  5. package/src/commons/ActionGroup/OnOffSmartLockStyle.js +51 -0
  6. package/src/commons/ActionGroup/index.js +3 -0
  7. package/src/commons/ConnectingProcess/index.js +5 -2
  8. package/src/commons/Device/ItemDevice.js +8 -3
  9. package/src/commons/MediaPlayer/__test__/index.test.js +45 -0
  10. package/src/commons/SubUnit/ShortDetail.js +10 -22
  11. package/src/commons/SubUnit/__test__/ShortDetail.test.js +57 -48
  12. package/src/configs/API.js +2 -2
  13. package/src/configs/Constants.js +13 -0
  14. package/src/screens/ActivityLog/hooks/index.js +18 -4
  15. package/src/screens/ActivityLog/index.js +3 -0
  16. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  17. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  18. package/src/screens/AddNewAction/SelectSensorDevices.js +4 -2
  19. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +10 -2
  20. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +4 -2
  21. package/src/screens/AddNewOneTap/index.js +32 -17
  22. package/src/screens/Automate/index.js +2 -2
  23. package/src/screens/Device/EditDevice/index.js +5 -3
  24. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  25. package/src/screens/Device/detail.js +1 -0
  26. package/src/screens/Notification/__test__/NotificationItem.test.js +15 -3
  27. package/src/screens/Notification/components/NotificationItem.js +52 -8
  28. package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +1 -0
  29. package/src/screens/ScanChipQR/hooks/index.js +90 -44
  30. package/src/screens/ScriptDetail/index.js +1 -6
  31. package/src/screens/SelectUnit/index.js +1 -0
  32. package/src/screens/SharedUnit/index.js +1 -1
  33. package/src/screens/SmartIr/__test__/SmartIr.test.js +61 -0
  34. package/src/screens/SmartIr/index.js +23 -0
  35. package/src/screens/SmartIr/styles.js +14 -0
  36. package/src/screens/Unit/AddMenu.js +4 -1
  37. package/src/screens/Unit/Detail.js +1 -1
  38. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/__test__/index.test.js +32 -1
  39. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/index.js +1 -1
  40. package/src/utils/I18n/translations/en.json +9 -2
  41. package/src/utils/I18n/translations/vi.json +9 -2
  42. package/src/utils/Route/index.js +1 -0
@@ -9,15 +9,17 @@ import { ViewButtonBottom } from '../../../commons';
9
9
  import { Colors } from '../../../configs';
10
10
 
11
11
  const FirstWarning = memo(({ route }) => {
12
- const { unit_id } = route.params;
12
+ const { unit_id, unit_name } = route.params;
13
13
  const t = useTranslations();
14
14
  const { goBack, navigate } = useNavigation();
15
15
 
16
16
  const onRight = useCallback(() => {
17
17
  navigate(Routes.ScanChipQR, {
18
18
  unit_id: unit_id,
19
+ unit_name: unit_name,
20
+ isNewFlow: true,
19
21
  });
20
- }, [navigate, unit_id]);
22
+ }, [navigate, unit_name, unit_id]);
21
23
 
22
24
  return (
23
25
  <View style={styles.screen}>
@@ -1,6 +1,6 @@
1
1
  import React, { memo, useCallback, useState } from 'react';
2
2
  import { ScrollView, SafeAreaView, Platform } from 'react-native';
3
- import { useNavigation } from '@react-navigation/native';
3
+ import { CommonActions, useNavigation } from '@react-navigation/native';
4
4
 
5
5
  import { API, Colors } from '../../configs';
6
6
  import { TESTID } from '../../configs/Constants';
@@ -12,7 +12,7 @@ import Text from '../../commons/Text';
12
12
  import { useTranslations } from '../../hooks/Common/useTranslations';
13
13
  import { axiosPost, axiosPut } from '../../utils/Apis/axios';
14
14
  import Routes from '../../utils/Route';
15
- import { popAction, replace } from '../../navigations/utils';
15
+ import { popAction } from '../../navigations/utils';
16
16
  import { AUTOMATE_TYPE } from '../../configs/Constants';
17
17
 
18
18
  const AddNewOneTap = memo(({ route }) => {
@@ -41,19 +41,33 @@ const AddNewOneTap = memo(({ route }) => {
41
41
  ? await axiosPut(API.AUTOMATE.UPDATE_AUTOMATE(automateId), params)
42
42
  : await axiosPost(API.AUTOMATE.CREATE_AUTOMATE(), params);
43
43
  if (success) {
44
- dispatch(
45
- replace(Routes.ScriptDetail, {
46
- unit: unit,
47
- id: data.id,
48
- name: name,
49
- type: type,
50
- automate: { ...automate, ...data },
51
- havePermission: true,
52
- isCreateScriptSuccess: true,
53
- isAutomateTab: isAutomateTab,
54
- isMultiUnits,
55
- })
56
- );
44
+ navigate(Routes.ScriptDetail, {
45
+ unit: unit,
46
+ id: data.id,
47
+ name: name,
48
+ type: type,
49
+ automate: { ...automate, ...data },
50
+ havePermission: true,
51
+ isCreateScriptSuccess: true,
52
+ isAutomateTab: isAutomateTab,
53
+ isMultiUnits,
54
+ });
55
+ dispatch((state) => {
56
+ const routes = state.routes.filter(
57
+ (r) =>
58
+ r.name !== Routes.AddNewOneTap &&
59
+ r.name !== Routes.AddNewAutoSmart &&
60
+ r.name !== Routes.SelectUnit &&
61
+ r.name !== Routes.SelectSensorDevices &&
62
+ r.name !== Routes.SetSchedule &&
63
+ r.name !== Routes.SelectAction
64
+ );
65
+ return CommonActions.reset({
66
+ ...state,
67
+ routes,
68
+ index: routes.length - 1,
69
+ });
70
+ });
57
71
  }
58
72
  }, [
59
73
  isMultiUnits,
@@ -61,10 +75,11 @@ const AddNewOneTap = memo(({ route }) => {
61
75
  type,
62
76
  name,
63
77
  automateData,
64
- automate,
65
78
  automateId,
66
- dispatch,
79
+ navigate,
80
+ automate,
67
81
  isAutomateTab,
82
+ dispatch,
68
83
  ]);
69
84
 
70
85
  const onChangeName = useCallback((text) => {
@@ -33,8 +33,8 @@ const Automate = () => {
33
33
  const prepareData = useCallback((rawData) => {
34
34
  rawData.forEach((item) => {
35
35
  item.automates = item.automates.sort((a, b) => {
36
- const aIsStar = a.script.is_star;
37
- const bIsStar = b.script.is_star;
36
+ const aIsStar = a.script?.is_star;
37
+ const bIsStar = b.script?.is_star;
38
38
  if ((aIsStar && bIsStar) || (!aIsStar && !bIsStar)) {
39
39
  return 0;
40
40
  } else if (aIsStar && !bIsStar) {
@@ -22,7 +22,8 @@ const EditDevice = memo(() => {
22
22
  const t = useTranslations();
23
23
  const navigation = useNavigation();
24
24
  const { params = {} } = useRoute();
25
- const { sensor, setSensorNameDetail, sensorNameDetail } = params;
25
+ const { sensor, setSensorNameDetail, sensorNameDetail, setSensorDetail } =
26
+ params;
26
27
  const [inputName, setInputName] = useState(sensorNameDetail || '');
27
28
  const [sensorName, setSensorName] = useState(sensorNameDetail || '');
28
29
  const { stateAlertAction, hideAlertAction, onShowRename, onShowDelete } =
@@ -37,17 +38,18 @@ const EditDevice = memo(() => {
37
38
  if (success) {
38
39
  setSensorName(data?.name);
39
40
  setSensorNameDetail(data?.name);
41
+ setSensorDetail && setSensorDetail({ ...sensor, name: data?.name });
40
42
  ToastBottomHelper.success(t('rename_successfully'));
41
43
  } else {
42
44
  ToastBottomHelper.error(t('rename_failed'));
43
45
  }
44
46
  hideAlertAction();
45
47
  }, [
46
- sensor.id,
48
+ sensor,
47
49
  inputName,
48
50
  hideAlertAction,
49
- setSensorName,
50
51
  setSensorNameDetail,
52
+ setSensorDetail,
51
53
  t,
52
54
  ]);
53
55
 
@@ -18,6 +18,7 @@ import EmergencyDetail from '../../../commons/Device/Emergency/EmergencyDetail';
18
18
  import EmergencyButton from '../../../commons/Device/Emergency/EmergencyButton';
19
19
  import FooterInfo from '../../../commons/Device/FooterInfo';
20
20
  import MediaPlayerDetail from '../../../commons/MediaPlayerDetail';
21
+ import SmartIr from '../../../screens/SmartIr';
21
22
  import { standardizeCameraScreenSize } from '../../../utils/Utils';
22
23
  import { Device } from '../../../configs';
23
24
  import { useSCContextSelector } from '../../../context';
@@ -122,6 +123,8 @@ export const SensorDisplayItem = ({
122
123
  }
123
124
  case 'info':
124
125
  return <FooterInfo data={item.configuration} />;
126
+ case 'smart_ir':
127
+ return <SmartIr item={item} />;
125
128
  default:
126
129
  break;
127
130
  }
@@ -268,6 +268,7 @@ const DeviceDetail = ({ route }) => {
268
268
  sensor,
269
269
  setSensorNameDetail: setSensorName,
270
270
  sensorNameDetail: sensorName,
271
+ setSensorDetail: setSensor,
271
272
  },
272
273
  });
273
274
  menuItems.push({
@@ -6,7 +6,7 @@ import axios from 'axios';
6
6
  import { SCProvider } from '../../../context';
7
7
  import { mockSCStore } from '../../../context/mockStore';
8
8
  import NotificationItem from '../components/NotificationItem';
9
- import { NOTIFICATION_TYPES } from '../../../configs/Constants';
9
+ import { NOTIFICATION_TYPES, SENSOR_TYPE } from '../../../configs/Constants';
10
10
  import Routes from '../../../utils/Route';
11
11
  import { API } from '../../../configs';
12
12
 
@@ -130,6 +130,8 @@ describe('test NotificationItem', () => {
130
130
  NOTIFICATION_TYPES.NOTIFY_REMOVE_UNIT,
131
131
  NOTIFICATION_TYPES.NOTIFY_REMOVE_MEMBER,
132
132
  NOTIFICATION_TYPES.NOTIFY_MEMBER_LEAVE_UNIT,
133
+ NOTIFICATION_TYPES.NOTIFY_REMOVE_SUB_UNIT,
134
+ NOTIFICATION_TYPES.NOTIFY_REMOVE_DEVICE,
133
135
  'default case',
134
136
  ];
135
137
 
@@ -148,7 +150,13 @@ describe('test NotificationItem', () => {
148
150
  });
149
151
  }
150
152
 
151
- const listSensorType = ['air_quality', 'turbidity', 'ph', 'clo', 'uv'];
153
+ const listSensorType = [
154
+ SENSOR_TYPE.AIR_QUALITY,
155
+ SENSOR_TYPE.TURBIDITY,
156
+ SENSOR_TYPE.PH,
157
+ SENSOR_TYPE.CLO,
158
+ SENSOR_TYPE.UV,
159
+ ];
152
160
  for (const sensorType of listSensorType) {
153
161
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
154
162
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
@@ -179,7 +187,11 @@ describe('test NotificationItem', () => {
179
187
  });
180
188
  }
181
189
 
182
- const listSensorType2 = ['smoke', 'fire'];
190
+ const listSensorType2 = [
191
+ SENSOR_TYPE.SMOKE,
192
+ SENSOR_TYPE.FIRE,
193
+ SENSOR_TYPE.SOS,
194
+ ];
183
195
  for (const sensorType of listSensorType2) {
184
196
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
185
197
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
@@ -7,7 +7,7 @@ import styles from '../styles/NotificationItemStyles';
7
7
  import Text from '../../../commons/Text';
8
8
  import { Colors, API, Images } from '../../../configs';
9
9
  import IconComponent from '../../../commons/IconComponent';
10
- import { NOTIFICATION_TYPES } from '../../../configs/Constants';
10
+ import { NOTIFICATION_TYPES, SENSOR_TYPE } from '../../../configs/Constants';
11
11
  import { useTranslations } from '../../../hooks/Common/useTranslations';
12
12
  import { axiosPost } from '../../../utils/Apis/axios';
13
13
  import Routes from '../../../utils/Route';
@@ -224,7 +224,7 @@ const NotificationItem = memo(({ item }) => {
224
224
  case NOTIFICATION_TYPES.NOTIFY_INDICATOR:
225
225
  const { sensor_type, summary_id } = paramsJSON;
226
226
  switch (sensor_type) {
227
- case 'air_quality':
227
+ case SENSOR_TYPE.AIR_QUALITY:
228
228
  return {
229
229
  content: customColorText(
230
230
  t('text_notification_content_air_quality_high'),
@@ -240,7 +240,7 @@ const NotificationItem = memo(({ item }) => {
240
240
  }),
241
241
  iconContent: <Image source={Images.logo} style={styles.logo} />,
242
242
  };
243
- case 'turbidity':
243
+ case SENSOR_TYPE.TURBIDITY:
244
244
  return {
245
245
  content: customColorText(
246
246
  t('text_notification_content_turbility_high'),
@@ -256,7 +256,7 @@ const NotificationItem = memo(({ item }) => {
256
256
  }),
257
257
  iconContent: <Image source={Images.logo} style={styles.logo} />,
258
258
  };
259
- case 'ph':
259
+ case SENSOR_TYPE.PH:
260
260
  return {
261
261
  content: customColorText(
262
262
  t('text_notification_content_pH_index_high'),
@@ -272,7 +272,7 @@ const NotificationItem = memo(({ item }) => {
272
272
  }),
273
273
  iconContent: <Image source={Images.logo} style={styles.logo} />,
274
274
  };
275
- case 'clo':
275
+ case SENSOR_TYPE.CLO:
276
276
  return {
277
277
  content: customColorText(
278
278
  t('text_notification_content_clo_high'),
@@ -288,7 +288,7 @@ const NotificationItem = memo(({ item }) => {
288
288
  }),
289
289
  iconContent: <Image source={Images.logo} style={styles.logo} />,
290
290
  };
291
- case 'uv':
291
+ case SENSOR_TYPE.UV:
292
292
  return {
293
293
  content: customColorText(
294
294
  t('text_notification_content_uv_index_high'),
@@ -304,7 +304,7 @@ const NotificationItem = memo(({ item }) => {
304
304
  }),
305
305
  iconContent: <Image source={Images.logo} style={styles.logo} />,
306
306
  };
307
- case 'smoke':
307
+ case SENSOR_TYPE.SMOKE:
308
308
  return {
309
309
  content: customColorText(
310
310
  t('text_notification_content_smoke'),
@@ -320,7 +320,7 @@ const NotificationItem = memo(({ item }) => {
320
320
  }),
321
321
  iconContent: <Image source={Images.logo} style={styles.logo} />,
322
322
  };
323
- case 'fire':
323
+ case SENSOR_TYPE.FIRE:
324
324
  return {
325
325
  content: customColorText(
326
326
  t('text_notification_content_fire'),
@@ -336,6 +336,22 @@ const NotificationItem = memo(({ item }) => {
336
336
  }),
337
337
  iconContent: <Image source={Images.logo} style={styles.logo} />,
338
338
  };
339
+ case SENSOR_TYPE.SOS:
340
+ return {
341
+ content: customColorText(
342
+ t('text_notification_content_active_sos'),
343
+ arrParams
344
+ ),
345
+ redirect: () =>
346
+ navigation.navigate(Routes.UnitStack, {
347
+ screen: Routes.DeviceDetail,
348
+ params: {
349
+ unitId,
350
+ sensorId,
351
+ },
352
+ }),
353
+ iconContent: <Image source={Images.logo} style={styles.logo} />,
354
+ };
339
355
  default:
340
356
  return {
341
357
  content: customColorText(
@@ -428,6 +444,9 @@ const NotificationItem = memo(({ item }) => {
428
444
  },
429
445
  });
430
446
  },
447
+ iconContent: (
448
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
449
+ ),
431
450
  };
432
451
  case NOTIFICATION_TYPES.NOTIFY_RENAME_SUB_UNIT:
433
452
  const stationId = paramsJSON?.sub_unit_id;
@@ -445,6 +464,31 @@ const NotificationItem = memo(({ item }) => {
445
464
  },
446
465
  });
447
466
  },
467
+ iconContent: (
468
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
469
+ ),
470
+ };
471
+ case NOTIFICATION_TYPES.NOTIFY_REMOVE_SUB_UNIT:
472
+ return {
473
+ content: customColorText(
474
+ t('text_notification_content_remove_sub_unit'),
475
+ arrParams
476
+ ),
477
+ redirect: () => null,
478
+ iconContent: (
479
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
480
+ ),
481
+ };
482
+ case NOTIFICATION_TYPES.NOTIFY_REMOVE_DEVICE:
483
+ return {
484
+ content: customColorText(
485
+ t('text_notification_content_remove_device'),
486
+ arrParams
487
+ ),
488
+ redirect: () => null,
489
+ iconContent: (
490
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
491
+ ),
448
492
  };
449
493
  default:
450
494
  return {
@@ -43,6 +43,7 @@ describe('test ScanChipQR', () => {
43
43
  station_id: 1,
44
44
  phoneNumber: '0909123456',
45
45
  chipName: 'Chip name',
46
+ isNewFlow: true,
46
47
  },
47
48
  };
48
49
  });
@@ -5,7 +5,17 @@ import { axiosPost } from '../../../utils/Apis/axios';
5
5
  import Routes from '../../../utils/Route';
6
6
 
7
7
  const useChipScan = (route) => {
8
- const { unit_id, imei } = route.params;
8
+ const {
9
+ unit_id,
10
+ unit_name,
11
+ imei,
12
+ isNewFlow,
13
+ phoneNumber,
14
+ chipName,
15
+ wifiName,
16
+ wifiPass,
17
+ station,
18
+ } = route.params;
9
19
  const navigation = useNavigation();
10
20
  const [loading, setLoading] = useState(false);
11
21
 
@@ -13,56 +23,92 @@ const useChipScan = (route) => {
13
23
  async (data) => {
14
24
  setLoading(true);
15
25
  const body = JSON.parse(data);
16
- const devicePrefixName = body?.imei.split('-')[0];
17
- switch (devicePrefixName) {
18
- case 'SENSOR':
19
- navigation.navigate(Routes.AddDeviceStack, {
20
- screen: Routes.AddGatewaySelectGateway,
21
- params: {
22
- scan_sensor_data: { ...body },
23
- addType: 'AddDeviceNewFlow',
24
- unit_id: unit_id,
25
- devicePrefixName,
26
- },
27
- });
28
- break;
29
- case 'ROBOT':
30
- case 'LITE':
31
- {
32
- const { success, data: new_chip } = await axiosPost(
33
- API.UNIT.CHIP_SCAN_GET_WIFI_INFO(),
34
- {
35
- imei: imei || body.imei,
36
- qr_code: body.imei,
37
- }
38
- );
39
- if (success) {
40
- if (new_chip.is_wifi) {
41
- navigation.navigate(Routes.ConnectWifiWarning, {
42
- wifi_ssid: new_chip.wifi_ssid,
43
- wifi_pass: new_chip.wifi_pass,
44
- chip_id: new_chip.id,
45
- unit_id: unit_id,
46
- devicePrefixName,
47
- body,
48
- });
26
+ if (isNewFlow) {
27
+ const devicePrefixName = body?.imei.split('-')[0];
28
+ switch (devicePrefixName) {
29
+ case 'SENSOR':
30
+ navigation.navigate(Routes.AddDeviceStack, {
31
+ screen: Routes.AddGatewaySelectGateway,
32
+ params: {
33
+ scan_sensor_data: { ...body },
34
+ addType: 'AddDeviceNewFlow',
35
+ unit_id: unit_id,
36
+ devicePrefixName,
37
+ },
38
+ });
39
+ break;
40
+ case 'ROBOT':
41
+ case 'LITE':
42
+ {
43
+ const { success, data: new_chip } = await axiosPost(
44
+ API.UNIT.CHIP_SCAN_GET_WIFI_INFO(),
45
+ {
46
+ imei: imei || body.imei,
47
+ qr_code: body.imei,
48
+ }
49
+ );
50
+ if (success) {
51
+ if (new_chip.is_wifi) {
52
+ navigation.navigate(Routes.ConnectWifiWarning, {
53
+ wifi_ssid: new_chip.wifi_ssid,
54
+ wifi_pass: new_chip.wifi_pass,
55
+ chip_id: new_chip.id,
56
+ unit_id: unit_id,
57
+ unit_name: unit_name,
58
+ devicePrefixName,
59
+ body,
60
+ });
61
+ } else {
62
+ navigation.navigate(Routes.ConnectingGateway, {
63
+ new_chip,
64
+ ...route.params,
65
+ });
66
+ }
49
67
  } else {
50
- navigation.navigate(Routes.ConnectingGateway, {
51
- new_chip,
52
- ...route.params,
53
- });
68
+ navigation.goBack();
54
69
  }
55
- } else {
56
- navigation.goBack();
57
70
  }
71
+ break;
72
+ default:
73
+ navigation.goBack();
74
+ break;
75
+ }
76
+ } else {
77
+ const { success, data: new_chip } = await axiosPost(
78
+ API.UNIT.CHIP_SCAN(unit_id),
79
+ {
80
+ imei: imei,
81
+ qr_code: body.imei,
82
+ phone: phoneNumber,
83
+ name: chipName,
84
+ station: station,
85
+ wifi_ssid: wifiName,
86
+ wifi_pass: wifiPass,
58
87
  }
59
- break;
60
- default:
88
+ );
89
+ if (success) {
90
+ navigation.navigate(Routes.ConnectingGateway, {
91
+ new_chip,
92
+ ...route.params,
93
+ });
94
+ } else {
61
95
  navigation.goBack();
62
- break;
96
+ }
63
97
  }
64
98
  },
65
- [imei, navigation, route.params, unit_id]
99
+ [
100
+ chipName,
101
+ imei,
102
+ isNewFlow,
103
+ navigation,
104
+ phoneNumber,
105
+ route.params,
106
+ station,
107
+ unit_id,
108
+ unit_name,
109
+ wifiName,
110
+ wifiPass,
111
+ ]
66
112
  );
67
113
 
68
114
  return {
@@ -236,12 +236,7 @@ const ScriptDetail = ({ route }) => {
236
236
  }, [name, automate]);
237
237
 
238
238
  const onGoBack = useCallback(() => {
239
- if (isCreateScriptSuccess || isCreateNewAction) {
240
- dispatch(popAction(5));
241
- isAutomateTab && goBack();
242
- } else {
243
- goBack();
244
- }
239
+ goBack();
245
240
  // eslint-disable-next-line react-hooks/exhaustive-deps
246
241
  }, [isCreateScriptSuccess]);
247
242
 
@@ -93,6 +93,7 @@ const SelectUnit = () => {
93
93
  const isSelectedItem = selectedItem?.id === id;
94
94
  return (
95
95
  <TouchableOpacity
96
+ key={id}
96
97
  onPress={onPressItem(item)}
97
98
  style={styles.wrapItem}
98
99
  testID={TESTID.ITEM_UNIT}
@@ -128,7 +128,7 @@ const Shared = () => {
128
128
  renderItem={({ item, index }) => {
129
129
  return (
130
130
  <SharedUnit
131
- key={`${item.id}-${item.is_star}-${item.is_pin}`}
131
+ key={`${item.id}-${item?.is_star}-${item?.is_pin}`}
132
132
  navigation={navigation}
133
133
  item={item}
134
134
  index={index}
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { TouchableOpacity } from 'react-native';
3
+ import renderer, { act } from 'react-test-renderer';
4
+ import SmartIr from '../index';
5
+ import { SCProvider } from '../../../context';
6
+ import { mockSCStore } from '../../../context/mockStore';
7
+
8
+ const wrapComponent = (item) => (
9
+ <SCProvider initState={mockSCStore({})}>
10
+ <SmartIr item={item} />
11
+ </SCProvider>
12
+ );
13
+ const mockNavigate = jest.fn();
14
+ jest.mock('@react-navigation/native', () => {
15
+ return {
16
+ ...jest.requireActual('@react-navigation/native'),
17
+ useNavigation: () => ({
18
+ navigate: mockNavigate,
19
+ }),
20
+ };
21
+ });
22
+ describe('Test SmartIr', () => {
23
+ let tree;
24
+ beforeEach(() => {
25
+ mockNavigate.mockClear();
26
+ });
27
+ test('render SmartIr', () => {
28
+ const item = {
29
+ configuration: { devices: [] },
30
+ id: 11,
31
+ order: 1,
32
+ template: 'smart_ir',
33
+ type: 'smart_ir',
34
+ };
35
+ act(() => {
36
+ tree = renderer.create(wrapComponent(item));
37
+ });
38
+ const instance = tree.root;
39
+ const itemAddNew = instance.findAllByType(TouchableOpacity);
40
+ expect(itemAddNew).toHaveLength(2);
41
+ });
42
+
43
+ test('render SmartIr on AddNew', () => {
44
+ const item = {
45
+ configuration: { devices: [] },
46
+ id: 11,
47
+ order: 1,
48
+ template: 'smart_ir',
49
+ type: 'smart_ir',
50
+ };
51
+ act(() => {
52
+ tree = renderer.create(wrapComponent(item));
53
+ });
54
+ const instance = tree.root;
55
+ const itemAddNew = instance.findAllByType(TouchableOpacity);
56
+ expect(itemAddNew).toHaveLength(2);
57
+ act(() => {
58
+ itemAddNew[0].props.onPress();
59
+ });
60
+ });
61
+ });
@@ -0,0 +1,23 @@
1
+ import React, { memo, useCallback } from 'react';
2
+ import { View, Alert } from 'react-native';
3
+ import { useTranslations } from '../../hooks/Common/useTranslations';
4
+ import ItemAddNew from '../../commons/Device/ItemAddNew';
5
+ import styles from './styles';
6
+
7
+ const SmartIr = memo(({ item }) => {
8
+ const t = useTranslations();
9
+ const AddRemoteControl = useCallback(() => {
10
+ Alert.alert(t('feature_under_development'));
11
+ }, [t]);
12
+ return (
13
+ <View style={styles.container}>
14
+ <ItemAddNew
15
+ title={t('add_remote_control')}
16
+ wrapStyle={styles.itemAddNew}
17
+ onAddNew={AddRemoteControl}
18
+ />
19
+ </View>
20
+ );
21
+ });
22
+
23
+ export default SmartIr;
@@ -0,0 +1,14 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ container: {
5
+ flex: 1,
6
+ paddingHorizontal: 16,
7
+ },
8
+ itemAddNew: {
9
+ flex: 1,
10
+ width: '100%',
11
+ justifyContent: 'center',
12
+ alignItems: 'center',
13
+ },
14
+ });
@@ -56,7 +56,10 @@ const AddMenu = memo(({ unit, afterItemClick, showAdd, setHideAdd }) => {
56
56
  route: Routes.AddGatewayStack,
57
57
  text: t('gateway') + ' Wifi',
58
58
  image: <AddDeviceIcon width={43} height={43} />,
59
- data: { screen: Routes.FirstWarning, params: { unit_id: unit.id } },
59
+ data: {
60
+ screen: Routes.FirstWarning,
61
+ params: { unit_id: unit?.id, unit_name: unit?.name },
62
+ },
60
63
  },
61
64
  {
62
65
  id: 6,
@@ -159,7 +159,7 @@ const UnitDetail = ({ route }) => {
159
159
  ]);
160
160
  setFavorites((prevData) => ({
161
161
  ...prevData,
162
- automates: data.filter((item) => item.script.is_star),
162
+ automates: data.filter((item) => item?.script?.is_star),
163
163
  }));
164
164
  }
165
165
  }