@eohjsc/react-native-smart-city 0.3.93 → 0.3.94

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 (32) hide show
  1. package/package.json +1 -1
  2. package/src/commons/SubUnit/OneTap/ItemOneTap.js +83 -85
  3. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +68 -24
  4. package/src/commons/SubUnit/OneTap/index.js +21 -1
  5. package/src/configs/API.js +1 -0
  6. package/src/screens/AddNewGateway/ConnectingDevice.js +7 -0
  7. package/src/screens/AddNewGateway/RenameNewDevices.js +2 -2
  8. package/src/screens/AddNewGateway/SelectDeviceType.js +67 -9
  9. package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +35 -0
  10. package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +183 -29
  11. package/src/screens/Automate/MultiUnits.js +28 -18
  12. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +36 -2
  13. package/src/screens/Automate/ScriptDetail/index.js +17 -3
  14. package/src/screens/Automate/Styles/MultiUnitsStyles.js +1 -1
  15. package/src/screens/Automate/__test__/MultiUnits.test.js +63 -6
  16. package/src/screens/Automate/__test__/index.test.js +44 -10
  17. package/src/screens/Automate/index.js +53 -38
  18. package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +24 -1
  19. package/src/screens/Sharing/InfoMemberUnit.js +2 -2
  20. package/src/screens/Sharing/MemberList.js +28 -7
  21. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +32 -18
  22. package/src/screens/Sharing/__test__/MemberList.test.js +37 -4
  23. package/src/screens/Unit/AddMenu.js +42 -19
  24. package/src/screens/Unit/__test__/AddMenu.test.js +68 -15
  25. package/src/screens/Unit/components/AutomateScript/index.js +1 -1
  26. package/src/utils/I18n/translations/en.js +1409 -0
  27. package/src/utils/I18n/translations/vi.js +1411 -0
  28. package/src/utils/I18n/translations.ts +2 -2
  29. package/src/utils/Permission/backend.js +7 -0
  30. package/src/screens/Sharing/__test__/MemberList2.test.js +0 -74
  31. package/src/utils/I18n/translations/en.json +0 -1142
  32. package/src/utils/I18n/translations/vi.json +0 -1139
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.3.93",
4
+ "version": "0.3.94",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -19,99 +19,97 @@ import { useNavigation } from '@react-navigation/native';
19
19
  import Routes from '../../../utils/Route';
20
20
  import { AccessibilityLabel, AUTOMATE_TYPE } from '../../../configs/Constants';
21
21
 
