@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 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.60",
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": "^3.1.4",
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: dateNow,
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
- ...eventPicker,
58
- currentChangeTime: 'start',
54
+ setEventPicker((state) => ({
55
+ ...state,
59
56
  showModalStart: true,
60
57
  showModalEnd: false,
61
- });
62
- }, [eventPicker]);
58
+ }));
59
+ }, []);
63
60
  const onEnd = useCallback(() => {
64
- setEventPicker({
65
- ...eventPicker,
66
- currentChangeTime: 'end',
67
- show: true,
61
+ setEventPicker((state) => ({
62
+ ...state,
68
63
  showModalStart: false,
69
64
  showModalEnd: true,
70
- });
71
- }, [eventPicker]);
72
- const onConfirmStart = (date) => {
73
- if (typeof date === 'number') {
74
- onCancel();
75
- return;
76
- }
77
- if (moment(date).valueOf() < eventPicker.endTime) {
78
- setEventPicker({
79
- ...eventPicker,
80
- currentChangeTime: 'start',
81
- showModalStart: false,
82
- startTime: moment(date).valueOf(),
83
- });
84
- } else {
85
- setEventPicker({
86
- ...eventPicker,
87
- currentChangeTime: 'start',
88
- showModalStart: false,
89
- startTime: moment(date).valueOf(),
90
- endTime: moment(date).add(1, 'day').valueOf(),
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
- setStartDate(moment(date).valueOf());
95
- };
92
+ },
93
+ [onCancel, setStartDate, setEndDate]
94
+ );
96
95
 
97
- const onConfirmEnd = (date) => {
98
- if (typeof date === 'number') {
99
- onCancel();
100
- return;
101
- }
102
- if (moment(date).valueOf() >= eventPicker.startTime) {
103
- setEventPicker({
104
- ...eventPicker,
105
- currentChangeTime: 'start',
106
- showModalEnd: false,
107
- endTime: moment(date).valueOf(),
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
- } else {
110
- setEventPicker({
111
- ...eventPicker,
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
- ...eventPicker,
124
- currentChangeTime: '',
126
+ setEventPicker((state) => ({
127
+ ...state,
125
128
  showModalEnd: false,
126
129
  showModalStart: false,
127
- });
128
- }, [eventPicker]);
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 { launchCamera, launchImageLibrary } from 'react-native-image-picker';
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
- quality: 1,
65
- saveToPhotos: true,
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
- launchCamera(options, (response) => {
72
- if (response.didCancel) {
73
- return;
74
- } else if (response.errorCode === 'camera_unavailable') {
75
- return;
76
- } else if (response.errorCode === 'permission') {
77
- return;
78
- } else if (response.errorCode === 'others') {
79
- return;
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
- quality: 1,
98
+ compressImageMaxWidth: 1280,
99
+ compressImageMaxHeight: 720,
100
+ compressImageQuality: 0.8,
103
101
  };
104
- launchImageLibrary(options, (response) => {
105
- if (response.didCancel) {
106
- return;
107
- } else if (response.errorCode === 'camera_unavailable') {
108
- return;
109
- } else if (response.errorCode === 'permission') {
110
- return;
111
- } else if (response.errorCode === 'others') {
112
- return;
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>
@@ -27,7 +27,7 @@ function numberType(value) {
27
27
 
28
28
  function textType(value, entityId) {
29
29
  const textMap = textMaps[entityId];
30
- return textMap[value];
30
+ return textMap ? textMap[value] : '';
31
31
  }
32
32
 
33
33
  function keepValue(value) {
@@ -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.fileSize < MAX_FILE_SIZE_BYTES) {
32
+ if (!image || image.size < MAX_FILE_SIZE_BYTES) {
33
33
  return image;
34
34
  }
35
35
  const result = await ImageResizer.createResizedImage(
36
- image.uri,
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, Device } from '../../configs';
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
- quality: 0.8,
150
- includeBase64: Device.isIOS,
151
- saveToPhotos: true,
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, Device, Images } from '../../configs';
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 (bodyData, headers) => {
81
- const formData = createFormData(bodyData, ['background']);
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
- { background: imageUrl },
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
- quality: 0.8,
162
- includeBase64: Device.isIOS,
163
- saveToPhotos: true,
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: unit.background,
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(({ unit, summary, summaryDetail }) => {
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 listIdsConfig = useMemo(() => {
137
- return listConfigs;
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
- }, 5000); // fetch each 5 second
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={t('last_updated_%{minutes}_minutes_ago', { minutes: 5 })}
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
  );
@@ -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
- name: item.fileName,
169
- type: item.type,
170
- uri: item.uri,
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 your phone number and chip name",
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 số điện thoại và tên chip của bạn",
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
  }