@eohjsc/react-native-smart-city 0.4.66 → 0.4.68
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/android/build.gradle +3 -3
- package/package.json +2 -2
- package/src/commons/Device/ConnectedViewHeader.js +3 -13
- package/src/commons/Device/ItemDevice.js +54 -92
- package/src/commons/Device/ItemDeviceWrapper.js +109 -0
- package/src/commons/Device/LastUpdatedText.js +31 -0
- package/src/commons/Device/__test__/ConnectedViewHeader.test.js +10 -4
- package/src/commons/SubUnit/DeviceTemplate/ConfigAndEvaluation/ConfigAndEvaluation.js +46 -0
- package/src/commons/SubUnit/DeviceTemplate/ConfigAndEvaluation/index.js +12 -0
- package/src/commons/SubUnit/DeviceTemplate/ConfigValue/ConfigValue.js +41 -0
- package/src/commons/SubUnit/DeviceTemplate/ConfigValue/index.js +12 -0
- package/src/commons/SubUnit/DeviceTemplate/DeviceTemplate.js +21 -0
- package/src/commons/SubUnit/DeviceTemplate/EvaluationOverConfig/EvaluationOverConfig.js +79 -0
- package/src/commons/SubUnit/DeviceTemplate/EvaluationOverConfig/index.js +12 -0
- package/src/commons/SubUnit/DeviceTemplate/index.js +9 -0
- package/src/commons/SubUnit/DeviceTemplate/register.js +14 -0
- package/src/commons/SubUnit/DeviceTemplate/styles/ConfigValueStyles.js +23 -0
- package/src/commons/SubUnit/ShortDetail.js +68 -42
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +113 -9
- package/src/screens/Device/__test__/detail.test.js +2 -6
- package/src/screens/Device/components/SensorConnectStatusViewHeader.js +54 -50
- package/src/screens/Device/hooks/useEvaluateValue.js +5 -0
- package/src/screens/Sharing/Components/__test__/DeviceItem.test.js +2 -2
- package/src/screens/SmartAccount/ListDevice/__test__/DeviceItem.test.js +1 -1
- package/src/utils/Converter/time.js +4 -0
- package/src/utils/Permission/common.js +3 -1
package/android/build.gradle
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
// original location:
|
|
11
11
|
// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle
|
|
12
12
|
|
|
13
|
-
def DEFAULT_COMPILE_SDK_VERSION =
|
|
13
|
+
def DEFAULT_COMPILE_SDK_VERSION = 32
|
|
14
14
|
def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3'
|
|
15
|
-
def DEFAULT_MIN_SDK_VERSION =
|
|
16
|
-
def DEFAULT_TARGET_SDK_VERSION =
|
|
15
|
+
def DEFAULT_MIN_SDK_VERSION = 24
|
|
16
|
+
def DEFAULT_TARGET_SDK_VERSION = 32
|
|
17
17
|
|
|
18
18
|
def safeExtGet(prop, fallback) {
|
|
19
19
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
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.68",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
"react-native-pager-view": "^5.4.1",
|
|
187
187
|
"react-native-parallax-scroll-view": "^0.21.3",
|
|
188
188
|
"react-native-parsed-text": "^0.0.22",
|
|
189
|
-
"react-native-permissions": "3.
|
|
189
|
+
"react-native-permissions": "3.6.0",
|
|
190
190
|
"react-native-popover-view": "^4.0.3",
|
|
191
191
|
"react-native-progress": "^5.0.0",
|
|
192
192
|
"react-native-reanimated": "1.10.1",
|
|
@@ -4,7 +4,7 @@ import { IconOutline } from '@ant-design/icons-react-native';
|
|
|
4
4
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
5
|
import { Colors } from '../../configs';
|
|
6
6
|
import Text from '../../commons/Text';
|
|
7
|
-
import
|
|
7
|
+
import LastUpdatedText from './LastUpdatedText';
|
|
8
8
|
|
|
9
9
|
const DisplayTextConnected = memo(({ type }) => {
|
|
10
10
|
const t = useTranslations();
|
|
@@ -26,9 +26,6 @@ const DisplayTextConnected = memo(({ type }) => {
|
|
|
26
26
|
const ConnectedViewHeader = memo(
|
|
27
27
|
({ lastUpdated, type, isDisplayTime, showWindDirection }) => {
|
|
28
28
|
const t = useTranslations();
|
|
29
|
-
const lastUpdatedStr = lastUpdated
|
|
30
|
-
? timeDifference(new Date(), lastUpdated)
|
|
31
|
-
: `5 ${t('seconds_ago')}`;
|
|
32
29
|
|
|
33
30
|
return (
|
|
34
31
|
<View style={styles.statusContainer}>
|
|
@@ -36,12 +33,10 @@ const ConnectedViewHeader = memo(
|
|
|
36
33
|
<IconOutline name={'wifi'} color={Colors.Green6} size={16} />
|
|
37
34
|
<DisplayTextConnected type={type} />
|
|
38
35
|
</View>
|
|
39
|
-
{
|
|
36
|
+
{isDisplayTime && (
|
|
40
37
|
<View style={styles.showWindDirection}>
|
|
41
38
|
{showWindDirection && <Text>{t('current_wind_direction')} </Text>}
|
|
42
|
-
<
|
|
43
|
-
{`${t('last_updated')} ${lastUpdatedStr}`}
|
|
44
|
-
</Text>
|
|
39
|
+
<LastUpdatedText lastUpdated={lastUpdated} showText />
|
|
45
40
|
</View>
|
|
46
41
|
)}
|
|
47
42
|
</View>
|
|
@@ -66,11 +61,6 @@ const styles = StyleSheet.create({
|
|
|
66
61
|
fontSize: 14,
|
|
67
62
|
color: Colors.Green6,
|
|
68
63
|
},
|
|
69
|
-
txtLastUpdate: {
|
|
70
|
-
marginLeft: 8,
|
|
71
|
-
lineHeight: 20,
|
|
72
|
-
marginTop: 8,
|
|
73
|
-
},
|
|
74
64
|
showWindDirection: {
|
|
75
65
|
flexDirection: 'column',
|
|
76
66
|
justifyContent: 'center',
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import React, { memo, useCallback } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
TouchableOpacity,
|
|
5
|
-
TouchableWithoutFeedback,
|
|
6
|
-
View,
|
|
7
|
-
} from 'react-native';
|
|
1
|
+
import React, { memo, useCallback, useMemo } from 'react';
|
|
2
|
+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
8
3
|
import Routes from '../../utils/Route';
|
|
9
4
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
10
5
|
import { useNavigation } from '@react-navigation/native';
|
|
@@ -12,18 +7,15 @@ import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
|
12
7
|
import ItemQuickAction from '../../commons/Action/ItemQuickAction';
|
|
13
8
|
import Text from '../../commons/Text';
|
|
14
9
|
import {
|
|
15
|
-
useHomeAssistantDeviceConnected,
|
|
16
10
|
useBluetoothDeviceConnected,
|
|
17
11
|
useEoHBackendDeviceConnected,
|
|
12
|
+
useHomeAssistantDeviceConnected,
|
|
18
13
|
} from '../../hooks/IoT';
|
|
19
14
|
|
|
20
15
|
import { Colors } from '../../configs';
|
|
21
|
-
import {
|
|
22
|
-
AccessibilityLabel,
|
|
23
|
-
DEVICE_TYPE,
|
|
24
|
-
DEVICE_SIZE,
|
|
25
|
-
} from '../../configs/Constants';
|
|
16
|
+
import { DEVICE_TYPE } from '../../configs/Constants';
|
|
26
17
|
import IconComponent from '../IconComponent';
|
|
18
|
+
import ItemDeviceWrapper from './ItemDeviceWrapper';
|
|
27
19
|
|
|
28
20
|
const ItemDevice = memo(
|
|
29
21
|
({ svgMain, description, title, sensor, unit, station, wrapStyle }) => {
|
|
@@ -52,29 +44,7 @@ const ItemDevice = memo(
|
|
|
52
44
|
});
|
|
53
45
|
}, [navigation, sensor, station, title, unit]);
|
|
54
46
|
|
|
55
|
-
const
|
|
56
|
-
if (!!sensor && sensor?.is_managed_by_backend) {
|
|
57
|
-
if (sensor?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
58
|
-
return Colors.Gray4;
|
|
59
|
-
}
|
|
60
|
-
if (isBluetoothConnected) {
|
|
61
|
-
return Colors.Gray4;
|
|
62
|
-
}
|
|
63
|
-
if (isFetchingStatusFromEoHBackend || isEoHBackendConnected) {
|
|
64
|
-
return Colors.Gray4;
|
|
65
|
-
}
|
|
66
|
-
return Colors.Red6;
|
|
67
|
-
}
|
|
68
|
-
// not managed by backend
|
|
69
|
-
if (sensor?.device_type === DEVICE_TYPE.GOOGLE_HOME) {
|
|
70
|
-
if (isHomeAssistantConnecting || isHomeAssistantConnected) {
|
|
71
|
-
return Colors.Gray4;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return Colors.Red6;
|
|
75
|
-
})();
|
|
76
|
-
|
|
77
|
-
const textConnected = (() => {
|
|
47
|
+
const textConnected = useMemo(() => {
|
|
78
48
|
if (!!sensor && sensor?.is_managed_by_backend) {
|
|
79
49
|
if (sensor?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
80
50
|
return t('connected');
|
|
@@ -100,9 +70,17 @@ const ItemDevice = memo(
|
|
|
100
70
|
}
|
|
101
71
|
}
|
|
102
72
|
return t('disconnected');
|
|
103
|
-
}
|
|
73
|
+
}, [
|
|
74
|
+
isBluetoothConnected,
|
|
75
|
+
isEoHBackendConnected,
|
|
76
|
+
isFetchingStatusFromEoHBackend,
|
|
77
|
+
isHomeAssistantConnected,
|
|
78
|
+
isHomeAssistantConnecting,
|
|
79
|
+
sensor,
|
|
80
|
+
t,
|
|
81
|
+
]);
|
|
104
82
|
|
|
105
|
-
const canRenderQuickAction = (() => {
|
|
83
|
+
const canRenderQuickAction = useMemo(() => {
|
|
106
84
|
if (!!sensor && sensor?.is_managed_by_backend) {
|
|
107
85
|
if (sensor?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
108
86
|
return true;
|
|
@@ -120,50 +98,52 @@ const ItemDevice = memo(
|
|
|
120
98
|
return isHomeAssistantConnected;
|
|
121
99
|
}
|
|
122
100
|
return true;
|
|
123
|
-
}
|
|
101
|
+
}, [
|
|
102
|
+
isBluetoothConnected,
|
|
103
|
+
isFetchingStatusFromEoHBackend,
|
|
104
|
+
isHomeAssistantConnected,
|
|
105
|
+
sensor,
|
|
106
|
+
]);
|
|
124
107
|
|
|
125
108
|
return (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
<ItemDeviceWrapper
|
|
110
|
+
device={sensor}
|
|
111
|
+
unit={unit}
|
|
112
|
+
station={station}
|
|
113
|
+
wrapStyle={wrapStyle}
|
|
129
114
|
>
|
|
130
|
-
<View
|
|
131
|
-
style={[styles.container, wrapStyle, { borderColor }]}
|
|
132
|
-
accessibilityLabel={AccessibilityLabel.SUB_UNIT_DEVICES}
|
|
133
|
-
>
|
|
134
|
-
<View style={styles.boxIcon}>
|
|
135
|
-
<TouchableOpacity onPress={goToSensorDisplay}>
|
|
136
|
-
<IconComponent icon={sensor?.icon_kit || sensor?.icon} />
|
|
137
|
-
</TouchableOpacity>
|
|
138
|
-
{canRenderQuickAction && (
|
|
139
|
-
<ItemQuickAction sensor={sensor} unit={unit} />
|
|
140
|
-
)}
|
|
141
|
-
</View>
|
|
115
|
+
<View style={styles.boxIcon}>
|
|
142
116
|
<TouchableOpacity onPress={goToSensorDisplay}>
|
|
117
|
+
<IconComponent icon={sensor?.icon_kit || sensor?.icon} />
|
|
118
|
+
</TouchableOpacity>
|
|
119
|
+
{!!canRenderQuickAction && (
|
|
120
|
+
<ItemQuickAction sensor={sensor} unit={unit} />
|
|
121
|
+
)}
|
|
122
|
+
</View>
|
|
123
|
+
<TouchableOpacity onPress={goToSensorDisplay}>
|
|
124
|
+
<Text
|
|
125
|
+
numberOfLines={1}
|
|
126
|
+
semibold
|
|
127
|
+
size={14}
|
|
128
|
+
color={Colors.Gray9}
|
|
129
|
+
style={styles.lineHeight22}
|
|
130
|
+
>
|
|
131
|
+
{title}
|
|
132
|
+
</Text>
|
|
133
|
+
<View style={styles.descriptionContainer}>
|
|
143
134
|
<Text
|
|
144
135
|
numberOfLines={1}
|
|
145
136
|
semibold
|
|
146
|
-
size={
|
|
147
|
-
color={Colors.
|
|
148
|
-
style={styles.
|
|
137
|
+
size={12}
|
|
138
|
+
color={Colors.Gray8}
|
|
139
|
+
style={styles.lineHeight20}
|
|
149
140
|
>
|
|
150
|
-
{
|
|
141
|
+
{description || textConnected}
|
|
151
142
|
</Text>
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
size={12}
|
|
157
|
-
color={Colors.Gray8}
|
|
158
|
-
style={styles.lineHeight20}
|
|
159
|
-
>
|
|
160
|
-
{description || textConnected}
|
|
161
|
-
</Text>
|
|
162
|
-
<IconOutline name="right" size={12} />
|
|
163
|
-
</View>
|
|
164
|
-
</TouchableOpacity>
|
|
165
|
-
</View>
|
|
166
|
-
</TouchableWithoutFeedback>
|
|
143
|
+
<IconOutline name="right" size={12} />
|
|
144
|
+
</View>
|
|
145
|
+
</TouchableOpacity>
|
|
146
|
+
</ItemDeviceWrapper>
|
|
167
147
|
);
|
|
168
148
|
}
|
|
169
149
|
);
|
|
@@ -171,27 +151,9 @@ const ItemDevice = memo(
|
|
|
171
151
|
export default ItemDevice;
|
|
172
152
|
|
|
173
153
|
const styles = StyleSheet.create({
|
|
174
|
-
container: {
|
|
175
|
-
padding: 12,
|
|
176
|
-
borderRadius: 10,
|
|
177
|
-
shadowColor: Colors.Shadow,
|
|
178
|
-
shadowOffset: {
|
|
179
|
-
width: 0,
|
|
180
|
-
height: 2,
|
|
181
|
-
},
|
|
182
|
-
shadowOpacity: 0.1,
|
|
183
|
-
shadowRadius: 3,
|
|
184
|
-
elevation: 4,
|
|
185
|
-
width: DEVICE_SIZE.width,
|
|
186
|
-
height: DEVICE_SIZE.height,
|
|
187
|
-
backgroundColor: Colors.White,
|
|
188
|
-
justifyContent: 'space-between',
|
|
189
|
-
marginBottom: 8,
|
|
190
|
-
borderWidth: 1,
|
|
191
|
-
},
|
|
192
154
|
boxIcon: {
|
|
193
155
|
flexDirection: 'row',
|
|
194
|
-
|
|
156
|
+
flex: 1,
|
|
195
157
|
},
|
|
196
158
|
descriptionContainer: {
|
|
197
159
|
flexDirection: 'row',
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React, { memo, useCallback, useMemo } from 'react';
|
|
2
|
+
import { StyleSheet, TouchableWithoutFeedback, View } from 'react-native';
|
|
3
|
+
import Routes from '../../utils/Route';
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
useBluetoothDeviceConnected,
|
|
8
|
+
useEoHBackendDeviceConnected,
|
|
9
|
+
useHomeAssistantDeviceConnected,
|
|
10
|
+
} from '../../hooks/IoT';
|
|
11
|
+
|
|
12
|
+
import { Colors } from '../../configs';
|
|
13
|
+
import {
|
|
14
|
+
AccessibilityLabel,
|
|
15
|
+
DEVICE_SIZE,
|
|
16
|
+
DEVICE_TYPE,
|
|
17
|
+
} from '../../configs/Constants';
|
|
18
|
+
|
|
19
|
+
const ItemDeviceWrapper = memo(
|
|
20
|
+
({ device, unit, station, wrapStyle, children }) => {
|
|
21
|
+
const navigation = useNavigation();
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
isConnected: isEoHBackendConnected,
|
|
25
|
+
isFetchingStatus: isFetchingStatusFromEoHBackend,
|
|
26
|
+
} = useEoHBackendDeviceConnected(device);
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
isConnected: isHomeAssistantConnected,
|
|
30
|
+
isConnecting: isHomeAssistantConnecting,
|
|
31
|
+
} = useHomeAssistantDeviceConnected(device);
|
|
32
|
+
|
|
33
|
+
const { isConnected: isBluetoothConnected } =
|
|
34
|
+
useBluetoothDeviceConnected(device);
|
|
35
|
+
|
|
36
|
+
const goToSensorDisplay = useCallback(() => {
|
|
37
|
+
navigation.navigate(Routes.DeviceDetail, {
|
|
38
|
+
unitData: unit,
|
|
39
|
+
station,
|
|
40
|
+
sensorData: device,
|
|
41
|
+
title: device.name,
|
|
42
|
+
});
|
|
43
|
+
}, [navigation, device, station, unit]);
|
|
44
|
+
|
|
45
|
+
const borderColor = useMemo(() => {
|
|
46
|
+
if (!!device && device?.is_managed_by_backend) {
|
|
47
|
+
if (device?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
48
|
+
return Colors.Gray4;
|
|
49
|
+
}
|
|
50
|
+
if (isBluetoothConnected) {
|
|
51
|
+
return Colors.Gray4;
|
|
52
|
+
}
|
|
53
|
+
if (isFetchingStatusFromEoHBackend || isEoHBackendConnected) {
|
|
54
|
+
return Colors.Gray4;
|
|
55
|
+
}
|
|
56
|
+
return Colors.Red6;
|
|
57
|
+
}
|
|
58
|
+
// not managed by backend
|
|
59
|
+
if (device?.device_type === DEVICE_TYPE.GOOGLE_HOME) {
|
|
60
|
+
if (isHomeAssistantConnecting || isHomeAssistantConnected) {
|
|
61
|
+
return Colors.Gray4;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return Colors.Red6;
|
|
65
|
+
}, [
|
|
66
|
+
isBluetoothConnected,
|
|
67
|
+
isEoHBackendConnected,
|
|
68
|
+
isFetchingStatusFromEoHBackend,
|
|
69
|
+
isHomeAssistantConnected,
|
|
70
|
+
isHomeAssistantConnecting,
|
|
71
|
+
device,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<TouchableWithoutFeedback
|
|
76
|
+
onPress={goToSensorDisplay}
|
|
77
|
+
accessibilityLabel={`${AccessibilityLabel.SENSOR_NAME}-${device?.id}`}
|
|
78
|
+
>
|
|
79
|
+
<View
|
|
80
|
+
style={[styles.container, wrapStyle, { borderColor }]}
|
|
81
|
+
accessibilityLabel={AccessibilityLabel.SUB_UNIT_DEVICES}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</View>
|
|
85
|
+
</TouchableWithoutFeedback>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export default ItemDeviceWrapper;
|
|
91
|
+
|
|
92
|
+
const styles = StyleSheet.create({
|
|
93
|
+
container: {
|
|
94
|
+
padding: 12,
|
|
95
|
+
borderRadius: 10,
|
|
96
|
+
shadowColor: Colors.Shadow,
|
|
97
|
+
shadowOffset: {
|
|
98
|
+
width: 0,
|
|
99
|
+
height: 2,
|
|
100
|
+
},
|
|
101
|
+
shadowOpacity: 0.1,
|
|
102
|
+
shadowRadius: 3,
|
|
103
|
+
elevation: 4,
|
|
104
|
+
width: DEVICE_SIZE.width,
|
|
105
|
+
backgroundColor: Colors.White,
|
|
106
|
+
marginBottom: 8,
|
|
107
|
+
borderWidth: 1,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
2
|
+
import { timeDifference } from '../../utils/Converter/time';
|
|
3
|
+
import Text from '../Text';
|
|
4
|
+
import { Colors } from '../../configs';
|
|
5
|
+
import React, { memo } from 'react';
|
|
6
|
+
import { StyleSheet } from 'react-native';
|
|
7
|
+
|
|
8
|
+
const styles = StyleSheet.create({
|
|
9
|
+
txtLastUpdate: {
|
|
10
|
+
marginLeft: 8,
|
|
11
|
+
lineHeight: 20,
|
|
12
|
+
marginTop: 8,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const LastUpdatedText = memo(({ lastUpdated, showText }) => {
|
|
17
|
+
const t = useTranslations();
|
|
18
|
+
|
|
19
|
+
const lastUpdatedStr = lastUpdated
|
|
20
|
+
? timeDifference(new Date(), lastUpdated)
|
|
21
|
+
: `5 ${t('seconds_ago')}`;
|
|
22
|
+
return (
|
|
23
|
+
<Text color={Colors.Gray7} size={12} style={styles.txtLastUpdate}>
|
|
24
|
+
{!!showText && t('last_updated')}
|
|
25
|
+
{!!showText && ' '}
|
|
26
|
+
{lastUpdatedStr}
|
|
27
|
+
</Text>
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export default LastUpdatedText;
|
|
@@ -28,7 +28,11 @@ describe('Test ConnectedViewHeader', () => {
|
|
|
28
28
|
const instance = tree.root;
|
|
29
29
|
const texts = instance.findAllByType(Text);
|
|
30
30
|
expect(texts[0].props.children).toEqual(t('connected_via_internet'));
|
|
31
|
-
expect(texts[1].props.children).toEqual(
|
|
31
|
+
expect(texts[1].props.children).toEqual([
|
|
32
|
+
t('last_updated'),
|
|
33
|
+
' ',
|
|
34
|
+
'2 years ago',
|
|
35
|
+
]);
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
it('render ConnectedViewHeader no last updated', async () => {
|
|
@@ -37,8 +41,10 @@ describe('Test ConnectedViewHeader', () => {
|
|
|
37
41
|
});
|
|
38
42
|
const instance = tree.root;
|
|
39
43
|
const texts = instance.findAllByType(Text);
|
|
40
|
-
expect(texts[1].props.children).toEqual(
|
|
41
|
-
t('last_updated')
|
|
42
|
-
|
|
44
|
+
expect(texts[1].props.children).toEqual([
|
|
45
|
+
t('last_updated'),
|
|
46
|
+
' ',
|
|
47
|
+
'5 seconds ago',
|
|
48
|
+
]);
|
|
43
49
|
});
|
|
44
50
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import styles from '../styles/ConfigValueStyles';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import Text from '../../../Text';
|
|
5
|
+
import LastUpdatedText from '../../../Device/LastUpdatedText';
|
|
6
|
+
import { EvaluationConfigWrapper } from '../EvaluationOverConfig/EvaluationOverConfig';
|
|
7
|
+
|
|
8
|
+
const ConfigAndEvaluationDisplay = memo(
|
|
9
|
+
({ valueEvaluation, stationItem, configValue }) => {
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<View>
|
|
13
|
+
<View style={styles.rowTop}>
|
|
14
|
+
<Text type="H4" bold>
|
|
15
|
+
{stationItem?.configuration?.config_data?.name}
|
|
16
|
+
</Text>
|
|
17
|
+
</View>
|
|
18
|
+
<Text type="Body" color={valueEvaluation?.color}>
|
|
19
|
+
{valueEvaluation?.text}
|
|
20
|
+
</Text>
|
|
21
|
+
</View>
|
|
22
|
+
<View style={styles.rowBottom}>
|
|
23
|
+
<Text style={styles.textValue} bold>
|
|
24
|
+
{configValue?.value || '-'}
|
|
25
|
+
</Text>
|
|
26
|
+
<Text type="H4">{stationItem?.configuration?.config_data?.unit}</Text>
|
|
27
|
+
</View>
|
|
28
|
+
{configValue?.last_updated && (
|
|
29
|
+
<LastUpdatedText lastUpdated={configValue?.last_updated} />
|
|
30
|
+
)}
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const ConfigAndEvaluation = memo(({ device, stationItem }) => {
|
|
37
|
+
return (
|
|
38
|
+
<EvaluationConfigWrapper
|
|
39
|
+
device={device}
|
|
40
|
+
stationItem={stationItem}
|
|
41
|
+
Child={ConfigAndEvaluationDisplay}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default ConfigAndEvaluation;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ConfigAndEvaluation from './ConfigAndEvaluation';
|
|
2
|
+
import { registerTemplate } from '../register';
|
|
3
|
+
|
|
4
|
+
const isWidget = (item) => {
|
|
5
|
+
return item.template === 'ConfigAndEvaluation';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const isSettingValid = (configuration) => {
|
|
9
|
+
return configuration.config && configuration.evaluation;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
registerTemplate(isWidget, isSettingValid, ConfigAndEvaluation, {});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
|
2
|
+
import styles from '../styles/ConfigValueStyles';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import Text from '../../../Text';
|
|
5
|
+
import { useConfigGlobalState } from '../../../../iot/states';
|
|
6
|
+
import { useWatchConfigs } from '../../../../hooks/IoT';
|
|
7
|
+
import LastUpdatedText from '../../../Device/LastUpdatedText';
|
|
8
|
+
|
|
9
|
+
const ConfigValue = ({ device, stationItem }) => {
|
|
10
|
+
// eslint-disable-next-line no-unused-vars
|
|
11
|
+
const [configValues, _] = useConfigGlobalState('configValues');
|
|
12
|
+
const configValue = configValues[stationItem.configuration?.config];
|
|
13
|
+
const configIds = useMemo(() => {
|
|
14
|
+
return [stationItem.configuration?.config];
|
|
15
|
+
}, [stationItem.configuration?.config]);
|
|
16
|
+
|
|
17
|
+
useWatchConfigs(configIds);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<View>
|
|
22
|
+
<View style={styles.rowTop}>
|
|
23
|
+
<Text type="H4" bold>
|
|
24
|
+
{stationItem?.configuration?.config_data?.name}
|
|
25
|
+
</Text>
|
|
26
|
+
</View>
|
|
27
|
+
</View>
|
|
28
|
+
<View style={styles.rowBottom}>
|
|
29
|
+
<Text style={styles.textValue} bold>
|
|
30
|
+
{configValue?.value || '-'}
|
|
31
|
+
</Text>
|
|
32
|
+
<Text type="H4">{stationItem?.configuration?.config_data?.unit}</Text>
|
|
33
|
+
</View>
|
|
34
|
+
{configValue?.last_updated && (
|
|
35
|
+
<LastUpdatedText lastUpdated={configValue?.last_updated} />
|
|
36
|
+
)}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default memo(ConfigValue);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ConfigValue from './ConfigValue';
|
|
2
|
+
import { registerTemplate } from '../register';
|
|
3
|
+
|
|
4
|
+
const isWidget = (item) => {
|
|
5
|
+
return item.template === 'ConfigValue';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const isSettingValid = (configuration) => {
|
|
9
|
+
return configuration.config;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
registerTemplate(isWidget, isSettingValid, ConfigValue, {});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { getTemplate } from './';
|
|
3
|
+
import ItemDeviceWrapper from '../../Device/ItemDeviceWrapper';
|
|
4
|
+
|
|
5
|
+
export const DeviceTemplate = memo(
|
|
6
|
+
({ device, stationItem, unit, station, index }) => {
|
|
7
|
+
const Template = getTemplate(stationItem);
|
|
8
|
+
if (!Template) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return (
|
|
12
|
+
<ItemDeviceWrapper device={device} unit={unit} station={station}>
|
|
13
|
+
<Template.Display
|
|
14
|
+
device={device}
|
|
15
|
+
stationItem={stationItem}
|
|
16
|
+
index={index}
|
|
17
|
+
/>
|
|
18
|
+
</ItemDeviceWrapper>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
|
2
|
+
import styles from '../styles/ConfigValueStyles';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import Text from '../../../Text';
|
|
5
|
+
import { useConfigGlobalState } from '../../../../iot/states';
|
|
6
|
+
import {
|
|
7
|
+
useEvaluateValue,
|
|
8
|
+
useValueEvaluation,
|
|
9
|
+
} from '../../../../screens/Device/hooks/useEvaluateValue';
|
|
10
|
+
import { useWatchConfigs } from '../../../../hooks/IoT';
|
|
11
|
+
import LastUpdatedText from '../../../Device/LastUpdatedText';
|
|
12
|
+
|
|
13
|
+
export const EvaluationConfigWrapper = memo(
|
|
14
|
+
({ device, stationItem, Child }) => {
|
|
15
|
+
// eslint-disable-next-line no-unused-vars
|
|
16
|
+
const [configValues, _] = useConfigGlobalState('configValues');
|
|
17
|
+
const configValue = configValues[stationItem.configuration?.config];
|
|
18
|
+
const configIds = useMemo(() => {
|
|
19
|
+
return [stationItem.configuration?.config];
|
|
20
|
+
}, [stationItem.configuration?.config]);
|
|
21
|
+
|
|
22
|
+
useWatchConfigs(configIds);
|
|
23
|
+
|
|
24
|
+
const valueEvaluationObject = useValueEvaluation(
|
|
25
|
+
stationItem.configuration?.config,
|
|
26
|
+
device.unit_id,
|
|
27
|
+
stationItem.configuration?.evaluation
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const valueEvaluation = useEvaluateValue()(
|
|
31
|
+
configValue?.value,
|
|
32
|
+
valueEvaluationObject
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Child
|
|
37
|
+
valueEvaluation={valueEvaluation}
|
|
38
|
+
stationItem={stationItem}
|
|
39
|
+
configValue={configValue}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const EvaluationOverConfigDisplay = memo(
|
|
46
|
+
({ valueEvaluation, stationItem, configValue }) => {
|
|
47
|
+
return (
|
|
48
|
+
<>
|
|
49
|
+
<View>
|
|
50
|
+
<View style={styles.rowTop}>
|
|
51
|
+
<Text type="H4" bold>
|
|
52
|
+
{stationItem?.configuration?.config_data?.name}
|
|
53
|
+
</Text>
|
|
54
|
+
</View>
|
|
55
|
+
</View>
|
|
56
|
+
<View style={styles.rowBottom}>
|
|
57
|
+
<Text style={styles.textValue} bold color={valueEvaluation?.color}>
|
|
58
|
+
{valueEvaluation?.text}
|
|
59
|
+
</Text>
|
|
60
|
+
</View>
|
|
61
|
+
{configValue?.last_updated && (
|
|
62
|
+
<LastUpdatedText lastUpdated={configValue?.last_updated} />
|
|
63
|
+
)}
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const EvaluationOverConfig = memo(({ device, stationItem }) => {
|
|
70
|
+
return (
|
|
71
|
+
<EvaluationConfigWrapper
|
|
72
|
+
device={device}
|
|
73
|
+
stationItem={stationItem}
|
|
74
|
+
Child={EvaluationOverConfigDisplay}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export default EvaluationOverConfig;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import EvaluationOverConfig from './EvaluationOverConfig';
|
|
2
|
+
import { registerTemplate } from '../register';
|
|
3
|
+
|
|
4
|
+
const isWidget = (item) => {
|
|
5
|
+
return item.template === 'EvaluationOverConfig';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const isSettingValid = (configuration) => {
|
|
9
|
+
return configuration.config && configuration.evaluation;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
registerTemplate(isWidget, isSettingValid, EvaluationOverConfig, {});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DeviceItemTemplates } from './register';
|
|
2
|
+
|
|
3
|
+
export * from './ConfigAndEvaluation';
|
|
4
|
+
export * from './ConfigValue';
|
|
5
|
+
export * from './EvaluationOverConfig';
|
|
6
|
+
|
|
7
|
+
export const getTemplate = (item) => {
|
|
8
|
+
return DeviceItemTemplates.find((w) => w.detect(item));
|
|
9
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DeviceItemTemplates = [];
|
|
2
|
+
export const registerTemplate = (
|
|
3
|
+
isWidget,
|
|
4
|
+
isSettingValid,
|
|
5
|
+
DisplayComponent,
|
|
6
|
+
defaultConfiguration
|
|
7
|
+
) => {
|
|
8
|
+
DeviceItemTemplates.push({
|
|
9
|
+
detect: isWidget,
|
|
10
|
+
isSettingValid: isSettingValid,
|
|
11
|
+
Display: DisplayComponent,
|
|
12
|
+
defaultConfiguration,
|
|
13
|
+
});
|
|
14
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export default StyleSheet.create({
|
|
4
|
+
rowTop: {
|
|
5
|
+
flexDirection: 'row',
|
|
6
|
+
justifyContent: 'space-between',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
},
|
|
9
|
+
rowBottom: {
|
|
10
|
+
flexDirection: 'row',
|
|
11
|
+
alignItems: 'flex-end',
|
|
12
|
+
},
|
|
13
|
+
batteryStatus: {
|
|
14
|
+
flexDirection: 'row',
|
|
15
|
+
justifyContent: 'space-between',
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
},
|
|
18
|
+
textValue: {
|
|
19
|
+
fontSize: 28,
|
|
20
|
+
lineHeight: 32,
|
|
21
|
+
marginRight: 8,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -16,6 +16,7 @@ import { standardizeCameraScreenSize } from '../../utils/Utils';
|
|
|
16
16
|
import Routes from '../../utils/Route';
|
|
17
17
|
import FastImage from 'react-native-fast-image';
|
|
18
18
|
import MediaPlayerDetail from '../MediaPlayerDetail';
|
|
19
|
+
import { DeviceTemplate } from './DeviceTemplate/DeviceTemplate';
|
|
19
20
|
|
|
20
21
|
const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
|
|
21
22
|
Device.screenWidth - 32
|
|
@@ -25,15 +26,12 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
|
|
|
25
26
|
const t = useTranslations();
|
|
26
27
|
const { navigate } = useNavigation();
|
|
27
28
|
|
|
28
|
-
useDevicesStatus(unit, station?.
|
|
29
|
+
useDevicesStatus(unit, station?.devices);
|
|
29
30
|
|
|
30
31
|
const configsNeedWatching = useMemo(() => {
|
|
31
32
|
const configIds = [];
|
|
32
|
-
(station?.
|
|
33
|
-
if (
|
|
34
|
-
device?.quick_action?.config_id &&
|
|
35
|
-
device?.device_type !== DEVICE_TYPE.GOOGLE_HOME
|
|
36
|
-
) {
|
|
33
|
+
(station?.devices || []).forEach((device) => {
|
|
34
|
+
if (device?.quick_action?.config_id && device?.is_managed_by_backend) {
|
|
37
35
|
configIds.push(device.quick_action.config_id);
|
|
38
36
|
}
|
|
39
37
|
});
|
|
@@ -108,51 +106,79 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
|
|
|
108
106
|
});
|
|
109
107
|
};
|
|
110
108
|
|
|
109
|
+
const renderSubUnitItem = (device, stationItem, index) => {
|
|
110
|
+
return (
|
|
111
|
+
<DeviceTemplate
|
|
112
|
+
device={device}
|
|
113
|
+
stationItem={stationItem}
|
|
114
|
+
index={index}
|
|
115
|
+
key={index}
|
|
116
|
+
unit={unit}
|
|
117
|
+
station={station}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const renderDeviceList = () => {
|
|
123
|
+
if (!station.devices) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return station.devices
|
|
128
|
+
.map((device, index) => {
|
|
129
|
+
const displays = [];
|
|
130
|
+
if (device.device_type === DEVICE_TYPE.HANET) {
|
|
131
|
+
displays.push(
|
|
132
|
+
<ItemHanetDevice
|
|
133
|
+
key={`sensor-${device.id}`}
|
|
134
|
+
id={device.id}
|
|
135
|
+
svgMain={device.icon || 'sensor'}
|
|
136
|
+
title={device.name}
|
|
137
|
+
index={index}
|
|
138
|
+
sensor={device}
|
|
139
|
+
unit={unit}
|
|
140
|
+
station={station}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
displays.push(
|
|
145
|
+
<ItemDevice
|
|
146
|
+
key={`sensor-${device.id}`}
|
|
147
|
+
id={device.id}
|
|
148
|
+
svgMain={device.icon || 'sensor'}
|
|
149
|
+
statusIcon={device.action && device.action.icon}
|
|
150
|
+
statusColor={device.action && device.action.color}
|
|
151
|
+
description={device.value}
|
|
152
|
+
title={device.name}
|
|
153
|
+
index={index}
|
|
154
|
+
sensor={device}
|
|
155
|
+
unit={unit}
|
|
156
|
+
station={station}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (device.station_items) {
|
|
161
|
+
displays.push(
|
|
162
|
+
...device.station_items.map(renderSubUnitItem.bind(device, device))
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return displays;
|
|
166
|
+
})
|
|
167
|
+
.flat();
|
|
168
|
+
};
|
|
169
|
+
|
|
111
170
|
return (
|
|
112
171
|
<Section style={styles.noShadow}>
|
|
113
172
|
{renderCamera()}
|
|
114
173
|
|
|
115
|
-
{!!station?.
|
|
174
|
+
{!!station?.devices?.length && (
|
|
116
175
|
<Text type={'H4'} semibold style={styles.device}>{`${t('device')} (${
|
|
117
|
-
station?.
|
|
176
|
+
station?.devices?.length
|
|
118
177
|
})`}</Text>
|
|
119
178
|
)}
|
|
120
179
|
|
|
121
180
|
<View style={styles.boxDevices}>
|
|
122
|
-
{
|
|
123
|
-
station.sensors.map((sensor, index) => {
|
|
124
|
-
switch (sensor.device_type) {
|
|
125
|
-
case DEVICE_TYPE.HANET:
|
|
126
|
-
return (
|
|
127
|
-
<ItemHanetDevice
|
|
128
|
-
key={`sensor-${sensor.id}`}
|
|
129
|
-
id={sensor.id}
|
|
130
|
-
svgMain={sensor.icon || 'sensor'}
|
|
131
|
-
title={sensor.name}
|
|
132
|
-
index={index}
|
|
133
|
-
sensor={sensor}
|
|
134
|
-
unit={unit}
|
|
135
|
-
station={station}
|
|
136
|
-
/>
|
|
137
|
-
);
|
|
138
|
-
default:
|
|
139
|
-
return (
|
|
140
|
-
<ItemDevice
|
|
141
|
-
key={`sensor-${sensor.id}`}
|
|
142
|
-
id={sensor.id}
|
|
143
|
-
svgMain={sensor.icon || 'sensor'}
|
|
144
|
-
statusIcon={sensor.action && sensor.action.icon}
|
|
145
|
-
statusColor={sensor.action && sensor.action.color}
|
|
146
|
-
description={sensor.value}
|
|
147
|
-
title={sensor.name}
|
|
148
|
-
index={index}
|
|
149
|
-
sensor={sensor}
|
|
150
|
-
unit={unit}
|
|
151
|
-
station={station}
|
|
152
|
-
/>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
})}
|
|
181
|
+
{renderDeviceList()}
|
|
156
182
|
{isOwner && (
|
|
157
183
|
<ItemAddNew title={t('add_new_device')} onAddNew={handleOnAddNew} />
|
|
158
184
|
)}
|
|
@@ -9,6 +9,12 @@ import ShortDetailSubUnit from '../ShortDetail';
|
|
|
9
9
|
import ItemAddNew from '../../Device/ItemAddNew';
|
|
10
10
|
import Routes from '../../../utils/Route';
|
|
11
11
|
import { keyPermission } from '../../../utils/Permission/common';
|
|
12
|
+
import ItemDevice from '../../Device/ItemDevice';
|
|
13
|
+
import { DeviceTemplate } from '../DeviceTemplate/DeviceTemplate';
|
|
14
|
+
import ItemHanetDevice from '../../Device/Hanet/ItemHanetDevice';
|
|
15
|
+
import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
16
|
+
|
|
17
|
+
jest.mock('../../../iot/Monitor');
|
|
12
18
|
|
|
13
19
|
const wrapComponent = (props) => (
|
|
14
20
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -28,7 +34,7 @@ jest.mock('@react-navigation/native', () => {
|
|
|
28
34
|
navigate: mockedNavigate,
|
|
29
35
|
}),
|
|
30
36
|
useIsFocused: () => true,
|
|
31
|
-
useFocusEffect: jest.fn(),
|
|
37
|
+
useFocusEffect: jest.fn((handler) => handler()),
|
|
32
38
|
};
|
|
33
39
|
});
|
|
34
40
|
|
|
@@ -53,7 +59,7 @@ describe('test ShortDetail Subunit', () => {
|
|
|
53
59
|
camera: null,
|
|
54
60
|
id: 71,
|
|
55
61
|
name: 'Station 1',
|
|
56
|
-
|
|
62
|
+
devices: [],
|
|
57
63
|
},
|
|
58
64
|
],
|
|
59
65
|
user_id: 64,
|
|
@@ -120,7 +126,7 @@ describe('test ShortDetail Subunit', () => {
|
|
|
120
126
|
});
|
|
121
127
|
|
|
122
128
|
it('render ShortDetail with device', async () => {
|
|
123
|
-
props.station.
|
|
129
|
+
props.station.devices = [
|
|
124
130
|
{
|
|
125
131
|
action: {
|
|
126
132
|
color: '#00979D',
|
|
@@ -146,12 +152,110 @@ describe('test ShortDetail Subunit', () => {
|
|
|
146
152
|
tree = await create(wrapComponent(props));
|
|
147
153
|
});
|
|
148
154
|
const instance = tree.root;
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
const itemDevices = instance.findAllByType(ItemDevice);
|
|
156
|
+
expect(itemDevices.length).toBe(1);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('render watch config if managed by backend', async () => {
|
|
160
|
+
props.station.devices = [
|
|
161
|
+
{
|
|
162
|
+
action: {
|
|
163
|
+
color: '#00979D',
|
|
164
|
+
icon: 'caret-up',
|
|
165
|
+
id: 1,
|
|
166
|
+
key: '',
|
|
167
|
+
},
|
|
168
|
+
action2: null,
|
|
169
|
+
chip_id: 1,
|
|
170
|
+
description: null,
|
|
171
|
+
icon: '',
|
|
172
|
+
id: 1,
|
|
173
|
+
name: 'People Counting',
|
|
174
|
+
quick_action: { config_id: 1 },
|
|
175
|
+
remote_control_options: {},
|
|
176
|
+
station: {},
|
|
177
|
+
status: null,
|
|
178
|
+
status2: null,
|
|
179
|
+
is_managed_by_backend: true,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
await act(async () => {
|
|
184
|
+
tree = await create(wrapComponent(props));
|
|
185
|
+
});
|
|
186
|
+
expect(watchMultiConfigs).toBeCalledWith([1]);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
['ConfigAndEvaluation', 'ConfigValue', 'EvaluationOverConfig'].forEach(
|
|
190
|
+
(template) => {
|
|
191
|
+
it(`render with device template ${template}`, async () => {
|
|
192
|
+
props.station.devices = [
|
|
193
|
+
{
|
|
194
|
+
action: {
|
|
195
|
+
color: '#00979D',
|
|
196
|
+
icon: 'caret-up',
|
|
197
|
+
id: 1,
|
|
198
|
+
key: '',
|
|
199
|
+
},
|
|
200
|
+
action2: null,
|
|
201
|
+
chip_id: 1,
|
|
202
|
+
description: null,
|
|
203
|
+
icon: '',
|
|
204
|
+
id: 1,
|
|
205
|
+
name: 'People Counting',
|
|
206
|
+
quick_action: null,
|
|
207
|
+
remote_control_options: {},
|
|
208
|
+
station: {},
|
|
209
|
+
status: null,
|
|
210
|
+
status2: null,
|
|
211
|
+
station_items: [
|
|
212
|
+
{
|
|
213
|
+
template: template,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
await act(async () => {
|
|
220
|
+
tree = await create(wrapComponent(props));
|
|
221
|
+
});
|
|
222
|
+
const instance = tree.root;
|
|
223
|
+
const itemDevices = instance.findAllByType(DeviceTemplate);
|
|
224
|
+
expect(itemDevices.length).toBe(1);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
it('render with device hanet', async () => {
|
|
230
|
+
props.station.devices = [
|
|
231
|
+
{
|
|
232
|
+
device_type: 'HANET',
|
|
233
|
+
action: {
|
|
234
|
+
color: '#00979D',
|
|
235
|
+
icon: 'caret-up',
|
|
236
|
+
id: 1,
|
|
237
|
+
key: '',
|
|
238
|
+
},
|
|
239
|
+
action2: null,
|
|
240
|
+
chip_id: 1,
|
|
241
|
+
description: null,
|
|
242
|
+
icon: '',
|
|
243
|
+
id: 1,
|
|
244
|
+
name: 'People Counting',
|
|
245
|
+
quick_action: null,
|
|
246
|
+
remote_control_options: {},
|
|
247
|
+
station: {},
|
|
248
|
+
status: null,
|
|
249
|
+
status2: null,
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
await act(async () => {
|
|
254
|
+
tree = await create(wrapComponent(props));
|
|
255
|
+
});
|
|
256
|
+
const instance = tree.root;
|
|
257
|
+
const itemDevices = instance.findAllByType(ItemHanetDevice);
|
|
258
|
+
expect(itemDevices.length).toBe(1);
|
|
155
259
|
});
|
|
156
260
|
|
|
157
261
|
it('render ShortDetail add new device', async () => {
|
|
@@ -628,12 +628,8 @@ describe('test DeviceDetail', () => {
|
|
|
628
628
|
await act(async () => {
|
|
629
629
|
tree = await create(wrapComponent(store, account, route));
|
|
630
630
|
});
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
(el) =>
|
|
634
|
-
el.props.accessibilityLabel === AccessibilityLabel.SENSOR_DISPLAY_ITEM
|
|
635
|
-
);
|
|
636
|
-
expect(sensorDisplayItem).toHaveLength(0);
|
|
631
|
+
const urls = mock.history.get.map((x) => x.url);
|
|
632
|
+
expect(urls).not.toContain(API.DEVICE.DISPLAY_VALUES_V2(1));
|
|
637
633
|
});
|
|
638
634
|
|
|
639
635
|
it('HeaderDevice button more onClick', async () => {
|
|
@@ -30,68 +30,72 @@ export const SensorConnectStatusViewHeader = ({
|
|
|
30
30
|
return <></>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
if (sensor
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<>
|
|
45
|
-
<ConnectedViewHeader
|
|
46
|
-
lastUpdated={lastUpdated}
|
|
47
|
-
isDisplayTime={isDisplayTime}
|
|
48
|
-
showWindDirection={showWindDirection}
|
|
49
|
-
/>
|
|
50
|
-
{children}
|
|
51
|
-
</>
|
|
52
|
-
);
|
|
53
|
-
} else if (connectedViaBle) {
|
|
54
|
-
return (
|
|
55
|
-
<>
|
|
56
|
-
<ConnectedViewHeader
|
|
57
|
-
lastUpdated={lastUpdated}
|
|
58
|
-
type={'Bluetooth'}
|
|
59
|
-
isDisplayTime={isDisplayTime}
|
|
60
|
-
showWindDirection={showWindDirection}
|
|
61
|
-
/>
|
|
62
|
-
{children}
|
|
63
|
-
</>
|
|
64
|
-
);
|
|
65
|
-
} else {
|
|
66
|
-
return (
|
|
67
|
-
<DisconnectedView sensor={sensor} isDeviceHasBle={isDeviceHasBle} />
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
// not managed by backend
|
|
72
|
-
if (sensor?.device_type === DEVICE_TYPE.GOOGLE_HOME) {
|
|
73
|
-
if (connectedViaHomeAssistant) {
|
|
33
|
+
const header = () => {
|
|
34
|
+
if (!!sensor && sensor?.is_managed_by_backend) {
|
|
35
|
+
if (sensor?.device_type === DEVICE_TYPE.LG_THINQ) {
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<ConnectedViewHeader lastUpdated={lastUpdated} />
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (connectedViaNetwork) {
|
|
74
43
|
return (
|
|
75
44
|
<>
|
|
76
45
|
<ConnectedViewHeader
|
|
77
46
|
lastUpdated={lastUpdated}
|
|
78
47
|
isDisplayTime={isDisplayTime}
|
|
79
|
-
|
|
48
|
+
showWindDirection={showWindDirection}
|
|
49
|
+
/>
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
} else if (connectedViaBle) {
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<ConnectedViewHeader
|
|
56
|
+
lastUpdated={lastUpdated}
|
|
57
|
+
type={'Bluetooth'}
|
|
58
|
+
isDisplayTime={isDisplayTime}
|
|
59
|
+
showWindDirection={showWindDirection}
|
|
80
60
|
/>
|
|
81
|
-
{children}
|
|
82
61
|
</>
|
|
83
62
|
);
|
|
84
63
|
} else {
|
|
85
64
|
return (
|
|
86
|
-
<DisconnectedView
|
|
87
|
-
sensor={sensor}
|
|
88
|
-
type={'HomeAssistant'}
|
|
89
|
-
isDeviceHasBle={isDeviceHasBle}
|
|
90
|
-
/>
|
|
65
|
+
<DisconnectedView sensor={sensor} isDeviceHasBle={isDeviceHasBle} />
|
|
91
66
|
);
|
|
92
67
|
}
|
|
93
68
|
} else {
|
|
94
|
-
|
|
69
|
+
// not managed by backend
|
|
70
|
+
if (sensor?.device_type === DEVICE_TYPE.GOOGLE_HOME) {
|
|
71
|
+
if (connectedViaHomeAssistant) {
|
|
72
|
+
return (
|
|
73
|
+
<>
|
|
74
|
+
<ConnectedViewHeader
|
|
75
|
+
lastUpdated={lastUpdated}
|
|
76
|
+
isDisplayTime={isDisplayTime}
|
|
77
|
+
type={'HomeAssistant'}
|
|
78
|
+
/>
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
return (
|
|
83
|
+
<DisconnectedView
|
|
84
|
+
sensor={sensor}
|
|
85
|
+
type={'HomeAssistant'}
|
|
86
|
+
isDeviceHasBle={isDeviceHasBle}
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
return <DisconnectedView sensor={sensor} />;
|
|
92
|
+
}
|
|
95
93
|
}
|
|
96
|
-
}
|
|
94
|
+
};
|
|
95
|
+
return (
|
|
96
|
+
<>
|
|
97
|
+
{header()}
|
|
98
|
+
{children}
|
|
99
|
+
</>
|
|
100
|
+
);
|
|
97
101
|
};
|
|
@@ -146,3 +146,8 @@ export const useGetEvaluateValue = (configId, unitId) => {
|
|
|
146
146
|
|
|
147
147
|
return valueEvaluations[configId];
|
|
148
148
|
};
|
|
149
|
+
|
|
150
|
+
export const useValueEvaluation = (configId, unitId, valueEvaluationId) => {
|
|
151
|
+
const valueEvaluations = useGetEvaluateValue(configId, unitId);
|
|
152
|
+
return valueEvaluations?.find((v) => v.id === valueEvaluationId);
|
|
153
|
+
};
|
|
@@ -20,8 +20,8 @@ const wrapComponent = (item) => (
|
|
|
20
20
|
</SCProvider>
|
|
21
21
|
);
|
|
22
22
|
|
|
23
|
-
describe('test
|
|
24
|
-
it('test
|
|
23
|
+
describe('test DeviceTemplate', () => {
|
|
24
|
+
it('test DeviceTemplate', async () => {
|
|
25
25
|
const item = {
|
|
26
26
|
id: 1,
|
|
27
27
|
name: 'abc',
|
|
@@ -8,6 +8,10 @@ export const timeDifference = (current, previous, symbol = false) => {
|
|
|
8
8
|
let msPerMonth = msPerDay * 30;
|
|
9
9
|
let msPerYear = msPerDay * 365;
|
|
10
10
|
|
|
11
|
+
if (typeof previous === 'string') {
|
|
12
|
+
previous = moment(previous).toDate();
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
let elapsed = current - previous;
|
|
12
16
|
|
|
13
17
|
if (elapsed < msPerMinute) {
|
|
@@ -56,7 +56,9 @@ export const keyPermission = {
|
|
|
56
56
|
: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
|
|
57
57
|
CAMERA: isAndroid ? PERMISSIONS.ANDROID.CAMERA : PERMISSIONS.IOS.CAMERA,
|
|
58
58
|
SELECT_PHOTO: isAndroid
|
|
59
|
-
?
|
|
59
|
+
? Platform.Version >= 33
|
|
60
|
+
? PERMISSIONS.ANDROID.READ_MEDIA_IMAGES
|
|
61
|
+
: PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE
|
|
60
62
|
: PERMISSIONS.IOS.PHOTO_LIBRARY,
|
|
61
63
|
};
|
|
62
64
|
|