22
- const ItemOneTap = memo(
23
- ({ isOwner, automate = {}, unit, wrapSyles, onPressItem }) => {
24
- const { navigate } = useNavigation();
25
- const { id, type, script, activate_at, author = '' } = automate;
26
- const t = useTranslations();
22
+ const ItemOneTap = memo(({ automate = {}, wrapSyles, onPressItem }) => {
23
+ const { navigate } = useNavigation();
24
+ const { id, type, script, activate_at, author = '' } = automate;
25
+ const t = useTranslations();
27
26
 
28
- const goToDetail = useCallback(() => {
29
- navigate(Routes.ScriptDetail, {
30
- id,
31
- preAutomate: automate,
32
- });
33
- }, [automate, navigate, id]);
27
+ const goToDetail = useCallback(() => {
28
+ navigate(Routes.ScriptDetail, {
29
+ id,
30
+ preAutomate: automate,
31
+ });
32
+ }, [automate, navigate, id]);
34
33
 
35
- const handleScriptAction = useCallback(async () => {
36
- const { success } = await axiosPost(API.AUTOMATE.ACTION_ONE_TAP(id));
37
- if (success) {
38
- ToastBottomHelper.success(t('Activated successfully.'));
39
- } else {
40
- ToastBottomHelper.error(t('Activation failed.'));
41
- }
42
- // eslint-disable-next-line react-hooks/exhaustive-deps
43
- }, [id]);
34
+ const handleScriptAction = useCallback(async () => {
35
+ const { success } = await axiosPost(API.AUTOMATE.ACTION_ONE_TAP(id));
36
+ if (success) {
37
+ ToastBottomHelper.success(t('activated_successfully'));
38
+ } else {
39
+ ToastBottomHelper.error(t('activation_failed'));
40
+ }
41
+ // eslint-disable-next-line react-hooks/exhaustive-deps
42
+ }, [id]);
44
43
 
45
- const displayIcon = () => {
46
- const iconKit = script?.icon_kit;
47
- if (iconKit) {
48
- return <FImage source={{ uri: iconKit }} style={styles.iconSensor} />;
49
- }
50
- if (type === AUTOMATE_TYPE.ONE_TAP) {
51
- return <OneTap />;
52
- }
53
- if (type === AUTOMATE_TYPE.VALUE_CHANGE) {
54
- return <ValueChange />;
55
- }
56
- if ([AUTOMATE_TYPE.EVENT].includes(type)) {
57
- return <Event />;
58
- }
59
- return <Schedule />;
60
- };
61
- const activateAt = activate_at
62
- ? timeDifference(new Date(), moment(activate_at), true)
63
- : null;
64
- return (
65
- <TouchableWithoutFeedback
66
- onPress={onPressItem || goToDetail}
67
- accessibilityLabel={`${AccessibilityLabel.AUTOMATE_SCRIPT_NAME}-${id}`}
68
- >
69
- <View style={[styles.container, wrapSyles]}>
70
- <View style={styles.boxIcon}>
71
- {displayIcon()}
72
- {type === AUTOMATE_TYPE.ONE_TAP && (
73
- <TouchableOpacity
74
- accessibilityLabel={AccessibilityLabel.AUTOMATE_SCRIPT_ACTION}
75
- onPress={handleScriptAction}
76
- >
77
- <CheckCircle />
78
- </TouchableOpacity>
79
- )}
80
- </View>
81
- <TouchableOpacity
82
- accessibilityLabel={AccessibilityLabel.GO_DETAIL}
83
- onPress={onPressItem || goToDetail}
44
+ const displayIcon = () => {
45
+ const iconKit = script?.icon_kit;
46
+ if (iconKit) {
47
+ return <FImage source={{ uri: iconKit }} style={styles.iconSensor} />;
48
+ }
49
+ if (type === AUTOMATE_TYPE.ONE_TAP) {
50
+ return <OneTap />;
51
+ }
52
+ if (type === AUTOMATE_TYPE.VALUE_CHANGE) {
53
+ return <ValueChange />;
54
+ }
55
+ if ([AUTOMATE_TYPE.EVENT].includes(type)) {
56
+ return <Event />;
57
+ }
58
+ return <Schedule />;
59
+ };
60
+ const activateAt = activate_at
61
+ ? timeDifference(new Date(), moment(activate_at), true)
62
+ : null;
63
+ return (
64
+ <TouchableWithoutFeedback
65
+ onPress={onPressItem || goToDetail}
66
+ accessibilityLabel={`${AccessibilityLabel.AUTOMATE_SCRIPT_NAME}-${id}`}
67
+ >
68
+ <View style={[styles.container, wrapSyles]}>
69
+ <View style={styles.boxIcon}>
70
+ {displayIcon()}
71
+ {type === AUTOMATE_TYPE.ONE_TAP && (
72
+ <TouchableOpacity
73
+ accessibilityLabel={AccessibilityLabel.AUTOMATE_SCRIPT_ACTION}
74
+ onPress={handleScriptAction}
75
+ >
76
+ <CheckCircle />
77
+ </TouchableOpacity>
78
+ )}
79
+ </View>
80
+ <TouchableOpacity
81
+ accessibilityLabel={AccessibilityLabel.GO_DETAIL}
82
+ onPress={onPressItem || goToDetail}
83
+ >
84
+ <Text
85
+ numberOfLines={1}
86
+ semibold
87
+ size={14}
88
+ color={Colors.Gray9}
89
+ type="Body"
90
+ style={styles.name}
84
91
  >
92
+ {script?.name}
93
+ </Text>
94
+ <Text numberOfLines={1} type={'Label'} color={Colors.Gray7}>
95
+ {t('created_by', { name: author })}
96
+ </Text>
97
+ <View style={styles.descriptionContainer}>
85
98
  <Text
86
99
  numberOfLines={1}
87
100
  semibold
88
- size={14}
89
- color={Colors.Gray9}
90
- type="Body"
91
- style={styles.name}
101
+ size={12}
102
+ color={Colors.Gray8}
103
+ type="Label"
92
104
  >
93
- {script?.name}
105
+ {activateAt && t('activated_time', { time: activateAt })}
94
106
  </Text>
95
- <Text numberOfLines={1} type={'Label'} color={Colors.Gray7}>
96
- {`${t('create_by')} ${author}`}
97
- </Text>
98
- <View style={styles.descriptionContainer}>
99
- <Text
100
- numberOfLines={1}
101
- semibold
102
- size={12}
103
- color={Colors.Gray8}
104
- type="Label"
105
- >
106
- {activateAt && t('activated_time', { time: activateAt })}
107
- </Text>
108
- <IconOutline name="right" size={12} />
109
- </View>
110
- </TouchableOpacity>
111
- </View>
112
- </TouchableWithoutFeedback>
113
- );
114
- }
115
- );
107
+ <IconOutline name="right" size={12} />
108
+ </View>
109
+ </TouchableOpacity>
110
+ </View>
111
+ </TouchableWithoutFeedback>
112
+ );
113
+ });
116
114
 
