@eohjsc/react-native-smart-city 0.7.20 → 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 (67) hide show
  1. package/assets/images/Schedule.svg +39 -0
  2. package/assets/images/ValueChange.svg +49 -0
  3. package/package.json +1 -1
  4. package/src/Images/Common/default_end_device.png +0 -0
  5. package/src/commons/Automate/ButtonAddCondition.js +51 -0
  6. package/src/commons/Automate/ItemConditionScriptDetail.js +28 -15
  7. package/src/commons/Automate/ItemConditionScriptDetailStyles.js +9 -0
  8. package/src/commons/Dashboard/MyUnit/index.js +19 -20
  9. package/src/commons/DevMode/Search.js +1 -1
  10. package/src/commons/Device/RainningSensor/CurrentRainSensor.js +5 -5
  11. package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +1 -3
  12. package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
  13. package/src/configs/API.js +16 -1
  14. package/src/configs/AccessibilityLabel.js +9 -1
  15. package/src/configs/Images.js +1 -0
  16. package/src/context/actionType.ts +5 -0
  17. package/src/context/reducer.ts +30 -1
  18. package/src/navigations/AddMemberStack.js +3 -3
  19. package/src/navigations/UnitStack.js +8 -0
  20. package/src/screens/AddCommon/SelectUnit.js +3 -2
  21. package/src/screens/AddLocationMaps/__test__/index.test.js +13 -13
  22. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +73 -30
  23. package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +9 -11
  24. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +115 -10
  25. package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +7 -3
  26. package/src/screens/Automate/AddNewAutoSmart/__test__/AddAutomationTypeSmart.test.js +31 -0
  27. package/src/screens/Automate/ScriptDetail/Components/DeleteCondition.js +51 -0
  28. package/src/screens/Automate/ScriptDetail/Components/ModalAddCondition.js +196 -0
  29. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +18 -0
  30. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +441 -47
  31. package/src/screens/Automate/ScriptDetail/index.js +359 -72
  32. package/src/screens/Automate/ScriptDetail/utils.js +7 -31
  33. package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +173 -0
  34. package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +211 -0
  35. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +69 -13
  36. package/src/screens/ConfirmUnitDeletion/index.js +14 -14
  37. package/src/screens/Sharing/Components/ConfigItem.js +34 -0
  38. package/src/screens/Sharing/Components/DeviceItem.js +77 -0
  39. package/src/screens/Sharing/Components/ItemChangeRole.js +3 -4
  40. package/src/screens/Sharing/Components/ShareDeviceSelector.js +255 -0
  41. package/src/screens/Sharing/Components/Styles/CheckBoxCustomStyles.js +1 -1
  42. package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +11 -27
  43. package/src/screens/Sharing/{Styles/SelectPermissionStyles.js → Components/Styles/ShareDeviceSelectorStyles.js} +3 -11
  44. package/src/screens/Sharing/Components/SubUnitItem.js +28 -0
  45. package/src/screens/Sharing/Components/SubUnitTreeView.js +68 -0
  46. package/src/screens/Sharing/Components/TitleCheckBox.js +23 -41
  47. package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +7 -7
  48. package/src/screens/Sharing/Components/__test__/ShareDeviceSelector.test.js +298 -0
  49. package/src/screens/Sharing/Components/index.js +14 -1
  50. package/src/screens/Sharing/InfoMemberUnit.js +20 -20
  51. package/src/screens/Sharing/SelectShareDevice.js +11 -255
  52. package/src/screens/Sharing/SelectUser.js +12 -12
  53. package/src/screens/Sharing/UpdateShareDevice.js +45 -301
  54. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +58 -11
  55. package/src/screens/Sharing/__test__/SelectShareDevice.test.js +51 -160
  56. package/src/screens/Sharing/__test__/SelectUser.test.js +72 -10
  57. package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +49 -209
  58. package/src/utils/I18n/translations/en.js +22 -1
  59. package/src/utils/I18n/translations/vi.js +23 -3
  60. package/src/utils/Route/index.js +1 -0
  61. package/src/commons/Sharing/StationDevicePermissions.js +0 -204
  62. package/src/screens/Sharing/Components/CheckBoxConfig.js +0 -44
  63. package/src/screens/Sharing/Components/CheckBoxSubUnit.js +0 -35
  64. package/src/screens/Sharing/Components/EndDevice.js +0 -93
  65. package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +0 -18
  66. package/src/screens/Sharing/Components/Styles/TitleCheckBoxStyles.js +0 -21
  67. package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +0 -31
