@eohjsc/react-native-smart-city 0.7.40 → 0.7.42

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.
Files changed (53) hide show
  1. package/package.json +1 -1
  2. package/src/commons/Dashboard/MyDashboardDevice/index.js +14 -12
  3. package/src/commons/Dashboard/MyUnit/index.js +4 -3
  4. package/src/commons/DateTimeRangeChange/index.js +5 -5
  5. package/src/commons/Device/HorizontalBarChart.js +11 -24
  6. package/src/commons/Device/PowerConsumptionChart.js +195 -103
  7. package/src/commons/FieldTemplate/ChooseUserField/index.js +5 -1
  8. package/src/commons/Form/CurrencyInput.js +9 -18
  9. package/src/commons/SelectGateway/index.js +2 -1
  10. package/src/commons/SelectSubUnit/index.js +5 -1
  11. package/src/commons/SelectUnit/index.js +1 -1
  12. package/src/commons/SubUnit/Favorites/index.js +35 -10
  13. package/src/commons/SubUnit/ShortDetail.js +17 -4
  14. package/src/commons/SubUnit/__test__/Favorites.test.js +90 -0
  15. package/src/commons/SubUnit/__test__/ShortDetail.test.js +45 -2
  16. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +17 -9
  17. package/src/hooks/IoT/__test__/useValueEvaluation.test.js +12 -12
  18. package/src/hooks/IoT/useValueEvaluation.js +7 -3
  19. package/src/hooks/IoT/useWatchSharedChips.js +8 -4
  20. package/src/hooks/useMqtt.js +8 -4
  21. package/src/iot/UpdateStates.js +37 -16
  22. package/src/iot/mqtt.js +23 -0
  23. package/src/navigations/AutomateStack.js +5 -1
  24. package/src/screens/ActivityLog/hooks/index.js +12 -4
  25. package/src/screens/AddLocationMaps/index.js +6 -3
  26. package/src/screens/AddNewGateway/RenameNewDevices.js +2 -1
  27. package/src/screens/Automate/AddNewAction/ChooseConfig.js +2 -1
  28. package/src/screens/Automate/AddNewAction/ReceiverSelect.js +5 -1
  29. package/src/screens/Automate/MultiUnits.js +2 -1
  30. package/src/screens/Automate/ScriptDetail/index.js +11 -3
  31. package/src/screens/Automate/hooks/useAction.js +3 -1
  32. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +16 -5
  33. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +10 -0
  34. package/src/screens/Device/__test__/DeviceDetail-modbus.test.js +37 -8
  35. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +16 -5
  36. package/src/screens/Device/__test__/DeviceDetail.test.js +17 -6
  37. package/src/screens/Device/__test__/sensorDisplayItem.test.js +47 -11
  38. package/src/screens/Device/components/SensorDisplayItem.js +23 -5
  39. package/src/screens/Device/detail.js +10 -3
  40. package/src/screens/Device/hooks/useEvaluateValue.js +7 -3
  41. package/src/screens/Device/styles.js +4 -0
  42. package/src/screens/SelectUnit/index.js +3 -1
  43. package/src/screens/Sharing/InfoMemberUnit.js +3 -1
  44. package/src/screens/SideMenuDetail/index.js +3 -1
  45. package/src/screens/Unit/SelectAddToFavorites.js +6 -2
  46. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +8 -48
  47. package/src/screens/UnitSummary/components/PowerConsumption/__test__/PowerConsumption.test.js +121 -6
  48. package/src/screens/UnitSummary/components/PowerConsumption/index.js +6 -46
  49. package/src/screens/UnitSummary/index.js +2 -1
  50. package/src/utils/I18n/translations/en.js +1 -0
  51. package/src/utils/I18n/translations/vi.js +1 -0
  52. package/src/utils/chartHelper/index.js +53 -0
  53. package/src/utils/chartHelper/getMaxValueIndex.js +0 -11
@@ -1,17 +1,15 @@
1
- import React, { memo, useCallback, useMemo, useState } from 'react';
2
- import { View, StyleSheet } from 'react-native';
3
- import Text from '../../../../commons/Text';
4
- import { API, Colors } from '../../../../configs';
5
- import moment from 'moment';
1
+ import { memo, useMemo } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
6
3
  import { Section, Today } from '../../../../commons';
