@eohjsc/react-native-smart-city 0.2.60 → 0.2.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 +2 -2
- package/src/commons/Device/HistoryChart.js +67 -65
- package/src/commons/ImagePicker/index.js +27 -33
- package/src/commons/UnitSummary/AirQuality/index.js +9 -7
- package/src/iot/RemoteControl/GoogleHome.js +1 -1
- package/src/screens/SubUnit/AddSubUnit.js +3 -3
- package/src/screens/SubUnit/EditSubUnit.js +8 -6
- package/src/screens/SubUnit/__test__/EditSubUnit.test.js +2 -2
- package/src/screens/Unit/ManageUnit.js +11 -14
- package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +55 -57
- package/src/screens/UnitSummary/components/PowerConsumption/index.js +23 -20
- package/src/screens/UnitSummary/components/Temperature/index.js +15 -14
- package/src/screens/UnitSummary/components/UvIndex/index.js +6 -5
- package/src/screens/UnitSummary/components/WaterQuality/index.js +9 -7
- package/src/screens/UnitSummary/index.js +11 -7
- package/src/utils/Apis/axios.js +4 -4
- package/src/utils/I18n/translations/en.json +1 -1
- package/src/utils/I18n/translations/vi.json +3 -2
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.2.
|
|
4
|
+
"version": "0.2.61",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"react-native-geocoder": "^0.5.0",
|
|
158
158
|
"react-native-gesture-handler": "^1.7.0",
|
|
159
159
|
"react-native-get-location": "^2.0.0",
|
|
160
|
-
"react-native-image-picker": "^
|
|
160
|
+
"react-native-image-crop-picker": "^0.37.2",
|
|
161
161
|
"react-native-image-resizer": "^1.4.5",
|
|
162
162
|
"react-native-input-credit-card": "^0.5.5",
|
|
163
163
|
"react-native-iphone-x-helper": "^1.2.1",
|
|
@@ -38,94 +38,97 @@ const HistoryChart = memo(
|
|
|
38
38
|
configuration,
|
|
39
39
|
}) => {
|
|
40
40
|
const t = useTranslations();
|
|
41
|
-
const dateNow = moment().valueOf();
|
|
42
41
|
const [chartOptions, setChartOptions] = useState({
|
|
43
42
|
index: -1,
|
|
44
43
|
showAll: true,
|
|
45
44
|
});
|
|
46
45
|
const [eventPicker, setEventPicker] = useState({
|
|
47
|
-
currentChangeTime: '',
|
|
48
46
|
showModalEnd: false,
|
|
49
47
|
showModalStart: false,
|
|
50
48
|
startTime: startDate ? startDate : moment().subtract(1, 'day').valueOf(),
|
|
51
|
-
endTime:
|
|
49
|
+
endTime: endDate ? endDate : moment().valueOf(),
|
|
52
50
|
});
|
|
53
51
|
const [price, setPrice] = useState(null);
|
|
54
52
|
|
|
55
53
|
const onStart = useCallback(() => {
|
|
56
|
-
setEventPicker({
|
|
57
|
-
...
|
|
58
|
-
currentChangeTime: 'start',
|
|
54
|
+
setEventPicker((state) => ({
|
|
55
|
+
...state,
|
|
59
56
|
showModalStart: true,
|
|
60
57
|
showModalEnd: false,
|
|
61
|
-
});
|
|
62
|
-
}, [
|
|
58
|
+
}));
|
|
59
|
+
}, []);
|
|
63
60
|
const onEnd = useCallback(() => {
|
|
64
|
-
setEventPicker({
|
|
65
|
-
...
|
|
66
|
-
currentChangeTime: 'end',
|
|
67
|
-
show: true,
|
|
61
|
+
setEventPicker((state) => ({
|
|
62
|
+
...state,
|
|
68
63
|
showModalStart: false,
|
|
69
64
|
showModalEnd: true,
|
|
70
|
-
});
|
|
71
|
-
}, [
|
|
72
|
-
const onConfirmStart = (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
65
|
+
}));
|
|
66
|
+
}, []);
|
|
67
|
+
const onConfirmStart = useCallback(
|
|
68
|
+
(date) => {
|
|
69
|
+
setEventPicker((state) => {
|
|
70
|
+
if (typeof date === 'number') {
|
|
71
|
+
onCancel();
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
if (moment(date).valueOf() < state.endTime) {
|
|
75
|
+
setStartDate(moment(date).valueOf());
|
|
76
|
+
return {
|
|
77
|
+
...state,
|
|
78
|
+
showModalStart: false,
|
|
79
|
+
startTime: moment(date).valueOf(),
|
|
80
|
+
};
|
|
81
|
+
} else {
|
|
82
|
+
setStartDate(moment(date).valueOf());
|
|
83
|
+
setEndDate(moment(date).add(1, 'day').valueOf());
|
|
84
|
+
return {
|
|
85
|
+
...state,
|
|
86
|
+
showModalStart: false,
|
|
87
|
+
startTime: moment(date).valueOf(),
|
|
88
|
+
endTime: moment(date).add(1, 'day').valueOf(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
91
|
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
};
|
|
92
|
+
},
|
|
93
|
+
[onCancel, setStartDate, setEndDate]
|
|
94
|
+
);
|
|
96
95
|
|
|
97
|
-
const onConfirmEnd = (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
const onConfirmEnd = useCallback(
|
|
97
|
+
(date) => {
|
|
98
|
+
setEventPicker((state) => {
|
|
99
|
+
if (typeof date === 'number') {
|
|
100
|
+
onCancel();
|
|
101
|
+
return state;
|
|
102
|
+
}
|
|
103
|
+
if (moment(date).valueOf() > state.startTime) {
|
|
104
|
+
setEndDate(moment(date).valueOf());
|
|
105
|
+
return {
|
|
106
|
+
...state,
|
|
107
|
+
showModalEnd: false,
|
|
108
|
+
endTime: moment(date).valueOf(),
|
|
109
|
+
};
|
|
110
|
+
} else {
|
|
111
|
+
setStartDate(moment(date).add(-1, 'day').valueOf());
|
|
112
|
+
setEndDate(moment(date).valueOf());
|
|
113
|
+
return {
|
|
114
|
+
...state,
|
|
115
|
+
showModalEnd: false,
|
|
116
|
+
startTime: moment(date).add(-1, 'day').valueOf(),
|
|
117
|
+
endTime: moment(date).valueOf(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
108
120
|
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
currentChangeTime: 'start',
|
|
113
|
-
showModalEnd: false,
|
|
114
|
-
endTime: moment(date).valueOf(),
|
|
115
|
-
startTime: moment(date).subtract(1, 'day').valueOf(),
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
setEndDate(moment(date).valueOf());
|
|
119
|
-
};
|
|
121
|
+
},
|
|
122
|
+
[onCancel, setStartDate, setEndDate]
|
|
123
|
+
);
|
|
120
124
|
|
|
121
125
|
const onCancel = useCallback(() => {
|
|
122
|
-
setEventPicker({
|
|
123
|
-
...
|
|
124
|
-
currentChangeTime: '',
|
|
126
|
+
setEventPicker((state) => ({
|
|
127
|
+
...state,
|
|
125
128
|
showModalEnd: false,
|
|
126
129
|
showModalStart: false,
|
|
127
|
-
});
|
|
128
|
-
}, [
|
|
130
|
+
}));
|
|
131
|
+
}, []);
|
|
129
132
|
const onShowOneChart = useCallback(
|
|
130
133
|
(index) => {
|
|
131
134
|
if (index === chartOptions.index) {
|
|
@@ -191,7 +194,6 @@ const HistoryChart = memo(
|
|
|
191
194
|
onStart={onStart}
|
|
192
195
|
onEnd={onEnd}
|
|
193
196
|
endTime={eventPicker.endTime}
|
|
194
|
-
date={dateNow}
|
|
195
197
|
formatType={formatType}
|
|
196
198
|
/>
|
|
197
199
|
</View>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
2
|
import { Platform, PermissionsAndroid } from 'react-native';
|
|
3
|
-
import
|
|
3
|
+
import ImagePickerCrop from 'react-native-image-crop-picker';
|
|
4
|
+
|
|
4
5
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
6
|
|
|
6
7
|
import ButtonPopup from '../ButtonPopup';
|
|
@@ -54,34 +55,29 @@ const ImagePicker = ({
|
|
|
54
55
|
}
|
|
55
56
|
}, []);
|
|
56
57
|
|
|
57
|
-
// options info: check https://github.com/react-native-image-picker/react-native-image-picker
|
|
58
58
|
const captureImage = useCallback(
|
|
59
59
|
async (type) => {
|
|
60
60
|
let options = optionsCapture
|
|
61
61
|
? optionsCapture
|
|
62
62
|
: {
|
|
63
63
|
mediaType: type,
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
compressImageMaxWidth: 1280,
|
|
65
|
+
compressImageMaxHeight: 720,
|
|
66
|
+
compressImageQuality: 0.8,
|
|
66
67
|
};
|
|
67
68
|
|
|
68
69
|
let isCameraPermitted = await requestCameraPermission();
|
|
69
70
|
let isStoragePermitted = await requestExternalWritePermission();
|
|
70
71
|
if (isCameraPermitted && isStoragePermitted) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
setImageUrl(response);
|
|
83
|
-
setShowImagePicker(false);
|
|
84
|
-
});
|
|
72
|
+
await ImagePickerCrop.openCamera(options)
|
|
73
|
+
.then((response) => {
|
|
74
|
+
setImageUrl(response);
|
|
75
|
+
setShowImagePicker(false);
|
|
76
|
+
})
|
|
77
|
+
.catch((e) => {
|
|
78
|
+
/* eslint-disable no-console */
|
|
79
|
+
console.log('ERROR ' + e);
|
|
80
|
+
});
|
|
85
81
|
}
|
|
86
82
|
},
|
|
87
83
|
[
|
|
@@ -94,26 +90,24 @@ const ImagePicker = ({
|
|
|
94
90
|
);
|
|
95
91
|
|
|
96
92
|
const chooseFile = useCallback(
|
|
97
|
-
(type) => {
|
|
93
|
+
async (type) => {
|
|
98
94
|
let options = optionsSelect
|
|
99
95
|
? optionsSelect
|
|
100
96
|
: {
|
|
101
97
|
mediaType: type,
|
|
102
|
-
|
|
98
|
+
compressImageMaxWidth: 1280,
|
|
99
|
+
compressImageMaxHeight: 720,
|
|
100
|
+
compressImageQuality: 0.8,
|
|
103
101
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
setImageUrl(response);
|
|
115
|
-
setShowImagePicker(false);
|
|
116
|
-
});
|
|
102
|
+
await ImagePickerCrop.openPicker(options)
|
|
103
|
+
.then((response) => {
|
|
104
|
+
setImageUrl(response);
|
|
105
|
+
setShowImagePicker(false);
|
|
106
|
+
})
|
|
107
|
+
.catch((e) => {
|
|
108
|
+
/* eslint-disable no-console */
|
|
109
|
+
console.log('ERROR ' + e);
|
|
110
|
+
});
|
|
117
111
|
},
|
|
118
112
|
[setImageUrl, setShowImagePicker, optionsSelect]
|
|
119
113
|
);
|
|
@@ -63,6 +63,14 @@ const AirQuality = memo(({ summaryDetail }) => {
|
|
|
63
63
|
return outdoor_pm10_id || outdoor_pm2_5_id || outdoor_co_id ? true : false;
|
|
64
64
|
}, [outdoor_pm10_id, outdoor_pm2_5_id, outdoor_co_id]);
|
|
65
65
|
|
|
66
|
+
const configs = useMemo(() => {
|
|
67
|
+
return [
|
|
68
|
+
{ id: outdoor_pm2_5_id, title: 'PM2.5', color: 'red' },
|
|
69
|
+
{ id: outdoor_pm10_id, title: 'PM10', color: 'blue' },
|
|
70
|
+
{ id: outdoor_co_id, title: 'CO', color: 'orange' },
|
|
71
|
+
];
|
|
72
|
+
}, [outdoor_pm10_id, outdoor_pm2_5_id, outdoor_co_id]);
|
|
73
|
+
|
|
66
74
|
const [indexOutdoor, setIndexOutdoor] = useState(0);
|
|
67
75
|
const onSelectOutdoor = useCallback((i) => {
|
|
68
76
|
setIndexOutdoor(i);
|
|
@@ -154,13 +162,7 @@ const AirQuality = memo(({ summaryDetail }) => {
|
|
|
154
162
|
)}
|
|
155
163
|
{showBoxHistory && (
|
|
156
164
|
<Section type={'border'}>
|
|
157
|
-
<ConfigHistoryChart
|
|
158
|
-
configs={[
|
|
159
|
-
{ id: outdoor_pm2_5_id, title: 'PM2.5', color: 'red' },
|
|
160
|
-
{ id: outdoor_pm10_id, title: 'PM10', color: 'blue' },
|
|
161
|
-
{ id: outdoor_co_id, title: 'CO', color: 'orange' },
|
|
162
|
-
]}
|
|
163
|
-
/>
|
|
165
|
+
<ConfigHistoryChart configs={configs} />
|
|
164
166
|
</Section>
|
|
165
167
|
)}
|
|
166
168
|
</View>
|
|
@@ -29,11 +29,11 @@ import styles from './AddSubUnitStyles';
|
|
|
29
29
|
const MAX_FILE_SIZE_BYTES = 1.5 * 1024 * 1024; // 1.5mb
|
|
30
30
|
|
|
31
31
|
const prepareImageToUpload = async (image) => {
|
|
32
|
-
if (!image || image.
|
|
32
|
+
if (!image || image.size < MAX_FILE_SIZE_BYTES) {
|
|
33
33
|
return image;
|
|
34
34
|
}
|
|
35
35
|
const result = await ImageResizer.createResizedImage(
|
|
36
|
-
image.
|
|
36
|
+
image.path,
|
|
37
37
|
1280,
|
|
38
38
|
1280,
|
|
39
39
|
'JPEG',
|
|
@@ -214,7 +214,7 @@ const AddSubUnit = ({ route }) => {
|
|
|
214
214
|
</Text>
|
|
215
215
|
{wallpaper ? (
|
|
216
216
|
<Image
|
|
217
|
-
source={{ uri: wallpaper.uri }}
|
|
217
|
+
source={{ uri: wallpaper.uri || wallpaper.path }}
|
|
218
218
|
style={styles.wallpaper}
|
|
219
219
|
/>
|
|
220
220
|
) : (
|
|
@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
|
|
4
4
|
import { useIsFocused, useNavigation } from '@react-navigation/native';
|
|
5
5
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
6
6
|
|
|
7
|
-
import { Colors, API
|
|
7
|
+
import { Colors, API } from '../../configs';
|
|
8
8
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
9
9
|
import {
|
|
10
10
|
axiosPatch,
|
|
@@ -84,9 +84,11 @@ const EditSubUnit = ({ route }) => {
|
|
|
84
84
|
},
|
|
85
85
|
[unit.id, station.id, t]
|
|
86
86
|
);
|
|
87
|
+
|
|
87
88
|
const updateBackground = useCallback(
|
|
88
89
|
async (headers) => {
|
|
89
|
-
const formData = createFormData(imageUrl, ['background']);
|
|
90
|
+
const formData = createFormData({ background: imageUrl }, ['background']);
|
|
91
|
+
|
|
90
92
|
const { success } = await axiosPatch(
|
|
91
93
|
API.SUB_UNIT.MANAGE_SUB_UNIT(unit.id, station.id),
|
|
92
94
|
formData,
|
|
@@ -146,9 +148,9 @@ const EditSubUnit = ({ route }) => {
|
|
|
146
148
|
const options = {
|
|
147
149
|
mediaType: 'photo',
|
|
148
150
|
maxWidth: 1024,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
compressImageMaxWidth: 1280,
|
|
152
|
+
compressImageMaxHeight: 720,
|
|
153
|
+
compressImageQuality: 0.8,
|
|
152
154
|
};
|
|
153
155
|
|
|
154
156
|
const contactsName = listContacts.map((item) => item.name);
|
|
@@ -193,7 +195,7 @@ const EditSubUnit = ({ route }) => {
|
|
|
193
195
|
<Image
|
|
194
196
|
style={styles.image}
|
|
195
197
|
source={{
|
|
196
|
-
uri: resourcePath.uri,
|
|
198
|
+
uri: resourcePath.uri || resourcePath.path,
|
|
197
199
|
}}
|
|
198
200
|
resizeMode="cover"
|
|
199
201
|
/>
|
|
@@ -381,7 +381,7 @@ describe('Test EditSubUnit', () => {
|
|
|
381
381
|
const imagePicker = instance.findByType(ImagePicker);
|
|
382
382
|
const image = instance.findByType(Image);
|
|
383
383
|
expect(image.props.source).toEqual({
|
|
384
|
-
uri:
|
|
384
|
+
uri: undefined,
|
|
385
385
|
});
|
|
386
386
|
await act(async () => {
|
|
387
387
|
await imagePicker.props.setImageUrl({ uri: 'path' });
|
|
@@ -413,7 +413,7 @@ describe('Test EditSubUnit', () => {
|
|
|
413
413
|
const imagePicker = instance.findByType(ImagePicker);
|
|
414
414
|
const image = instance.findByType(Image);
|
|
415
415
|
expect(image.props.source).toEqual({
|
|
416
|
-
uri:
|
|
416
|
+
uri: undefined,
|
|
417
417
|
});
|
|
418
418
|
await act(async () => {
|
|
419
419
|
await imagePicker.props.setImageUrl({ uri: 'path' });
|
|
@@ -3,7 +3,7 @@ import { View, TouchableOpacity, Image, Platform } from 'react-native';
|
|
|
3
3
|
import Animated from 'react-native-reanimated';
|
|
4
4
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
5
|
|
|
6
|
-
import { Colors, API,
|
|
6
|
+
import { Colors, API, Images } from '../../configs';
|
|
7
7
|
import Routes from '../../utils/Route';
|
|
8
8
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
9
9
|
import {
|
|
@@ -77,8 +77,8 @@ const ManageUnit = ({ route }) => {
|
|
|
77
77
|
const [showImagePicker, setShowImagePicker] = useState(false);
|
|
78
78
|
|
|
79
79
|
const updateUnit = useCallback(
|
|
80
|
-
async (
|
|
81
|
-
const formData = createFormData(
|
|
80
|
+
async (headers) => {
|
|
81
|
+
const formData = createFormData({ background: imageUrl }, ['background']);
|
|
82
82
|
|
|
83
83
|
const { success, data } = await axiosPatch(
|
|
84
84
|
API.UNIT.MANAGE_UNIT(unit.id),
|
|
@@ -90,7 +90,7 @@ const ManageUnit = ({ route }) => {
|
|
|
90
90
|
ToastBottomHelper.success(t('unit_updated_successfully'));
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
-
[unit.id, t]
|
|
93
|
+
[unit.id, t, imageUrl]
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
const updateLocation = useCallback(
|
|
@@ -120,12 +120,9 @@ const ManageUnit = ({ route }) => {
|
|
|
120
120
|
|
|
121
121
|
useEffect(() => {
|
|
122
122
|
if (imageUrl) {
|
|
123
|
-
updateUnit(
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
headers: { 'Content-Type': 'multipart/form-data' },
|
|
127
|
-
}
|
|
128
|
-
);
|
|
123
|
+
updateUnit({
|
|
124
|
+
headers: { 'Content-Type': 'multipart/form-data' },
|
|
125
|
+
});
|
|
129
126
|
}
|
|
130
127
|
}, [imageUrl, updateUnit]);
|
|
131
128
|
|
|
@@ -158,9 +155,9 @@ const ManageUnit = ({ route }) => {
|
|
|
158
155
|
const options = {
|
|
159
156
|
mediaType: 'photo',
|
|
160
157
|
maxWidth: 1024,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
compressImageMaxWidth: 1280,
|
|
159
|
+
compressImageMaxHeight: 720,
|
|
160
|
+
compressImageQuality: 0.8,
|
|
164
161
|
};
|
|
165
162
|
|
|
166
163
|
return (
|
|
@@ -202,7 +199,7 @@ const ManageUnit = ({ route }) => {
|
|
|
202
199
|
<View style={styles.boxImage}>
|
|
203
200
|
<Image
|
|
204
201
|
source={{
|
|
205
|
-
uri:
|
|
202
|
+
uri: unitData.background,
|
|
206
203
|
}}
|
|
207
204
|
borderRadius={10}
|
|
208
205
|
style={styles.image}
|
|
@@ -12,7 +12,7 @@ import HistoryChart from '../../../../commons/Device/HistoryChart';
|
|
|
12
12
|
import { axiosGet } from '../../../../utils/Apis/axios';
|
|
13
13
|
import { TESTID } from '../../../../configs/Constants';
|
|
14
14
|
|
|
15
|
-
const ThreePhasePowerConsumption = memo(({
|
|
15
|
+
const ThreePhasePowerConsumption = memo(({ summaryDetail }) => {
|
|
16
16
|
const t = useTranslations();
|
|
17
17
|
const {
|
|
18
18
|
volt1Value,
|
|
@@ -133,8 +133,59 @@ const ThreePhasePowerConsumption = memo(({ unit, summary, summaryDetail }) => {
|
|
|
133
133
|
return !!listConfigs;
|
|
134
134
|
}, [listConfigs]);
|
|
135
135
|
|
|
136
|
-
const
|
|
137
|
-
return
|
|
136
|
+
const configs = useMemo(() => {
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
id: listConfigs?.volt_1,
|
|
140
|
+
title: 'Volt 1',
|
|
141
|
+
color: Colors.Red6,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: listConfigs?.volt_2,
|
|
145
|
+
title: 'Volt 2',
|
|
146
|
+
color: Colors.Red8,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: listConfigs?.volt_3,
|
|
150
|
+
title: 'Volt 3',
|
|
151
|
+
color: Colors.Red9,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: listConfigs?.current_1,
|
|
155
|
+
title: 'Current 1',
|
|
156
|
+
color: Colors.Blue10,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: listConfigs?.current_2,
|
|
160
|
+
title: 'Current 2',
|
|
161
|
+
color: Colors.Blue11,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
id: listConfigs?.current_3,
|
|
165
|
+
title: 'Current 3',
|
|
166
|
+
color: Colors.Blue12,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: listConfigs?.active_power,
|
|
170
|
+
title: 'Active Power',
|
|
171
|
+
color: Colors.Orange6,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: listConfigs?.power_factor_1,
|
|
175
|
+
title: 'Power Factor 1',
|
|
176
|
+
color: Colors.Green6,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: listConfigs?.power_factor_2,
|
|
180
|
+
title: 'Power Factor 2',
|
|
181
|
+
color: Colors.Green9,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: listConfigs?.power_factor_3,
|
|
185
|
+
title: 'Power Factor 3',
|
|
186
|
+
color: Colors.Green10,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
138
189
|
}, [listConfigs]);
|
|
139
190
|
|
|
140
191
|
const [startDate, setStartDate] = useState(
|
|
@@ -180,60 +231,7 @@ const ThreePhasePowerConsumption = memo(({ unit, summary, summaryDetail }) => {
|
|
|
180
231
|
/>
|
|
181
232
|
{showBoxHistory && (
|
|
182
233
|
<View>
|
|
183
|
-
<ConfigHistoryChart
|
|
184
|
-
configs={[
|
|
185
|
-
{
|
|
186
|
-
id: listIdsConfig.volt_1,
|
|
187
|
-
title: 'Volt 1',
|
|
188
|
-
color: Colors.Red6,
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
id: listIdsConfig.volt_2,
|
|
192
|
-
title: 'Volt 2',
|
|
193
|
-
color: Colors.Red8,
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
id: listIdsConfig.volt_3,
|
|
197
|
-
title: 'Volt 3',
|
|
198
|
-
color: Colors.Red9,
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
id: listIdsConfig.current_1,
|
|
202
|
-
title: 'Current 1',
|
|
203
|
-
color: Colors.Blue10,
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
id: listIdsConfig.current_2,
|
|
207
|
-
title: 'Current 2',
|
|
208
|
-
color: Colors.Blue11,
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
id: listIdsConfig.current_3,
|
|
212
|
-
title: 'Current 3',
|
|
213
|
-
color: Colors.Blue12,
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
id: listIdsConfig.active_power,
|
|
217
|
-
title: 'Active Power',
|
|
218
|
-
color: Colors.Orange6,
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
id: listIdsConfig.power_factor_1,
|
|
222
|
-
title: 'Power Factor 1',
|
|
223
|
-
color: Colors.Green6,
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
id: listIdsConfig.power_factor_2,
|
|
227
|
-
title: 'Power Factor 2',
|
|
228
|
-
color: Colors.Green9,
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
id: listIdsConfig.power_factor_3,
|
|
232
|
-
title: 'Power Factor 3',
|
|
233
|
-
color: Colors.Green10,
|
|
234
|
-
},
|
|
235
|
-
]}
|
|
236
|
-
/>
|
|
234
|
+
<ConfigHistoryChart configs={configs} />
|
|
237
235
|
</View>
|
|
238
236
|
)}
|
|
239
237
|
</Section>
|
|
@@ -109,6 +109,28 @@ const PowerConsumption = memo(({ summaryDetail }) => {
|
|
|
109
109
|
fetchData();
|
|
110
110
|
}
|
|
111
111
|
}, [startDate, endDate, listConfigs?.total_power, groupBy]);
|
|
112
|
+
|
|
113
|
+
const configs = useMemo(() => {
|
|
114
|
+
return [
|
|
115
|
+
{ id: listIdsConfig?.volt, title: 'Volt', color: 'red' },
|
|
116
|
+
{
|
|
117
|
+
id: listIdsConfig?.current,
|
|
118
|
+
title: 'Current',
|
|
119
|
+
color: 'blue',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: listIdsConfig?.active_power,
|
|
123
|
+
title: 'Active Power',
|
|
124
|
+
color: 'orange',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: listIdsConfig?.power_factor,
|
|
128
|
+
title: 'Power Factor',
|
|
129
|
+
color: 'green',
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
}, [listIdsConfig]);
|
|
133
|
+
|
|
112
134
|
return (
|
|
113
135
|
<>
|
|
114
136
|
<Section type={'border'}>
|
|
@@ -120,26 +142,7 @@ const PowerConsumption = memo(({ summaryDetail }) => {
|
|
|
120
142
|
/>
|
|
121
143
|
{showBoxHistory && (
|
|
122
144
|
<View>
|
|
123
|
-
<ConfigHistoryChart
|
|
124
|
-
configs={[
|
|
125
|
-
{ id: listIdsConfig.volt, title: 'Volt', color: 'red' },
|
|
126
|
-
{
|
|
127
|
-
id: listIdsConfig.active_power,
|
|
128
|
-
title: 'Current',
|
|
129
|
-
color: 'blue',
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
id: listIdsConfig.current,
|
|
133
|
-
title: 'Active Power',
|
|
134
|
-
color: 'orange',
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
id: listIdsConfig.power_factor,
|
|
138
|
-
title: 'Power Factor',
|
|
139
|
-
color: 'green',
|
|
140
|
-
},
|
|
141
|
-
]}
|
|
142
|
-
/>
|
|
145
|
+
<ConfigHistoryChart configs={configs} />
|
|
143
146
|
</View>
|
|
144
147
|
)}
|
|
145
148
|
</Section>
|
|
@@ -56,6 +56,20 @@ const Temperature = memo(({ summaryDetail }) => {
|
|
|
56
56
|
[summaryDetail]
|
|
57
57
|
);
|
|
58
58
|
|
|
59
|
+
const configs = useMemo(() => {
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
id: listConfigs?.temp,
|
|
63
|
+
title: t('text_temperature'),
|
|
64
|
+
color: Colors.Blue10,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: listConfigs?.humi,
|
|
68
|
+
title: t('text_humidity'),
|
|
69
|
+
color: Colors.Red6,
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}, [listConfigs?.humi, listConfigs?.temp, t]);
|
|
59
73
|
return (
|
|
60
74
|
<>
|
|
61
75
|
<Section type={'border'}>
|
|
@@ -78,20 +92,7 @@ const Temperature = memo(({ summaryDetail }) => {
|
|
|
78
92
|
</Section>
|
|
79
93
|
{showBoxHistory && (
|
|
80
94
|
<Section type={'border'}>
|
|
81
|
-
<ConfigHistoryChart
|
|
82
|
-
configs={[
|
|
83
|
-
{
|
|
84
|
-
id: listConfigs.temp,
|
|
85
|
-
title: t('text_temperature'),
|
|
86
|
-
color: Colors.Blue10,
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
id: listConfigs.humi,
|
|
90
|
-
title: t('text_humidity'),
|
|
91
|
-
color: Colors.Red6,
|
|
92
|
-
},
|
|
93
|
-
]}
|
|
94
|
-
/>
|
|
95
|
+
<ConfigHistoryChart configs={configs} />
|
|
95
96
|
</Section>
|
|
96
97
|
)}
|
|
97
98
|
</>
|
|
@@ -22,6 +22,11 @@ const UvIndex = memo(({ summaryDetail }) => {
|
|
|
22
22
|
} else if (summaryDetail.uv_value > 10) {
|
|
23
23
|
valueRefined = 10;
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
const configs = useMemo(() => {
|
|
27
|
+
return [{ id: uv_id, title: t('text_uv_index'), color: Colors.Blue10 }];
|
|
28
|
+
}, [t, uv_id]);
|
|
29
|
+
|
|
25
30
|
return (
|
|
26
31
|
<>
|
|
27
32
|
<Section type={'border'}>
|
|
@@ -70,11 +75,7 @@ const UvIndex = memo(({ summaryDetail }) => {
|
|
|
70
75
|
</Section>
|
|
71
76
|
{showBoxHistory && (
|
|
72
77
|
<Section type={'border'}>
|
|
73
|
-
<ConfigHistoryChart
|
|
74
|
-
configs={[
|
|
75
|
-
{ id: uv_id, title: t('text_uv_index'), color: Colors.Blue10 },
|
|
76
|
-
]}
|
|
77
|
-
/>
|
|
78
|
+
<ConfigHistoryChart configs={configs} />
|
|
78
79
|
</Section>
|
|
79
80
|
)}
|
|
80
81
|
</>
|
|
@@ -12,6 +12,14 @@ const WaterQuality = memo(({ summaryDetail }) => {
|
|
|
12
12
|
const showBoxHistory = useMemo(() => {
|
|
13
13
|
return ph_id || tur_id || clo_id ? true : false;
|
|
14
14
|
}, [ph_id, tur_id, clo_id]);
|
|
15
|
+
|
|
16
|
+
const configs = useMemo(() => {
|
|
17
|
+
return [
|
|
18
|
+
{ id: ph_id, title: 'pH', color: 'red' },
|
|
19
|
+
{ id: tur_id, title: 'Turbidity', color: 'blue' },
|
|
20
|
+
{ id: clo_id, title: 'Chlorine residual', color: 'orange' },
|
|
21
|
+
];
|
|
22
|
+
}, [ph_id, tur_id, clo_id]);
|
|
15
23
|
return (
|
|
16
24
|
<>
|
|
17
25
|
<Section type={'border'}>
|
|
@@ -52,13 +60,7 @@ const WaterQuality = memo(({ summaryDetail }) => {
|
|
|
52
60
|
</Section>
|
|
53
61
|
{showBoxHistory && (
|
|
54
62
|
<Section type={'border'}>
|
|
55
|
-
<ConfigHistoryChart
|
|
56
|
-
configs={[
|
|
57
|
-
{ id: ph_id, title: 'pH', color: 'red' },
|
|
58
|
-
{ id: tur_id, title: 'Turbidity', color: 'blue' },
|
|
59
|
-
{ id: clo_id, title: 'Chlorine residual', color: 'orange' },
|
|
60
|
-
]}
|
|
61
|
-
/>
|
|
63
|
+
<ConfigHistoryChart configs={configs} />
|
|
62
64
|
</Section>
|
|
63
65
|
)}
|
|
64
66
|
</>
|
|
@@ -4,6 +4,7 @@ import { useNavigation } from '@react-navigation/native';
|
|
|
4
4
|
import { TouchableOpacity } from 'react-native';
|
|
5
5
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
6
6
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
7
|
+
import moment from 'moment';
|
|
7
8
|
|
|
8
9
|
import { API, Colors } from '../../configs';
|
|
9
10
|
import Routes from '../../utils/Route';
|
|
@@ -18,6 +19,7 @@ import Temperature from './components/Temperature';
|
|
|
18
19
|
import UvIndex from './components/UvIndex';
|
|
19
20
|
import WaterQuality from './components/WaterQuality';
|
|
20
21
|
import { TESTID } from '../../configs/Constants';
|
|
22
|
+
import { timeDifference } from '../../utils/Converter/time';
|
|
21
23
|
|
|
22
24
|
const UnitSummary = memo(({ route }) => {
|
|
23
25
|
const t = useTranslations();
|
|
@@ -25,6 +27,7 @@ const UnitSummary = memo(({ route }) => {
|
|
|
25
27
|
const [summaryDetail, setSummaryDetail] = useState({});
|
|
26
28
|
|
|
27
29
|
const [loading, setLoading] = useState(false);
|
|
30
|
+
const [lastUpdated, setLastUpdated] = useState();
|
|
28
31
|
const navigation = useNavigation();
|
|
29
32
|
|
|
30
33
|
const getComponentAndGuide = useCallback(() => {
|
|
@@ -75,6 +78,7 @@ const UnitSummary = memo(({ route }) => {
|
|
|
75
78
|
setLoading(false);
|
|
76
79
|
if (success) {
|
|
77
80
|
setSummaryDetail(data.data);
|
|
81
|
+
setLastUpdated(data.data.last_updated);
|
|
78
82
|
}
|
|
79
83
|
}, [summary.id, unit.id]);
|
|
80
84
|
|
|
@@ -84,7 +88,7 @@ const UnitSummary = memo(({ route }) => {
|
|
|
84
88
|
|
|
85
89
|
const autoUpdate = setInterval(() => {
|
|
86
90
|
fetchSummaryDetail();
|
|
87
|
-
},
|
|
91
|
+
}, 10000); // fetch each 10 second
|
|
88
92
|
|
|
89
93
|
return () => clearInterval(autoUpdate);
|
|
90
94
|
}, [fetchSummaryDetail]);
|
|
@@ -98,11 +102,15 @@ const UnitSummary = memo(({ route }) => {
|
|
|
98
102
|
const ComponentName = UnitSummaryDetail.componentName;
|
|
99
103
|
const GuideName = UnitSummaryDetail.guideName;
|
|
100
104
|
|
|
105
|
+
const lastUpdatedStr = lastUpdated
|
|
106
|
+
? `${t('last_updated')} ${timeDifference(moment(), moment(lastUpdated))}`
|
|
107
|
+
: null;
|
|
108
|
+
|
|
101
109
|
return (
|
|
102
110
|
<View style={[styles.container]}>
|
|
103
111
|
<WrapHeaderScrollable
|
|
104
112
|
title={summary.name}
|
|
105
|
-
subTitle={
|
|
113
|
+
subTitle={lastUpdatedStr}
|
|
106
114
|
rightComponent={
|
|
107
115
|
GuideName ? (
|
|
108
116
|
<View style={styles.rightComponent}>
|
|
@@ -122,11 +130,7 @@ const UnitSummary = memo(({ route }) => {
|
|
|
122
130
|
loading={loading}
|
|
123
131
|
onRefresh={onRefresh}
|
|
124
132
|
>
|
|
125
|
-
<ComponentName
|
|
126
|
-
summaryDetail={summaryDetail}
|
|
127
|
-
unit={unit}
|
|
128
|
-
summary={summary}
|
|
129
|
-
/>
|
|
133
|
+
<ComponentName summaryDetail={summaryDetail} unit={unit} />
|
|
130
134
|
</WrapHeaderScrollable>
|
|
131
135
|
</View>
|
|
132
136
|
);
|
package/src/utils/Apis/axios.js
CHANGED
|
@@ -2,6 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import { deleteData, getData, storeData } from '../Storage';
|
|
3
3
|
import { ToastBottomHelper } from '../Utils';
|
|
4
4
|
import NetInfo from '@react-native-community/netinfo';
|
|
5
|
+
import { Platform } from 'react-native';
|
|
5
6
|
|
|
6
7
|
export const replaceParams = (apiURL, params) => {
|
|
7
8
|
let _result = apiURL;
|
|
@@ -165,13 +166,12 @@ export function createFormData(data, list_file_field) {
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
formData.append(key, {
|
|
168
|
-
|
|
169
|
-
type: item.
|
|
170
|
-
|
|
169
|
+
uri: Platform.OS === 'ios' ? item.sourceURL : item.path,
|
|
170
|
+
type: item.mime,
|
|
171
|
+
name: item.filename || item.path?.split('/').pop(),
|
|
171
172
|
});
|
|
172
173
|
return;
|
|
173
174
|
}
|
|
174
|
-
|
|
175
175
|
formData.append(key, data[key]);
|
|
176
176
|
});
|
|
177
177
|
|
|
@@ -744,7 +744,7 @@
|
|
|
744
744
|
"rssi_node": "RSSI Node",
|
|
745
745
|
"edit_actions_list": "Edit Actions List",
|
|
746
746
|
"des_edit_actions_list": "Hold and hover to rearrange actions order",
|
|
747
|
-
"please_add_your_phone_number_and_chip_name": "Please add
|
|
747
|
+
"please_add_your_phone_number_and_chip_name": "Please add gateway name",
|
|
748
748
|
"phone_number_of_data_sim": "Phone number of data sim",
|
|
749
749
|
"select_a_sub_unit": "Select a sub-unit that you want to add this gateway",
|
|
750
750
|
"all_camera": "All Cameras",
|
|
@@ -747,7 +747,7 @@
|
|
|
747
747
|
"request_fail": "Request fail",
|
|
748
748
|
"modbus_fail": "Modbus failrate",
|
|
749
749
|
"rssi_node": "RSSI Node",
|
|
750
|
-
"please_add_your_phone_number_and_chip_name": "Vui lòng thêm
|
|
750
|
+
"please_add_your_phone_number_and_chip_name": "Vui lòng thêm tên gateway",
|
|
751
751
|
"phone_number_of_data_sim": "Số điện thoại của dữ liệu sim",
|
|
752
752
|
"select_a_sub_unit": "Lựa chọn một khu vực mà bạn muốn thêm gateway",
|
|
753
753
|
"all_camera": "All Cameras",
|
|
@@ -855,5 +855,6 @@
|
|
|
855
855
|
"volume": "Âm lượng",
|
|
856
856
|
"this_notification_will_be_updated_soon": "Thông báo này sẽ sớm được cập nhật",
|
|
857
857
|
"text_submit": "Xác nhận",
|
|
858
|
-
"tap_to_add_new_schedule": "Nhấn + để thêm lịch trình mới"
|
|
858
|
+
"tap_to_add_new_schedule": "Nhấn + để thêm lịch trình mới",
|
|
859
|
+
"choose_at_least_one": "Vui lòng chọn ít nhất 1 thiết bị."
|
|
859
860
|
}
|