@eohjsc/react-native-smart-city 0.7.22 → 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/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/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 +3 -1
- package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
- package/src/configs/API.js +6 -0
- package/src/configs/AccessibilityLabel.js +2 -0
- package/src/screens/ActivityLog/__test__/index.test.js +10 -0
- package/src/screens/ActivityLog/hooks/index.js +1 -1
- 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__/SetupConfigCondition.test.js +37 -8
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +5 -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 -15
- 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/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/utils/Apis/axios.js +6 -0
- package/src/utils/I18n/translations/en.js +8 -0
- package/src/utils/I18n/translations/vi.js +8 -0
- package/src/screens/Automate/constants.js +0 -0
|
@@ -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;
|
|
@@ -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 = {
|
|
@@ -54,7 +54,7 @@ import Routes from '../../utils/Route';
|
|
|
54
54
|
import { getData as getLocalData } from '../../utils/Storage';
|
|
55
55
|
import { API, Colors, SCConfig } from '../../configs';
|
|
56
56
|
import { DEVICE_TYPE, AccessibilityLabel } from '../../configs/Constants';
|
|
57
|
-
import { axiosGet } from '../../utils/Apis/axios';
|
|
57
|
+
import { axiosGet, axiosPost } from '../../utils/Apis/axios';
|
|
58
58
|
import { notImplemented } from '../../utils/Utils';
|
|
59
59
|
import { useReceiveNotifications } from '../../hooks';
|
|
60
60
|
import useChipJsonConfiguration, {
|
|
@@ -482,6 +482,31 @@ const DeviceDetail = ({ route }) => {
|
|
|
482
482
|
fetchDataDeviceDetail();
|
|
483
483
|
}, [device, isNetworkConnected, fetchDataDeviceDetail]);
|
|
484
484
|
|
|
485
|
+
const fetchDeviceStatus = useCallback(async () => {
|
|
486
|
+
if (
|
|
487
|
+
!isNetworkConnected ||
|
|
488
|
+
!device.is_managed_by_backend ||
|
|
489
|
+
configIdsTemp.current.length
|
|
490
|
+
) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const { success, data } = await axiosPost(
|
|
495
|
+
API.UNIT.END_DEVICES_STATUS(unit.id),
|
|
496
|
+
{
|
|
497
|
+
end_device_ids: [device.id],
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
success && setAction(Action.SET_DEVICES_STATUS, data);
|
|
502
|
+
}, [
|
|
503
|
+
isNetworkConnected,
|
|
504
|
+
unit.id,
|
|
505
|
+
device.id,
|
|
506
|
+
device.is_managed_by_backend,
|
|
507
|
+
setAction,
|
|
508
|
+
]);
|
|
509
|
+
|
|
485
510
|
const onRefresh = useCallback(async () => {
|
|
486
511
|
await fetchSensorDetail();
|
|
487
512
|
await fetchDataDeviceDetail();
|
|
@@ -495,9 +520,11 @@ const DeviceDetail = ({ route }) => {
|
|
|
495
520
|
})();
|
|
496
521
|
}
|
|
497
522
|
await checkScanDevicesBLE();
|
|
523
|
+
await fetchDeviceStatus();
|
|
498
524
|
}, [
|
|
499
525
|
fetchSensorDetail,
|
|
500
526
|
fetchDataDeviceDetail,
|
|
527
|
+
fetchDeviceStatus,
|
|
501
528
|
unit?.remote_control_options,
|
|
502
529
|
isNetworkConnected,
|
|
503
530
|
checkScanDevicesBLE,
|
|
@@ -516,11 +543,20 @@ const DeviceDetail = ({ route }) => {
|
|
|
516
543
|
return;
|
|
517
544
|
}
|
|
518
545
|
|
|
519
|
-
const {
|
|
520
|
-
|
|
546
|
+
const {
|
|
547
|
+
configs,
|
|
548
|
+
options,
|
|
549
|
+
config,
|
|
550
|
+
from_config,
|
|
551
|
+
to_config,
|
|
552
|
+
history_configs,
|
|
553
|
+
realtime_configs,
|
|
554
|
+
} = configuration;
|
|
521
555
|
|
|
522
556
|
configs?.forEach((object) => configIdsSet.add(object.id));
|
|
523
557
|
options?.forEach((option) => configIdsSet.add(option.config));
|
|
558
|
+
history_configs?.forEach((object) => configIdsSet.add(object.id));
|
|
559
|
+
realtime_configs?.forEach((object) => configIdsSet.add(object.id));
|
|
524
560
|
|
|
525
561
|
if (config) {
|
|
526
562
|
const configId = config.id || config;
|
|
@@ -622,6 +658,13 @@ const DeviceDetail = ({ route }) => {
|
|
|
622
658
|
}, [display.items, isNetworkConnected, device, mqttConfigs])
|
|
623
659
|
);
|
|
624
660
|
|
|
661
|
+
useFocusEffect(
|
|
662
|
+
useCallback(() => {
|
|
663
|
+
fetchDeviceStatus();
|
|
664
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
665
|
+
}, [])
|
|
666
|
+
);
|
|
667
|
+
|
|
625
668
|
useWatchConfigs(chipFiltered.length ? [] : configIdsTemp.current);
|
|
626
669
|
|
|
627
670
|
const isShowEmergencyResolve =
|
|
@@ -20,19 +20,22 @@ const wrapComponent = () => (
|
|
|
20
20
|
|
|
21
21
|
describe('Test PlayBackCamera', () => {
|
|
22
22
|
let tree;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
jest.useFakeTimers();
|
|
26
|
+
global.mockedUseRoute.mockReturnValue({
|
|
27
|
+
params: {
|
|
28
|
+
item: {
|
|
29
|
+
configuration: {
|
|
30
|
+
time_zone: 0,
|
|
31
|
+
playback: 'rtsp://example.com/playback',
|
|
32
|
+
name: 'name',
|
|
33
|
+
uri: 'rtsp://example.com/stream',
|
|
34
|
+
},
|
|
32
35
|
},
|
|
36
|
+
thumbnail: {},
|
|
33
37
|
},
|
|
34
|
-
|
|
35
|
-
},
|
|
38
|
+
});
|
|
36
39
|
});
|
|
37
40
|
|
|
38
41
|
it('Test render', async () => {
|
|
@@ -129,7 +132,9 @@ describe('Test PlayBackCamera', () => {
|
|
|
129
132
|
},
|
|
130
133
|
});
|
|
131
134
|
});
|
|
132
|
-
|
|
135
|
+
await act(async () => {
|
|
136
|
+
jest.runAllTimers();
|
|
137
|
+
});
|
|
133
138
|
//NOTE: isFirstTime = false
|
|
134
139
|
await act(async () => {
|
|
135
140
|
timerScroll[0].props.onScroll({
|
|
@@ -147,7 +152,37 @@ describe('Test PlayBackCamera', () => {
|
|
|
147
152
|
});
|
|
148
153
|
const media = instance.findByType(MediaPlayerFull);
|
|
149
154
|
expect(media.props.uri).toEqual(
|
|
150
|
-
|
|
155
|
+
`rtsp://example.com/playback=${moment().format('YYYYMMDDT003730\\Z')}`
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('Test render when playback is null', async () => {
|
|
160
|
+
global.mockedUseRoute.mockReturnValue({
|
|
161
|
+
params: {
|
|
162
|
+
item: {
|
|
163
|
+
configuration: {
|
|
164
|
+
time_zone: 0,
|
|
165
|
+
playback: null,
|
|
166
|
+
name: 'name',
|
|
167
|
+
uri: 'rtsp://example.com/stream',
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
thumbnail: {},
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
await act(async () => {
|
|
174
|
+
tree = await create(wrapComponent());
|
|
175
|
+
});
|
|
176
|
+
const instance = tree.root;
|
|
177
|
+
const buttonAddDate = instance.findAll(
|
|
178
|
+
(el) =>
|
|
179
|
+
el.props.accessibilityLabel === AccessibilityLabel.ON_PRESS_ADD_DATE &&
|
|
180
|
+
el.type === TouchableOpacity
|
|
151
181
|
);
|
|
182
|
+
await act(async () => {
|
|
183
|
+
await buttonAddDate[0].props.onPress();
|
|
184
|
+
});
|
|
185
|
+
const media = instance.findByType(MediaPlayerFull);
|
|
186
|
+
expect(media.props.uri).toEqual('rtsp://example.com/stream');
|
|
152
187
|
});
|
|
153
188
|
});
|
package/src/utils/Apis/axios.js
CHANGED
|
@@ -75,6 +75,12 @@ const parseErrorResponse = async (error) => {
|
|
|
75
75
|
if (message instanceof Array) {
|
|
76
76
|
message = message[0];
|
|
77
77
|
}
|
|
78
|
+
if (message instanceof Object) {
|
|
79
|
+
return await parseErrorResponse({
|
|
80
|
+
...error,
|
|
81
|
+
data: message,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
78
84
|
if (message?.message) {
|
|
79
85
|
message = message.message;
|
|
80
86
|
}
|