@eohjsc/react-native-smart-city 0.4.59 → 0.4.61
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 -2
- package/src/commons/Action/ItemQuickAction.js +1 -1
- package/src/commons/Action/__test__/ItemQuickAction.test.js +22 -8
- package/src/commons/Automate/ItemAutomate.js +4 -9
- package/src/commons/Button/index.js +4 -2
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +49 -36
- package/src/commons/Grid/GridItem.js +20 -0
- package/src/commons/Grid/GridItemStyles.js +32 -0
- package/src/configs/API.js +0 -2
- package/src/configs/Constants.js +0 -1
- package/src/context/actionType.ts +1 -0
- package/src/context/reducer.ts +19 -1
- package/src/screens/Automate/AddNewAction/ChooseAction.js +0 -2
- package/src/screens/Automate/AddNewAction/ChooseConfig.js +46 -161
- package/src/screens/Automate/AddNewAction/Components/SelectDevices.js +2 -6
- package/src/screens/Automate/AddNewAction/NewActionWrapper.js +10 -6
- package/src/screens/Automate/AddNewAction/SelectMonitorDevices.js +1 -0
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +143 -173
- package/src/screens/Automate/AddNewAction/Styles/SelectActionStyles.js +8 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupSensorStyles.js +29 -62
- package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +77 -9
- package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +23 -83
- package/src/screens/Automate/AddNewAction/__test__/SelectControlDevices.test.js +2 -19
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +125 -94
- package/src/screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart.js +0 -4
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +24 -27
- package/src/screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart.js +0 -4
- package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +1 -21
- package/src/screens/Automate/ScriptDetail/utils.js +42 -19
- package/src/screens/Automate/index.js +2 -4
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +9 -0
- package/src/screens/Device/components/SensorDisplayItem.js +3 -0
- package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +1 -1
- package/src/screens/Device/hooks/useEvaluateValue.js +10 -6
- package/src/screens/Notification/__test__/Notification.test.js +10 -0
- package/src/screens/Unit/__test__/AddMenu.test.js +76 -0
- package/src/screens/WaterQualityGuide/__test__/index.test.js +0 -5
- package/src/utils/I18n/translations/en.js +2 -0
- package/src/utils/I18n/translations/vi.js +2 -0
- package/src/utils/Route/index.js +5 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eohjsc/react-native-smart-city",
|
|
3
3
|
"title": "React Native Smart Home",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.61",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"android-deploy-test": "bundle exec fastlane android beta",
|
|
38
38
|
"reset-cache": "react-native start --reset-cache",
|
|
39
39
|
"merge_conflict": "yarn jest && yarn update_coverage_result && yarn check_coverage_config",
|
|
40
|
-
"jest": "jest --detectOpenHandles",
|
|
41
40
|
"jest1": "jest --detectOpenHandles --coverage=0",
|
|
42
41
|
"example": "yarn --cwd example",
|
|
43
42
|
"pods": "cd example && pod-install --quiet",
|
|
@@ -18,7 +18,7 @@ const ItemQuickAction = memo(
|
|
|
18
18
|
interval,
|
|
19
19
|
will_auto_update_status,
|
|
20
20
|
} = quick_action || {};
|
|
21
|
-
const [action, setAction] = useState(sensor
|
|
21
|
+
const [action, setAction] = useState(sensor?.action);
|
|
22
22
|
// eslint-disable-next-line no-unused-vars
|
|
23
23
|
const [configValues, _] = useConfigGlobalState('configValues');
|
|
24
24
|
const [isOn, setIsOn] = useState(false);
|
|
@@ -8,7 +8,6 @@ import { factory } from 'factory-girl';
|
|
|
8
8
|
import IconComponent from '../../IconComponent';
|
|
9
9
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
10
10
|
import Toast from 'react-native-toast-message';
|
|
11
|
-
|
|
12
11
|
class Sensor {}
|
|
13
12
|
|
|
14
13
|
factory.define('Sensor', Sensor, {});
|
|
@@ -63,21 +62,17 @@ describe('Test ItemQuickAction', () => {
|
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
it('render with no action', async () => {
|
|
66
|
-
const newSensor = await factory.build('Sensor');
|
|
67
65
|
await act(async () => {
|
|
68
|
-
tree = await create(<ItemQuickAction
|
|
66
|
+
tree = await create(<ItemQuickAction />);
|
|
69
67
|
});
|
|
70
68
|
const instance = tree.root;
|
|
71
|
-
const buttonOnActionPress = instance.
|
|
69
|
+
const buttonOnActionPress = instance.findAll(
|
|
72
70
|
(el) =>
|
|
73
71
|
el.props.accessibilityLabel ===
|
|
74
72
|
`${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
|
|
75
73
|
el.type === TouchableOpacity
|
|
76
74
|
);
|
|
77
|
-
|
|
78
|
-
await buttonOnActionPress.props.onPress();
|
|
79
|
-
});
|
|
80
|
-
expect(Toast.show).not.toBeCalled();
|
|
75
|
+
expect(buttonOnActionPress).toHaveLength(0);
|
|
81
76
|
});
|
|
82
77
|
|
|
83
78
|
it('click quick action icon down , isSendingCommand = true', async () => {
|
|
@@ -244,4 +239,23 @@ describe('Test ItemQuickAction', () => {
|
|
|
244
239
|
expect(icon.props.icon).toEqual(sensor.quick_action.off_action.icon);
|
|
245
240
|
expect(icon.props.icon).not.toEqual(sensor.quick_action.on_action.icon);
|
|
246
241
|
};
|
|
242
|
+
it('render quick action only show status can not control', async () => {
|
|
243
|
+
sensor.quick_action.off_action = null;
|
|
244
|
+
sensor.quick_action.on_action = null;
|
|
245
|
+
|
|
246
|
+
await act(async () => {
|
|
247
|
+
tree = await create(<ItemQuickAction sensor={sensor} />);
|
|
248
|
+
});
|
|
249
|
+
const instance = tree.root;
|
|
250
|
+
const buttonOnActionPress = instance.find(
|
|
251
|
+
(el) =>
|
|
252
|
+
el.props.accessibilityLabel ===
|
|
253
|
+
`${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
|
|
254
|
+
el.type === TouchableOpacity
|
|
255
|
+
);
|
|
256
|
+
await act(async () => {
|
|
257
|
+
await buttonOnActionPress.props.onPress();
|
|
258
|
+
});
|
|
259
|
+
expect(Toast.show).not.toBeCalled();
|
|
260
|
+
});
|
|
247
261
|
});
|
|
@@ -20,11 +20,11 @@ const ItemAutomate = ({
|
|
|
20
20
|
const item = AUTOMATES[automate?.type];
|
|
21
21
|
const isItemOneTap = AUTOMATES[automate?.type] === AUTOMATES.one_tap;
|
|
22
22
|
const Icon = item?.icon;
|
|
23
|
-
const
|
|
23
|
+
const valueEvaluations = useGetEvaluateValue(automate?.config, automate.unit);
|
|
24
24
|
|
|
25
25
|
const textCondition = useMemo(() => {
|
|
26
|
-
return generateAutomationConditionText(automate,
|
|
27
|
-
}, [automate, t,
|
|
26
|
+
return generateAutomationConditionText(automate, valueEvaluations, t);
|
|
27
|
+
}, [automate, t, valueEvaluations]);
|
|
28
28
|
|
|
29
29
|
const renderText = useMemo(() => {
|
|
30
30
|
if (textCondition) {
|
|
@@ -45,12 +45,7 @@ const ItemAutomate = ({
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
setSelectedIndex(
|
|
49
|
-
if (currentIndex !== index) {
|
|
50
|
-
return index;
|
|
51
|
-
}
|
|
52
|
-
return -1;
|
|
53
|
-
});
|
|
48
|
+
setSelectedIndex(index);
|
|
54
49
|
}, [index, setSelectedIndex, onPress]);
|
|
55
50
|
|
|
56
51
|
return (
|
|
@@ -121,10 +121,10 @@ const TextSize = {
|
|
|
121
121
|
// Type
|
|
122
122
|
// auth, primary, info, cancel, disabled, disabledBorder, primaryBorder, alert, alertBorder, underline, setupBorder
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
const Button = ({
|
|
125
125
|
title,
|
|
126
126
|
onPress,
|
|
127
|
-
width,
|
|
127
|
+
width = 100,
|
|
128
128
|
height = 48,
|
|
129
129
|
activeOpacity,
|
|
130
130
|
type,
|
|
@@ -178,6 +178,8 @@ export default ({
|
|
|
178
178
|
);
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
+
export default Button;
|
|
182
|
+
|
|
181
183
|
const styles = StyleSheet.create({
|
|
182
184
|
button: {
|
|
183
185
|
width: '100%',
|
|
@@ -9,43 +9,57 @@ import IconComponent from '../../IconComponent';
|
|
|
9
9
|
import images from '../../../configs/Images';
|
|
10
10
|
import FImage from '../../FImage';
|
|
11
11
|
|
|
12
|
-
const CurrentRainSensor = memo(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
const CurrentRainSensor = memo(
|
|
13
|
+
({
|
|
14
|
+
data = [],
|
|
15
|
+
isWidgetOrder,
|
|
16
|
+
size = 180,
|
|
17
|
+
textType = 'H2',
|
|
18
|
+
iconSize = 30,
|
|
19
|
+
}) => {
|
|
20
|
+
const item = data.length
|
|
21
|
+
? data[0]
|
|
22
|
+
: {
|
|
23
|
+
evaluate: {},
|
|
24
|
+
};
|
|
25
|
+
const { text, backgroundColor, borderColor, icon, icon_kit_data } =
|
|
26
|
+
item.evaluate || {};
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/>
|
|
36
|
-
{icon_kit_data?.icon || icon ? (
|
|
37
|
-
<IconComponent icon={icon_kit_data?.icon || icon} />
|
|
38
|
-
) : (
|
|
39
|
-
<FImage
|
|
40
|
-
source={images.activeCurrentSensor}
|
|
41
|
-
style={styles.iconDefault}
|
|
28
|
+
return (
|
|
29
|
+
<View style={[styles.standard, isWidgetOrder && styles.marginBottomZero]}>
|
|
30
|
+
<CircleView
|
|
31
|
+
size={size}
|
|
32
|
+
backgroundColor={backgroundColor}
|
|
33
|
+
borderWidth={2}
|
|
34
|
+
borderColor={borderColor}
|
|
35
|
+
style={styles.center}
|
|
36
|
+
>
|
|
37
|
+
<LinearGradient
|
|
38
|
+
style={styles.linearView}
|
|
39
|
+
colors={[Colors.TransparentWhite, 'white']}
|
|
40
|
+
start={{ x: 1, y: 0 }}
|
|
41
|
+
end={{ x: 1, y: 1 }}
|
|
42
42
|
/>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
{icon_kit_data?.icon || icon ? (
|
|
44
|
+
<IconComponent
|
|
45
|
+
size={iconSize}
|
|
46
|
+
iconSize={iconSize}
|
|
47
|
+
icon={icon_kit_data?.icon || icon}
|
|
48
|
+
/>
|
|
49
|
+
) : (
|
|
50
|
+
<FImage
|
|
51
|
+
source={images.activeCurrentSensor}
|
|
52
|
+
style={styles.iconDefault}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
<Text type={textType} style={styles.text}>
|
|
56
|
+
{text}
|
|
57
|
+
</Text>
|
|
58
|
+
</CircleView>
|
|
59
|
+
</View>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
49
63
|
|
|
50
64
|
export default CurrentRainSensor;
|
|
51
65
|
|
|
@@ -76,7 +90,6 @@ const styles = StyleSheet.create({
|
|
|
76
90
|
text: {
|
|
77
91
|
marginTop: 8,
|
|
78
92
|
lineHeight: 32,
|
|
79
|
-
fontSize: 24,
|
|
80
93
|
},
|
|
81
94
|
iconDefault: {
|
|
82
95
|
width: 37,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { TouchableWithoutFeedback, View } from 'react-native';
|
|
3
|
+
import styles from './GridItemStyles';
|
|
4
|
+
|
|
5
|
+
const GridItem = memo(
|
|
6
|
+
({ icon, accessibilityLabel, selected, onPress, item, children }) => {
|
|
7
|
+
const isActive = selected && styles.active;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TouchableWithoutFeedback
|
|
11
|
+
onPress={() => onPress && onPress(item)}
|
|
12
|
+
accessibilityLabel={accessibilityLabel}
|
|
13
|
+
>
|
|
14
|
+
<View style={[styles.container, isActive]}>{children}</View>
|
|
15
|
+
</TouchableWithoutFeedback>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export default GridItem;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Constants, Colors } from '../../configs';
|
|
3
|
+
|
|
4
|
+
const marginItem = 12;
|
|
5
|
+
const marginHorizontal = 16;
|
|
6
|
+
const widthItem = (Constants.width - marginHorizontal * 2 - marginItem) / 2;
|
|
7
|
+
|
|
8
|
+
export default StyleSheet.create({
|
|
9
|
+
container: {
|
|
10
|
+
padding: 12,
|
|
11
|
+
borderRadius: 10,
|
|
12
|
+
shadowColor: Colors.Shadow,
|
|
13
|
+
shadowOffset: {
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 2,
|
|
16
|
+
},
|
|
17
|
+
shadowOpacity: 0.1,
|
|
18
|
+
shadowRadius: 3,
|
|
19
|
+
elevation: 4,
|
|
20
|
+
width: widthItem,
|
|
21
|
+
backgroundColor: Colors.White,
|
|
22
|
+
justifyContent: 'space-between',
|
|
23
|
+
marginBottom: 16,
|
|
24
|
+
},
|
|
25
|
+
active: {
|
|
26
|
+
borderColor: Colors.Primary,
|
|
27
|
+
borderWidth: 2,
|
|
28
|
+
},
|
|
29
|
+
lineHeight22: {
|
|
30
|
+
lineHeight: 22,
|
|
31
|
+
},
|
|
32
|
+
});
|
package/src/configs/API.js
CHANGED
|
@@ -181,8 +181,6 @@ const API = {
|
|
|
181
181
|
SET_READ: (id) => `/notifications/eoh/${id}/set_read/`,
|
|
182
182
|
},
|
|
183
183
|
VALUE_EVALUATIONS: () => '/property_manager/config_value_evaluations/',
|
|
184
|
-
FETCH_VALUE_EVALUATION: (id) =>
|
|
185
|
-
`/property_manager/config_value_evaluations/${id}/`,
|
|
186
184
|
EXTERNAL: {
|
|
187
185
|
GOOGLE_MAP: {
|
|
188
186
|
AUTO_COMPLETE:
|
package/src/configs/Constants.js
CHANGED
|
@@ -24,6 +24,7 @@ export const Action = {
|
|
|
24
24
|
CHANGE_HOME_ASSISTANT_CONN_STATE: 'CHANGE_HOME_ASSISTANT_CONN_STATE',
|
|
25
25
|
SET_LG_THINQ_CONNECTED: 'SET_LG_THINQ_CONNECTED',
|
|
26
26
|
UPDATE_VALUE_EVALUATIONS: 'UPDATE_VALUE_EVALUATIONS',
|
|
27
|
+
INIT_VALUE_EVALUATIONS: 'INIT_VALUE_EVALUATIONS',
|
|
27
28
|
NEED_UPDATE_VALUE_EVALUATIONS: 'NEED_UPDATE_VALUE_EVALUATIONS',
|
|
28
29
|
ON_RECEIVE_NOTIFICATION: 'ON_RECEIVE_NOTIFICATION',
|
|
29
30
|
SET_DEVICES_STATUS: 'SET_DEVICES_STATUS',
|
package/src/context/reducer.ts
CHANGED
|
@@ -416,13 +416,31 @@ export const reducer = (currentState: ContextData, action: Action) => {
|
|
|
416
416
|
data,
|
|
417
417
|
(dict, item) => {
|
|
418
418
|
item.configs.map((configId) => {
|
|
419
|
-
dict[configId]
|
|
419
|
+
if (!dict[configId]) {
|
|
420
|
+
dict[configId] = [item];
|
|
421
|
+
} else {
|
|
422
|
+
dict[configId] = [...dict[configId], item];
|
|
423
|
+
}
|
|
420
424
|
});
|
|
421
425
|
return dict;
|
|
422
426
|
},
|
|
423
427
|
currentState.valueEvaluations
|
|
424
428
|
),
|
|
425
429
|
};
|
|
430
|
+
|
|
431
|
+
case Action.INIT_VALUE_EVALUATIONS:
|
|
432
|
+
// eslint-disable-next-line no-case-declarations
|
|
433
|
+
const { configId } = payload;
|
|
434
|
+
// eslint-disable-next-line no-case-declarations
|
|
435
|
+
const valueEvaluations = currentState.valueEvaluations || {};
|
|
436
|
+
if (valueEvaluations[configId] === undefined) {
|
|
437
|
+
valueEvaluations[configId] = [];
|
|
438
|
+
}
|
|
439
|
+
return {
|
|
440
|
+
...currentState,
|
|
441
|
+
valueEvaluations,
|
|
442
|
+
};
|
|
443
|
+
|
|
426
444
|
case Action.NEED_UPDATE_VALUE_EVALUATIONS:
|
|
427
445
|
return {
|
|
428
446
|
...currentState,
|
|
@@ -1,47 +1,29 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { View } from 'react-native';
|
|
3
3
|
import { useNavigation } from '@react-navigation/native';
|
|
4
4
|
|
|
5
5
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
6
6
|
import Text from '../../../commons/Text';
|
|
7
7
|
import { axiosGet } from '../../../utils/Apis/axios';
|
|
8
|
-
import { API, Colors
|
|
8
|
+
import { API, Colors } from '../../../configs';
|
|
9
9
|
import Routes from '../../../utils/Route';
|
|
10
10
|
import styles from './Styles/SelectActionStyles';
|
|
11
|
-
import { TitleCheckBox } from '../../Sharing/Components';
|
|
12
11
|
import { LoadingSelectAction } from './Components';
|
|
13
|
-
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
14
|
-
import {
|
|
15
|
-
generateAutomationConditionText,
|
|
16
|
-
generateAutomationDataConditionText,
|
|
17
|
-
} from '../ScriptDetail/utils';
|
|
18
|
-
import { useSCContextSelector } from '../../../context';
|
|
19
12
|
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
20
13
|
import NewActionWrapper from './NewActionWrapper';
|
|
14
|
+
import GridItem from '../../../commons/Grid/GridItem';
|
|
21
15
|
|
|
22
16
|
const ChooseConfig = ({ route }) => {
|
|
23
17
|
const t = useTranslations();
|
|
24
18
|
const { navigate } = useNavigation();
|
|
25
|
-
const {
|
|
26
|
-
device,
|
|
27
|
-
automate = {},
|
|
28
|
-
newCondition,
|
|
29
|
-
closeScreen,
|
|
30
|
-
} = route?.params || {};
|
|
19
|
+
const { device, automate = {}, closeScreen } = route?.params || {};
|
|
31
20
|
|
|
32
21
|
const [configs, setConfigs] = useState([]);
|
|
33
|
-
const [
|
|
22
|
+
const [selectedConfigId, setSelectedConfigId] = useState(automate?.config_id);
|
|
34
23
|
const [isLoading, setIsLoading] = useState(false);
|
|
35
|
-
const valueEvaluations = useSCContextSelector((state) => {
|
|
36
|
-
return state.valueEvaluations;
|
|
37
|
-
});
|
|
38
|
-
const [conditions, setConditions] = useState({});
|
|
39
24
|
const fetchData = useCallback(async () => {
|
|
40
25
|
setIsLoading(true);
|
|
41
26
|
const params = {};
|
|
42
|
-
if (automate?.type === AUTOMATE_TYPE.EVENT) {
|
|
43
|
-
params.type = 'event';
|
|
44
|
-
}
|
|
45
27
|
|
|
46
28
|
const { success, data: automateData } = await axiosGet(
|
|
47
29
|
API.AUTOMATE.DISPLAY_CONFIGS(device.id),
|
|
@@ -52,157 +34,60 @@ const ChooseConfig = ({ route }) => {
|
|
|
52
34
|
setConfigs(automateData);
|
|
53
35
|
}
|
|
54
36
|
setIsLoading(false);
|
|
55
|
-
}, [device.id
|
|
56
|
-
|
|
57
|
-
const onSave = useCallback(() => {
|
|
58
|
-
let condition = conditions[checkedItem?.id];
|
|
59
|
-
const isDefault =
|
|
60
|
-
automate?.config_id && automate?.config_id === checkedItem?.id;
|
|
61
|
-
if (!condition && !isDefault) {
|
|
62
|
-
ToastBottomHelper.error(t('please_choose_condition_before_continue'));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
navigate(Routes.ValueChangeName, {
|
|
67
|
-
automate: {
|
|
68
|
-
...automate,
|
|
69
|
-
...condition,
|
|
70
|
-
},
|
|
71
|
-
closeScreen,
|
|
72
|
-
});
|
|
73
|
-
}, [conditions, checkedItem?.id, navigate, automate, closeScreen, t]);
|
|
74
|
-
|
|
75
|
-
const onChecked = useCallback(
|
|
76
|
-
(_, isChecked, id) => {
|
|
77
|
-
setCheckedItem(isChecked ? configs.find((i) => i?.id === id) : {});
|
|
78
|
-
},
|
|
79
|
-
[configs]
|
|
80
|
-
);
|
|
37
|
+
}, [device.id]);
|
|
81
38
|
|
|
82
|
-
const
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
configuration: item.evaluate_configuration,
|
|
92
|
-
},
|
|
93
|
-
t
|
|
94
|
-
);
|
|
39
|
+
const goToSetupConfig = useCallback(
|
|
40
|
+
(config) => {
|
|
41
|
+
setSelectedConfigId(config?.id);
|
|
42
|
+
automate.config = config?.id;
|
|
43
|
+
navigate(Routes.SetupConfigCondition, {
|
|
44
|
+
config,
|
|
45
|
+
automate,
|
|
46
|
+
closeScreen,
|
|
47
|
+
});
|
|
95
48
|
},
|
|
96
|
-
[automate
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const renderConfigs = useCallback(
|
|
100
|
-
(configs) => {
|
|
101
|
-
const onPressItem = (item) => () => {
|
|
102
|
-
navigate(Routes.SetupConfigCondition, {
|
|
103
|
-
item,
|
|
104
|
-
defaultCondition: conditions[item.id],
|
|
105
|
-
closeScreen,
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
if (configs.length) {
|
|
109
|
-
return configs.map((item) => {
|
|
110
|
-
const hasCondition = conditions[item.id];
|
|
111
|
-
const isChecked = checkedItem?.id === item?.id;
|
|
112
|
-
const isDefault = automate?.config_id === item?.id;
|
|
113
|
-
return (
|
|
114
|
-
<View style={styles.wrapItem} key={item?.id}>
|
|
115
|
-
<TitleCheckBox
|
|
116
|
-
onPress={onChecked}
|
|
117
|
-
id={item?.id}
|
|
118
|
-
title={item?.name}
|
|
119
|
-
titleStyle={styles.titleStyle}
|
|
120
|
-
wrapStyle={styles.wrapStyleCheckBox}
|
|
121
|
-
isChecked={isChecked}
|
|
122
|
-
/>
|
|
123
|
-
<TouchableOpacity
|
|
124
|
-
onPress={onPressItem(item)}
|
|
125
|
-
style={[styles.wrapCondition, styles.shadowView]}
|
|
126
|
-
accessibilityLabel={`config-${item.id}`}
|
|
127
|
-
>
|
|
128
|
-
<Text type="Body" color={Colors.Gray7}>
|
|
129
|
-
{t('condition')}
|
|
130
|
-
</Text>
|
|
131
|
-
<Text
|
|
132
|
-
numberOfLines={1}
|
|
133
|
-
type="H4"
|
|
134
|
-
semibold={isChecked}
|
|
135
|
-
style={styles.description}
|
|
136
|
-
>
|
|
137
|
-
{hasCondition
|
|
138
|
-
? renderCondition(item)
|
|
139
|
-
: isDefault
|
|
140
|
-
? generateAutomationConditionText(
|
|
141
|
-
automate,
|
|
142
|
-
valueEvaluations[automate?.config_id],
|
|
143
|
-
t
|
|
144
|
-
)
|
|
145
|
-
: t('no_condition')}
|
|
146
|
-
</Text>
|
|
147
|
-
{hasCondition && (
|
|
148
|
-
<Image source={Images.arrowBack} style={styles.arrowRight} />
|
|
149
|
-
)}
|
|
150
|
-
</TouchableOpacity>
|
|
151
|
-
</View>
|
|
152
|
-
);
|
|
153
|
-
});
|
|
154
|
-
} else {
|
|
155
|
-
return (
|
|
156
|
-
<View style={styles.textCenter}>
|
|
157
|
-
<Text type="Body" center color={Colors.Gray7}>
|
|
158
|
-
{t('end_device_not_support_script', {
|
|
159
|
-
not_support: t(automate?.type),
|
|
160
|
-
support:
|
|
161
|
-
automate?.type === AUTOMATE_TYPE.EVENT
|
|
162
|
-
? t(AUTOMATE_TYPE.VALUE_CHANGE)
|
|
163
|
-
: t(AUTOMATE_TYPE.EVENT),
|
|
164
|
-
})}
|
|
165
|
-
</Text>
|
|
166
|
-
</View>
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
[
|
|
171
|
-
automate,
|
|
172
|
-
checkedItem?.id,
|
|
173
|
-
closeScreen,
|
|
174
|
-
conditions,
|
|
175
|
-
navigate,
|
|
176
|
-
onChecked,
|
|
177
|
-
renderCondition,
|
|
178
|
-
t,
|
|
179
|
-
valueEvaluations,
|
|
180
|
-
]
|
|
49
|
+
[automate, closeScreen, navigate]
|
|
181
50
|
);
|
|
182
51
|
|
|
183
52
|
useEffect(() => {
|
|
184
53
|
fetchData();
|
|
185
54
|
}, [fetchData]);
|
|
186
55
|
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
newCondition &&
|
|
189
|
-
setConditions((prev) => ({
|
|
190
|
-
...prev,
|
|
191
|
-
[newCondition.config]: newCondition,
|
|
192
|
-
}));
|
|
193
|
-
}, [newCondition]);
|
|
194
|
-
|
|
195
56
|
return (
|
|
196
57
|
<NewActionWrapper
|
|
197
58
|
name={t('set_up {name}', { name: device?.name })}
|
|
198
59
|
nextTitle={t('continue')}
|
|
199
|
-
onNext={onSave}
|
|
200
|
-
canNext={checkedItem?.id}
|
|
201
60
|
>
|
|
202
|
-
{isLoading
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
61
|
+
{isLoading && <LoadingSelectAction style={styles.container} />}
|
|
62
|
+
{!isLoading && !configs.length && (
|
|
63
|
+
<View style={styles.textCenter}>
|
|
64
|
+
<Text type="Body" center color={Colors.Gray7}>
|
|
65
|
+
{t('end_device_not_support_script', {
|
|
66
|
+
not_support: t(automate?.type),
|
|
67
|
+
support:
|
|
68
|
+
automate?.type === AUTOMATE_TYPE.EVENT
|
|
69
|
+
? t(AUTOMATE_TYPE.VALUE_CHANGE)
|
|
70
|
+
: t(AUTOMATE_TYPE.EVENT),
|
|
71
|
+
})}
|
|
72
|
+
</Text>
|
|
73
|
+
</View>
|
|
74
|
+
)}
|
|
75
|
+
{!isLoading && (
|
|
76
|
+
<View style={styles.boxDevices}>
|
|
77
|
+
{configs.map((config) => (
|
|
78
|
+
<GridItem
|
|
79
|
+
selected={config?.id === selectedConfigId}
|
|
80
|
+
onPress={goToSetupConfig}
|
|
81
|
+
item={config}
|
|
82
|
+
accessibilityLabel={`config-${config?.id}`}
|
|
83
|
+
key={config?.id}
|
|
84
|
+
>
|
|
85
|
+
<Text numberOfLines={1} semibold type="Body" color={Colors.Gray9}>
|
|
86
|
+
{config.name}
|
|
87
|
+
</Text>
|
|
88
|
+
</GridItem>
|
|
89
|
+
))}
|
|
90
|
+
</View>
|
|
206
91
|
)}
|
|
207
92
|
</NewActionWrapper>
|
|
208
93
|
);
|
|
@@ -30,15 +30,11 @@ const SelectDevices = ({
|
|
|
30
30
|
} else {
|
|
31
31
|
setSelectedDevice(sensor);
|
|
32
32
|
}
|
|
33
|
+
onPressContinue(sensor, indexStation);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
return (
|
|
36
|
-
<NewActionWrapper
|
|
37
|
-
nextTitle={t('continue')}
|
|
38
|
-
onNext={() => onPressContinue(selectedDevice, indexStation)}
|
|
39
|
-
canNext={Object.keys(selectedDevice || {}).length}
|
|
40
|
-
name={title}
|
|
41
|
-
>
|
|
37
|
+
<NewActionWrapper name={title}>
|
|
42
38
|
{listStation.length ? (
|
|
43
39
|
<NavBar
|
|
44
40
|
listStation={listStation}
|
|
@@ -11,6 +11,8 @@ import { AccessibilityLabel } from '../../../configs/Constants';
|
|
|
11
11
|
import { HeaderCustom } from '../../../commons';
|
|
12
12
|
|
|
13
13
|
const NewActionWrapper = ({ name, children, canNext, onNext, nextTitle }) => {
|
|
14
|
+
const hasNext =
|
|
15
|
+
canNext !== undefined || onNext !== undefined || nextTitle !== undefined;
|
|
14
16
|
const { navigate } = useNavigation();
|
|
15
17
|
const { params = {} } = useRoute();
|
|
16
18
|
const { closeScreen } = params;
|
|
@@ -42,12 +44,14 @@ const NewActionWrapper = ({ name, children, canNext, onNext, nextTitle }) => {
|
|
|
42
44
|
wrapTitleStyle={styles.wrapTitleStyle}
|
|
43
45
|
/>
|
|
44
46
|
<KeyboardAwareScrollView>{children}</KeyboardAwareScrollView>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
{hasNext && (
|
|
48
|
+
<BottomButtonView
|
|
49
|
+
style={styles.bottomButtonView}
|
|
50
|
+
mainTitle={nextTitle}
|
|
51
|
+
onPressMain={onNext}
|
|
52
|
+
typeMain={canNext ? 'primary' : 'disabled'}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
51
55
|
</View>
|
|
52
56
|
);
|
|
53
57
|
};
|