@eohjsc/react-native-smart-city 0.7.21 → 0.7.22

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 (48) hide show
  1. package/package.json +1 -1
  2. package/src/Images/Common/default_end_device.png +0 -0
  3. package/src/commons/Dashboard/MyUnit/index.js +19 -20
  4. package/src/commons/DevMode/Search.js +1 -1
  5. package/src/commons/Device/RainningSensor/CurrentRainSensor.js +5 -5
  6. package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +1 -3
  7. package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
  8. package/src/configs/API.js +4 -0
  9. package/src/configs/AccessibilityLabel.js +3 -1
  10. package/src/configs/Images.js +1 -0
  11. package/src/navigations/AddMemberStack.js +3 -3
  12. package/src/screens/AddCommon/SelectUnit.js +3 -2
  13. package/src/screens/AddLocationMaps/__test__/index.test.js +13 -13
  14. package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +9 -11
  15. package/src/screens/Automate/AddNewAutoSmart/__test__/AddAutomationTypeSmart.test.js +31 -0
  16. package/src/screens/Automate/ScriptDetail/utils.js +0 -20
  17. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +69 -13
  18. package/src/screens/ConfirmUnitDeletion/index.js +14 -14
  19. package/src/screens/Sharing/Components/ConfigItem.js +34 -0
  20. package/src/screens/Sharing/Components/DeviceItem.js +77 -0
  21. package/src/screens/Sharing/Components/ItemChangeRole.js +3 -4
  22. package/src/screens/Sharing/Components/ShareDeviceSelector.js +255 -0
  23. package/src/screens/Sharing/Components/Styles/CheckBoxCustomStyles.js +1 -1
  24. package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +11 -27
  25. package/src/screens/Sharing/{Styles/SelectPermissionStyles.js → Components/Styles/ShareDeviceSelectorStyles.js} +3 -11
  26. package/src/screens/Sharing/Components/SubUnitItem.js +28 -0
  27. package/src/screens/Sharing/Components/SubUnitTreeView.js +68 -0
  28. package/src/screens/Sharing/Components/TitleCheckBox.js +23 -41
  29. package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +7 -7
  30. package/src/screens/Sharing/Components/__test__/ShareDeviceSelector.test.js +298 -0
  31. package/src/screens/Sharing/Components/index.js +14 -1
  32. package/src/screens/Sharing/InfoMemberUnit.js +20 -20
  33. package/src/screens/Sharing/SelectShareDevice.js +11 -255
  34. package/src/screens/Sharing/SelectUser.js +12 -12
  35. package/src/screens/Sharing/UpdateShareDevice.js +45 -301
  36. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +58 -11
  37. package/src/screens/Sharing/__test__/SelectShareDevice.test.js +51 -160
  38. package/src/screens/Sharing/__test__/SelectUser.test.js +72 -10
  39. package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +49 -209
  40. package/src/utils/I18n/translations/en.js +1 -1
  41. package/src/utils/I18n/translations/vi.js +2 -2
  42. package/src/commons/Sharing/StationDevicePermissions.js +0 -204
  43. package/src/screens/Sharing/Components/CheckBoxConfig.js +0 -44
  44. package/src/screens/Sharing/Components/CheckBoxSubUnit.js +0 -35
  45. package/src/screens/Sharing/Components/EndDevice.js +0 -93
  46. package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +0 -18
  47. package/src/screens/Sharing/Components/Styles/TitleCheckBoxStyles.js +0 -21
  48. package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +0 -31
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.7.21",
4
+ "version": "0.7.22",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -1,40 +1,39 @@
1
+ import { API, Colors, Images, SCConfig } from '../../../configs';
2
+ import { AccessibilityLabel, DEVICE_TYPE } from '../../../configs/Constants';
3
+ import { Dimensions, TouchableOpacity, View } from 'react-native';
1
4
  import React, {
2
5
  memo,
3
6
  useCallback,
4
- useEffect,
5
- useState,
6
7
  useContext,
8
+ useEffect,
7
9
  useMemo,
8
10
  useRef,
11
+ useState,
9
12
  } from 'react';
