@eohjsc/react-native-smart-city 0.2.90 → 0.2.93
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/Device/current-state.svg +3 -0
- package/assets/images/Device/door-state.svg +3 -0
- package/assets/images/Device/wind-strength.svg +12 -0
- package/package.json +1 -1
- package/src/commons/Action/ItemQuickAction.js +1 -0
- package/src/commons/Action/__test__/ItemQuickAction.test.js +49 -2
- package/src/commons/ActionGroup/ColorPickerTemplate.js +30 -24
- package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +60 -12
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/__test__/index.test.js +47 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +2 -0
- package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplateStyle.js +2 -1
- package/src/commons/ActionGroup/OnOffTemplate/index.js +48 -28
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +31 -11
- package/src/commons/ActionGroup/OptionsDropdownActionTemplateStyle.js +5 -2
- package/src/commons/ActionGroup/SliderRangeTemplate.js +19 -5
- package/src/commons/ActionGroup/TimerActionTemplate.js +14 -10
- package/src/commons/ActionGroup/TimerActionTemplateStyles.js +12 -0
- package/src/commons/ActionGroup/TwoButtonTemplate/TwoButtonTemplateStyles.js +55 -0
- package/src/commons/ActionGroup/TwoButtonTemplate/index.js +170 -0
- package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +74 -0
- package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +107 -0
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +71 -0
- package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +1 -1
- package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +112 -0
- package/src/commons/ActionGroup/index.js +4 -1
- package/src/commons/Calendar/index.js +5 -1
- package/src/commons/CameraDevice/index.js +6 -1
- package/src/commons/ConnectingProcess/__test__/Connecting.test.js +4 -1
- package/src/commons/Device/HistoryChart.js +2 -2
- package/src/commons/Device/HorizontalBarChart.js +6 -2
- package/src/commons/Device/ItemDevice.js +3 -13
- package/src/commons/IconComponent/index.js +32 -26
- package/src/commons/MediaPlayerDetail/index.js +16 -4
- package/src/commons/SubUnit/Favorites/index.js +11 -41
- package/src/commons/SubUnit/ShortDetail.js +7 -41
- package/src/commons/SubUnit/__test__/Favorites.test.js +33 -35
- package/src/configs/API.js +4 -0
- package/src/configs/Constants.js +26 -0
- package/src/context/actionType.ts +17 -0
- package/src/context/mockStore.ts +18 -0
- package/src/context/reducer.ts +102 -0
- package/src/hooks/Common/index.js +2 -0
- package/src/hooks/Common/useSensorsStatus.js +52 -0
- package/src/iot/RemoteControl/Bluetooth.js +2 -0
- package/src/iot/RemoteControl/GoogleHome.js +1 -0
- package/src/navigations/AutomateStack.js +16 -1
- package/src/navigations/UnitStack.js +27 -0
- package/src/screens/AddNewAction/Device/__test__/index.test.js +1 -1
- package/src/screens/AddNewAction/SelectAction.js +13 -15
- package/src/screens/AddNewAction/__test__/SelectAction.test.js +0 -7
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +2 -0
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +2 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +10 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +15 -0
- package/src/screens/AddNewGateway/SetupGatewayWifi.js +6 -1
- package/src/screens/AddNewGateway/__test__/SelectGateway.test.js +61 -0
- package/src/screens/AddNewGateway/__test__/SetupGateway.test.js +34 -0
- package/src/screens/AllCamera/index.js +1 -0
- package/src/screens/Automate/MultiUnits.js +9 -9
- package/src/screens/Automate/index.js +21 -20
- package/src/screens/Device/__test__/DetailHistoryChart.test.js +40 -0
- package/src/screens/Device/__test__/detail.test.js +119 -86
- package/src/screens/Device/detail.js +84 -80
- package/src/screens/Device/hooks/useFavoriteDevice.js +38 -0
- package/src/screens/EmergencyContacts/EmergencyContactsList.js +1 -1
- package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +41 -44
- package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +1 -0
- package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +18 -19
- package/src/screens/HanetCamera/Detail.js +20 -13
- package/src/screens/HanetCamera/ManageAccess.js +10 -52
- package/src/screens/HanetCamera/MemberInfo.js +59 -13
- package/src/screens/HanetCamera/__test__/ManageAccess.test.js +19 -0
- package/src/screens/HanetCamera/__test__/MemberInfo.test.js +57 -10
- package/src/screens/HanetCamera/components/RequestFaceIDPopup.js +90 -0
- package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +9 -12
- package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +10 -7
- package/src/screens/HanetCamera/styles/manageAccessStyles.js +0 -14
- package/src/screens/Notification/__test__/NotificationItem.test.js +64 -53
- package/src/screens/Notification/components/NotificationItem.js +13 -4
- package/src/screens/ScriptDetail/__test__/index.test.js +15 -4
- package/src/screens/ScriptDetail/hooks/useStarredScript.js +32 -0
- package/src/screens/ScriptDetail/index.js +11 -20
- package/src/screens/SharedUnit/__test__/TabHeader.test.js +5 -0
- package/src/screens/Sharing/SelectUser.js +3 -23
- package/src/screens/Sharing/__test__/SelectUser.test.js +12 -80
- package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +33 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +2 -0
- package/src/screens/Unit/ChooseLocation.js +5 -0
- package/src/screens/Unit/Detail.js +34 -44
- package/src/screens/Unit/ManageUnit.js +21 -20
- package/src/screens/Unit/ManageUnitStyles.js +1 -0
- package/src/screens/Unit/SelectAddress.js +8 -2
- package/src/screens/Unit/Summaries.js +12 -15
- package/src/screens/Unit/__test__/Detail.test.js +25 -0
- package/src/screens/Unit/components/MyUnitDevice/index.js +13 -10
- package/src/screens/Unit/components/__test__/Header.test.js +32 -0
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +2 -2
- package/src/screens/Unit/hook/useFavorites.js +28 -0
- package/src/utils/Apis/axios.js +7 -2
- package/src/utils/I18n/translations/en.json +2 -4
- package/src/utils/I18n/translations/vi.json +2 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, useState } from 'react';
|
|
2
2
|
import { Switch, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import { Icon } from '@ant-design/react-native';
|
|
3
4
|
import DateTimePickerModal from 'react-native-modal-datetime-picker';
|
|
4
5
|
import moment from 'moment';
|
|
5
6
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
@@ -167,18 +168,21 @@ const TimerActionTemplate = ({ actionGroup, doAction, sensor }) => {
|
|
|
167
168
|
<TouchableOpacity style={styles.timerButton} onPress={onShowTimer}>
|
|
168
169
|
<View style={styles.timerTitle}>
|
|
169
170
|
<Text>{title}</Text>
|
|
170
|
-
{
|
|
171
|
-
<
|
|
172
|
-
{
|
|
173
|
-
|
|
171
|
+
{configuration.config_hour && configuration.config_minute && (
|
|
172
|
+
<View style={styles.wrapTimer}>
|
|
173
|
+
<Icon style={styles.iconClockCircle} name={'clock-circle'} />
|
|
174
|
+
<Text type="Label" color={Colors.Gray7}>
|
|
175
|
+
{textTimer ? textTimer : t('set_time')}
|
|
176
|
+
</Text>
|
|
177
|
+
</View>
|
|
174
178
|
)}
|
|
175
179
|
</View>
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</
|
|
181
|
-
|
|
180
|
+
{configuration.config_hour && !configuration.config_minute && (
|
|
181
|
+
<View style={styles.timerButton}>
|
|
182
|
+
<Text style={styles.textTimerEndLine}>{textTimer}</Text>
|
|
183
|
+
<IconOutline name="right" size={20} />
|
|
184
|
+
</View>
|
|
185
|
+
)}
|
|
182
186
|
</TouchableOpacity>
|
|
183
187
|
{configuration.config_hour && configuration.config_minute && (
|
|
184
188
|
<Switch
|
|
@@ -24,4 +24,16 @@ export default StyleSheet.create({
|
|
|
24
24
|
flex: 1,
|
|
25
25
|
justifyContent: 'center',
|
|
26
26
|
},
|
|
27
|
+
wrapTimer: {
|
|
28
|
+
paddingTop: 10,
|
|
29
|
+
flexDirection: 'row',
|
|
30
|
+
},
|
|
31
|
+
iconClockCircle: {
|
|
32
|
+
fontSize: 16,
|
|
33
|
+
color: Colors.Black,
|
|
34
|
+
paddingRight: 15,
|
|
35
|
+
},
|
|
36
|
+
textTimerEndLine: {
|
|
37
|
+
paddingRight: 10,
|
|
38
|
+
},
|
|
27
39
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors } from '../../../configs';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
wrap: {
|
|
6
|
+
paddingVertical: 16,
|
|
7
|
+
paddingHorizontal: 16,
|
|
8
|
+
marginHorizontal: 20,
|
|
9
|
+
marginTop: 20,
|
|
10
|
+
flex: 1,
|
|
11
|
+
flexDirection: 'row',
|
|
12
|
+
justifyContent: 'center',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
},
|
|
15
|
+
bigCircle: {
|
|
16
|
+
backgroundColor: Colors.Gray2,
|
|
17
|
+
width: 160,
|
|
18
|
+
height: 160,
|
|
19
|
+
borderRadius: 200,
|
|
20
|
+
justifyContent: 'center',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
margin: 10,
|
|
23
|
+
|
|
24
|
+
shadowColor: Colors.Gray11,
|
|
25
|
+
shadowOffset: {
|
|
26
|
+
width: 0,
|
|
27
|
+
height: 8,
|
|
28
|
+
},
|
|
29
|
+
shadowOpacity: 1,
|
|
30
|
+
shadowRadius: 12,
|
|
31
|
+
elevation: 5,
|
|
32
|
+
},
|
|
33
|
+
smallCircle: {
|
|
34
|
+
backgroundColor: Colors.White,
|
|
35
|
+
width: 130,
|
|
36
|
+
height: 130,
|
|
37
|
+
borderRadius: 200,
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
|
|
41
|
+
shadowColor: Colors.Black,
|
|
42
|
+
shadowOffset: {
|
|
43
|
+
width: 0,
|
|
44
|
+
height: 4,
|
|
45
|
+
},
|
|
46
|
+
shadowOpacity: 0.15,
|
|
47
|
+
shadowRadius: 12,
|
|
48
|
+
elevation: 2,
|
|
49
|
+
},
|
|
50
|
+
textBig: {
|
|
51
|
+
marginTop: 18,
|
|
52
|
+
fontSize: 16,
|
|
53
|
+
color: Colors.Gray8,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Icon } from '@ant-design/react-native';
|
|
2
|
+
import React, { memo, useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { Colors } from '../../../configs';
|
|
6
|
+
import { DEVICE_TYPE, TESTID } from '../../../configs/Constants';
|
|
7
|
+
import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
8
|
+
import { useConfigGlobalState } from '../../../iot/states';
|
|
9
|
+
import Text from '../../Text';
|
|
10
|
+
import styles from './TwoButtonTemplateStyles';
|
|
11
|
+
|
|
12
|
+
const TwoButtonTemplate = memo(({ actionGroup, doAction, sensor }) => {
|
|
13
|
+
const { configuration } = actionGroup;
|
|
14
|
+
const { button1, button2 } = configuration;
|
|
15
|
+
const [isOn, setIsOn] = useState(true);
|
|
16
|
+
const [isStart, setIsStart] = useState(true);
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
const [configValues] = useConfigGlobalState('configValues');
|
|
19
|
+
const isLight = false;
|
|
20
|
+
|
|
21
|
+
const actionName = useCallback(
|
|
22
|
+
(text) => {
|
|
23
|
+
const actionNameType = `${
|
|
24
|
+
sensor?.name
|
|
25
|
+
} ${actionGroup?.title?.toLowerCase()} ${text}`;
|
|
26
|
+
return actionNameType.replace(/\s+/g, ' ').trim();
|
|
27
|
+
},
|
|
28
|
+
[actionGroup?.title, sensor?.name]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const triggerAction1 = useCallback(() => {
|
|
32
|
+
if (button1?.action_on_data && button1?.action_off_data) {
|
|
33
|
+
if (isOn) {
|
|
34
|
+
doAction(button1?.action_off_data, null, actionName('off'));
|
|
35
|
+
} else {
|
|
36
|
+
doAction(button1?.action_on_data, null, actionName('on'));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (sensor?.is_managed_by_backend) {
|
|
40
|
+
configuration.config && watchMultiConfigs([configuration.config]);
|
|
41
|
+
}
|
|
42
|
+
}, [
|
|
43
|
+
actionName,
|
|
44
|
+
button1,
|
|
45
|
+
configuration.config,
|
|
46
|
+
doAction,
|
|
47
|
+
isOn,
|
|
48
|
+
sensor?.is_managed_by_backend,
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
const triggerAction2 = useCallback(() => {
|
|
52
|
+
if (button2?.action_on_data && button2?.action_off_data) {
|
|
53
|
+
if (isStart) {
|
|
54
|
+
doAction(button2?.action_off_data, null, actionName('stop'));
|
|
55
|
+
} else {
|
|
56
|
+
doAction(button2?.action_on_data, null, actionName('start'));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (sensor?.is_managed_by_backend) {
|
|
60
|
+
configuration.config && watchMultiConfigs([configuration.config]);
|
|
61
|
+
}
|
|
62
|
+
}, [
|
|
63
|
+
actionName,
|
|
64
|
+
button2?.action_off_data,
|
|
65
|
+
button2?.action_on_data,
|
|
66
|
+
configuration.config,
|
|
67
|
+
doAction,
|
|
68
|
+
isStart,
|
|
69
|
+
sensor?.is_managed_by_backend,
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const configValue1 = configValues[button1?.config];
|
|
74
|
+
const configValue2 = configValues[button2?.config];
|
|
75
|
+
if (button1?.is_on_value && button1?.is_on_value.length > 0) {
|
|
76
|
+
setIsOn(button1?.is_on_value.includes(configValue1));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (button2?.is_on_value && button2?.is_on_value.length > 0) {
|
|
80
|
+
setIsStart(button2?.is_on_value.includes(configValue2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setIsOn(configValue1);
|
|
85
|
+
setIsStart(configValue2);
|
|
86
|
+
}, [
|
|
87
|
+
configuration.config,
|
|
88
|
+
configValues,
|
|
89
|
+
configuration.is_on_value,
|
|
90
|
+
configuration,
|
|
91
|
+
button1?.config,
|
|
92
|
+
button1?.is_on_value,
|
|
93
|
+
button2?.config,
|
|
94
|
+
button2?.is_on_value,
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (sensor?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (sensor?.is_managed_by_backend) {
|
|
102
|
+
watchMultiConfigs([configuration.config]);
|
|
103
|
+
}
|
|
104
|
+
}, [sensor, configuration.config]);
|
|
105
|
+
|
|
106
|
+
const RenderTwoButtonAction = () => {
|
|
107
|
+
const buttons = [
|
|
108
|
+
{
|
|
109
|
+
icon_on: button1?.icon_on,
|
|
110
|
+
icon_off: button1?.icon_off,
|
|
111
|
+
text_on: button1?.text_on,
|
|
112
|
+
text_off: button1?.text_off,
|
|
113
|
+
onPress: triggerAction1,
|
|
114
|
+
isCheckOnOff: isOn,
|
|
115
|
+
testID: TESTID.BUTTON_TEMPLATE_1,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
icon_on: button2?.icon_on,
|
|
119
|
+
icon_off: button2?.icon_off,
|
|
120
|
+
text_on: button2?.text_on,
|
|
121
|
+
text_off: button2?.text_off,
|
|
122
|
+
onPress: triggerAction2,
|
|
123
|
+
isCheckOnOff: isStart,
|
|
124
|
+
testID: TESTID.BUTTON_TEMPLATE_1,
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
return (
|
|
128
|
+
<>
|
|
129
|
+
{buttons.map((item, index) => (
|
|
130
|
+
<TouchableOpacity
|
|
131
|
+
testID={item.testID}
|
|
132
|
+
style={styles.bigCircle}
|
|
133
|
+
onPress={item.onPress}
|
|
134
|
+
>
|
|
135
|
+
<View style={styles.smallCircle}>
|
|
136
|
+
<Icon
|
|
137
|
+
name={item?.isCheckOnOff ? item?.icon_on : item?.icon_off}
|
|
138
|
+
size={44}
|
|
139
|
+
color={item?.isCheckOnOff ? Colors.Green7 : Colors.Gray6}
|
|
140
|
+
/>
|
|
141
|
+
<Text
|
|
142
|
+
style={[
|
|
143
|
+
styles.textBig,
|
|
144
|
+
{ color: item?.isCheckOnOff ? Colors.Gray8 : Colors.Gray6 },
|
|
145
|
+
]}
|
|
146
|
+
>
|
|
147
|
+
{item?.isCheckOnOff ? item?.text_on : item?.text_off}
|
|
148
|
+
</Text>
|
|
149
|
+
</View>
|
|
150
|
+
</TouchableOpacity>
|
|
151
|
+
))}
|
|
152
|
+
</>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<>
|
|
158
|
+
<View style={styles.wrap}>
|
|
159
|
+
<RenderTwoButtonAction />
|
|
160
|
+
</View>
|
|
161
|
+
{!!actionGroup.title && !isLight && (
|
|
162
|
+
<Text size={20} semibold center>
|
|
163
|
+
{actionGroup.title}
|
|
164
|
+
</Text>
|
|
165
|
+
)}
|
|
166
|
+
</>
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
export default TwoButtonTemplate;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import ColorPickerTemplate from '../ColorPickerTemplate';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
import { useConfigGlobalState } from '../../../iot/states';
|
|
8
|
+
import ColorPicker from 'react-native-wheel-color-picker';
|
|
9
|
+
|
|
10
|
+
jest.mock('../../../iot/Monitor');
|
|
11
|
+
const mockDoAction = jest.fn();
|
|
12
|
+
jest.mock('../../../iot/states', () => ({
|
|
13
|
+
useConfigGlobalState: jest.fn(),
|
|
14
|
+
}));
|
|
15
|
+
const mockSetState = jest.fn();
|
|
16
|
+
jest.mock('react', () => {
|
|
17
|
+
return {
|
|
18
|
+
...jest.requireActual('react'),
|
|
19
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
20
|
+
memo: (x) => x,
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
const wrapComponent = (actionGroup, doAction, sensor) => (
|
|
24
|
+
<SCProvider initState={mockSCStore({})}>
|
|
25
|
+
<ColorPickerTemplate
|
|
26
|
+
actionGroup={actionGroup}
|
|
27
|
+
doAction={doAction}
|
|
28
|
+
sensor={sensor}
|
|
29
|
+
/>
|
|
30
|
+
</SCProvider>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
describe('Test ColorPickerTemplate', () => {
|
|
34
|
+
let wrapper;
|
|
35
|
+
let actionGroup;
|
|
36
|
+
|
|
37
|
+
const action_color_data = {
|
|
38
|
+
color: '#00979D',
|
|
39
|
+
command_prefer_over_bluetooth: false,
|
|
40
|
+
command_prefer_over_googlehome: false,
|
|
41
|
+
command_prefer_over_internet: true,
|
|
42
|
+
googlehome_actions: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
watchMultiConfigs.mockClear();
|
|
47
|
+
mockDoAction.mockClear();
|
|
48
|
+
actionGroup = {
|
|
49
|
+
template: 'ColorPickerTemplate',
|
|
50
|
+
configuration: {
|
|
51
|
+
config: 5,
|
|
52
|
+
action_color_data: action_color_data,
|
|
53
|
+
},
|
|
54
|
+
title: '',
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('render template ColorPickerTemplate', async () => {
|
|
59
|
+
useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
|
|
60
|
+
const sensor = {
|
|
61
|
+
is_managed_by_backend: true,
|
|
62
|
+
name: 'Sensor',
|
|
63
|
+
};
|
|
64
|
+
await act(async () => {
|
|
65
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
66
|
+
});
|
|
67
|
+
const instance = wrapper.root;
|
|
68
|
+
const picker = instance.findAllByType(ColorPicker);
|
|
69
|
+
expect(picker).toHaveLength(1);
|
|
70
|
+
await act(async () => {
|
|
71
|
+
await picker[0].props.onColorChangeComplete();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { TESTID } from '../../../configs/Constants';
|
|
2
|
+
import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { act, create } from 'react-test-renderer';
|
|
5
|
+
import OnOffSmartLock from '../OnOffSmartLock/OnOffSmartLock';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
import { useConfigGlobalState } from '../../../iot/states';
|
|
9
|
+
|
|
10
|
+
jest.mock('../../../iot/Monitor');
|
|
11
|
+
const mockDoAction = jest.fn();
|
|
12
|
+
jest.mock('../../../iot/states', () => ({
|
|
13
|
+
useConfigGlobalState: jest.fn(),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const wrapComponent = (actionGroup, doAction, sensor) => (
|
|
17
|
+
<SCProvider initState={mockSCStore({})}>
|
|
18
|
+
<OnOffSmartLock
|
|
19
|
+
actionGroup={actionGroup}
|
|
20
|
+
doAction={doAction}
|
|
21
|
+
sensor={sensor}
|
|
22
|
+
/>
|
|
23
|
+
</SCProvider>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
describe('Test OnOffTemplate', () => {
|
|
27
|
+
let wrapper;
|
|
28
|
+
let actionGroup;
|
|
29
|
+
|
|
30
|
+
const action_on_data = {
|
|
31
|
+
color: '#00979D',
|
|
32
|
+
command_prefer_over_bluetooth: true,
|
|
33
|
+
command_prefer_over_googlehome: false,
|
|
34
|
+
command_prefer_over_internet: false,
|
|
35
|
+
googlehome_actions: [],
|
|
36
|
+
icon: 'caret-up',
|
|
37
|
+
id: 20,
|
|
38
|
+
key: 'key-2',
|
|
39
|
+
};
|
|
40
|
+
const action_off_data = {
|
|
41
|
+
color: '#00979D',
|
|
42
|
+
command_prefer_over_bluetooth: true,
|
|
43
|
+
command_prefer_over_googlehome: false,
|
|
44
|
+
command_prefer_over_internet: false,
|
|
45
|
+
googlehome_actions: [],
|
|
46
|
+
icon: 'caret-up',
|
|
47
|
+
id: 20,
|
|
48
|
+
key: 'key-3',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
watchMultiConfigs.mockClear();
|
|
53
|
+
mockDoAction.mockClear();
|
|
54
|
+
actionGroup = {
|
|
55
|
+
template: 'OnOffSmartLockActionTemplate',
|
|
56
|
+
configuration: {
|
|
57
|
+
config: 5,
|
|
58
|
+
action_on_data: action_on_data,
|
|
59
|
+
action_off_data: action_off_data,
|
|
60
|
+
icon: 'up',
|
|
61
|
+
is_on_value: '2',
|
|
62
|
+
},
|
|
63
|
+
title: 'smartlock',
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('render with template OnOffSmartLockActionTemplate doAction lock', async () => {
|
|
68
|
+
useConfigGlobalState.mockImplementation(() => [{ 5: 2 }, jest.fn()]);
|
|
69
|
+
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
70
|
+
await act(async () => {
|
|
71
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
72
|
+
});
|
|
73
|
+
const instance = wrapper.root;
|
|
74
|
+
const button = instance.find(
|
|
75
|
+
(el) => el.props.testID === TESTID.BUTTON_ON_OFF
|
|
76
|
+
);
|
|
77
|
+
await act(async () => {
|
|
78
|
+
await button.props.onPress();
|
|
79
|
+
});
|
|
80
|
+
expect(mockDoAction).toBeCalledWith(
|
|
81
|
+
action_on_data,
|
|
82
|
+
'{"door_lock":0}',
|
|
83
|
+
'Sensor smartlock lock'
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('render with template OnOffSmartLockActionTemplate doAction unlock', async () => {
|
|
88
|
+
actionGroup.configuration.is_on_value = null;
|
|
89
|
+
const sensor = { is_managed_by_backend: false, name: 'Sensor' };
|
|
90
|
+
useConfigGlobalState.mockImplementation(() => [{ 5: 0 }, jest.fn()]);
|
|
91
|
+
await act(async () => {
|
|
92
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
93
|
+
});
|
|
94
|
+
const instance = wrapper.root;
|
|
95
|
+
const button = instance.find(
|
|
96
|
+
(el) => el.props.testID === TESTID.BUTTON_ON_OFF
|
|
97
|
+
);
|
|
98
|
+
await act(async () => {
|
|
99
|
+
await button.props.onPress();
|
|
100
|
+
});
|
|
101
|
+
expect(mockDoAction).toBeCalledWith(
|
|
102
|
+
action_off_data,
|
|
103
|
+
'{"door_lock":1}',
|
|
104
|
+
'Sensor smartlock unlock'
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import SliderRangeTemplate from '../SliderRangeTemplate';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
import { useConfigGlobalState } from '../../../iot/states';
|
|
8
|
+
import SliderRange from 'react-native-slider';
|
|
9
|
+
|
|
10
|
+
jest.mock('../../../iot/Monitor');
|
|
11
|
+
const mockDoAction = jest.fn();
|
|
12
|
+
jest.mock('../../../iot/states', () => ({
|
|
13
|
+
useConfigGlobalState: jest.fn(),
|
|
14
|
+
}));
|
|
15
|
+
const mockSetState = jest.fn();
|
|
16
|
+
jest.mock('react', () => {
|
|
17
|
+
return {
|
|
18
|
+
...jest.requireActual('react'),
|
|
19
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
20
|
+
memo: (x) => x,
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
const wrapComponent = (actionGroup, doAction, sensor) => (
|
|
24
|
+
<SCProvider initState={mockSCStore({})}>
|
|
25
|
+
<SliderRangeTemplate
|
|
26
|
+
actionGroup={actionGroup}
|
|
27
|
+
doAction={doAction}
|
|
28
|
+
sensor={sensor}
|
|
29
|
+
/>
|
|
30
|
+
</SCProvider>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
describe('Test SliderRangeTemplate', () => {
|
|
34
|
+
let wrapper;
|
|
35
|
+
let actionGroup;
|
|
36
|
+
|
|
37
|
+
const action_brightness_data = {
|
|
38
|
+
color: '#00979D',
|
|
39
|
+
command_prefer_over_bluetooth: false,
|
|
40
|
+
command_prefer_over_googlehome: false,
|
|
41
|
+
command_prefer_over_internet: true,
|
|
42
|
+
googlehome_actions: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
watchMultiConfigs.mockClear();
|
|
47
|
+
mockDoAction.mockClear();
|
|
48
|
+
actionGroup = {
|
|
49
|
+
template: 'ColorPickerTemplate',
|
|
50
|
+
configuration: {
|
|
51
|
+
config: 5,
|
|
52
|
+
action_brightness_data: action_brightness_data,
|
|
53
|
+
},
|
|
54
|
+
title: '',
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('render template SliderRangeTemplate', async () => {
|
|
59
|
+
useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
|
|
60
|
+
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
61
|
+
await act(async () => {
|
|
62
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
63
|
+
});
|
|
64
|
+
const instance = wrapper.root;
|
|
65
|
+
const silderRange = instance.findAllByType(SliderRange);
|
|
66
|
+
expect(silderRange).toHaveLength(1);
|
|
67
|
+
await act(async () => {
|
|
68
|
+
await silderRange[0].props.onSlidingComplete();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -60,7 +60,7 @@ describe('Test TimerActionTemplate success with config value', () => {
|
|
|
60
60
|
const instance = wrapper.root;
|
|
61
61
|
|
|
62
62
|
const texts = instance.findAllByType(Text);
|
|
63
|
-
expect(texts).toHaveLength(
|
|
63
|
+
expect(texts).toHaveLength(7);
|
|
64
64
|
expect(texts[0].props.children).toEqual('Timer');
|
|
65
65
|
expect(texts[1].props.children).toEqual('Setting at 18:30');
|
|
66
66
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
3
|
+
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import TwoButtonTemplate from '../TwoButtonTemplate';
|
|
5
|
+
|
|
6
|
+
jest.mock('react', () => ({
|
|
7
|
+
...jest.requireActual('react'),
|
|
8
|
+
useState: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe('Test TwoButtonTemplate', () => {
|
|
12
|
+
const action_on_data = {
|
|
13
|
+
color: '#00979D',
|
|
14
|
+
command_prefer_over_bluetooth: true,
|
|
15
|
+
command_prefer_over_googlehome: false,
|
|
16
|
+
command_prefer_over_internet: false,
|
|
17
|
+
googlehome_actions: [],
|
|
18
|
+
icon: 'caret-up',
|
|
19
|
+
id: 20,
|
|
20
|
+
key: '5ed1d4dc-a905-47cd-b0c9-f979644bd21a',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const action_off_data = {
|
|
24
|
+
color: '#00979D',
|
|
25
|
+
command_prefer_over_bluetooth: true,
|
|
26
|
+
command_prefer_over_googlehome: false,
|
|
27
|
+
command_prefer_over_internet: false,
|
|
28
|
+
googlehome_actions: [],
|
|
29
|
+
icon: 'caret-up',
|
|
30
|
+
id: 20,
|
|
31
|
+
key: '5ed1d4dc-a905-47cd-b0c9-f979644bd21a',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const actionGroup = {
|
|
35
|
+
configuration: {
|
|
36
|
+
button1: {
|
|
37
|
+
action_off: 'f49e1577-493d-4bae-a9ab-3b0f96a4ec52',
|
|
38
|
+
icon_off: 'poweroff',
|
|
39
|
+
text_off: 'OFF',
|
|
40
|
+
action_on: '94600cbe-2035-47d5-bd43-89ace5d59796',
|
|
41
|
+
icon_on: 'poweroff',
|
|
42
|
+
text_on: 'ON',
|
|
43
|
+
config: 621,
|
|
44
|
+
},
|
|
45
|
+
button2: {
|
|
46
|
+
action_off: 'f49e1577-493d-4bae-a9ab-3b0f96a4ec52',
|
|
47
|
+
icon_off: 'caret-right',
|
|
48
|
+
text_off: 'STOP',
|
|
49
|
+
action_on: '94600cbe-2035-47d5-bd43-89ace5d59796',
|
|
50
|
+
icon_on: 'caret-right',
|
|
51
|
+
text_on: 'START',
|
|
52
|
+
config: 621,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
let wrapper;
|
|
57
|
+
|
|
58
|
+
const setState = jest.fn();
|
|
59
|
+
useState.mockImplementation((init) => [init, setState]);
|
|
60
|
+
|
|
61
|
+
const assertRender = (state, text) => {
|
|
62
|
+
useState.mockImplementationOnce((init) => [state, setState]);
|
|
63
|
+
const mockDoAction = jest.fn();
|
|
64
|
+
act(() => {
|
|
65
|
+
wrapper = create(
|
|
66
|
+
<TwoButtonTemplate actionGroup={actionGroup} doAction={mockDoAction} />
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const renderJson = wrapper.toJSON();
|
|
71
|
+
|
|
72
|
+
expect(renderJson?.children[0].children[0].children[1].children).toEqual([
|
|
73
|
+
'OFF',
|
|
74
|
+
]);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
test('render state on', () => {
|
|
78
|
+
assertRender(false, 'OFF');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const assertActionCall = (state, action_data) => {
|
|
82
|
+
useState.mockImplementationOnce((init) => [state, setState]);
|
|
83
|
+
const mockDoAction = jest.fn();
|
|
84
|
+
act(() => {
|
|
85
|
+
wrapper = create(
|
|
86
|
+
<TwoButtonTemplate actionGroup={actionGroup} doAction={mockDoAction} />
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(mockDoAction).not.toHaveBeenCalled();
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
test('action state on', () => {
|
|
94
|
+
assertActionCall(true, action_off_data);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('action state off', () => {
|
|
98
|
+
assertActionCall(false, action_on_data);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('render TouchableOpacity TwoButtonTemplate', async () => {
|
|
102
|
+
const mockDoAction = jest.fn();
|
|
103
|
+
await act(() => {
|
|
104
|
+
wrapper = create(
|
|
105
|
+
<TwoButtonTemplate actionGroup={actionGroup} doAction={mockDoAction} />
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
const instance = wrapper.root;
|
|
109
|
+
const touchableOpacities = instance.findAllByType(TouchableOpacity);
|
|
110
|
+
expect(touchableOpacities.length).toEqual(2);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -13,6 +13,7 @@ import SmartTiviActionTemplate from './SmartTiviActionTemplate/SmartTiviActionTe
|
|
|
13
13
|
import ColorPickerTemplate from './ColorPickerTemplate';
|
|
14
14
|
import SliderRangeTemplate from './SliderRangeTemplate';
|
|
15
15
|
import OnOffSmartLock from './OnOffSmartLock/OnOffSmartLock';
|
|
16
|
+
import TwoButtonTemplate from './TwoButtonTemplate';
|
|
16
17
|
|
|
17
18
|
export const getActionComponent = (template) => {
|
|
18
19
|
switch (template) {
|
|
@@ -23,7 +24,7 @@ export const getActionComponent = (template) => {
|
|
|
23
24
|
case 'OnOffButtonActionTemplate':
|
|
24
25
|
case 'OnOffSimpleActionTemplate':
|
|
25
26
|
return OnOffTemplate;
|
|
26
|
-
case '
|
|
27
|
+
case 'OnOffSmartLockActionTemplate':
|
|
27
28
|
return OnOffSmartLock;
|
|
28
29
|
case 'one_button_action_template': // todo refactor later with backend
|
|
29
30
|
case 'OneBigButtonActionTemplate':
|
|
@@ -44,6 +45,8 @@ export const getActionComponent = (template) => {
|
|
|
44
45
|
return ColorPickerTemplate;
|
|
45
46
|
case 'slider_range_template':
|
|
46
47
|
return SliderRangeTemplate;
|
|
48
|
+
case 'two_button_action_template':
|
|
49
|
+
return TwoButtonTemplate;
|
|
47
50
|
default:
|
|
48
51
|
return null;
|
|
49
52
|
}
|