@@ -0,0 +1,173 @@
1
+ import { useNavigation } from '@react-navigation/native';
2
+ import moment from 'moment';
3
+ import React, { memo, useCallback, useState } from 'react';
4
+ import { ScrollView } from 'react-native';
5
+ import Calendar from '../../../commons/Calendar';
6
+ import WheelDateTimePicker from '../../../commons/WheelDateTimePicker';
7
+ import { useBoolean } from '../../../hooks/Common';
8
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
9
+ import Routes from '../../../utils/Route';
10
+ import NewActionWrapper from '../AddNewAction/NewActionWrapper';
11
+ import RepeatOptionsPopup, {
12
+ REPEAT_OPTIONS,
13
+ } from './components/RepeatOptionsPopup';
14
+ import RowItem from './components/RowItem';
15
+ import SelectWeekday from './components/SelectWeekday';
16
+ import styles from './styles/indexStyles';
17
+ import { axiosPost, axiosPut } from '../../../utils/Apis/axios';
18
+ import { API } from '../../../configs';
19
+ import { AUTOMATE_TYPE } from '../../../configs/Constants';
20
+
21
+ const getDateString = (date, t) => {
22
+ //Move outside component to prevent re-creation on every render.
23
+ const today = moment();
24
+ if (date.isSame(today, 'day')) {
25
+ return date.format(`[${t('today')}], D MMMM YYYY `);
26
+ }
27
+ return date.format('ddd, D MMMM YYYY');
28
+ };
29
+
30
+ const AddEditConditionSchedule = ({ route }) => {
31
+ const t = useTranslations();
32
+ const { automate, condition = {}, isUpdateCondition } = route.params;
33
+ const { navigate } = useNavigation();
34
+ const [repeat, setRepeat] = useState(
35
+ condition.repeat ? condition.repeat : REPEAT_OPTIONS.ONCE
36
+ );
37
+ const [time, setTime] = useState(
38
+ condition.time_repeat
39
+ ? moment(condition.time_repeat, 'HH:mm:ss')
40
+ : moment().second(0)
41
+ );
42
+ const [date, setDate] = useState(
43
+ condition.date_repeat
44
+ ? moment(condition.date_repeat, 'YYYY-MM-DD')
45
+ : moment()
46
+ );
47
+ const [weekday, setWeekday] = useState(
48
+ condition.weekday_repeat ? condition.weekday_repeat : []
49
+ );
50
+
51
+ const [showRepeatOptions, setShowRepeatOptions, setHideRepeatOptions] =
52
+ useBoolean();
53
+ const [showTimePicker, setShowTimePicker, setHideTimePicker] = useBoolean();
54
+ const [showCalendar, setShowCalendar, setHideCalendar] = useBoolean();
55
+
56
+ const handleOnSave = useCallback(async () => {
57
+ const data = {
58
+ type: AUTOMATE_TYPE.SCHEDULE,
59
+ repeat,
60
+ time_repeat: time.format('HH:mm:ss'),
61
+ date_repeat:
62
+ repeat === REPEAT_OPTIONS.ONCE ? date.format('YYYY-MM-DD') : null,
63
+ weekday_repeat: repeat === REPEAT_OPTIONS.EVERYWEEK ? weekday : null,
64
+ };
65
+
66
+ let response;
67
+ if (isUpdateCondition) {
68
+ response = await axiosPut(
69
+ API.AUTOMATE.UPDATE_CONDITION(automate.id, condition.id),
70
+ data
71
+ );
72
+ } else {
73
+ response = await axiosPost(API.AUTOMATE.ADD_CONDITION(automate.id), data);
74
+ }
75
+ const { success } = response;
76
+ if (success) {
77
+ navigate({
78
+ name: Routes.ScriptDetail,
79
+ params: { preAutomate: automate },
80
+ });
81
+ }
82
+ }, [
83
+ repeat,
84
+ time,
85
+ date,
86
+ weekday,
87
+ isUpdateCondition,
88
+ automate,
89
+ condition.id,
90
+ navigate,
91
+ ]);
92
+
93
+ const onSetRepeatOption = useCallback(
94
+ (value) => {
95
+ setRepeat(value);
96
+ setHideRepeatOptions();
97
+ },
98
+ [setRepeat, setHideRepeatOptions]
99
+ );
100
+
101
+ const onTimePicked = useCallback(
102
+ (timeData) => {
103
+ setTime(moment(timeData));
104
+ },
105
+ [setTime]
106
+ );
107
+
108
+ const onDatePicked = useCallback(
109
+ (datePicked) => {
110
+ setDate(datePicked);
111
+ },
112
+ [setDate]
113
+ );
114
+
115
+ return (
116
+ <NewActionWrapper
117
+ name={t('set_schedule')}
118
+ onNext={handleOnSave}
119
+ canNext={true}
120
+ nextTitle={t('save')}
121
+ >
122
+ <ScrollView
123
+ contentContainerStyle={styles.scollView}
124
+ scrollIndicatorInsets={{ right: 1 }}
125
+ >
126
+ <RowItem
127
+ title={t('set_time')}
128
+ value={time.format('HH:mm')}
129
+ icon="clock-circle"
130
+ onPress={setShowTimePicker}
131
+ />
132
+ {repeat === REPEAT_OPTIONS.ONCE && (
133
+ <RowItem
134
+ title={t('select_date')}
135
+ value={getDateString(date, t)}
136
+ icon="calendar"
137
+ onPress={setShowCalendar}
138
+ />
139
+ )}
140
+ {repeat === REPEAT_OPTIONS.EVERYWEEK && (
141
+ <SelectWeekday weekday={weekday} setWeekday={setWeekday} />
142
+ )}
143
+ <RowItem
144
+ title={t('repeat')}
145
+ value={t(`${repeat}`)}
146
+ arrow
147
+ onPress={setShowRepeatOptions}
148
+ />
149
+ </ScrollView>
150
+ <RepeatOptionsPopup
151
+ isVisible={showRepeatOptions}
152
+ onHide={setHideRepeatOptions}
153
+ onSetRepeat={onSetRepeatOption}
154
+ />
155
+ <WheelDateTimePicker
156
+ mode="time"
157
+ isVisible={showTimePicker}
158
+ defaultValue={time.valueOf()}
159
+ onCancel={setHideTimePicker}
160
+ onPicked={onTimePicked}
161
+ />
162
+ <Calendar
163
+ isVisible={showCalendar}
164
+ defaultDate={date}
165
+ minDate={moment()}
166
+ onCancel={setHideCalendar}
167
+ onConfirm={onDatePicked}
168
+ />
169
+ </NewActionWrapper>
170
+ );
171
+ };
172
+
173
+ export default memo(AddEditConditionSchedule);
@@ -0,0 +1,211 @@
1
+ import { useNavigation, useRoute } from '@react-navigation/native';
2
+ import moment from 'moment';
3
+ import React from 'react';
4
+ import { act, create } from 'react-test-renderer';
5
+ import Calendar from '../../../../commons/Calendar';
6
+ import WheelDateTimePicker from '../../../../commons/WheelDateTimePicker';
7
+ import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
8
+ import { SCProvider } from '../../../../context';
9
+ import { mockSCStore } from '../../../../context/mockStore';
10
+ import Routes from '../../../../utils/Route';
11
+ import RepeatOptionsPopup, {
12
+ REPEAT_OPTIONS,
13
+ } from '../components/RepeatOptionsPopup';
14
+
15
+ import RowItem from '../components/RowItem';
16
+ import SelectWeekday from '../components/SelectWeekday';
17
+ import AddEditConditionSchedule from '../AddEditConditionSchedule';
18
+ import { AUTOMATE_TYPE } from '../../../../configs/Constants';
19
+ import NewActionWrapper from '../../AddNewAction/NewActionWrapper';
20
+ import { API } from '../../../../configs';
21
+ import MockAdapter from 'axios-mock-adapter';
22
+ import api from '../../../../utils/Apis/axios';
23
+
24
+ const wrapComponent = (route) => {
25
+ useRoute.mockReturnValue(route);
26
+ return (
27
+ <SCProvider initState={mockSCStore({})}>
28
+ <AddEditConditionSchedule route={route} />
29
+ </SCProvider>
30
+ );
31
+ };
32
+
33
+ const mock = new MockAdapter(api.axiosInstance);
34
+
35
+ describe('Test AddEditConditionSchedule', () => {
36
+ let tree;
37
+ let route = {
38
+ params: {
39
+ automate: { type: 'schedule', unit: 1, id: 1 },
40
+ condition: {
41
+ id: 1,
42
+ type: AUTOMATE_TYPE.SCHEDULE,
43
+ repeat: 'once',
44
+ time_repeat: '19:00:00',
45
+ date_repeat: '2025-01-01',
46
+ weekday_repeat: [],
47
+ },
48
+ isUpdateCondition: true,
49
+ closeScreen: 'ScriptDetail',
50
+ },
51
+ };
52
+
53
+ const mockedNavigate = useNavigation().navigate;
54
+
55
+ beforeEach(() => {
56
+ mockedNavigate.mockClear();
57
+ Date.now = jest.fn(() => new Date('2025-01-01T19:00:00.000Z'));
58
+ });
59
+
60
+ it('test render SetSchedule', async () => {
61
+ await act(async () => {
62
+ tree = await create(wrapComponent(route));
63
+ });
64
+ const instance = tree.root;
65
+ const rowItems = instance.findAllByType(RowItem);
66
+ const timePicker = instance.findByType(WheelDateTimePicker);
67
+ const popup = instance.findByType(RepeatOptionsPopup);
68
+ const calendar = instance.findByType(Calendar);
69
+ const header = instance.findByProps({
70
+ accessibilityLabel: AccessibilityLabel.ICON_CLOSE,
71
+ });
72
+
73
+ await act(async () => {
74
+ await rowItems[0].props.onPress();
75
+ });
76
+ expect(timePicker.props.isVisible).toBeTruthy();
77
+
78
+ await act(async () => {
79
+ await rowItems[2].props.onPress();
80
+ });
81
+ expect(popup.props.isVisible).toBeTruthy();
82
+
83
+ await act(async () => {
84
+ await rowItems[1].props.onPress();
85
+ });
86
+ expect(calendar.props.isVisible).toBeTruthy();
87
+
88
+ await act(async () => {
89
+ await header.props.onPress();
90
+ });
91
+ expect(global.mockedNavigate).toHaveBeenCalledWith('ScriptDetail', {
92
+ automate: { id: 1, type: 'schedule', unit: 1 },
93
+ closeScreen: 'ScriptDetail',
94
+ condition: {
95
+ id: 1,
96
+ repeat: 'once',
97
+ time_repeat: '19:00:00',
98
+ date_repeat: '2025-01-01',
99
+ type: 'schedule',
100
+ weekday_repeat: [],
101
+ },
102
+ isUpdateCondition: true,
103
+ });
104
+ });
105
+
106
+ it('test repeat options popup', async () => {
107
+ await act(async () => {
108
+ tree = await create(wrapComponent(route));
109
+ });
110
+ const instance = tree.root;
111
+ const popup = instance.findByType(RepeatOptionsPopup);
112
+ let rowItems = instance.findAllByType(RowItem);
113
+ expect(rowItems).toHaveLength(3);
114
+
115
+ await act(async () => {
116
+ await popup.props.onSetRepeat(REPEAT_OPTIONS.EVERYDAY);
117
+ });
118
+ rowItems = instance.findAllByType(RowItem);
119
+ expect(rowItems).toHaveLength(2);
120
+
121
+ await act(async () => {
122
+ await popup.props.onSetRepeat(REPEAT_OPTIONS.EVERYWEEK);
123
+ });
124
+ const selectWeekday = instance.findByType(SelectWeekday);
125
+ rowItems = instance.findAllByType(RowItem);
126
+ expect(rowItems).toHaveLength(2);
127
+ expect(selectWeekday).toBeDefined();
128
+ });
129
+
130
+ it('test pick date and time', async () => {
131
+ await act(async () => {
132
+ tree = await create(wrapComponent(route));
133
+ });
134
+ const instance = tree.root;
135
+ const timePicker = instance.findByType(WheelDateTimePicker);
136
+ const calendar = instance.findByType(Calendar);
137
+ const rowItems = instance.findAllByType(RowItem);
138
+
139
+ const time = moment();
140
+ const date = moment();
141
+ expect(rowItems[0].props.value).toBe('19:00');
142
+ expect(rowItems[1].props.value).toBe(date.format('[Today], D MMMM YYYY '));
143
+
144
+ time.hour(10).minute(30);
145
+ date.add(1, 'days');
146
+ await act(async () => {
147
+ await timePicker.props.onPicked(time);
148
+ await calendar.props.onConfirm(date);
149
+ });
150
+ expect(rowItems[0].props.value).toBe(time.format('HH:mm'));
151
+ expect(rowItems[1].props.value).toBe(date.format('ddd, D MMMM YYYY'));
152
+ });
153
+
154
+ it('test save isUpdateCondition', async () => {
155
+ mock.onPut(API.AUTOMATE.UPDATE_CONDITION(1, 1)).reply(200);
156
+ await act(async () => {
157
+ tree = await create(wrapComponent(route));
158
+ });
159
+ const instance = tree.root;
160
+ const button = instance.findByType(NewActionWrapper);
161
+
162
+ await act(async () => {
163
+ await button.props.onNext();
164
+ });
165
+ expect(global.mockedNavigate).toHaveBeenCalledWith({
166
+ name: 'ScriptDetail',
167
+ params: { preAutomate: { id: 1, type: 'schedule', unit: 1 } },
168
+ });
169
+ });
170
+
171
+ it('test call api isUpdateCondition fail', async () => {
172
+ mock.onPut(API.AUTOMATE.UPDATE_CONDITION(1, 1)).reply(400);
173
+ await act(async () => {
174
+ tree = await create(wrapComponent(route));
175
+ });
176
+ const instance = tree.root;
177
+ const popup = instance.findByType(RepeatOptionsPopup);
178
+
179
+ await act(async () => {
180
+ await popup.props.onSetRepeat(REPEAT_OPTIONS.EVERYWEEK);
181
+ });
182
+ const button = instance.findByType(NewActionWrapper);
183
+
184
+ await act(async () => {
185
+ await button.props.onNext();
186
+ });
187
+ expect(global.mockedNavigate).toBeDefined();
188
+ });
189
+
190
+ it('test save isAddCondition', async () => {
191
+ // route.params.condition = {};
192
+ route.params = {
193
+ automate: { id: 1 },
194
+ closeScreen: Routes.ScriptDetail,
195
+ };
196
+ mock.onPost(API.AUTOMATE.ADD_CONDITION(1)).reply(200);
197
+ await act(async () => {
198
+ tree = await create(wrapComponent(route));
199
+ });
200
+ const instance = tree.root;
201
+ const button = instance.findByType(NewActionWrapper);
202
+
203
+ await act(async () => {
204
+ await button.props.onNext();
205
+ });
206
+ expect(global.mockedNavigate).toHaveBeenCalledWith({
207
+ name: 'ScriptDetail',
208
+ params: { preAutomate: { id: 1 } },
209
+ });
210
+ });
211
+ });
@@ -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 = '',