@eohjsc/react-native-smart-city 0.7.3-rc10 → 0.7.3-rc12
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/Action/__test__/ItemQuickAction.test.js +2 -2
- package/src/commons/ActionGroup/__test__/index.test.js +2 -2
- package/src/commons/DateTimeRangeChange/DateTimeButton.js +1 -1
- package/src/commons/Device/HorizontalBarChart.js +54 -34
- package/src/commons/Grid/GridItem.js +10 -2
- package/src/commons/IconComponent/index.js +4 -4
- package/src/commons/OneTapTemplate/__test__/StatesGridActionTemplate.test.js +4 -4
- package/src/configs/Theme.js +1 -1
- package/src/navigations/SharedStack.js +2 -0
- package/src/screens/Automate/AddNewAction/ChooseAction.js +17 -3
- package/src/screens/Automate/AddNewAction/ChooseConfig.js +7 -6
- package/src/screens/Automate/AddNewAction/SelectControlDevices.js +27 -17
- package/src/screens/Automate/AddNewAction/SelectMonitorDevices.js +17 -10
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +35 -32
- package/src/screens/Automate/AddNewAction/SetupScriptDelay.js +1 -1
- package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +3 -3
- package/src/screens/Automate/AddNewAction/Styles/SetupSensorStyles.js +20 -4
- package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +1 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +12 -11
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +29 -0
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +7 -7
- package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +12 -4
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +2 -0
- package/src/screens/Automate/SetSchedule/components/RowItem.js +5 -5
- package/src/screens/Notification/components/NotificationItem.js +2 -2
- package/src/screens/SelectUnit/index.js +1 -1
- package/src/utils/I18n/translations/en.js +1 -1
- package/src/utils/I18n/translations/vi.js +3 -1
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
1
2
|
import { factory } from 'factory-girl';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { TouchableOpacity } from 'react-native';
|
|
4
5
|
import Toast from 'react-native-toast-message';
|
|
5
|
-
import AntDesign from 'react-native-vector-icons/AntDesign';
|
|
6
6
|
import { act, create } from 'react-test-renderer';
|
|
7
7
|
import { Colors } from '../../../configs';
|
|
8
8
|
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
@@ -94,7 +94,7 @@ describe('Test ItemQuickAction', () => {
|
|
|
94
94
|
await buttonOnActionPress.props.onPress();
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
const icon = instance.findByType(
|
|
97
|
+
const icon = instance.findByType(IconOutline);
|
|
98
98
|
expect(icon.props.color).toEqual(Colors.TextGray);
|
|
99
99
|
});
|
|
100
100
|
|
|
@@ -413,7 +413,7 @@ describe('Test ActionGroup', () => {
|
|
|
413
413
|
config: 5,
|
|
414
414
|
is_on_value: 0,
|
|
415
415
|
action: 'action1-47b3-43f6-ba45-83cd1cf5d8f2',
|
|
416
|
-
icon: '
|
|
416
|
+
icon: 'up-circle',
|
|
417
417
|
text: 'Text',
|
|
418
418
|
action_data: actionData,
|
|
419
419
|
},
|
|
@@ -421,7 +421,7 @@ describe('Test ActionGroup', () => {
|
|
|
421
421
|
config: 6,
|
|
422
422
|
is_on_value: 0,
|
|
423
423
|
action: 'action2-47b3-43f6-ba45-83cd1cf5d8f2',
|
|
424
|
-
icon: '
|
|
424
|
+
icon: 'up-circle',
|
|
425
425
|
text: 'Text',
|
|
426
426
|
action_data: actionData,
|
|
427
427
|
},
|
|
@@ -1,11 +1,46 @@
|
|
|
1
|
-
import React, { memo, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { View, StyleSheet } from 'react-native';
|
|
3
1
|
import { isEmpty } from 'lodash';
|
|
2
|
+
import React, { memo, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { Colors } from '../../configs';
|
|
6
6
|
import { getMaxValueIndex } from '../../utils/chartHelper/getMaxValueIndex';
|
|
7
7
|
import Highcharts from '../Highcharts';
|
|
8
8
|
|
|
9
|
+
// https://github.com/facebook/hermes/issues/114#issuecomment-887106990
|
|
10
|
+
// 'show source' unstable, work sometime, use this to generate formatter function
|
|
11
|
+
|
|
12
|
+
// function formatter() {
|
|
13
|
+
// 'show source';
|
|
14
|
+
// const { unit, price } = JSON.parse(this.series.name);
|
|
15
|
+
// const textColor =
|
|
16
|
+
// this.color === '#00979D'
|
|
17
|
+
// ? this.y === 0
|
|
18
|
+
// ? '#262626'
|
|
19
|
+
// : '#FFFFFF'
|
|
20
|
+
// : '#262626';
|
|
21
|
+
// const valueStyle = `color:${textColor};font-weight:normal;font-size:12px;`;
|
|
22
|
+
// const costStyle = valueStyle + 'font-weight:bold;';
|
|
23
|
+
// let label = `<span style="${valueStyle}">` + `${this.y}${unit}`;
|
|
24
|
+
// if (price === '' || price === null || isNaN(price)) {
|
|
25
|
+
// return label + '</span>';
|
|
26
|
+
// }
|
|
27
|
+
// const formatMoney = (number) => {
|
|
28
|
+
// const formatNumber = number.toFixed();
|
|
29
|
+
// return (
|
|
30
|
+
// parseInt(formatNumber, 10)
|
|
31
|
+
// .toFixed(0)
|
|
32
|
+
// .toString()
|
|
33
|
+
// .replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.') + 'đ'
|
|
34
|
+
// );
|
|
35
|
+
// };
|
|
36
|
+
// return (
|
|
37
|
+
// label +
|
|
38
|
+
// `/<span style="${costStyle}">` +
|
|
39
|
+
// formatMoney(this.y * price) +
|
|
40
|
+
// '</span></span>'
|
|
41
|
+
// );
|
|
42
|
+
// }
|
|
43
|
+
|
|
9
44
|
const HorizontalBarChart = memo(({ datas, config }) => {
|
|
10
45
|
const [chartOptions, setChartOptions] = useState({
|
|
11
46
|
chart: {
|
|
@@ -57,38 +92,23 @@ const HorizontalBarChart = memo(({ datas, config }) => {
|
|
|
57
92
|
dataLabels: {
|
|
58
93
|
enabled: true,
|
|
59
94
|
useHTML: true,
|
|
60
|
-
formatter: function () {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const formatNumber = number.toFixed();
|
|
78
|
-
return (
|
|
79
|
-
parseInt(formatNumber, 10)
|
|
80
|
-
.toFixed(0)
|
|
81
|
-
.toString()
|
|
82
|
-
.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.') + 'đ'
|
|
83
|
-
);
|
|
84
|
-
};
|
|
85
|
-
return (
|
|
86
|
-
label +
|
|
87
|
-
`/<span style="${costStyle}">` +
|
|
88
|
-
formatMoney(this.y * price) +
|
|
89
|
-
'</span></span>'
|
|
90
|
-
);
|
|
91
|
-
},
|
|
95
|
+
formatter: `function formatter() {
|
|
96
|
+
var _JSON$parse = JSON.parse(this.series.name),
|
|
97
|
+
unit = _JSON$parse.unit,
|
|
98
|
+
price = _JSON$parse.price;
|
|
99
|
+
var textColor = this.color === '#00979D' ? this.y === 0 ? '#262626' : '#FFFFFF' : '#262626';
|
|
100
|
+
var valueStyle = "color:" + textColor + ";font-weight:normal;font-size:12px;";
|
|
101
|
+
var costStyle = valueStyle + 'font-weight:bold;';
|
|
102
|
+
var label = "<span style=\\"" + valueStyle + "\\">" + ("" + this.y + unit);
|
|
103
|
+
if (price === '' || price === null || isNaN(price)) {
|
|
104
|
+
return label + '</span>';
|
|
105
|
+
}
|
|
106
|
+
var formatMoney = function formatMoney(number) {
|
|
107
|
+
var formatNumber = number.toFixed();
|
|
108
|
+
return parseInt(formatNumber, 10).toFixed(0).toString().replace(/(\\d)(?=(\\d\\d\\d)+(?!\\d))/g, '$1.') + 'đ';
|
|
109
|
+
};
|
|
110
|
+
return label + ("/<span style=\\"" + costStyle + "\\">") + formatMoney(this.y * price) + '</span></span>';
|
|
111
|
+
}`,
|
|
92
112
|
align: 'right',
|
|
93
113
|
inside: false,
|
|
94
114
|
},
|
|
@@ -3,7 +3,15 @@ import { TouchableWithoutFeedback, View } from 'react-native';
|
|
|
3
3
|
import styles from './GridItemStyles';
|
|
4
4
|
|
|
5
5
|
const GridItem = memo(
|
|
6
|
-
({
|
|
6
|
+
({
|
|
7
|
+
icon,
|
|
8
|
+
accessibilityLabel,
|
|
9
|
+
selected,
|
|
10
|
+
onPress,
|
|
11
|
+
item,
|
|
12
|
+
children,
|
|
13
|
+
style = {},
|
|
14
|
+
}) => {
|
|
7
15
|
const isActive = selected && styles.active;
|
|
8
16
|
|
|
9
17
|
return (
|
|
@@ -11,7 +19,7 @@ const GridItem = memo(
|
|
|
11
19
|
onPress={() => onPress && onPress(item)}
|
|
12
20
|
accessibilityLabel={accessibilityLabel}
|
|
13
21
|
>
|
|
14
|
-
<View style={[styles.container, isActive]}>{children}</View>
|
|
22
|
+
<View style={[styles.container, style, isActive]}>{children}</View>
|
|
15
23
|
</TouchableWithoutFeedback>
|
|
16
24
|
);
|
|
17
25
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { IconFill, IconOutline } from '@ant-design/icons-react-native';
|
|
2
2
|
import React, { memo, useMemo } from 'react';
|
|
3
3
|
import { StyleSheet } from 'react-native';
|
|
4
4
|
import { Colors } from '../../configs';
|
|
@@ -30,7 +30,7 @@ const IconComponent = memo(
|
|
|
30
30
|
} else if (newIcon.includes('TwoTone')) {
|
|
31
31
|
newIcon = newIcon.substring(0, newIcon.length - 'TwoTone'.length);
|
|
32
32
|
}
|
|
33
|
-
newIcon = newIcon.replace(/[A-Z]/g, (m) => m.toLowerCase());
|
|
33
|
+
newIcon = newIcon.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());
|
|
34
34
|
}
|
|
35
35
|
return newIcon;
|
|
36
36
|
}, [icon]);
|
|
@@ -62,7 +62,7 @@ const IconComponent = memo(
|
|
|
62
62
|
);
|
|
63
63
|
} else if (icon.includes('Filled')) {
|
|
64
64
|
return (
|
|
65
|
-
<
|
|
65
|
+
<IconFill
|
|
66
66
|
name={displayIcon}
|
|
67
67
|
color={colorIcon}
|
|
68
68
|
size={size}
|
|
@@ -76,7 +76,7 @@ const IconComponent = memo(
|
|
|
76
76
|
? 'poweroff'
|
|
77
77
|
: displayIcon;
|
|
78
78
|
return (
|
|
79
|
-
<
|
|
79
|
+
<IconOutline
|
|
80
80
|
name={iconCT}
|
|
81
81
|
color={colorIcon}
|
|
82
82
|
size={size}
|
|
@@ -27,7 +27,7 @@ describe('Test StatesGridActionTemplate', () => {
|
|
|
27
27
|
config: 1024,
|
|
28
28
|
is_on_value: 1,
|
|
29
29
|
action: '800ff454-4e2a-4a38-bad6-1bded728193e',
|
|
30
|
-
icon: '
|
|
30
|
+
icon: 'up-circle',
|
|
31
31
|
icon_kit: 41,
|
|
32
32
|
text: 'Auto',
|
|
33
33
|
},
|
|
@@ -35,7 +35,7 @@ describe('Test StatesGridActionTemplate', () => {
|
|
|
35
35
|
config: 1024,
|
|
36
36
|
is_on_value: 2,
|
|
37
37
|
action: '4e43da81-469e-4d23-a66b-2656db7cf196',
|
|
38
|
-
icon: '
|
|
38
|
+
icon: 'up-circle',
|
|
39
39
|
icon_kit: 42,
|
|
40
40
|
text: 'Cool',
|
|
41
41
|
},
|
|
@@ -43,7 +43,7 @@ describe('Test StatesGridActionTemplate', () => {
|
|
|
43
43
|
config: 1024,
|
|
44
44
|
is_on_value: 3,
|
|
45
45
|
action: '63f1bbfa-0e42-4401-9ea2-4aa07327ff26',
|
|
46
|
-
icon: '
|
|
46
|
+
icon: 'up-circle',
|
|
47
47
|
icon_kit: 44,
|
|
48
48
|
text: 'Dry',
|
|
49
49
|
},
|
|
@@ -51,7 +51,7 @@ describe('Test StatesGridActionTemplate', () => {
|
|
|
51
51
|
config: 1024,
|
|
52
52
|
is_on_value: 4,
|
|
53
53
|
action: '8ba3e471-dd84-478b-87f3-6008aead8804',
|
|
54
|
-
icon: '
|
|
54
|
+
icon: 'up-circle',
|
|
55
55
|
icon_kit: 43,
|
|
56
56
|
text: 'Fan Only',
|
|
57
57
|
},
|
package/src/configs/Theme.js
CHANGED
|
@@ -14,7 +14,13 @@ import RenderActionItem from './RenderActionItem';
|
|
|
14
14
|
const ChooseAction = ({ route }) => {
|
|
15
15
|
const t = useTranslations();
|
|
16
16
|
const { navigate } = useNavigation();
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
unitId,
|
|
19
|
+
device,
|
|
20
|
+
automateId,
|
|
21
|
+
numberActionCanAdd,
|
|
22
|
+
multiUnit = {},
|
|
23
|
+
} = route.params;
|
|
18
24
|
const [data, setData] = useState([]);
|
|
19
25
|
const [actions, setActions] = useState([]);
|
|
20
26
|
|
|
@@ -48,7 +54,7 @@ const ChooseAction = ({ route }) => {
|
|
|
48
54
|
API.AUTOMATE.ADD_SCRIPT_ACTION(automateId),
|
|
49
55
|
{
|
|
50
56
|
list_action,
|
|
51
|
-
unit: unitId,
|
|
57
|
+
unit: unitId || multiUnit.id,
|
|
52
58
|
}
|
|
53
59
|
);
|
|
54
60
|
|
|
@@ -58,7 +64,15 @@ const ChooseAction = ({ route }) => {
|
|
|
58
64
|
merge: true,
|
|
59
65
|
params: { saveAt: moment().valueOf() },
|
|
60
66
|
});
|
|
61
|
-
}, [
|
|
67
|
+
}, [
|
|
68
|
+
actions,
|
|
69
|
+
numberActionCanAdd,
|
|
70
|
+
automateId,
|
|
71
|
+
unitId,
|
|
72
|
+
multiUnit.id,
|
|
73
|
+
navigate,
|
|
74
|
+
t,
|
|
75
|
+
]);
|
|
62
76
|
|
|
63
77
|
const handleOnSelectAction = (action) => {
|
|
64
78
|
setActions((prevActions) => {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native';
|
|
1
2
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
3
|
import { View } from 'react-native';
|
|
3
|
-
import { useNavigation } from '@react-navigation/native';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import GridItem from '../../../commons/Grid/GridItem';
|
|
6
6
|
import Text from '../../../commons/Text';
|
|
7
|
-
import { axiosGet } from '../../../utils/Apis/axios';
|
|
8
7
|
import { API, Colors } from '../../../configs';
|
|
8
|
+
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
9
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
10
|
+
import { axiosGet } from '../../../utils/Apis/axios';
|
|
9
11
|
import Routes from '../../../utils/Route';
|
|
10
|
-
import styles from './Styles/SelectActionStyles';
|
|
11
12
|
import { LoadingSelectAction } from './Components';
|
|
12
|
-
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
13
13
|
import NewActionWrapper from './NewActionWrapper';
|
|
14
|
-
import
|
|
14
|
+
import styles from './Styles/SelectActionStyles';
|
|
15
15
|
|
|
16
16
|
const ChooseConfig = ({ route }) => {
|
|
17
17
|
const t = useTranslations();
|
|
@@ -44,6 +44,7 @@ const ChooseConfig = ({ route }) => {
|
|
|
44
44
|
config,
|
|
45
45
|
automate,
|
|
46
46
|
closeScreen,
|
|
47
|
+
unitId: automate?.unit,
|
|
47
48
|
});
|
|
48
49
|
},
|
|
49
50
|
[automate, closeScreen, navigate]
|
|
@@ -8,8 +8,13 @@ import SelectDevices from './Components/SelectDevices';
|
|
|
8
8
|
|
|
9
9
|
const SelectControlDevices = ({ route }) => {
|
|
10
10
|
const t = useTranslations();
|
|
11
|
-
const {
|
|
12
|
-
|
|
11
|
+
const {
|
|
12
|
+
unitId,
|
|
13
|
+
closeScreen,
|
|
14
|
+
automateId,
|
|
15
|
+
numberActionCanAdd,
|
|
16
|
+
multiUnit = {},
|
|
17
|
+
} = route.params || {};
|
|
13
18
|
|
|
14
19
|
const [stations, setStations] = useState([]);
|
|
15
20
|
const [listStation, setListStation] = useState([]);
|
|
@@ -19,22 +24,26 @@ const SelectControlDevices = ({ route }) => {
|
|
|
19
24
|
const [loading, setLoading] = useState(true);
|
|
20
25
|
|
|
21
26
|
const fetchDetails = useCallback(async () => {
|
|
22
|
-
await fetchWithCache(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
index
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
await fetchWithCache(
|
|
28
|
+
API.UNIT.DEVICE_CONTROL(unitId || multiUnit.id),
|
|
29
|
+
{},
|
|
30
|
+
(response) => {
|
|
31
|
+
const { success, data } = response;
|
|
32
|
+
if (success) {
|
|
33
|
+
const newData = data.filter((item) => item.sensors.length > 0);
|
|
34
|
+
const listMenu = newData.map((item, index) => ({
|
|
35
|
+
text: item.name,
|
|
36
|
+
station: item,
|
|
37
|
+
index: index,
|
|
38
|
+
}));
|
|
39
|
+
setStations(newData);
|
|
40
|
+
setListMenuItem(listMenu);
|
|
41
|
+
setListStation(listMenu);
|
|
42
|
+
}
|
|
34
43
|
}
|
|
35
|
-
|
|
44
|
+
);
|
|
36
45
|
setLoading(false);
|
|
37
|
-
}, [unitId]);
|
|
46
|
+
}, [multiUnit.id, unitId]);
|
|
38
47
|
|
|
39
48
|
useEffect(() => {
|
|
40
49
|
fetchDetails();
|
|
@@ -48,9 +57,10 @@ const SelectControlDevices = ({ route }) => {
|
|
|
48
57
|
device: selectedDevice,
|
|
49
58
|
closeScreen,
|
|
50
59
|
numberActionCanAdd,
|
|
60
|
+
multiUnit,
|
|
51
61
|
});
|
|
52
62
|
},
|
|
53
|
-
[navigate, unitId, automateId, closeScreen, numberActionCanAdd]
|
|
63
|
+
[navigate, unitId, automateId, closeScreen, numberActionCanAdd, multiUnit]
|
|
54
64
|
);
|
|
55
65
|
|
|
56
66
|
if (loading) {
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
1
|
import { useNavigation } from '@react-navigation/native';
|
|
2
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { API } from '../../../configs';
|
|
5
|
+
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
4
6
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
5
7
|
import { fetchWithCache } from '../../../utils/Apis/axios';
|
|
6
|
-
import { API } from '../../../configs';
|
|
7
8
|
import Routes from '../../../utils/Route';
|
|
8
9
|
import SelectDevices from './Components/SelectDevices';
|
|
9
|
-
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
10
10
|
|
|
11
11
|
const SelectMonitorDevices = ({ route }) => {
|
|
12
12
|
const t = useTranslations();
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
automate = {},
|
|
15
|
+
isCreateNewAction,
|
|
16
|
+
closeScreen,
|
|
17
|
+
multiUnit = {},
|
|
18
|
+
} = route.params || {};
|
|
19
|
+
const { type, unit, sensor_id } = automate;
|
|
14
20
|
|
|
15
21
|
const [stations, setStations] = useState([]);
|
|
16
22
|
const [listStation, setListStation] = useState([]);
|
|
@@ -22,11 +28,11 @@ const SelectMonitorDevices = ({ route }) => {
|
|
|
22
28
|
|
|
23
29
|
const fetchDetails = useCallback(async () => {
|
|
24
30
|
const configs = { params: {} };
|
|
25
|
-
if (
|
|
31
|
+
if (type === AUTOMATE_TYPE.EVENT) {
|
|
26
32
|
configs.params.type = 'event';
|
|
27
33
|
}
|
|
28
34
|
await fetchWithCache(
|
|
29
|
-
API.UNIT.DEVICE_SENSOR(
|
|
35
|
+
API.UNIT.DEVICE_SENSOR(unit || multiUnit.id),
|
|
30
36
|
configs,
|
|
31
37
|
(response) => {
|
|
32
38
|
const { success, data } = response;
|
|
@@ -46,17 +52,17 @@ const SelectMonitorDevices = ({ route }) => {
|
|
|
46
52
|
}
|
|
47
53
|
);
|
|
48
54
|
setLoading(false);
|
|
49
|
-
}, [
|
|
55
|
+
}, [multiUnit.id, type, unit]);
|
|
50
56
|
|
|
51
57
|
useEffect(() => {
|
|
52
|
-
if (!
|
|
58
|
+
if (!sensor_id) {
|
|
53
59
|
return;
|
|
54
60
|
}
|
|
55
61
|
let selectSensor = {};
|
|
56
62
|
let found = false;
|
|
57
63
|
for (let i = 0; i < stations.length; i++) {
|
|
58
64
|
for (let j = 0; j < stations[i].sensors.length; j++) {
|
|
59
|
-
if (stations[i].sensors[j].id ===
|
|
65
|
+
if (stations[i].sensors[j].id === sensor_id) {
|
|
60
66
|
selectSensor = stations[i].sensors[j];
|
|
61
67
|
found = true;
|
|
62
68
|
break;
|
|
@@ -67,7 +73,7 @@ const SelectMonitorDevices = ({ route }) => {
|
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
setDefaultSelectedDevice(selectSensor);
|
|
70
|
-
}, [
|
|
76
|
+
}, [sensor_id, stations]);
|
|
71
77
|
|
|
72
78
|
useEffect(() => {
|
|
73
79
|
fetchDetails();
|
|
@@ -86,6 +92,7 @@ const SelectMonitorDevices = ({ route }) => {
|
|
|
86
92
|
stationName: stations[indexStation]?.name,
|
|
87
93
|
isCreateNewAction,
|
|
88
94
|
closeScreen,
|
|
95
|
+
unitId: automate?.unit,
|
|
89
96
|
});
|
|
90
97
|
},
|
|
91
98
|
[navigate, automate, stations, isCreateNewAction, closeScreen]
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import React, { useMemo, useState } from 'react';
|
|
2
|
-
import { View
|
|
2
|
+
import { View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import styles from './Styles/SetupSensorStyles';
|
|
5
|
-
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
6
|
-
import Text from '../../../commons/Text';
|
|
7
4
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
8
|
-
import
|
|
5
|
+
import { Button } from '../../../commons';
|
|
6
|
+
import TextInput from '../../../commons/Form/TextInput';
|
|
9
7
|
import GridItem from '../../../commons/Grid/GridItem';
|
|
10
|
-
import Routes from '../../../utils/Route';
|
|
11
8
|
import ModalCustom from '../../../commons/Modal/ModalCustom';
|
|
9
|
+
import Text from '../../../commons/Text';
|
|
10
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
11
|
+
import Routes from '../../../utils/Route';
|
|
12
12
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
13
|
-
import
|
|
14
|
-
import
|
|
13
|
+
import NewActionWrapper from './NewActionWrapper';
|
|
14
|
+
import styles from './Styles/SetupSensorStyles';
|
|
15
15
|
|
|
16
16
|
const valueEvaluationToOptions = (valueEvaluation) => {
|
|
17
17
|
if (valueEvaluation.template === 'range') {
|
|
@@ -54,7 +54,7 @@ const SetupConfigCondition = () => {
|
|
|
54
54
|
value: '<',
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
|
-
label: `${t('
|
|
57
|
+
label: `${t('is_equal')} (=)`,
|
|
58
58
|
value: '=',
|
|
59
59
|
},
|
|
60
60
|
{
|
|
@@ -132,41 +132,44 @@ const SetupConfigCondition = () => {
|
|
|
132
132
|
style={styles.modal}
|
|
133
133
|
>
|
|
134
134
|
<View style={styles.modalContent}>
|
|
135
|
-
<Text type="Body">
|
|
135
|
+
<Text type="Body" bold style={styles.titleCondition}>
|
|
136
136
|
{t('when_value_is', { config_name: config.name })}
|
|
137
137
|
</Text>
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
data={normalConditions}
|
|
141
|
-
renderItem={({ item }) => {
|
|
138
|
+
<View style={styles.flatListCondition}>
|
|
139
|
+
{normalConditions.map((item) => {
|
|
142
140
|
return (
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
</
|
|
141
|
+
<GridItem
|
|
142
|
+
onPress={() => {
|
|
143
|
+
automate.condition = item.value;
|
|
144
|
+
setCustomCondition(item.value);
|
|
145
|
+
}}
|
|
146
|
+
selected={item.value === customCondition}
|
|
147
|
+
style={styles.gridItem}
|
|
148
|
+
>
|
|
149
|
+
<Text type="Body">{item.label}</Text>
|
|
150
|
+
</GridItem>
|
|
153
151
|
);
|
|
154
|
-
}}
|
|
155
|
-
|
|
152
|
+
})}
|
|
153
|
+
</View>
|
|
154
|
+
|
|
156
155
|
<View style={styles.inputValue}>
|
|
157
|
-
<Text>{t('value')}</Text>
|
|
158
156
|
<TextInput
|
|
159
157
|
keyboardType="decimal-pad"
|
|
160
158
|
type="number"
|
|
161
159
|
maxLength={10}
|
|
160
|
+
placeholder={t('value')}
|
|
162
161
|
onChange={(value) => {
|
|
163
162
|
const floatValue = parseFloat(value.replace(',', '.'));
|
|
164
163
|
automate.value = floatValue;
|
|
165
164
|
}}
|
|
166
|
-
|
|
165
|
+
textInputStyle={styles.numberInput}
|
|
166
|
+
wrapStyle={styles.wrapTextInput}
|
|
167
167
|
/>
|
|
168
168
|
</View>
|
|
169
|
-
|
|
169
|
+
|
|
170
|
+
<Button
|
|
171
|
+
type="primary"
|
|
172
|
+
title={t('continue')}
|
|
170
173
|
testID={'continue_button'}
|
|
171
174
|
onPress={() => {
|
|
172
175
|
if (
|
|
@@ -179,9 +182,9 @@ const SetupConfigCondition = () => {
|
|
|
179
182
|
setIsShowModal(false);
|
|
180
183
|
navigate(Routes.ValueChangeName, { automate, closeScreen });
|
|
181
184
|
}}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
style={styles.buttonContinue}
|
|
186
|
+
textSemiBold={false}
|
|
187
|
+
/>
|
|
185
188
|
</View>
|
|
186
189
|
</ModalCustom>
|
|
187
190
|
</NewActionWrapper>
|
|
@@ -17,9 +17,9 @@ import moment from 'moment';
|
|
|
17
17
|
const SetupScriptNotify = ({ route }) => {
|
|
18
18
|
const t = useTranslations();
|
|
19
19
|
const { goBack, navigate } = useNavigation();
|
|
20
|
-
const { automate = {}, unitId } = route
|
|
20
|
+
const { automate = {}, unitId, multiUnit } = route.params || {};
|
|
21
21
|
const { id: automateId } = automate;
|
|
22
|
-
const [notify, setNotify] = useState({ unit: unitId });
|
|
22
|
+
const [notify, setNotify] = useState({ unit: unitId || multiUnit.id });
|
|
23
23
|
|
|
24
24
|
const onChangeTitle = (value) => {
|
|
25
25
|
setNotify((state) => ({
|
|
@@ -47,7 +47,7 @@ const SetupScriptNotify = ({ route }) => {
|
|
|
47
47
|
params: { saveAt: moment().valueOf() },
|
|
48
48
|
});
|
|
49
49
|
} else {
|
|
50
|
-
ToastBottomHelper.error(t('
|
|
50
|
+
ToastBottomHelper.error(t('error_please_try_later'));
|
|
51
51
|
}
|
|
52
52
|
}, [automateId, navigate, notify, t]);
|
|
53
53
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
-
import {
|
|
2
|
+
import { Colors, Theme } from '../../../../configs';
|
|
3
3
|
|
|
4
4
|
export default StyleSheet.create({
|
|
5
5
|
...Theme,
|
|
@@ -11,10 +11,9 @@ export default StyleSheet.create({
|
|
|
11
11
|
},
|
|
12
12
|
inputValue: { marginBottom: 10 },
|
|
13
13
|
numberInput: {
|
|
14
|
-
borderRadius:
|
|
14
|
+
borderRadius: 8,
|
|
15
15
|
borderWidth: 1,
|
|
16
|
-
height:
|
|
17
|
-
marginTop: 10,
|
|
16
|
+
height: 50,
|
|
18
17
|
},
|
|
19
18
|
boxDevices: {
|
|
20
19
|
flexWrap: 'wrap',
|
|
@@ -43,4 +42,21 @@ export default StyleSheet.create({
|
|
|
43
42
|
width: '100%',
|
|
44
43
|
borderRadius: 10,
|
|
45
44
|
},
|
|
45
|
+
titleCondition: {
|
|
46
|
+
marginBottom: 16,
|
|
47
|
+
},
|
|
48
|
+
wrapTextInput: {
|
|
49
|
+
marginTop: 0,
|
|
50
|
+
},
|
|
51
|
+
flatListCondition: {
|
|
52
|
+
display: 'flex',
|
|
53
|
+
flexDirection: 'row',
|
|
54
|
+
justifyContent: 'space-between',
|
|
55
|
+
},
|
|
56
|
+
gridItem: {
|
|
57
|
+
width: 'fit-content',
|
|
58
|
+
},
|
|
59
|
+
buttonContinue: {
|
|
60
|
+
flex: 0,
|
|
61
|
+
},
|
|
46
62
|
});
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native';
|
|
1
2
|
import React from 'react';
|
|
3
|
+
import { TouchableWithoutFeedback } from 'react-native';
|
|
2
4
|
import { act, create } from 'react-test-renderer';
|
|
3
|
-
import { SCProvider } from '../../../../context';
|
|
4
|
-
import { mockSCStore } from '../../../../context/mockStore';
|
|
5
|
-
import SetupConfigCondition from '../SetupConfigCondition';
|
|
6
|
-
import { useRoute } from '@react-navigation/native';
|
|
7
|
-
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
8
5
|
import { Text } from '../../../../commons';
|
|
9
|
-
import GridItem from '../../../../commons/Grid/GridItem';
|
|
10
|
-
import { TouchableWithoutFeedback } from 'react-native';
|
|
11
|
-
import Routes from '../../../../utils/Route';
|
|
12
|
-
import { ModalCustom } from '../../../../commons/Modal';
|
|
13
6
|
import { showAllGridItems } from '../../../../commons/ActionTemplate/__test__/utils';
|
|
14
7
|
import TextInput from '../../../../commons/Form/TextInput';
|
|
15
|
-
import
|
|
8
|
+
import GridItem from '../../../../commons/Grid/GridItem';
|
|
9
|
+
import { ModalCustom } from '../../../../commons/Modal';
|
|
10
|
+
import { SCProvider } from '../../../../context';
|
|
11
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
12
|
+
import Routes from '../../../../utils/Route';
|
|
13
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
14
|
+
import SetupConfigCondition from '../SetupConfigCondition';
|
|
16
15
|
|
|
17
16
|
jest.mock('react', () => {
|
|
18
17
|
return {
|
|
@@ -214,8 +213,10 @@ describe('Test SetupConfigCondition', () => {
|
|
|
214
213
|
});
|
|
215
214
|
expect(modal.props.isVisible).toBeFalsy();
|
|
216
215
|
|
|
216
|
+
const modalGridItems = instance.findAllByType(GridItem);
|
|
217
|
+
|
|
217
218
|
await act(async () => {
|
|
218
|
-
|
|
219
|
+
modalGridItems[1].findByType(TouchableWithoutFeedback).props.onPress();
|
|
219
220
|
});
|
|
220
221
|
|
|
221
222
|
const input = instance.findByType(TextInput);
|
|
@@ -69,6 +69,35 @@ describe('Test SetupScriptNotify', () => {
|
|
|
69
69
|
expect(spyToast).toHaveBeenCalled();
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
it('SetupScriptNotify onPress create script notify success with multi unit', async () => {
|
|
73
|
+
route.params.unitId = null;
|
|
74
|
+
route.params.multiUnit = { id: 1 };
|
|
75
|
+
const spyToast = jest.spyOn(ToastBottomHelper, 'success');
|
|
76
|
+
mock.onPost(API.AUTOMATE.ADD_SCRIPT_NOTIFY(1)).reply(200);
|
|
77
|
+
await act(async () => {
|
|
78
|
+
tree = await renderer.create(wrapComponent(route));
|
|
79
|
+
});
|
|
80
|
+
const instance = tree.root;
|
|
81
|
+
const inputs = instance.findAllByType(_TextInput);
|
|
82
|
+
expect(inputs).toHaveLength(2);
|
|
83
|
+
|
|
84
|
+
await act(async () => {
|
|
85
|
+
inputs[0].props.onChange('Title');
|
|
86
|
+
});
|
|
87
|
+
const touchable = instance.findAllByType(TouchableWithoutFeedback);
|
|
88
|
+
await act(async () => {
|
|
89
|
+
touchable[0].props.onPress();
|
|
90
|
+
});
|
|
91
|
+
await act(async () => {
|
|
92
|
+
inputs[1].props.onChange('Message');
|
|
93
|
+
});
|
|
94
|
+
const button = instance.findByType(BottomButtonView);
|
|
95
|
+
await act(async () => {
|
|
96
|
+
button.props.onPressMain();
|
|
97
|
+
});
|
|
98
|
+
expect(spyToast).toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
72
101
|
it('SetupScriptNotify onPress create script notify error', async () => {
|
|
73
102
|
const spyToast = jest.spyOn(ToastBottomHelper, 'error');
|
|
74
103
|
mock.onPost(API.AUTOMATE.ADD_SCRIPT_NOTIFY(1)).reply(400);
|
|
@@ -7,16 +7,16 @@ import Text from '../../../commons/Text';
|
|
|
7
7
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
8
8
|
import Routes from '../../../utils/Route';
|
|
9
9
|
import styles from './styles/AddNewAutoSmartStyles';
|
|
10
|
+
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
10
11
|
|
|
11
12
|
const AddTypeSmart = ({ smartTypes, route }) => {
|
|
12
13
|
const t = useTranslations();
|
|
13
14
|
const { navigate, goBack } = useNavigation();
|
|
14
15
|
const { automate = {}, closeScreen } = route?.params || {};
|
|
16
|
+
const { id, unit, type } = automate;
|
|
15
17
|
|
|
16
18
|
const [selectedIndex, setSelectedIndex] = useState(
|
|
17
|
-
|
|
18
|
-
? smartTypes.findIndex((obj) => obj.type === automate.type)
|
|
19
|
-
: -1
|
|
19
|
+
id ? smartTypes.findIndex((obj) => obj.type === type) : -1
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
const handleOnContinue = useCallback(
|
|
@@ -27,18 +27,18 @@ const AddTypeSmart = ({ smartTypes, route }) => {
|
|
|
27
27
|
...automate,
|
|
28
28
|
type: dataAutomate?.type,
|
|
29
29
|
},
|
|
30
|
-
unitId:
|
|
30
|
+
unitId: unit,
|
|
31
31
|
closeScreen: closeScreen,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
if (!
|
|
34
|
+
if (!unit && dataAutomate.type !== AUTOMATE_TYPE.SCHEDULE) {
|
|
35
35
|
navigate(Routes.SelectUnit, params);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
navigate(dataAutomate.route, params);
|
|
40
40
|
},
|
|
41
|
-
[smartTypes, automate, closeScreen, navigate]
|
|
41
|
+
[smartTypes, automate, unit, closeScreen, navigate]
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
const onSelectType = (index) => {
|
|
@@ -51,7 +51,7 @@ const AddTypeSmart = ({ smartTypes, route }) => {
|
|
|
51
51
|
<HeaderCustom isShowClose onClose={goBack} />
|
|
52
52
|
<View style={styles.container}>
|
|
53
53
|
<Text semibold type={'H2'} style={styles.titleCreate}>
|
|
54
|
-
{
|
|
54
|
+
{id ? t('update_smart') : t('create_smart')}
|
|
55
55
|
</Text>
|
|
56
56
|
<Text type={'Body'} style={styles.titleChoose}>
|
|
57
57
|
{t('choose_the_automation_method_you_want')}
|
|
@@ -40,6 +40,7 @@ const AddActionScript = memo(
|
|
|
40
40
|
closeScreen: currentScreenName,
|
|
41
41
|
numberActionCanAdd:
|
|
42
42
|
max_actions_per_automation - numberActionAdded,
|
|
43
|
+
routeName: unit ? null : Routes.SelectControlDevices,
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
navigate(
|
|
@@ -54,10 +55,17 @@ const AddActionScript = memo(
|
|
|
54
55
|
image: <Notify />,
|
|
55
56
|
onClick: () => {
|
|
56
57
|
setIsVisible(false);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
if (unit) {
|
|
59
|
+
navigate(Routes.SetupScriptNotify, {
|
|
60
|
+
automate,
|
|
61
|
+
unitId: unit,
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
navigate(Routes.SelectUnit, {
|
|
65
|
+
automate,
|
|
66
|
+
routeName: Routes.SetupScriptNotify,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
61
69
|
},
|
|
62
70
|
},
|
|
63
71
|
{
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import AntDesign from 'react-native-vector-icons/AntDesign';
|
|
3
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
4
4
|
import Text from '../../../../commons/Text';
|
|
5
|
-
import styles from '../styles/RowItemStyles';
|
|
6
5
|
import { Colors } from '../../../../configs';
|
|
6
|
+
import styles from '../styles/RowItemStyles';
|
|
7
7
|
|
|
8
8
|
const RowItem = ({ title, value, icon = null, arrow = false, onPress }) => {
|
|
9
9
|
return (
|
|
@@ -17,8 +17,8 @@ const RowItem = ({ title, value, icon = null, arrow = false, onPress }) => {
|
|
|
17
17
|
</Text>
|
|
18
18
|
</View>
|
|
19
19
|
<View style={[styles.itemRight, arrow && styles.center]}>
|
|
20
|
-
{arrow && <
|
|
21
|
-
{icon && <
|
|
20
|
+
{arrow && <IconOutline name="right" color={Colors.Gray7} />}
|
|
21
|
+
{icon && <IconOutline name={icon} size={17} color={Colors.Black} />}
|
|
22
22
|
</View>
|
|
23
23
|
</TouchableOpacity>
|
|
24
24
|
);
|
|
@@ -3,6 +3,7 @@ import moment from 'moment';
|
|
|
3
3
|
import React, { memo, useCallback, useState } from 'react';
|
|
4
4
|
import { Image, TouchableOpacity, View } from 'react-native';
|
|
5
5
|
|
|
6
|
+
import Notify from '../../../../assets/images/Notify.svg';
|
|
6
7
|
import IconComponent from '../../../commons/IconComponent';
|
|
7
8
|
import Text from '../../../commons/Text';
|
|
8
9
|
import { API, Colors, SCConfig } from '../../../configs';
|
|
@@ -16,7 +17,6 @@ import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
|
16
17
|
import { axiosPost } from '../../../utils/Apis/axios';
|
|
17
18
|
import Routes from '../../../utils/Route';
|
|
18
19
|
import styles from '../styles/NotificationItemStyles';
|
|
19
|
-
import Notify from '../../../../assets/images/Notify.svg';
|
|
20
20
|
|
|
21
21
|
const NotificationItem = memo(({ item }) => {
|
|
22
22
|
const t = useTranslations();
|
|
@@ -72,7 +72,7 @@ const NotificationItem = memo(({ item }) => {
|
|
|
72
72
|
},
|
|
73
73
|
iconContent: (
|
|
74
74
|
<IconComponent
|
|
75
|
-
icon=
|
|
75
|
+
icon="usergroup-add"
|
|
76
76
|
style={styles.backgroundSummer}
|
|
77
77
|
/>
|
|
78
78
|
),
|
|
@@ -840,7 +840,7 @@ export default {
|
|
|
840
840
|
select_unit_members: 'Select from Unit members',
|
|
841
841
|
select_contacts: 'Select contacts',
|
|
842
842
|
no_contact: 'No contacts',
|
|
843
|
-
|
|
843
|
+
is_equal: 'is equal',
|
|
844
844
|
is_below: 'is below',
|
|
845
845
|
is_above: 'is above',
|
|
846
846
|
text_notification_content_air_quality_high:
|
|
@@ -94,8 +94,8 @@ export default {
|
|
|
94
94
|
verify: 'Xác nhận',
|
|
95
95
|
text_new_unit: 'Địa điểm',
|
|
96
96
|
text_sub_units: 'Khu vực',
|
|
97
|
+
is_equal: 'bằng',
|
|
97
98
|
is_below: 'dưới',
|
|
98
|
-
is: 'bằng',
|
|
99
99
|
is_above: 'trên',
|
|
100
100
|
edit_actions_list: 'Chỉnh sửa danh sách hành động',
|
|
101
101
|
des_edit_actions_list:
|
|
@@ -1320,6 +1320,8 @@ export default {
|
|
|
1320
1320
|
smart_supplier: 'Nhà Cung Cấp Thông Minh',
|
|
1321
1321
|
text_email_or_phone_number: 'Email hoặc Số điện thoại',
|
|
1322
1322
|
enter_password: 'Mật khẩu',
|
|
1323
|
+
you_need_to_enter_password:
|
|
1324
|
+
'Bạn cần nhập mật khẩu để xác nhận yêu cầu của mình',
|
|
1323
1325
|
connecting_smart_account: 'Đang kết nối tài khoản',
|
|
1324
1326
|
warning_connecting_smart_account:
|
|
1325
1327
|
'Đừng tắt thiết bị hoặc đóng ứng dụng này trong quá trình thiết lập. Quá trình thiết lập có thể mất vài ' +
|