7
- import ListQualityIndicator from '../../../../commons/Device/WaterQualitySensor/ListQualityIndicator';
8
4
  import PMSensorIndicator from '../../../../commons/Device/PMSensor/PMSensorIndicator';
9
- import VisualChart from '../../../Device/components/VisualChart';
10
- import { useTranslations } from '../../../../hooks/Common/useTranslations';
11
5
  import PowerConsumptionChart from '../../../../commons/Device/PowerConsumptionChart';
12
- import { axiosGet } from '../../../../utils/Apis/axios';
6
+ import ListQualityIndicator from '../../../../commons/Device/WaterQualitySensor/ListQualityIndicator';
7
+ import Text from '../../../../commons/Text';
8
+ import { Colors } from '../../../../configs';
13
9
  import { AccessibilityLabel } from '../../../../configs/Constants';
10
+ import { useTranslations } from '../../../../hooks/Common/useTranslations';
14
11
  import { useWatchConfigs } from '../../../../hooks/IoT';
12
+ import VisualChart from '../../../Device/components/VisualChart';
15
13
 
16
14
  const ThreePhasePowerConsumption = memo(({ summaryDetail }) => {
17
15
  const t = useTranslations();
@@ -114,35 +112,6 @@ const ThreePhasePowerConsumption = memo(({ summaryDetail }) => {
114
112
  return !!listConfigs;
115
113
  }, [listConfigs]);
116
114
 
117
- const [groupBy, setGroupBy] = useState('date');
118
- const [getData, setData] = useState({});
119
- const [chartConfig, setChartConfig] = useState({
120
- unit: 'kWh',
121
- price: '',
122
- });
123
-
124
- const fetchData = useCallback(
125
- async (startDate, endDate) => {
126
- let params = new URLSearchParams();
127
- params.append('config', total_power);
128
- params.append('group_by', groupBy);
129
- if (groupBy === 'date') {
130
- params.append('date_from', moment(startDate).format('YYYY-MM-DD'));
131
- params.append('date_to', moment(endDate).format('YYYY-MM-DD'));
132
- }
133
- const { success, data } = await axiosGet(
134
- API.VALUE_CONSUME.DISPLAY_HISTORY(),
135
- {
136
- params,
137
- }
138
- );
139
- if (success) {
140
- setData(data);
141
- }
142
- },
143
- [groupBy, total_power]
144
- );
145
-
146
115
  const dataTotal = useMemo(() => {
147
116
  return total_power
148
117
  ? [
@@ -185,16 +154,7 @@ const ThreePhasePowerConsumption = memo(({ summaryDetail }) => {
185
154
  </Text>
186
155
 
187
156
  <PMSensorIndicator data={dataTotal} style={styles.styleTotalPower} />
188
- {total_power && (
189
- <PowerConsumptionChart
190
- onChangeDate={fetchData}
191
- datas={getData}
192
- chartConfig={chartConfig}
193
- setChartConfig={setChartConfig}
194
- groupBy={groupBy}
195
- setGroupBy={setGroupBy}
196
- />
197
- )}
157
+ {total_power && <PowerConsumptionChart powerConfigId={total_power} />}
198
158
  </Section>
199
159
  </>
200
160
  );
@@ -1,15 +1,17 @@
1
- import React from 'react';
2
- import renderer, { act, create } from 'react-test-renderer';
3
1
  import MockAdapter from 'axios-mock-adapter';
2
+ import renderer, { act, create } from 'react-test-renderer';
4
3
 
5
- import { AccessibilityLabel } from '../../../../../configs/Constants';
6
- import { API, Colors } from '../../../../../configs';
4
+ import moment from 'moment';
5
+ import { Today } from '../../../../../commons';
6
+ import DateTimeRangeChange from '../../../../../commons/DateTimeRangeChange';
7
+ import PowerConsumptionChart from '../../../../../commons/Device/PowerConsumptionChart';
7
8
  import ListQualityIndicator from '../../../../../commons/Device/WaterQualitySensor/ListQualityIndicator';
8
- import PowerConsumption from '../index';
9
+ import { API, Colors } from '../../../../../configs';
10
+ import { AccessibilityLabel } from '../../../../../configs/Constants';
9
11
  import { SCProvider } from '../../../../../context';
10
12
  import { mockSCStore } from '../../../../../context/mockStore';
11
13
  import api from '../../../../../utils/Apis/axios';
12
- import { Today } from '../../../../../commons';
14
+ import PowerConsumption from '../index';
13
15
 
14
16
  const mock = new MockAdapter(api.axiosInstance);
15
17
 
@@ -193,4 +195,117 @@ describe('Test PowerConsumption', () => {
193
195
  const listQualityIndicator = instance.findByType(ListQualityIndicator);
194
196
  expect(listQualityIndicator.props.data).toEqual([]);
195
197
  });
198
+
199
+ it('render PowerConsumption with total sum is 0', async () => {
200
+ const summaryDetail = {
201
+ listConfigs: {
202
+ total_power: 207,
203
+ },
204
+ };
205
+
206
+ const data = [
207
+ {
208
+ config: 207,
209
+ data: [
210
+ { x: 'Fri-14.06', y: 0 },
211
+ { x: 'Sat-15.06', y: 0 },
212
+ ],
213
+ },
214
+ ];
215
+ mock.onGet(API.VALUE_CONSUME.DISPLAY_HISTORY()).reply(200, data);
216
+ await act(async () => {
217
+ tree = await create(wrapComponent(summaryDetail));
218
+ });
219
+ const instance = tree.root;
220
+
221
+ const input_calculate_cost = instance.find(
222
+ (el) =>
223
+ el.props.accessibilityLabel === AccessibilityLabel.INPUT_CALCULATE_COST
224
+ );
225
+ await act(async () => {
226
+ input_calculate_cost.props.onChangeText('1000');
227
+ });
228
+ const button_calculate_cost = instance.find(
229
+ (el) =>
230
+ el.props.accessibilityLabel === AccessibilityLabel.BUTTON_CALCULATE_COST
231
+ );
232
+ await act(async () => {
233
+ button_calculate_cost.props.onPress();
234
+ });
235
+ const totalPrice = instance.find(
236
+ (el) => el.props.accessibilityLabel === AccessibilityLabel.TOTAL_PRICE
237
+ );
238
+ expect(totalPrice.props.children).toEqual('0 đ');
239
+ });
240
+
241
+ it('render PowerConsumption with empty data array', async () => {
242
+ const summaryDetail = {
243
+ listConfigs: {
244
+ total_power: 207,
245
+ },
246
+ };
247
+
248
+ mock.onGet(API.VALUE_CONSUME.DISPLAY_HISTORY()).reply(200, []);
249
+ await act(async () => {
250
+ tree = await create(wrapComponent(summaryDetail));
251
+ });
252
+ const instance = tree.root;
253
+
254
+ const input_calculate_cost = instance.find(
255
+ (el) =>
256
+ el.props.accessibilityLabel === AccessibilityLabel.INPUT_CALCULATE_COST
257
+ );
258
+ await act(async () => {
259
+ input_calculate_cost.props.onChangeText('1000');
260
+ });
261
+ const button_calculate_cost = instance.find(
262
+ (el) =>
263
+ el.props.accessibilityLabel === AccessibilityLabel.BUTTON_CALCULATE_COST
264
+ );
265
+ await act(async () => {
266
+ button_calculate_cost.props.onPress();
267
+ });
268
+
269
+ const totalPrice = instance.find(
270
+ (el) => el.props.accessibilityLabel === AccessibilityLabel.TOTAL_PRICE
271
+ );
272
+ expect(totalPrice.props.children).toEqual('0 đ');
273
+ });
274
+
275
+ it('cover selectStart and selectEnd in PowerConsumptionChart', async () => {
276
+ const summaryDetail = {
277
+ listConfigs: {
278
+ total_power: 207,
279
+ },
280
+ };
281
+
282
+ mock.onGet(API.VALUE_CONSUME.DISPLAY_HISTORY()).reply(200, []);
283
+ await act(async () => {
284
+ tree = await create(wrapComponent(summaryDetail));
285
+ });
286
+ const instance = tree.root;
287
+
288
+ const powerConsumptionChart = instance.findByType(PowerConsumptionChart);
289
+ const dateTimeRangeChange =
290
+ powerConsumptionChart.findByType(DateTimeRangeChange);
291
+ expect(dateTimeRangeChange).toBeDefined();
292
+
293
+ const newStartDate = moment().subtract(10, 'days');
294
+ const newEndDate = moment().subtract(1, 'days');
295
+
296
+ await act(async () => {
297
+ dateTimeRangeChange.props.selectStart(newStartDate);
298
+ });
299
+ await act(async () => {
300
+ dateTimeRangeChange.props.selectEnd(newEndDate);
301
+ });
302
+
303
+ // Check if the component still renders correctly after date changes
304
+ expect(
305
+ powerConsumptionChart.findByType(DateTimeRangeChange).props.startTime
306
+ ).toEqual(newStartDate);
307
+ expect(
308
+ powerConsumptionChart.findByType(DateTimeRangeChange).props.endTime
309
+ ).toEqual(newEndDate);
310
+ });
196
311
  });
@@ -1,18 +1,16 @@
1
- import React, { memo, useMemo, useState, useCallback } from 'react';
1
+ import { memo, useCallback, useMemo } from 'react';
2
2
  import { StyleSheet } from 'react-native';
3
3
  import { useTranslations } from '../../../../hooks/Common/useTranslations';
4
- import moment from 'moment';
5
4
 
6
- import { API, Colors } from '../../../../configs';
7
- import Text from '../../../../commons/Text';
8
5
  import { Section, Today } from '../../../../commons';
9
- import ListQualityIndicator from '../../../../commons/Device/WaterQualitySensor/ListQualityIndicator';
10
6
  import PMSensorIndicator from '../../../../commons/Device/PMSensor/PMSensorIndicator';
11
7
  import PowerConsumptionChart from '../../../../commons/Device/PowerConsumptionChart';
8
+ import ListQualityIndicator from '../../../../commons/Device/WaterQualitySensor/ListQualityIndicator';
9
+ import Text from '../../../../commons/Text';
10
+ import { Colors } from '../../../../configs';
12
11
  import { AccessibilityLabel } from '../../../../configs/Constants';
13
- import { axiosGet } from '../../../../utils/Apis/axios';
14
- import VisualChart from '../../../Device/components/VisualChart';
15
12
  import { useWatchConfigs } from '../../../../hooks/IoT';
13
+ import VisualChart from '../../../Device/components/VisualChart';
16
14
 
17
15
  const PowerConsumption = memo(({ summaryDetail }) => {
18
16
  const t = useTranslations();
@@ -21,16 +19,9 @@ const PowerConsumption = memo(({ summaryDetail }) => {
21
19
  listConfigs || {};
22
20
  useWatchConfigs([volt, current, active_power, power_factor, total_power]);
23
21
 
24
- const [groupBy, setGroupBy] = useState('date');
25
- const [getData, setData] = useState([]);
26
- const [chartConfig, setChartConfig] = useState({
27
- unit: 'kWh',
28
- price: '',
29
- });
30
22
  const showBoxHistory = useMemo(() => {
31
23
  return !!listConfigs;
32
24
  }, [listConfigs]);
33
-
34
25
  const createDataItem = useCallback(
35
26
  (id, color, title, measure) => ({
36
27
  id,
@@ -80,28 +71,6 @@ const PowerConsumption = memo(({ summaryDetail }) => {
80
71
  : [];
81
72
  }, [createDataItem, total_power]);
82
73
 
83
- const fetchData = useCallback(
84
- async (startDate, endDate) => {
85
- let params = new URLSearchParams();
86
- params.append('config', total_power);
87
- params.append('group_by', groupBy);
88
- if (groupBy === 'date') {
89
- params.append('date_from', moment(startDate).format('YYYY-MM-DD'));
90
- params.append('date_to', moment(endDate).format('YYYY-MM-DD'));
91
- }
92
- const { success, data } = await axiosGet(
93
- API.VALUE_CONSUME.DISPLAY_HISTORY(),
94
- {
95
- params,
96
- }
97
- );
98
- if (success) {
99
- setData(data);
100
- }
101
- },
102
- [groupBy, total_power]
103
- );
104
-
105
74
  return (
106
75
  <>
107
76
  <Section type={'border'}>
@@ -122,16 +91,7 @@ const PowerConsumption = memo(({ summaryDetail }) => {
122
91
  </Text>
123
92
 
124
93
  <PMSensorIndicator data={dataTotal} style={styles.styleTotalPower} />
125
- {total_power && (
126
- <PowerConsumptionChart
127
- onChangeDate={fetchData}
128
- datas={getData}
129
- chartConfig={chartConfig}
130
- setChartConfig={setChartConfig}
131
- groupBy={groupBy}
132
- setGroupBy={setGroupBy}
133
- />
134
- )}
94
+ {total_power && <PowerConsumptionChart powerConfigId={total_power} />}
135
95
  </Section>
136
96
  </>
137
97
  );
@@ -104,7 +104,8 @@ const UnitSummary = memo(({ route }) => {
104
104
  const fetchUnitSummary = useCallback(async () => {
105
105
  const { success, data } = await axiosGet(
106
106
  API.UNIT.UNIT_SUMMARY(unit?.id),
107
- {}
107
+ {},
108
+ true
108
109
  );
109
110
  if (success) {
110
111
  const newData = data.filter((item) => item.id === summaryId);
@@ -529,6 +529,7 @@ export default {
529
529
  saved_vehicle: 'Saved Vehicle',
530
530
  set_a_number: 'Set a number',
531
531
  text_total_power_consumption: 'Total Power Consumption',
532
+ power_consumption_chart: 'Power Consumption Chart',
532
533
  input_price_to_calculate_electricity_cost:
533
534
  'Input price to calculate electricity cost',
534
535
  calculate_cost: 'Calculate cost',
@@ -590,6 +590,7 @@ export default {
590
590
  save_this_vehicle: 'Lưu và đặt phương tiện mặc định',
591
591
  saved_vehicle: 'Phương tiện đã lưu',
592
592
  text_total_power_consumption: 'Tổng điện năng tiêu thụ',
593
+ power_consumption_chart: 'Biểu đồ điện năng tiêu thụ',
593
594
  input_price_to_calculate_electricity_cost:
594
595
  'Nhập số tiền để tính giá tiền điện đã sử dụng',
595
596
  calculate_cost: 'Tính giá điện',
@@ -0,0 +1,53 @@
1
+ export const getMaxValueIndex = (data) => {
2
+ let max = {};
3
+ let _index = 0;
4
+ for (let i = 0; i < data.length; i++) {
5
+ if (max.y == null || data[i].y > max.y) {
6
+ max = { ...data[i] };
7
+ _index = i;
8
+ }
9
+ }
10
+ return { _index, max };
11
+ };
12
+
13
+ export const createDataLabelFormatter = () => {
14
+ return `function () {
15
+ const { unit, price } = JSON.parse(this.series.name || '{}');
16
+
17
+ // Re-define formatMoney for WebView scope since this function is stringified
18
+ const _formatMoney = (number) => {
19
+ const formatNumber = number.toFixed();
20
+ return (
21
+ parseInt(formatNumber, 10)
22
+ .toFixed(0)
23
+ .toString()
24
+ .replace(/(\\d)(?=(\\d\\d\\d)+(?!\\d))/g, '$1.') + 'đ'
25
+ );
26
+ };
27
+
28
+ // Hardcode Primary color or access it if available.
29
+ const Colors = { Primary: '#00979D' };
30
+
31
+ const textColor =
32
+ this.color === Colors.Primary
33
+ ? this.y === 0
34
+ ? '#262626'
35
+ : '#FFFFFF'
36
+ : '#262626';
37
+
38
+ const valueStyle = "color:" + textColor + ";font-weight:normal;font-size:12px;";
39
+ const costStyle = valueStyle + 'font-weight:bold;';
40
+ const label = "<span style=\\"" + valueStyle + "\\">" + this.y + (unit || '') + "</span>";
41
+
42
+ if (price === '' || price === null || isNaN(price)) {
43
+ return label;
44
+ }
45
+
46
+ return (
47
+ label +
48
+ "<span style=\\"" + costStyle + "\\">" + "/" +
49
+ _formatMoney(this.y * price) +
50
+ "</span></span>"
51
+ );
52
+ }`;
53
+ };
@@ -1,11 +0,0 @@
1
- export const getMaxValueIndex = (data) => {
2
- let max = {};
3
- let _index = 0;
4
- for (let i = 0; i < data.length; i++) {
5
- if (!max.y || data[i].y > max.y) {
6
- max = { ...data[i] };
7
- _index = i;
8
- }
9
- }
10
- return { _index, max };
11
- };