117
115
  export default ItemOneTap;
@@ -16,11 +16,13 @@ import Routes from '../../../../utils/Route';
16
16
  import api from '../../../../utils/Apis/axios';
17
17
  import { API } from '../../../../configs';
18
18
  import { useNavigation } from '@react-navigation/native';
19
+ import { ToastBottomHelper } from '../../../../utils/Utils';
20
+ import { getTranslate } from '../../../../utils/I18n';
19
21
 
20
22
  const mock = new MockAdapter(api.axiosInstance);
21
23
 
22
- const wrapComponent = (data) => (
23
- <SCProvider initState={mockSCStore({})}>
24
+ const wrapComponent = (data, storeData = {}) => (
25
+ <SCProvider initState={mockSCStore(storeData)}>
24
26
  <SubUnitAutomate {...data} />
25
27
  </SCProvider>
26
28
  );
@@ -33,33 +35,34 @@ jest.mock('react-redux', () => {
33
35
  });
34
36
 
35
37
  let tree;
36
- let data = {
37
- isOwner: true,
38
- listAutomate: [
39
- {
40
- text: 'Scenario',
41
- data: [
42
- {
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
- },
52
- },
53
- ],
54
- type: AUTOMATE_TABS.SCENARIO,
55
- },
56
- ],
57
- };
38
+ let data;
58
39
 
