@eohjsc/react-native-smart-city 0.7.21 → 0.7.23
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/package.json +1 -1
- package/src/Images/Common/default_end_device.png +0 -0
- package/src/commons/ActionGroup/TerminalBoxTemplate.js +3 -0
- package/src/commons/ActionTemplate/OnOffButtonAction.js +38 -4
- package/src/commons/ActionTemplate/OnOffSimpleAction.js +55 -15
- package/src/commons/ActionTemplate/OnOffSmartLockAction.js +46 -8
- package/src/commons/ActionTemplate/SwitchButtonAction.js +35 -4
- package/src/commons/ActionTemplate/ThreeButtonAction.js +13 -3
- package/src/commons/ActionTemplate/__test__/OnOffButtonAction.test.js +46 -7
- package/src/commons/ActionTemplate/__test__/OnOffSimpleAction.test.js +66 -6
- package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +53 -13
- package/src/commons/ActionTemplate/__test__/SwitchButtonAction.test.js +46 -7
- package/src/commons/ActionTemplate/__test__/index.test.js +6 -2
- package/src/commons/ActionTemplate/index.js +65 -10
- 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/MediaPlayerDetail/MediaPlayerFull.js +26 -32
- package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +8 -6
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +6 -0
- package/src/commons/SubUnit/OneTap/index.js +5 -0
- package/src/commons/UnitSummary/ConfigHistoryChart/index.js +9 -11
- package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +2 -2
- package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
- package/src/configs/API.js +10 -0
- package/src/configs/AccessibilityLabel.js +5 -1
- package/src/configs/Images.js +1 -0
- package/src/navigations/AddMemberStack.js +3 -3
- package/src/screens/ActivityLog/__test__/index.test.js +10 -0
- package/src/screens/ActivityLog/hooks/index.js +1 -1
- package/src/screens/AddCommon/SelectUnit.js +3 -2
- package/src/screens/AddLocationMaps/__test__/index.test.js +13 -13
- package/src/screens/Automate/AddNewAction/ChooseAction.js +15 -51
- package/src/screens/Automate/AddNewAction/SelectControlDevices.js +13 -3
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +74 -54
- package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +114 -4
- package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +9 -11
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +37 -8
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +5 -0
- package/src/screens/Automate/AddNewAutoSmart/__test__/AddAutomationTypeSmart.test.js +31 -0
- package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +18 -2
- package/src/screens/Automate/Components/InputName.js +7 -6
- package/src/screens/Automate/Constants.js +12 -0
- package/src/screens/Automate/EditActionsList/UpdateActionScript.js +24 -55
- package/src/screens/Automate/EditActionsList/__tests__/UpdateActionScript.test.js +298 -41
- package/src/screens/Automate/EditActionsList/__tests__/index.test.js +2 -2
- package/src/screens/Automate/EditActionsList/index.js +26 -14
- package/src/screens/Automate/MultiUnits.js +9 -1
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +3 -3
- package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +4 -10
- package/src/screens/Automate/ScriptDetail/Components/DeleteScript.js +2 -4
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +78 -0
- package/src/screens/Automate/ScriptDetail/index.js +16 -10
- package/src/screens/Automate/ScriptDetail/utils.js +39 -35
- package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +27 -160
- package/src/screens/Automate/SetSchedule/EditSchedule.js +269 -0
- package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +327 -22
- package/src/screens/Automate/SetSchedule/__test__/index.test.js +35 -22
- package/src/screens/Automate/SetSchedule/components/RepeatOptionsPopup.js +2 -8
- package/src/screens/Automate/SetSchedule/index.js +15 -129
- package/src/screens/Automate/SetSchedule/styles/indexStyles.js +9 -0
- package/src/screens/Automate/__test__/MultiUnits.test.js +6 -1
- package/src/screens/Automate/hooks/useAction.js +222 -0
- package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +69 -13
- package/src/screens/ConfirmUnitDeletion/index.js +14 -14
- package/src/screens/Device/__test__/detail.test.js +48 -1
- package/src/screens/Device/detail.js +46 -3
- package/src/screens/PlayBackCamera/__test__/index.test.js +48 -13
- package/src/screens/PlayBackCamera/index.js +1 -1
- 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/Apis/axios.js +6 -0
- package/src/utils/I18n/translations/en.js +9 -1
- package/src/utils/I18n/translations/vi.js +10 -2
- package/src/commons/Sharing/StationDevicePermissions.js +0 -204
- package/src/screens/Automate/constants.js +0 -0
- 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
|
@@ -1,141 +1,27 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native';
|
|
2
|
-
import
|
|
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';
|
|
2
|
+
import React, { useCallback } from 'react';
|
|
9
3
|
import Routes from '../../../utils/Route';
|
|
10
|
-
import
|
|
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';
|
|
4
|
+
import EditSchedule from './EditSchedule';
|
|
17
5
|
|
|
18
6
|
const SetSchedule = ({ route }) => {
|
|
19
|
-
const t = useTranslations();
|
|
20
7
|
const { automate = {}, closeScreen } = route?.params || {};
|
|
21
8
|
const { navigate } = useNavigation();
|
|
22
|
-
const [repeat, setRepeat] = useState(automate.repeat || REPEAT_OPTIONS.ONCE);
|
|
23
9
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
? moment(automate.time_repeat, 'HH:mm:ss')
|
|
35
|
-
: moment().second(0)
|
|
36
|
-
);
|
|
37
|
-
const [date, setDate] = useState(
|
|
38
|
-
automate.date_repeat ? moment(automate.date_repeat, 'YYYY-MM-DD') : moment()
|
|
39
|
-
);
|
|
40
|
-
const [weekday, setWeekday] = useState(automate.weekday_repeat || []);
|
|
41
|
-
|
|
42
|
-
const [showRepeatOptions, setShowRepeatOptions, setHideRepeatOptions] =
|
|
43
|
-
useBoolean();
|
|
44
|
-
const [showTimePicker, setShowTimePicker, setHideTimePicker] = useBoolean();
|
|
45
|
-
const [showCalendar, setShowCalendar, setHideCalendar] = useBoolean();
|
|
46
|
-
|
|
47
|
-
const handleOnSave = useCallback(() => {
|
|
48
|
-
navigate(Routes.ValueChangeName, {
|
|
49
|
-
closeScreen: closeScreen,
|
|
50
|
-
automate: {
|
|
51
|
-
...automate,
|
|
52
|
-
repeat: repeat,
|
|
53
|
-
time_repeat: time.format('HH:mm:ss'),
|
|
54
|
-
date_repeat: date.format('YYYY-MM-DD'),
|
|
55
|
-
weekday_repeat: weekday,
|
|
56
|
-
},
|
|
57
|
-
unitId: automate.unit,
|
|
58
|
-
});
|
|
59
|
-
}, [navigate, closeScreen, automate, repeat, time, date, weekday]);
|
|
60
|
-
|
|
61
|
-
const onSetRepeatOption = useCallback(
|
|
62
|
-
(value) => {
|
|
63
|
-
setRepeat(value);
|
|
64
|
-
setHideRepeatOptions();
|
|
10
|
+
const handleOnSave = useCallback(
|
|
11
|
+
(data) => {
|
|
12
|
+
navigate(Routes.ValueChangeName, {
|
|
13
|
+
closeScreen: closeScreen,
|
|
14
|
+
automate: {
|
|
15
|
+
...automate,
|
|
16
|
+
conditions: [data],
|
|
17
|
+
},
|
|
18
|
+
unitId: automate.unit,
|
|
19
|
+
});
|
|
65
20
|
},
|
|
66
|
-
[
|
|
21
|
+
[navigate, closeScreen, automate]
|
|
67
22
|
);
|
|
68
23
|
|
|
69
|
-
|
|
70
|
-
(timeData) => {
|
|
71
|
-
setTime(moment(timeData));
|
|
72
|
-
},
|
|
73
|
-
[setTime]
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const onDatePicked = useCallback(
|
|
77
|
-
(datePicked) => {
|
|
78
|
-
setDate(datePicked);
|
|
79
|
-
},
|
|
80
|
-
[setDate]
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<NewActionWrapper
|
|
85
|
-
name={t('set_schedule')}
|
|
86
|
-
onNext={handleOnSave}
|
|
87
|
-
canNext
|
|
88
|
-
nextTitle={t('save')}
|
|
89
|
-
>
|
|
90
|
-
<ScrollView
|
|
91
|
-
contentContainerStyle={styles.scollView}
|
|
92
|
-
scrollIndicatorInsets={{ right: 1 }}
|
|
93
|
-
>
|
|
94
|
-
<RowItem
|
|
95
|
-
title={t('set_time')}
|
|
96
|
-
value={time.format('HH:mm')}
|
|
97
|
-
icon="clock-circle"
|
|
98
|
-
onPress={setShowTimePicker}
|
|
99
|
-
/>
|
|
100
|
-
{repeat === REPEAT_OPTIONS.ONCE && (
|
|
101
|
-
<RowItem
|
|
102
|
-
title={t('select_date')}
|
|
103
|
-
value={getDateString(date)}
|
|
104
|
-
icon="calendar"
|
|
105
|
-
onPress={setShowCalendar}
|
|
106
|
-
/>
|
|
107
|
-
)}
|
|
108
|
-
{repeat === REPEAT_OPTIONS.EVERYWEEK && (
|
|
109
|
-
<SelectWeekday weekday={weekday} setWeekday={setWeekday} />
|
|
110
|
-
)}
|
|
111
|
-
<RowItem
|
|
112
|
-
title={t('repeat')}
|
|
113
|
-
value={t(`${repeat}`)}
|
|
114
|
-
arrow
|
|
115
|
-
onPress={setShowRepeatOptions}
|
|
116
|
-
/>
|
|
117
|
-
</ScrollView>
|
|
118
|
-
<RepeatOptionsPopup
|
|
119
|
-
isVisible={showRepeatOptions}
|
|
120
|
-
onHide={setHideRepeatOptions}
|
|
121
|
-
onSetRepeat={onSetRepeatOption}
|
|
122
|
-
/>
|
|
123
|
-
<WheelDateTimePicker
|
|
124
|
-
mode="time"
|
|
125
|
-
isVisible={showTimePicker}
|
|
126
|
-
defaultValue={time.valueOf()}
|
|
127
|
-
onCancel={setHideTimePicker}
|
|
128
|
-
onPicked={onTimePicked}
|
|
129
|
-
/>
|
|
130
|
-
<Calendar
|
|
131
|
-
isVisible={showCalendar}
|
|
132
|
-
defaultDate={date}
|
|
133
|
-
minDate={moment()}
|
|
134
|
-
onCancel={setHideCalendar}
|
|
135
|
-
onConfirm={onDatePicked}
|
|
136
|
-
/>
|
|
137
|
-
</NewActionWrapper>
|
|
138
|
-
);
|
|
24
|
+
return <EditSchedule onSave={handleOnSave} />;
|
|
139
25
|
};
|
|
140
26
|
|
|
141
|
-
export default
|
|
27
|
+
export default SetSchedule;
|
|
@@ -20,4 +20,13 @@ export default StyleSheet.create({
|
|
|
20
20
|
borderTopWidth: 1,
|
|
21
21
|
backgroundColor: Colors.White,
|
|
22
22
|
},
|
|
23
|
+
inputWrap: {
|
|
24
|
+
marginTop: 0,
|
|
25
|
+
},
|
|
26
|
+
inputNumber: {
|
|
27
|
+
borderWidth: 1,
|
|
28
|
+
borderColor: Colors.Gray4,
|
|
29
|
+
borderStyle: 'solid',
|
|
30
|
+
borderRadius: 10,
|
|
31
|
+
},
|
|
23
32
|
});
|
|
@@ -190,11 +190,16 @@ describe('Test MultiUnits', () => {
|
|
|
190
190
|
await act(async () => {
|
|
191
191
|
ItemAddNews[0].props.onAddNew();
|
|
192
192
|
});
|
|
193
|
-
expect(global.mockedNavigate).
|
|
193
|
+
expect(global.mockedNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
|
|
194
194
|
screen: Routes.ScenarioName,
|
|
195
195
|
params: {
|
|
196
196
|
automate: {
|
|
197
197
|
type: AUTOMATE_TYPE.ONE_TAP,
|
|
198
|
+
conditions: [
|
|
199
|
+
{
|
|
200
|
+
type: AUTOMATE_TYPE.ONE_TAP,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
198
203
|
unit: undefined,
|
|
199
204
|
},
|
|
200
205
|
closeScreen: undefined,
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { API } from '../../../configs';
|
|
4
|
+
import {
|
|
5
|
+
axiosDelete,
|
|
6
|
+
axiosGet,
|
|
7
|
+
axiosPost,
|
|
8
|
+
axiosPut,
|
|
9
|
+
} from '../../../utils/Apis/axios';
|
|
10
|
+
|
|
11
|
+
const useAction = (device, scriptItems, activatedScript = {}) => {
|
|
12
|
+
const {
|
|
13
|
+
action_script,
|
|
14
|
+
toggle_script,
|
|
15
|
+
order = scriptItems.length + 1,
|
|
16
|
+
} = activatedScript;
|
|
17
|
+
const [saveActions, setSaveActions] = useState([]);
|
|
18
|
+
const [displayActions, setDisplayActions] = useState([]);
|
|
19
|
+
|
|
20
|
+
const listAction = useMemo(() => {
|
|
21
|
+
return saveActions
|
|
22
|
+
.filter((item) => !item.is_toggle)
|
|
23
|
+
.map((item) => ({
|
|
24
|
+
action: item.action,
|
|
25
|
+
data: item.data,
|
|
26
|
+
order: order + item.index,
|
|
27
|
+
}));
|
|
28
|
+
}, [saveActions, order]);
|
|
29
|
+
|
|
30
|
+
const listToggle = useMemo(() => {
|
|
31
|
+
return saveActions
|
|
32
|
+
.filter((item) => item.is_toggle)
|
|
33
|
+
.map((item) => ({
|
|
34
|
+
action_on: item.action_on,
|
|
35
|
+
action_off: item.action_off,
|
|
36
|
+
config: item.config,
|
|
37
|
+
action_on_data: item.action_on_data,
|
|
38
|
+
action_off_data: item.action_off_data,
|
|
39
|
+
is_on_values: item.is_on_values,
|
|
40
|
+
order: order + item.index,
|
|
41
|
+
}));
|
|
42
|
+
}, [saveActions, order]);
|
|
43
|
+
|
|
44
|
+
const fetchDisplayActions = useCallback(async () => {
|
|
45
|
+
const { success, data } = await axiosGet(
|
|
46
|
+
API.DEVICE.DISPLAY_ACTIONS(device.id)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
success && setDisplayActions(data);
|
|
50
|
+
}, [device.id]);
|
|
51
|
+
|
|
52
|
+
const onSelectAction = useCallback((action) => {
|
|
53
|
+
setSaveActions((prevActions) => {
|
|
54
|
+
const index = prevActions.findIndex(
|
|
55
|
+
(item) => item.index === action.index
|
|
56
|
+
);
|
|
57
|
+
if (index !== -1) {
|
|
58
|
+
const newActions = [...prevActions];
|
|
59
|
+
newActions[index] = action;
|
|
60
|
+
return newActions;
|
|
61
|
+
} else {
|
|
62
|
+
return [...prevActions, action];
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}, []);
|
|
66
|
+
|
|
67
|
+
const onAddAction = useCallback(
|
|
68
|
+
async (automateId, unitId, startOrder, numberAction) => {
|
|
69
|
+
if (!listAction.length) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const { success } = await axiosPost(
|
|
73
|
+
API.AUTOMATE.ADD_SCRIPT_ACTION(automateId),
|
|
74
|
+
{
|
|
75
|
+
list_action: listAction,
|
|
76
|
+
...(startOrder && { start_order: startOrder }),
|
|
77
|
+
...(numberAction && { number_action: numberAction }),
|
|
78
|
+
unit: unitId,
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
return success;
|
|
82
|
+
},
|
|
83
|
+
[listAction]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const onAddToggle = useCallback(
|
|
87
|
+
async (automateId, unitId, startOrder, numberAction) => {
|
|
88
|
+
if (!listToggle.length) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const { success } = await axiosPost(
|
|
92
|
+
API.AUTOMATE.ADD_SCRIPT_TOGGLE(automateId),
|
|
93
|
+
{
|
|
94
|
+
list_action: listToggle,
|
|
95
|
+
...(startOrder && { start_order: startOrder }),
|
|
96
|
+
...(numberAction && { number_action: numberAction }),
|
|
97
|
+
unit: unitId,
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
return success;
|
|
101
|
+
},
|
|
102
|
+
[listToggle]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const onAddSubmit = useCallback(
|
|
106
|
+
async (automateId, unitId) => {
|
|
107
|
+
const actionSuccess = await onAddAction(automateId, unitId);
|
|
108
|
+
const toggleSuccess = await onAddToggle(automateId, unitId);
|
|
109
|
+
return actionSuccess || toggleSuccess;
|
|
110
|
+
},
|
|
111
|
+
[onAddAction, onAddToggle]
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const onDeleteScript = useCallback(async (automateId, scriptId) => {
|
|
115
|
+
const { success } = await axiosDelete(
|
|
116
|
+
API.AUTOMATE.DELETE_SCRIPT_ITEM(automateId, scriptId)
|
|
117
|
+
);
|
|
118
|
+
return success;
|
|
119
|
+
}, []);
|
|
120
|
+
|
|
121
|
+
const onUpdateAction = useCallback(
|
|
122
|
+
async (automateId, scriptId, unitId) => {
|
|
123
|
+
if (!action_script) {
|
|
124
|
+
const success = await onDeleteScript(automateId, scriptId);
|
|
125
|
+
return (
|
|
126
|
+
success &&
|
|
127
|
+
(await onAddAction(
|
|
128
|
+
automateId,
|
|
129
|
+
unitId,
|
|
130
|
+
listAction[0].order,
|
|
131
|
+
saveActions.length
|
|
132
|
+
))
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const { success } = await axiosPut(
|
|
136
|
+
API.AUTOMATE.UPDATE_SCRIPT_ACTION(automateId),
|
|
137
|
+
{
|
|
138
|
+
id: scriptId,
|
|
139
|
+
list_action: listAction,
|
|
140
|
+
number_action: saveActions.length,
|
|
141
|
+
unit: unitId,
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
return success;
|
|
145
|
+
},
|
|
146
|
+
[action_script, listAction, saveActions.length, onAddAction, onDeleteScript]
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const onUpdateToggle = useCallback(
|
|
150
|
+
async (automateId, scriptId, unitId) => {
|
|
151
|
+
if (!toggle_script) {
|
|
152
|
+
const success = await onDeleteScript(automateId, scriptId);
|
|
153
|
+
return (
|
|
154
|
+
success &&
|
|
155
|
+
(await onAddToggle(
|
|
156
|
+
automateId,
|
|
157
|
+
unitId,
|
|
158
|
+
listToggle[0].order,
|
|
159
|
+
saveActions.length
|
|
160
|
+
))
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const { success } = await axiosPut(
|
|
164
|
+
API.AUTOMATE.UPDATE_SCRIPT_TOGGLE(automateId),
|
|
165
|
+
{
|
|
166
|
+
id: scriptId,
|
|
167
|
+
list_action: listToggle,
|
|
168
|
+
number_action: saveActions.length,
|
|
169
|
+
unit: unitId,
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
return success;
|
|
173
|
+
},
|
|
174
|
+
[toggle_script, listToggle, saveActions.length, onAddToggle, onDeleteScript]
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const onUpdateSubmit = useCallback(
|
|
178
|
+
async (automateId, scriptId, unitId) => {
|
|
179
|
+
if (saveActions[0].is_toggle) {
|
|
180
|
+
const toggleSuccess = await onUpdateToggle(
|
|
181
|
+
automateId,
|
|
182
|
+
scriptId,
|
|
183
|
+
unitId
|
|
184
|
+
);
|
|
185
|
+
const actionSuccess = await onAddAction(automateId, unitId);
|
|
186
|
+
return toggleSuccess || actionSuccess;
|
|
187
|
+
} else {
|
|
188
|
+
const actionSuccess = await onUpdateAction(
|
|
189
|
+
automateId,
|
|
190
|
+
scriptId,
|
|
191
|
+
unitId
|
|
192
|
+
);
|
|
193
|
+
const toggleSuccess = await onAddToggle(automateId, unitId);
|
|
194
|
+
return actionSuccess || toggleSuccess;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
[saveActions, onAddAction, onAddToggle, onUpdateAction, onUpdateToggle]
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
fetchDisplayActions();
|
|
202
|
+
}, [fetchDisplayActions]);
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
displayActions,
|
|
206
|
+
saveActions,
|
|
207
|
+
|
|
208
|
+
setDisplayActions,
|
|
209
|
+
setSaveActions,
|
|
210
|
+
onSelectAction,
|
|
211
|
+
|
|
212
|
+
onAddAction,
|
|
213
|
+
onAddToggle,
|
|
214
|
+
onAddSubmit,
|
|
215
|
+
|
|
216
|
+
onUpdateAction,
|
|
217
|
+
onUpdateToggle,
|
|
218
|
+
onUpdateSubmit,
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export default useAction;
|
|
@@ -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 () => {
|
|
@@ -8,6 +8,7 @@ import CurrentRainSensor from '../../../commons/Device/RainningSensor/CurrentRai
|
|
|
8
8
|
import { AlertSendConfirm } from '../../../commons/EmergencyButton/AlertSendConfirm';
|
|
9
9
|
import { AlertSent } from '../../../commons/EmergencyButton/AlertSent';
|
|
10
10
|
import Text from '../../../commons/Text';
|
|
11
|
+
import { SensorConnectStatusViewHeader } from '../components/SensorConnectStatusViewHeader';
|
|
11
12
|
import { API } from '../../../configs';
|
|
12
13
|
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
13
14
|
import { SCProvider } from '../../../context';
|
|
@@ -369,10 +370,19 @@ describe('test DeviceDetail', () => {
|
|
|
369
370
|
const instance = tree.root;
|
|
370
371
|
const scrollView = instance.findByType(ScrollView);
|
|
371
372
|
const refreshControl = scrollView.props.refreshControl;
|
|
373
|
+
expect(mock.history.post).toHaveLength(2);
|
|
372
374
|
await act(async () => {
|
|
373
375
|
refreshControl.props.onRefresh();
|
|
374
376
|
});
|
|
375
377
|
expect(scrollView).toBeDefined();
|
|
378
|
+
expect(mock.history.post).toHaveLength(4);
|
|
379
|
+
const urls = mock.history.post.map((item) => item.url);
|
|
380
|
+
expect(
|
|
381
|
+
urls.filter((url) => url === API.UNIT.END_DEVICES_STATUS(1))
|
|
382
|
+
).toHaveLength(2);
|
|
383
|
+
expect(
|
|
384
|
+
urls.filter((url) => url === API.HOME_ASSISTANT.CHECK_SEND_EMAIL())
|
|
385
|
+
).toHaveLength(2);
|
|
376
386
|
});
|
|
377
387
|
|
|
378
388
|
it('Should render SensorDisplayItem', async () => {
|
|
@@ -760,7 +770,7 @@ describe('test DeviceDetail', () => {
|
|
|
760
770
|
|
|
761
771
|
it('Test fetchUnitDetail', async () => {
|
|
762
772
|
const unitId = 1;
|
|
763
|
-
mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200);
|
|
773
|
+
mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200, { id: unitId });
|
|
764
774
|
await act(async () => {
|
|
765
775
|
await create(
|
|
766
776
|
wrapComponent(store, account, {
|
|
@@ -773,6 +783,43 @@ describe('test DeviceDetail', () => {
|
|
|
773
783
|
expect(urls).toContain(API.UNIT.UNIT_DETAIL(unitId));
|
|
774
784
|
});
|
|
775
785
|
|
|
786
|
+
it('Test fetch end device status', async () => {
|
|
787
|
+
const unitId = 1;
|
|
788
|
+
mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200, { id: unitId });
|
|
789
|
+
mock.onPost(API.UNIT.END_DEVICES_STATUS(unitId)).reply(200, [
|
|
790
|
+
{
|
|
791
|
+
id: 1,
|
|
792
|
+
is_connected: true,
|
|
793
|
+
},
|
|
794
|
+
]);
|
|
795
|
+
await act(async () => {
|
|
796
|
+
tree = await create(
|
|
797
|
+
wrapComponent(store, account, {
|
|
798
|
+
...route,
|
|
799
|
+
params: { ...route.params, unitData: null, unitId: unitId },
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
});
|
|
803
|
+
const instance = tree.root;
|
|
804
|
+
const sensorConnectStatus = instance.findByType(
|
|
805
|
+
SensorConnectStatusViewHeader
|
|
806
|
+
);
|
|
807
|
+
expect(sensorConnectStatus.props.connectedViaNetwork).toBeTruthy();
|
|
808
|
+
expect(mock.history.post).toHaveLength(1);
|
|
809
|
+
expect(mock.history.post[0].url).toEqual(
|
|
810
|
+
API.UNIT.END_DEVICES_STATUS(unitId)
|
|
811
|
+
);
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it('Test not fetch end device status if not managed by backend', async () => {
|
|
815
|
+
route.params.sensorData.is_managed_by_backend = false;
|
|
816
|
+
await act(async () => {
|
|
817
|
+
tree = await create(wrapComponent(store, account, route));
|
|
818
|
+
});
|
|
819
|
+
const urls = mock.history.post.map((x) => x.url);
|
|
820
|
+
expect(urls).not.toContain(API.UNIT.END_DEVICES_STATUS(1));
|
|
821
|
+
});
|
|
822
|
+
|
|
776
823
|
it('should render device detail, useWatchConfig value', async () => {
|
|
777
824
|
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, []);
|
|
778
825
|
const responseDisplay = {
|