@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.
- package/assets/images/Schedule.svg +39 -0
- package/assets/images/ValueChange.svg +49 -0
- package/package.json +1 -1
- package/src/Images/Common/default_end_device.png +0 -0
- package/src/commons/Automate/ButtonAddCondition.js +51 -0
- package/src/commons/Automate/ItemConditionScriptDetail.js +28 -15
- package/src/commons/Automate/ItemConditionScriptDetailStyles.js +9 -0
- package/src/commons/Dashboard/MyUnit/index.js +19 -20
- package/src/commons/DevMode/Search.js +1 -1
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +5 -5
- package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +1 -3
- package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
- package/src/configs/API.js +16 -1
- package/src/configs/AccessibilityLabel.js +9 -1
- package/src/configs/Images.js +1 -0
- package/src/context/actionType.ts +5 -0
- package/src/context/reducer.ts +30 -1
- package/src/navigations/AddMemberStack.js +3 -3
- package/src/navigations/UnitStack.js +8 -0
- package/src/screens/AddCommon/SelectUnit.js +3 -2
- package/src/screens/AddLocationMaps/__test__/index.test.js +13 -13
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +73 -30
- package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +9 -11
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +115 -10
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +7 -3
- package/src/screens/Automate/AddNewAutoSmart/__test__/AddAutomationTypeSmart.test.js +31 -0
- package/src/screens/Automate/ScriptDetail/Components/DeleteCondition.js +51 -0
- package/src/screens/Automate/ScriptDetail/Components/ModalAddCondition.js +196 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +18 -0
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +441 -47
- package/src/screens/Automate/ScriptDetail/index.js +359 -72
- package/src/screens/Automate/ScriptDetail/utils.js +7 -31
- package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +173 -0
- package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +211 -0
- package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +69 -13
- package/src/screens/ConfirmUnitDeletion/index.js +14 -14
- package/src/screens/Sharing/Components/ConfigItem.js +34 -0
- package/src/screens/Sharing/Components/DeviceItem.js +77 -0
- package/src/screens/Sharing/Components/ItemChangeRole.js +3 -4
- package/src/screens/Sharing/Components/ShareDeviceSelector.js +255 -0
- package/src/screens/Sharing/Components/Styles/CheckBoxCustomStyles.js +1 -1
- package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +11 -27
- package/src/screens/Sharing/{Styles/SelectPermissionStyles.js → Components/Styles/ShareDeviceSelectorStyles.js} +3 -11
- package/src/screens/Sharing/Components/SubUnitItem.js +28 -0
- package/src/screens/Sharing/Components/SubUnitTreeView.js +68 -0
- package/src/screens/Sharing/Components/TitleCheckBox.js +23 -41
- package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +7 -7
- package/src/screens/Sharing/Components/__test__/ShareDeviceSelector.test.js +298 -0
- package/src/screens/Sharing/Components/index.js +14 -1
- package/src/screens/Sharing/InfoMemberUnit.js +20 -20
- package/src/screens/Sharing/SelectShareDevice.js +11 -255
- package/src/screens/Sharing/SelectUser.js +12 -12
- package/src/screens/Sharing/UpdateShareDevice.js +45 -301
- package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +58 -11
- package/src/screens/Sharing/__test__/SelectShareDevice.test.js +51 -160
- package/src/screens/Sharing/__test__/SelectUser.test.js +72 -10
- package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +49 -209
- package/src/utils/I18n/translations/en.js +22 -1
- package/src/utils/I18n/translations/vi.js +23 -3
- package/src/utils/Route/index.js +1 -0
- package/src/commons/Sharing/StationDevicePermissions.js +0 -204
- package/src/screens/Sharing/Components/CheckBoxConfig.js +0 -44
- package/src/screens/Sharing/Components/CheckBoxSubUnit.js +0 -35
- package/src/screens/Sharing/Components/EndDevice.js +0 -93
- package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +0 -18
- package/src/screens/Sharing/Components/Styles/TitleCheckBoxStyles.js +0 -21
- 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
|
|
5
|
-
import {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
6
|
-
import
|
|
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
|
|
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,
|
|
24
|
+
const [confirm, setConfirm] = useState('');
|
|
25
25
|
const [errorText, setErrorText] = useState();
|
|
26
26
|
|
|
27
27
|
const onChangePassword = useCallback((value) => {
|
|
28
|
-
|
|
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
|
|
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 = '',
|