10
- import { View, TouchableOpacity, Dimensions } from 'react-native';
13
+ import { SCContext, useSCContextSelector } from '../../../context';
14
+ import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
15
+ import { useBluetoothConnection, useWatchConfigs } from '../../../hooks/IoT';
11
16
  import {
12
- useNavigation,
13
- useIsFocused,
14
17
  useFocusEffect,
18
+ useIsFocused,
19
+ useNavigation,
15
20
  } from '@react-navigation/native';
16
- import NetInfo from '@react-native-community/netinfo';
17
- import { BleManager } from 'react-native-ble-plx';
18
- import { API, Colors, Images, SCConfig } from '../../../configs';
19
- import Text from '../../Text';
20
- import { axiosGet, fetchWithCache } from '../../../utils/Apis/axios';
21
21
 
22
- import styles from './styles';
23
- import { Section } from '../../Section';
24
- import { useTranslations } from '../../../hooks/Common/useTranslations';
25
- import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
26
- import { useWatchConfigs, useBluetoothConnection } from '../../../hooks/IoT';
27
- import { SCContext, useSCContextSelector } from '../../../context';
28
22
  import { Action } from '../../../context/actionType';
29
-
23
+ import { BleManager } from 'react-native-ble-plx';
30
24
  import Carousel from 'react-native-new-snap-carousel';
31
- import { AccessibilityLabel, DEVICE_TYPE } from '../../../configs/Constants';
32
- import Routes from '../../../utils/Route';
25
+ import FImage from '../../FImage';
33
26
  import MyUnitDevice from '../../../screens/Unit/components/MyUnitDevice';
27
+ import NetInfo from '@react-native-community/netinfo';
28
+ import Routes from '../../../utils/Route';
34
29
  import { STORAGE_KEY } from '../../../utils/Storage';
30
+ import { Section } from '../../Section';
31
+ import Text from '../../Text';
35
32
  import { preloadImagesFromUnits } from '../../../utils/Functions/preloadImages';
36
- import FImage from '../../FImage';
33
+ import styles from './styles';
37
34
  import { usePrevious } from '../../../hooks';
35
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
36
+ import { useUnitConnectRemoteDevices } from '../../../screens/Unit/hook/useUnitConnectRemoteDevices';
38
37
 
39
38
  let screenWidth = Dimensions.get('window').width;
40
39
 