59
40
  describe('test Item', () => {
60
41
  const mockedNavigate = useNavigation().navigate;
61
42
  beforeEach(() => {
62
43
  mockedNavigate.mockClear();
44
+ data = {
45
+ isOwner: true,
46
+ listAutomate: [
47
+ {
48
+ text: 'Scenario',
49
+ data: [
50
+ {
51
+ id: 1,
52
+ user: 6,
53
+ type: 'one_tap',
54
+ activate_at: '2021-09-17T05:30:00Z',
55
+ script: {
56
+ name: 'Joshua Ray',
57
+ icon: '',
58
+ icon_kit: '',
59
+ },
60
+ },
61
+ ],
62
+ type: AUTOMATE_TABS.SCENARIO,
63
+ },
64
+ ],
65
+ };
63
66
  });
64
67
 
65
68
  it('render SubUnitAutomate isOwner and handleOnAddNew', async () => {
@@ -189,6 +192,7 @@ describe('test Item', () => {
189
192
  preAutomate: data.listAutomate[0].data[0],
190
193
  });
191
194
  });
195
+
192
196
  it('render SubUnitAutomate script schedule and handleOnAddNew item automate', async () => {
193
197
  data.isOwner = false;
194
198
  data.type = 'schedule';
@@ -242,6 +246,46 @@ describe('test Item', () => {
242
246
  expect(goDetail).toHaveLength(1);
243
247
  });
244
248
 
249
+ it('add new automate when reach maximum', async () => {
250
+ data.isOwner = false;
251
+ data.type = 'schedule';
252
+ data.unit = { id: 1 };
253
+
254
+ await act(async () => {
255
+ tree = await create(
256
+ wrapComponent(data, {
257
+ auth: {
258
+ account: {
259
+ user: {
260
+ permissions: {
261
+ max_automations_per_unit: 0,
262
+ },
263
+ },
264
+ },
265
+ },
266
+ })
267
+ );
268
+ });
269
+
270
+ const instance = tree.root;
271
+ const item = instance.findAll(
272
+ (el) =>
273
+ el.props.accessibilityLabel ===
274
+ AccessibilityLabel.SUB_UNIT_ADD_DEVICE &&
275
+ el.type === TouchableWithoutFeedback
276
+ );
277
+
278
+ expect(item).toHaveLength(1);
279
+ const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
280
+ await act(async () => {
281
+ await item[0].props.onPress();
282
+ });
283
+ expect(mockedNavigate).not.toBeCalled();
284
+ expect(spyToastError).toBeCalledWith(
285
+ getTranslate('en', 'reach_max_automations_per_unit')
286
+ );
287
+ });
288
+
245
289
  it('render click select option by automation', async () => {
246
290
  await act(async () => {
247
291
  tree = await create(wrapComponent(data));
@@ -1,4 +1,10 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react';
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
2
8
  import { TouchableOpacity, View } from 'react-native';
3
9
 
4
10
  import { Section } from '../..';
@@ -15,15 +21,29 @@ import {
15
21
  import Text from '../../Text/index.js';
16
22
 
17
23
  import styles from './OneTapStyles.js';
24
+ import { ToastBottomHelper } from '../../../utils/Utils';
25
+ import { useBackendPermission } from '../../../utils/Permission/backend';
18
26
 
19
27
  const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
20
28
  const t = useTranslations();
21
29
  const { navigate } = useNavigation();
22
30
  const [automates, setAutomates] = useState(listAutomate[0]);
23
31
  const [indexAutomate, setIndexAutomate] = useState(0);
32
+ const permissions = useBackendPermission();
24
33
  const { name: currentScreen } = useRoute();
25
34
 
35
+ const totalAutomates = useMemo(
36
+ () => listAutomate.reduce((acc, item) => item.data.length + acc, 0),
37
+ [listAutomate]
38
+ );
39
+
26
40
  const handleOnAddNew = () => {
41
+ if (unit?.id) {
42
+ if (permissions.max_automations_per_unit <= totalAutomates) {
43
+ ToastBottomHelper.error(t('reach_max_automations_per_unit'));
44
+ return;
45
+ }
46
+ }
27
47
  switch (automates.type) {
28
48
  case AUTOMATE_TABS.SCENARIO:
29
49
  navigate(Routes.ScenarioName, {
@@ -215,6 +215,7 @@ const API = {
215
215
  },
216
216
  GATEWAY: {
217
217
  LIST: () => '/chip_manager/developer_mode_chips/',
218
+ COUNT: () => '/chip_manager/developer_mode_chips/count/',
218
219
  DETAIL: (id) => `/chip_manager/developer_mode_chips/${id}/`,
219
220
  REBOOT: (id) => `/chip_manager/developer_mode_chips/${id}/reboot_chip/`,
220
221
  },
@@ -81,6 +81,13 @@ const ConnectingDevice = ({
81
81
  if (found) {
82
82
  return { ...oldParams };
83
83
  }
84
+ if (data?.type === 'rejoin') {
85
+ return {
86
+ ...oldParams,
87
+ isRejoin: true,
88
+ sensorId: data?.sensor?.id,
89
+ };
90
+ }
84
91
  return oldParams;
85
92
  });
86
93
  },
@@ -21,7 +21,7 @@ const RenameNewDevices = memo(({ route }) => {
21
21
  const t = useTranslations();
22
22
  const { dispatch } = useNavigation();
23
23
 
24
- const { unit, subUnit, chipId, sensorId, addDeviceType } =
24
+ const { unit, subUnit, chipId, sensorId, addDeviceType, isRejoin } =
25
25
  route?.params || {};
26
26
  const [selectedItem, setSelectedItem] = useState({});
27
27
  const [isCanRename, setIsCanRename] = useState(false);
@@ -268,7 +268,7 @@ const RenameNewDevices = memo(({ route }) => {
268
268
  size={20}
269
269
  style={styles.textStatus}
270
270
  >
271
- {t('successfully_connected')}
271
+ {t(`successfully_${isRejoin ? 'rejoined' : 'connected'}`)}
272
272
  </Text>
273
273
  <Text size={14} color={Colors.Gray9}>
274
274
  {[unit?.name, subUnit?.name].filter(Boolean).join(' - ')}
@@ -14,13 +14,19 @@ import AddZigbeeDeviceIcon from '../../../assets/images/AddNewDevice/add-zigbee-
14
14
  import styles from './SelectDeviceTypeStyles';
15
15
  import AccessibilityLabel from '../../configs/AccessibilityLabel';
16
16
  import { DEVICE_TYPE } from '../../configs/Constants';
17
+ import { useBackendPermission } from '../../utils/Permission/backend';
18
+ import { axiosGet } from '../../utils/Apis/axios';
19
+ import API from '../../configs/API';
20
+ import { ToastBottomHelper } from '../../utils/Utils';
17
21
 
18
22
  const SelectDeviceGrid = ({ options, onSelect }) => {
19
23
  const [selectIndexes, setSelectIndexes] = useState();
20
24
  const onSelectOption = useCallback(
21
25
  (value) => () => {
26
+ if (onSelect(value) === false) {
27
+ return;
28
+ }
22
29
  setSelectIndexes(value);
23
- onSelect(value);
24
30
  },
25
31
  [onSelect]
26
32
  );
@@ -51,17 +57,33 @@ const SelectDeviceGrid = ({ options, onSelect }) => {
51
57
  );
52
58
  };
53
59
 
60
+ const getPermissionCode = (deviceType) => {
61
+ switch (deviceType) {
62
+ case 'gateway_qr':
63
+ return 'plug_and_play_gateway';
64
+ case 'wifi_device_qr':
65
+ return 'plug_and_play_wifi';
66
+ case 'modbus_device_qr':
67
+ return 'plug_and_play_modbus';
68
+ case 'zigbee':
69
+ default:
70
+ return 'plug_and_play_zigbee';
71
+ }
72
+ };
73
+
54
74
  const SelectDeviceType = ({ route }) => {
55
75
  const t = useTranslations();
56
76
  const { unit, subUnit } = route?.params || {};
57
77
  const { navigate, goBack } = useNavigation();
78
+ const [unitCountSummary, setUnitCountSummary] = useState();
58
79
  const [addType, setAddType] = useState();
59
80
  const [selectedAddType, setSelectedAddType] = useState();
81
+ const permissions = useBackendPermission();
60
82
 
61
83
  const listDeviceType = useMemo(() => {
62
84
  const list = [
63
85
  {
64
- id: 1,
86
+ id: 'gateway_qr',
65
87
  image: <AddGatewayIcon width={60} height={60} />,
66
88
  route: Routes.ScanGatewayQR,
67
89
  data: {
@@ -71,7 +93,7 @@ const SelectDeviceType = ({ route }) => {
71
93
  subtitle: t('central_controller'),
72
94
  },
73
95
  {
74
- id: 2,
96
+ id: 'wifi_device_qr',
75
97
  image: <AddWifiDeviceIcon width={60} height={60} />,
76
98
  route: subUnit?.id
77
99
  ? Routes.ScanWifiDeviceQR
@@ -85,7 +107,7 @@ const SelectDeviceType = ({ route }) => {
85
107
  subtitle: t('device_connect_without_gateway'),
86
108
  },
87
109
  {
88
- id: 3,
110
+ id: 'modbus_device_qr',
89
111
  image: <AddModbusDeviceIcon width={60} height={60} />,
90
112
  route: subUnit?.id ? Routes.ScanModbusQR : Routes.SelectDeviceSubUnit,
91
113
  data: {
@@ -97,7 +119,7 @@ const SelectDeviceType = ({ route }) => {
97
119
  subtitle: t('device_connect_directly_to_the_gateway'),
98
120
  },
99
121
  {
100
- id: 4,
122
+ id: 'zigbee',
101
123
  image: <AddZigbeeDeviceIcon width={60} height={60} />,
102
124
  route: subUnit?.id
103
125
  ? Routes.ConnectRouterGuide
@@ -111,19 +133,43 @@ const SelectDeviceType = ({ route }) => {
111
133
  subtitle: t('device_connect_remotely_to_the_gateway'),
112
134
  },
113
135
  ];
114
- if (!!subUnit?.id) {
136
+ if (subUnit?.id) {
115
137
  list.shift();
116
138
  }
117
139
  return list;
118
140
  }, [unit, t, subUnit]);
119
141
 
120
142
  const onRight = useCallback(() => {
121
- if (selectedAddType?.route && selectedAddType?.data) {
122
- navigate(selectedAddType?.route, selectedAddType?.data);
143
+ if (!selectedAddType?.route) {
144
+ return;
123
145
  }
146
+
147
+ navigate(selectedAddType?.route, selectedAddType?.data);
124
148
  }, [navigate, selectedAddType?.data, selectedAddType?.route]);
125
149
 
126
150
  const handleOnSelect = (itemSelect) => {
151
+ const needPermission = getPermissionCode(itemSelect);
152
+ if (!permissions?.[needPermission]) {
153
+ ToastBottomHelper.error(t(`no_permission_${needPermission}`));
154
+ return false;
155
+ }
156
+
157
+ if (['gateway_qr', 'wifi_device_qr'].includes(itemSelect)) {
158
+ if (permissions?.max_chips_per_unit <= unitCountSummary?.total_chips) {
159
+ ToastBottomHelper.error(t('reach_max_chips_per_unit'));
160
+ return false;
161
+ }
162
+ }
163
+
164
+ if (['wifi_device_qr', 'modbus_device_qr', 'zigbee'].includes(itemSelect)) {
165
+ if (
166
+ permissions?.max_configs_per_unit <= unitCountSummary?.total_configs
167
+ ) {
168
+ ToastBottomHelper.error(t('reach_max_configs_per_unit'));
169
+ return false;
170
+ }
171
+ }
172
+
127
173
  setAddType(itemSelect);
128
174
  };
129
175
 
@@ -131,6 +177,18 @@ const SelectDeviceType = ({ route }) => {
131
177
  setSelectedAddType(listDeviceType.find((item) => item.id === addType));
132
178
  }, [addType, listDeviceType]);
133
179
 
180
+ useEffect(() => {
181
+ const fetchCountSummary = async () => {
182
+ const { success, data } = await axiosGet(API.DEV_MODE.GATEWAY.COUNT(), {
183
+ unit: unit?.id,
184
+ });
185
+ if (success) {
186
+ setUnitCountSummary(data);
187
+ }
188
+ };
189
+ fetchCountSummary();
190
+ }, [unit?.id]);
191
+
134
192
  return (
135
193
  <View style={styles.container}>
136
194
  <HeaderCustom title={t('choose_type_of_device')} isShowSeparator />
@@ -141,7 +199,7 @@ const SelectDeviceType = ({ route }) => {
141
199
  leftTitle={t('cancel')}
142
200
  onLeftClick={goBack}
143
201
  rightTitle={t('text_next')}
144
- rightDisabled={!addType}
202
+ rightDisabled={!unitCountSummary || !addType}
145
203
  onRightClick={onRight}
146
204
  />
147
205
  </View>
@@ -121,4 +121,39 @@ describe('Test connecting modbus device', () => {
121
121
  sensorId: 1,
122
122
  });
123
123
  });
124
+
125
+ it('receive sensor from channel after rejoin zigbee', async () => {
126
+ mock.onPost().reply(200, {});
127
+ await act(async () => {
128
+ tree = await create(wrapComponent(route));
129
+ });
130
+ const channels = getPusher().channels;
131
+ let channel;
132
+ for (const key in channels) {
133
+ if (key.indexOf('cache-') === 0) {
134
+ channel = channels[key];
135
+ }
136
+ }
137
+ await act(async () => {
138
+ await channel.trigger('progress', {
139
+ data: { sensor: { id: 1, name: 'sensor' }, type: 'rejoin' },
140
+ });
141
+ });
142
+ await act(async () => {
143
+ await channel.trigger('progress', { success: 1 });
144
+ });
145
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.RenameNewDevices, {
146
+ addDeviceType: undefined,
147
+ unit: {
148
+ id: 1,
149
+ },
150
+ subUnit: {
151
+ id: 2,
152
+ station: 'Station 2',
153
+ },
154
+ chipId: 3,
155
+ sensorId: 1,
156
+ isRejoin: true,
157
+ });
158
+ });
124
159
  });