@@ -10,7 +10,7 @@ const Search = ({ onSearch }) => {
10
10
  <Image source={Images.search} style={styles.icon} />
11
11
  <TextInput
12
12
  style={styles.textInput}
13
- placeholder={t('what_are_you_looking_for')}
13
+ placeholder={t('search')}
14
14
  onChangeText={onSearch}
15
15
  />
16
16
  </View>
@@ -1,13 +1,13 @@
1
1
  import React, { useMemo } from 'react';
2
- import { View, StyleSheet } from 'react-native';
3
- import LinearGradient from 'react-native-linear-gradient';
2
+ import { StyleSheet, View } from 'react-native';
4
3
 
5
- import { Colors } from '../../../configs';
6
4
  import { CircleView } from '../../../commons';
7
- import Text from '../../../commons/Text';
5
+ import { Colors } from '../../../configs';
6
+ import FImage from '../../FImage';
8
7
  import IconComponent from '../../IconComponent';
8
+ import LinearGradient from 'react-native-linear-gradient';
9
+ import Text from '../../../commons/Text';
9
10
  import images from '../../../configs/Images';
10
- import FImage from '../../FImage';
11
11
  import { useTranslations } from '../../../hooks/Common/useTranslations';
12
12
 
13
13
  const CurrentRainSensor = ({
@@ -6,7 +6,6 @@ import { styles } from './IFrameWithConfigStyles';
6
6
  import IconComponent from '../../IconComponent';
7
7
  import { useConfigGlobalState } from '../../../iot/states';
8
8
  import { useFetchConfigHistory } from '../../UnitSummary/ConfigHistoryChart';
9
- import API from '../../../configs/API';
10
9
  import WebView from 'react-native-webview';
11
10
  import { TouchableOpacity, View } from 'react-native';
12
11
 
@@ -25,8 +24,7 @@ const IFrameWithConfig = memo(
25
24
  const [chartData, setChartData] = useState(configuration?.history_configs);
26
25
  const fetchDataDisplayHistory = useFetchConfigHistory(
27
26
  configuration?.history_configs,
28
- setChartData,
29
- API.CONFIG.DISPLAY_HISTORY_V4()
27
+ setChartData
30
28
  );
31
29
 
32
30
  const postMessage = useCallback((message) => {
@@ -252,7 +252,7 @@ describe('Test IFrame With Config', () => {
252
252
  });
253
253
 
254
254
  const mockAxios = new MockAdapter(api.axiosInstance);
255
- mockAxios.onGet(API.CONFIG.DISPLAY_HISTORY_V4()).reply(200, {
255
+ mockAxios.onGet(API.CONFIG.DISPLAY_HISTORY_V3()).reply(200, {
256
256
  configs: [
257
257
  {
258
258
  id: 1,
@@ -158,6 +158,8 @@ const API = {
158
158
  UNITS: () => '/property_manager/sharing/units/',
159
159
  UNIT_PERMISSIONS: (id) =>
160
160
  `/property_manager/sharing/units/${id}/permissions/`,
161
+ UNIT_PERMISSIONS_v2: (id) =>
162
+ `/property_manager/sharing/units/${id}/permissions_v2/`,
161
163
  UNITS_MEMBERS: (id) => `/property_manager/sharing/units/${id}/members/`,
162
164
  UNITS_MEMBER_DETAIL: (id, shareId) =>
163
165
  `/property_manager/sharing/units/${id}/members/${shareId}/`,
@@ -165,6 +167,8 @@ const API = {
165
167
  `/property_manager/sharing/units/${unit_id}/member/${member_id}/information/`,
166
168
  UNIT_MEMBER_SHARE_DEVICE: (unit_id, member_id) =>
167
169
  `/property_manager/sharing/units/${unit_id}/member/${member_id}/shared_devices/`,
170
+ UNIT_MEMBER_SHARE_DEVICE_V2: (unit_id, member_id) =>
171
+ `/property_manager/sharing/units/${unit_id}/member/${member_id}/shared_devices_v2/`,
168
172
  SHARE: () => '/property_manager/sharing/share/',
169
173
  SHARE_V2: () => '/property_manager/sharing/share_v2/',
170
174
  SEARCH_USER_BY_PHONE: (phone) => `/accounts/search/phone/${phone}/`,
@@ -452,7 +452,9 @@ export default {
452
452
  CHECK_BOX_CUSTOM: 'CHECK_BOX_CUSTOM',
453
453
  CHECK_BOX_CONFIG: 'CHECK_BOX_CONFIG',
454
454
  EXPAND_END_DEVICE: 'EXPAND_END_DEVICE',
455
- CLICK_NAME_END_DEVICE: 'CLICK_NAME_END_DEVICE',
455
+ NAME_END_DEVICE: 'CLICK_NAME_END_DEVICE',
456
+ ICON_END_DEVICE: 'ICON_END_DEVICE',
457
+ ICON_CHECK: 'ICON_CHECK',
456
458
  },
457
459
 
458
460
  // Select subunit
@@ -27,4 +27,5 @@ export default {
27
27
  inforCode: require('../Images/DevMode/inforCode.png'),
28
28
  activeCurrentSensor: require('../Images/Common/Sunny.png'),
29
29
  unitDefaultBackground: require('../Images/Common/unit_default_background.png'),
30
+ defaultEndDeviceIcon: require('../Images/Common/default_end_device.png'),
30
31
  };
@@ -1,12 +1,12 @@
1
- import { createNativeStackNavigator } from '@react-navigation/native-stack';
2
1
  import React, { memo } from 'react';
3
2
 
4
3
  import AddCommonSelectUnit from '../screens/AddCommon/SelectUnit';
5
4
  import Route from '../utils/Route';
6
- import { screenOptions } from './utils';
5
+ import SelectShareDevice from '../screens/Sharing/SelectShareDevice';
7
6
  import SharingInviteMembers from '../screens/Sharing/SelectUser';
8
7
  import UpdateShareDevice from '../screens/Sharing/UpdateShareDevice';
9
- import SelectShareDevice from '../screens/Sharing/SelectShareDevice';
8
+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
9
+ import { screenOptions } from './utils';
10
10
 
11
11
  const Stack = createNativeStackNavigator();
12
12
 
@@ -1,8 +1,9 @@
1
- import { useNavigation } from '@react-navigation/native';
2
- import { useTranslations } from '../../hooks/Common/useTranslations';
3
1
  import React, { useCallback, useEffect, useState } from 'react';
2
+
4
3
  import Routes from '../../utils/Route';
5
4
  import SelectUnit from '../../commons/SelectUnit';
5
+ import { useNavigation } from '@react-navigation/native';
6
+ import { useTranslations } from '../../hooks/Common/useTranslations';
6
7
 
7
8
  const AddCommonSelectUnit = ({ route }) => {
8
9
  const t = useTranslations();
@@ -1,22 +1,22 @@
1
- import MockAdapter from 'axios-mock-adapter';
2
- import React from 'react';
3
- import { Alert } from 'react-native';
4
- import RNAndroidLocationEnabler from 'react-native-android-location-enabler';
5
- import RNP from 'react-native-permissions';
1
+ import {
2
+ GEOLOCATION_ERROR,
3
+ OpenSetting,
4
+ } from '../../../utils/Permission/common';
6
5
  import { act, create } from 'react-test-renderer';
7
6
 
8
- import { useNavigation } from '@react-navigation/native';
9
- import { RESULTS } from 'react-native-permissions';
10
7
  import { API } from '../../../configs';
11
8
  import { AccessibilityLabel } from '../../../configs/Constants';
9
+ import AddLocationMaps from '../index';
10
+ import { Alert } from 'react-native';
11
+ import MockAdapter from 'axios-mock-adapter';
12
+ import { RESULTS } from 'react-native-permissions';
13
+ import RNAndroidLocationEnabler from 'react-native-android-location-enabler';
14
+ import RNP from 'react-native-permissions';
15
+ import React from 'react';
12
16
  import { SCProvider } from '../../../context';
13
- import { mockSCStore } from '../../../context/mockStore';
14
17
  import api from '../../../utils/Apis/axios';
15
- import {
16
- GEOLOCATION_ERROR,
17
- OpenSetting,
18
- } from '../../../utils/Permission/common';
19
- import AddLocationMaps from '../index';
18
+ import { mockSCStore } from '../../../context/mockStore';
19
+ import { useNavigation } from '@react-navigation/native';
20
20
 
21
21
  const wrapComponent = (route) => (
22
22
  <SCProvider initState={mockSCStore({})}>
@@ -1,20 +1,19 @@
1
- import React from 'react';
2
1
  import renderer, { act } from 'react-test-renderer';
3
- import MockAdapter from 'axios-mock-adapter';
4
2
 
3
+ import { API } from '../../../../configs';
5
4
  import ChooseConfig from '../ChooseConfig';
6
- import { SCProvider } from '../../../../context';
7
- import { mockSCStore } from '../../../../context/mockStore';
8
5
  import { DEVICE_TYPE } from '../../../../configs/Constants';
9
- import api from '../../../../utils/Apis/axios';
10
- import { API } from '../../../../configs';
11
- import TitleCheckBox from '../../../Sharing/Components/TitleCheckBox';
6
+ import GridItem from '../../../../commons/Grid/GridItem';
7
+ import MockAdapter from 'axios-mock-adapter';
8
+ import React from 'react';
9
+ import Routes from '../../../../utils/Route';
10
+ import { SCProvider } from '../../../../context';
12
11
  import Text from '../../../../commons/Text';
12
+ import { TouchableWithoutFeedback } from 'react-native';
13
+ import api from '../../../../utils/Apis/axios';
14
+ import { mockSCStore } from '../../../../context/mockStore';
13
15
  import t from '../../../../hooks/Common/useTranslations';
14
- import Routes from '../../../../utils/Route';
15
16
  import { useNavigation } from '@react-navigation/native';
16
- import { TouchableWithoutFeedback } from 'react-native';
17
- import GridItem from '../../../../commons/Grid/GridItem';
18
17
 
19
18
  const mock = new MockAdapter(api.axiosInstance);
20
19
 
@@ -44,7 +43,6 @@ describe('Test ChooseConfig', () => {
44
43
  await act(async () => {
45
44
  tree = await renderer.create(wrapComponent(route));
46
45
  });
47
- expect(tree.root.findAllByType(TitleCheckBox)).toHaveLength(0);
48
46
  expect(mock.history.get).toHaveLength(1);
49
47
  });
50
48
 
@@ -0,0 +1,31 @@
1
+ import { act, create } from 'react-test-renderer';
2
+
3
+ import AddAutomationTypeSmart from '../AddAutomationTypeSmart';
4
+ import AddTypeSmart from '../AddTypeSmart';
5
+ import React from 'react';
6
+ import { SCProvider } from '../../../../context';
7
+ import { mockSCStore } from '../../../../context/mockStore';
8
+
9
+ const wrapComponent = (route) => (
10
+ <SCProvider initState={mockSCStore({})}>
11
+ <AddAutomationTypeSmart route={route} />
12
+ </SCProvider>
13
+ );
14
+
15
+ describe('test AddNewAutoSmart', () => {
16
+ let tree;
17
+ let route = {
18
+ params: {
19
+ automate: { unit: 1 },
20
+ },
21
+ };
22
+
23
+ it('test render AddNewAutoSmart', async () => {
24
+ await act(async () => {
25
+ tree = await create(wrapComponent(route));
26
+ });
27
+ const instance = tree.root;
28
+ const items = instance.findAllByType(AddTypeSmart);
29
+ expect(items).toHaveLength(1);
30
+ });
31
+ });
@@ -1,26 +1,6 @@
1
1
  import { AUTOMATE_TYPE } from '../../../configs/Constants';
2
2
  import { REPEAT_OPTIONS } from '../SetSchedule/components/RepeatOptionsPopup';
3
3
 
4
- export const generateAutomationDataConditionText = (
5
- type,
6
- config_name,
7
- condition,
8
- valueEvaluation,
9
- t
10
- ) => {
11
- condition.config_name = config_name;
12
- let automate = {};
13
- if ([AUTOMATE_TYPE.VALUE_CHANGE].includes(type)) {
14
- automate = { value_change: condition };
15
- } else if (type === AUTOMATE_TYPE.SCHEDULE) {
16
- automate = { schedule: condition };
17
- } else if ([AUTOMATE_TYPE.EVENT].includes(type)) {
18
- automate = { event: condition };
19
- }
20
- automate.type = type;
21
- return generateAutomationConditionText(automate, valueEvaluation, t);
22
- };
23
-
24
4
  export const getAutomationData = (automate) => {
25
5
  const { type, event_sensor, event_action, schedule, event, value_change } =
26
6
  automate;
@@ -1,15 +1,18 @@
1
- import React from 'react';
2
1
  import renderer, { act } from 'react-test-renderer';
3
2
 
4
- import { SCProvider } from '../../../context';
5
- import { mockSCStore } from '../../../context/mockStore';
3
+ import API from '../../../configs/API';
4
+ import { AccessibilityLabel } from '../../../configs/Constants';
5
+ import { Button } from '../../../commons';
6
6
  import ConfirmUnitDeletion from '../index';
7
+ import MockAdapter from 'axios-mock-adapter';
8
+ import React from 'react';
9
+ import Routes from '../../../utils/Route';
10
+ import { SCProvider } from '../../../context';
11
+ import { ToastBottomHelper } from '../../../utils/Utils';
7
12
  import _TextInput from '../../../commons/Form/TextInput';
8
- import { TouchableOpacity } from 'react-native';
9
- import { AccessibilityLabel } from '../../../configs/Constants';
10
- import API from '../../../configs/API';
11
13
  import api from '../../../utils/Apis/axios';
12
- import MockAdapter from 'axios-mock-adapter';
14
+ import { mockSCStore } from '../../../context/mockStore';
15
+ import { useNavigation } from '@react-navigation/native';
13
16
 
14
17
  const mock = new MockAdapter(api.axiosInstance);
15
18
  const wrapComponent = (route, navigation) => (
@@ -21,7 +24,8 @@ const wrapComponent = (route, navigation) => (
21
24
  describe('Test ConfirmUnitDeletion', () => {
22
25
  let tree;
23
26
  let route;
24
-
27
+ const spyToast = jest.spyOn(ToastBottomHelper, 'success');
28
+ const mockNavigate = useNavigation().navigate;
25
29
  beforeAll(() => {
26
30
  route = {
27
31
  params: {
@@ -31,6 +35,10 @@ describe('Test ConfirmUnitDeletion', () => {
31
35
  },
32
36
  };
33
37
  });
38
+ beforeEach(() => {
39
+ spyToast.mockClear();
40
+ mockNavigate.mockClear();
41
+ });
34
42
 
35
43
  it('test render ConfirmUnitDeletion', async () => {
36
44
  await act(async () => {
@@ -43,7 +51,8 @@ describe('Test ConfirmUnitDeletion', () => {
43
51
  textInput.props.onChange();
44
52
  });
45
53
  });
46
- it('Onpress button ConfirmUnitDeletion ', async () => {
54
+ it('Onpress button ConfirmUnitDeletion success', async () => {
55
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(204);
47
56
  await act(async () => {
48
57
  tree = await renderer.create(wrapComponent(route));
49
58
  });
@@ -52,16 +61,63 @@ describe('Test ConfirmUnitDeletion', () => {
52
61
  const touchableOpacity = instance.find(
53
62
  (el) =>
54
63
  el.props.accessibilityLabel ===
55
- AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON &&
56
- el.type === TouchableOpacity
64
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
57
65
  );
58
66
  const textInput = instance.findByType(_TextInput);
67
+ await act(async () => {
68
+ textInput.props.onChange('YES');
69
+ });
59
70
  await act(async () => {
60
71
  touchableOpacity.props.onPress();
61
72
  });
73
+ expect(spyToast).toHaveBeenLastCalledWith('Unit was deleted successfully.');
74
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.Dashboard);
75
+ });
76
+
77
+ it('Onpress button ConfirmUnitDeletion response error', async () => {
78
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(400);
62
79
  await act(async () => {
63
- textInput.props.onChange();
80
+ tree = await renderer.create(wrapComponent(route));
81
+ });
82
+ const instance = tree.root;
83
+
84
+ const touchableOpacity = instance.find(
85
+ (el) =>
86
+ el.props.accessibilityLabel ===
87
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
88
+ );
89
+ const textInput = instance.findByType(_TextInput);
90
+ await act(async () => {
91
+ textInput.props.onChange('YES');
92
+ });
93
+ await act(async () => {
94
+ touchableOpacity.props.onPress();
95
+ });
96
+ expect(spyToast).not.toHaveBeenCalled();
97
+ expect(mockNavigate).not.toHaveBeenCalled();
98
+ });
99
+
100
+ it('Onpress button ConfirmUnitDeletion wrong text confirm', async () => {
101
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(204);
102
+ await act(async () => {
103
+ tree = await renderer.create(wrapComponent(route));
104
+ });
105
+ const instance = tree.root;
106
+
107
+ const touchableOpacity = instance.find(
108
+ (el) =>
109
+ el.props.accessibilityLabel ===
110
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
111
+ );
112
+ const textInput = instance.findByType(_TextInput);
113
+ await act(async () => {
114
+ textInput.props.onChange('XXX');
115
+ });
116
+ await act(async () => {
117
+ touchableOpacity.props.onPress();
64
118
  });
65
- mock.onDelete(API.UNIT.MANAGE_UNIT(1)).reply(204);
119
+ expect(spyToast).not.toHaveBeenCalled();
120
+ expect(mockNavigate).not.toHaveBeenCalled();
121
+ expect(textInput.props.errorText).toEqual('Please enter correct');
66
122
  });
67
123
  });
@@ -1,31 +1,31 @@
1
+ import { API, Colors } from '../../configs';
1
2
  import React, { useCallback, useContext, useState } from 'react';
2
- import { View } from 'react-native';
3
- import { useNavigation } from '@react-navigation/native';
4
3
 
5
- import { useTranslations } from '../../hooks/Common/useTranslations';
6
- import styles from './styles';
7
- import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
8
- import Text from '../../commons/Text';
9
- import { API, Colors } from '../../configs';
10
- import _TextInput from '../../commons/Form/TextInput';
4
+ import { AccessibilityLabel } from '../../configs/Constants';
5
+ import { Action } from '../../context/actionType';
11
6
  import { Button } from '../../commons';
12
7
  import Routes from '../../utils/Route';
13
- import { axiosDelete } from '../../utils/Apis/axios';
14
- import { ToastBottomHelper } from '../../utils/Utils';
15
- import { AccessibilityLabel } from '../../configs/Constants';
16
8
  import { SCContext } from '../../context';
17
- import { Action } from '../../context/actionType';
9
+ import Text from '../../commons/Text';
10
+ import { ToastBottomHelper } from '../../utils/Utils';
11
+ import { View } from 'react-native';
12
+ import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
13
+ import _TextInput from '../../commons/Form/TextInput';
14
+ import { axiosDelete } from '../../utils/Apis/axios';
15
+ import styles from './styles';
16
+ import { useNavigation } from '@react-navigation/native';
17
+ import { useTranslations } from '../../hooks/Common/useTranslations';
18
18
 
19
19
  const ConfirmUnitDeletion = ({ route }) => {
20
20
  const { setAction } = useContext(SCContext);
21
21
  const t = useTranslations();
22
22
  const { unit } = route?.params || {};
23
23
  const navigation = useNavigation();
24
- const [confirm, setConfrim] = useState('');
24
+ const [confirm, setConfirm] = useState('');
25
25
  const [errorText, setErrorText] = useState();
26
26
 
27
27
  const onChangePassword = useCallback((value) => {
28
- setConfrim(value);
28
+ setConfirm(value);
29
29
  }, []);
30
30
 
31
31
  const onSendPress = useCallback(async () => {
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+ import { Text } from '../../../commons';
4
+ import { TitleCheckBox } from '.';
5
+ import { View } from 'react-native';
6
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
+
8
+ const ConfigItem = ({ isChecked, item, onSelect }) => {
9
+ const t = useTranslations();
10
+ return (
11
+ <View style={styles.wrap}>
12
+ <TitleCheckBox
13
+ isChecked={isChecked}
14
+ item={item}
15
+ onSelect={onSelect}
16
+ checkBoxStyle={styles.wrapCheckBoxStyle}
17
+ />
18
+ <Text>{item?.isConfig ? t('view_only') : t('can_control')}</Text>
19
+ </View>
20
+ );
21
+ };
22
+
23
+ export default ConfigItem;
24
+
25
+ const styles = StyleSheet.create({
26
+ wrap: {
27
+ flexDirection: 'row',
28
+ alignItems: 'center',
29
+ justifyContent: 'space-between',
30
+ },
31
+ wrapCheckBoxStyle: {
32
+ marginLeft: -10,
33
+ },
34
+ });
@@ -0,0 +1,77 @@
1
+ import { Colors, Images } from '../../../configs';
2
+ import React, { useState } from 'react';
3
+ import { Text, TouchableOpacity, View } from 'react-native';
4
+
5
+ import { AccessibilityLabel } from '../../../configs/Constants';
6
+ import FImage from '../../../commons/FImage';
7
+ import IconComponent from '../../../commons/IconComponent';
8
+ import { IconOutline } from '@ant-design/icons-react-native';
9
+ import styles from './Styles/DeviceItemStyles';
10
+
11
+ const DeviceItem = ({ isChecked, item, onSelect, childrenRender }) => {
12
+ const { label, key, item: endDeviceItem } = item;
13
+ const { actions, read_configs, icon_kit, icon } = endDeviceItem;
14
+ const [isChildExpanded, setIsChildExpanded] = useState(false);
15
+ const onPressItem = () => {
16
+ onSelect(item, !isChecked);
17
+ };
18
+
19
+ return (
20
+ <View style={styles.wrap}>
21
+ <TouchableOpacity
22
+ onPress={onPressItem}
23
+ accessibilityLabel={`${AccessibilityLabel.SHARE_DEVICE.ICON_END_DEVICE}-${key}`}
24
+ >
25
+ {icon_kit || icon ? (
26
+ <IconComponent
27
+ icon={icon_kit || icon}
28
+ size={20}
29
+ style={styles.viewLeft}
30
+ />
31
+ ) : (
32
+ <FImage
33
+ source={Images.defaultEndDeviceIcon}
34
+ style={styles.viewLeft}
35
+ />
36
+ )}
37
+ </TouchableOpacity>
38
+ <View style={styles.wrapRight}>
39
+ <View style={styles.viewRight}>
40
+ <TouchableOpacity
41
+ onPress={onPressItem}
42
+ style={styles.wrapTextIcon}
43
+ accessibilityLabel={`${AccessibilityLabel.SHARE_DEVICE.NAME_END_DEVICE}-${key}`}
44
+ >
45
+ <Text numberOfLines={1} style={styles.text}>
46
+ {label}
47
+ </Text>
48
+ {isChecked && (
49
+ <IconOutline
50
+ name={'check'}
51
+ color={Colors.Primary}
52
+ size={20}
53
+ accessibilityLabel={`${AccessibilityLabel.SHARE_DEVICE.ICON_CHECK}-${key}`}
54
+ />
55
+ )}
56
+ </TouchableOpacity>
57
+ <View style={styles.expandView}>
58
+ {actions?.length + read_configs?.length > 0 && (
59
+ <IconOutline
60
+ onPress={() => setIsChildExpanded(!isChildExpanded)}
61
+ name={isChildExpanded ? 'up' : 'down'}
62
+ size={20}
63
+ color={Colors.Gray6}
64
+ accessibilityLabel={`${AccessibilityLabel.SHARE_DEVICE.EXPAND_END_DEVICE}-${key}`}
65
+ />
66
+ )}
67
+ </View>
68
+ </View>
69
+ <View style={styles.wrapChildren}>
70
+ {isChildExpanded && childrenRender}
71
+ </View>
72
+ </View>
73
+ </View>
74
+ );
75
+ };
76
+
77
+ export default DeviceItem;
@@ -1,16 +1,15 @@
1
1
  import React, { memo } from 'react';
2
2
  import { TouchableOpacity, View } from 'react-native';
3
- import Text from '../../../commons/Text';
4
- import { Colors } from '../../../configs';
5
3
 
6
- import styles from './Styles/ItemChangeRoleStyles';
4
+ import { Colors } from '../../../configs';
7
5
  import { RadioCircle } from '../../../commons';
6
+ import Text from '../../../commons/Text';
7
+ import styles from './Styles/ItemChangeRoleStyles';
8
8
 
9
9
  const ItemChangeRole = ({
10
10
  isChecked,
11
11
  onPress,
12
12
  wrapStyle,
13
- wrapCheckBoxStyle,
14
13
  icon,
15
14
  title = '',
16
15
  message = '',