@eohjsc/react-native-smart-city 0.5.7-rc1 → 0.5.8

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.5.7-rc1",
4
+ "version": "0.5.8",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -161,7 +161,6 @@
161
161
  "react-native-bootsplash": "^2.2.5",
162
162
  "react-native-calendars": "^1.1266.0",
163
163
  "react-native-chart-kit": "^6.5.0",
164
- "react-native-charts-wrapper": "^0.6.0",
165
164
  "react-native-credit-card-input": "^0.4.1",
166
165
  "react-native-crypto-aes-cbc": "^1.1.1",
167
166
  "react-native-dash": "^0.0.11",
@@ -51,7 +51,7 @@ const OnOffTemplate = memo(({ item = {}, doAction, sensor = {} }) => {
51
51
  const [isOn, setIsOn] = useState(false);
52
52
 
53
53
  const realTrigger = useCallback(
54
- async (action_data, config_value) => {
54
+ async (action_data, config_value, interrupted) => {
55
55
  if (!action_data) {
56
56
  return;
57
57
  }
@@ -66,7 +66,7 @@ const OnOffTemplate = memo(({ item = {}, doAction, sensor = {} }) => {
66
66
  config_value: config_value,
67
67
  };
68
68
  }
69
- await doAction(action_data, data);
69
+ await doAction(action_data, data, interrupted);
70
70
  if (
71
71
  is_managed_by_backend &&
72
72
  config &&
@@ -87,15 +87,15 @@ const OnOffTemplate = memo(({ item = {}, doAction, sensor = {} }) => {
87
87
  const triggerAction = useCallback(async () => {
88
88
  const action_data = isOn ? action_off_data : action_on_data;
89
89
  const config_value = isOn ? 0 : 1;
90
- realTrigger(action_data, config_value);
90
+ realTrigger(action_data, config_value, false);
91
91
  }, [isOn, action_off_data, action_on_data, realTrigger]);
92
92
 
93
93
  const triggerOnAction = useCallback(async () => {
94
- realTrigger(action_on_data, 1);
94
+ realTrigger(action_on_data, 1, true);
95
95
  }, [action_on_data, realTrigger]);
96
96
 
97
97
  const triggerOffAction = useCallback(async () => {
98
- realTrigger(action_off_data, 0);
98
+ realTrigger(action_off_data, 0, true);
99
99
  }, [action_off_data, realTrigger]);
100
100
 
101
101
  useUnwatchLGDeviceConfigControl(sensor, [config]);
@@ -60,8 +60,8 @@ const TerminalBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
60
60
  );
61
61
  const scrollViewRef = useRef();
62
62
  const sendCommand = useCallback(() => {
63
- doAction(action_data, JSON.stringify({ value: value }));
64
63
  setValue('');
64
+ doAction(action_data, JSON.stringify({ value: value }));
65
65
  }, [doAction, action_data, value]);
66
66
 
67
67
  const onInputChange = (e) => {
@@ -85,7 +85,7 @@ const TerminalBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
85
85
 
86
86
  const scrollToBottom = () => {
87
87
  setTimeout(() => {
88
- scrollViewRef.current.scrollToEnd({ animated: true });
88
+ scrollViewRef.current?.scrollToEnd({ animated: true });
89
89
  }, 100);
90
90
  };
91
91
 
@@ -165,6 +165,8 @@ const TerminalBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
165
165
  value={value}
166
166
  onChange={onInputChange}
167
167
  maxLength={255}
168
+ returnKeyType={'done'}
169
+ onSubmitEditing={sendCommand}
168
170
  />
169
171
  <TouchableOpacity
170
172
  style={styles.iconAndTextOption}
@@ -64,9 +64,12 @@ const TextBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
64
64
  transY={transY}
65
65
  >
66
66
  <_TextInput
67
+ autoFocus
67
68
  wrapStyle={styles.wrapInputStyle}
68
69
  value={value}
69
70
  onChange={onInputChange}
71
+ returnKeyType={'done'}
72
+ onSubmitEditing={onDone}
70
73
  />
71
74
  </AlertAction>
72
75
  </View>
@@ -122,7 +122,7 @@ describe('Test OneBigButtonTemplate', () => {
122
122
  await act(async () => {
123
123
  await button.props.onPress();
124
124
  });
125
- expect(mockDoAction).toHaveBeenCalledWith(action_data, undefined);
125
+ expect(mockDoAction).toHaveBeenCalledWith(action_data, undefined, false);
126
126
  };
127
127
 
128
128
  it('action state on', async () => {
@@ -148,7 +148,7 @@ describe('Test OnOffTemplate', () => {
148
148
  await act(async () => {
149
149
  await template.props.triggerAction();
150
150
  });
151
- expect(mockDoAction).toHaveBeenCalledWith(actionOffData, undefined);
151
+ expect(mockDoAction).toHaveBeenCalledWith(actionOffData, undefined, false);
152
152
  expect(watchMultiConfigs).toBeCalledTimes(0);
153
153
  });
154
154
 
@@ -165,7 +165,7 @@ describe('Test OnOffTemplate', () => {
165
165
  await act(async () => {
166
166
  await template.props.triggerAction();
167
167
  });
168
- expect(mockDoAction).toHaveBeenCalledWith(actionOnData, undefined);
168
+ expect(mockDoAction).toHaveBeenCalledWith(actionOnData, undefined, false);
169
169
  });
170
170
 
171
171
  it('template OnOffSimpleActionTemplate doAction with is_on_value and is_managed_by_backend', async () => {
@@ -180,7 +180,7 @@ describe('Test OnOffTemplate', () => {
180
180
  await act(async () => {
181
181
  await template.props.triggerAction();
182
182
  });
183
- expect(mockDoAction).toHaveBeenCalledWith(actionOffData, undefined);
183
+ expect(mockDoAction).toHaveBeenCalledWith(actionOffData, undefined, false);
184
184
  expect(watchMultiConfigs).toBeCalledTimes(0);
185
185
  });
186
186
 
@@ -207,7 +207,7 @@ describe('Test OnOffTemplate', () => {
207
207
  await act(async () => {
208
208
  await template[0].props.triggerAction();
209
209
  });
210
- expect(mockDoAction).toHaveBeenCalledWith(actionData, undefined);
210
+ expect(mockDoAction).toHaveBeenCalledWith(actionData, undefined, false);
211
211
  });
212
212
 
213
213
  it('render with template OnOffSimpleActionTemplate with just action_data lg_thinq', async () => {
@@ -242,7 +242,7 @@ describe('Test OnOffTemplate', () => {
242
242
  await act(async () => {
243
243
  jest.runAllTimers();
244
244
  });
245
- expect(mockDoAction).toHaveBeenCalledWith(actionData, undefined);
245
+ expect(mockDoAction).toHaveBeenCalledWith(actionData, undefined, false);
246
246
  });
247
247
 
248
248
  it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger off', async () => {
@@ -272,10 +272,14 @@ describe('Test OnOffTemplate', () => {
272
272
  await act(async () => {
273
273
  await template[0].props.triggerAction();
274
274
  });
275
- expect(mockDoAction).toHaveBeenCalledWith(actionOffData, {
276
- config_id: 5,
277
- config_value: 0,
278
- });
275
+ expect(mockDoAction).toHaveBeenCalledWith(
276
+ actionOffData,
277
+ {
278
+ config_id: 5,
279
+ config_value: 0,
280
+ },
281
+ false
282
+ );
279
283
  });
280
284
 
281
285
  it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger on', async () => {
@@ -305,10 +309,14 @@ describe('Test OnOffTemplate', () => {
305
309
  await act(async () => {
306
310
  await template[0].props.triggerAction();
307
311
  });
308
- expect(mockDoAction).toHaveBeenCalledWith(actionOnData, {
309
- config_id: 5,
310
- config_value: 1,
311
- });
312
+ expect(mockDoAction).toHaveBeenCalledWith(
313
+ actionOnData,
314
+ {
315
+ config_id: 5,
316
+ config_value: 1,
317
+ },
318
+ false
319
+ );
312
320
  });
313
321
 
314
322
  it('render with template OnOffSimpleActionTemplate with zigbee device wrong action_data', async () => {
@@ -375,14 +375,16 @@ describe('Test ActionGroup', () => {
375
375
  });
376
376
  expect(mockDoAction).toHaveBeenCalledWith(
377
377
  actionGroup.configuration.action_on_data,
378
- undefined
378
+ undefined,
379
+ true
379
380
  );
380
381
  await act(async () => {
381
382
  buttons[0].props.onPressOut();
382
383
  });
383
384
  expect(mockDoAction).toHaveBeenCalledWith(
384
385
  actionGroup.configuration.action_off_data,
385
- undefined
386
+ undefined,
387
+ true
386
388
  );
387
389
  });
388
390
 
@@ -25,7 +25,7 @@ const styles = StyleSheet.create({
25
25
  marginHorizontal: 8,
26
26
  flexDirection: 'row',
27
27
  justifyContent: 'space-between',
28
- width: 130,
28
+ width: 150,
29
29
  alignItems: 'center',
30
30
  },
31
31
  txtTime: {
@@ -31,6 +31,7 @@ const _TextInput = ({
31
31
  onSelectionChange,
32
32
  accessibilityLabelError,
33
33
  onEndEditing,
34
+ returnKeyType = 'default',
34
35
  }) => {
35
36
  const errorStyle = !!errorText && styles.errorWrap;
36
37
  return (
@@ -71,6 +72,7 @@ const _TextInput = ({
71
72
  selection={selection}
72
73
  onSelectionChange={onSelectionChange}
73
74
  onEndEditing={onEndEditing}
75
+ returnKeyType={returnKeyType}
74
76
  />
75
77
  {extraText && extraText}
76
78
  {!!errorText && (
@@ -1,6 +1,37 @@
1
- import React, { useState } from 'react';
1
+ import React, { useMemo, useState } from 'react';
2
2
  import WebView from 'react-native-webview';
3
3
 
4
+ const flattenText = (item, key) => {
5
+ let str = '';
6
+ if (item && typeof item === 'object' && item.length === undefined) {
7
+ str += flattenObject(item);
8
+ } else if (item && typeof item === 'object' && item.length !== undefined) {
9
+ str += '[';
10
+ item.forEach((k2) => {
11
+ str += `${flattenText(k2)}, `;
12
+ });
13
+ if (item.length > 0) {
14
+ str = str.slice(0, str.length - 2);
15
+ }
16
+ str += ']';
17
+ } else if (typeof item === 'string' && item.slice(0, 8) === 'function') {
18
+ str += `${item}`;
19
+ } else if (typeof item === 'string') {
20
+ // eslint-disable-next-line no-useless-escape
21
+ str += `\"${item.replace(/"/g, '\\"')}\"`;
22
+ } else {
23
+ str += `${item}`;
24
+ }
25
+ return str;
26
+ };
27
+
28
+ const flattenObject = (obj, str = '{') => {
29
+ Object.keys(obj).forEach(function (key) {
30
+ str += `${key}: ${flattenText(obj[key])}, `;
31
+ });
32
+ return `${str.slice(0, str.length - 2)}}`;
33
+ };
34
+
4
35
  const Highcharts = (props) => {
5
36
  const [init] = useState(`<html>
6
37
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0" />
@@ -36,11 +67,12 @@ const Highcharts = (props) => {
36
67
  }
37
68
  <script src="https://code.highcharts.com/modules/exporting.js"></script>
38
69
  <script>
70
+ window.chartObj = null;
39
71
  $(function () {
40
72
  Highcharts.setOptions(${JSON.stringify(
41
73
  props.options
42
74
  )});
43
- Highcharts.${
75
+ window.chartObj = Highcharts.${
44
76
  props.stock ? 'stockChart' : 'chart'
45
77
  }('container', `);
46
78
  const [end] = useState(` );
@@ -53,46 +85,13 @@ const Highcharts = (props) => {
53
85
  </body>
54
86
  </html>`);
55
87
 
56
- const flattenText = (item, key) => {
57
- let str = '';
58
- if (item && typeof item === 'object' && item.length === undefined) {
59
- str += flattenObject(item);
60
- } else if (item && typeof item === 'object' && item.length !== undefined) {
61
- str += '[';
62
- item.forEach((k2) => {
63
- str += `${flattenText(k2)}, `;
64
- });
65
- if (item.length > 0) {
66
- str = str.slice(0, str.length - 2);
67
- }
68
- str += ']';
69
- } else if (typeof item === 'string' && item.slice(0, 8) === 'function') {
70
- str += `${item}`;
71
- } else if (typeof item === 'string') {
72
- // eslint-disable-next-line no-useless-escape
73
- str += `\"${item.replace(/"/g, '\\"')}\"`;
74
- } else {
75
- str += `${item}`;
76
- }
77
- return str;
78
- };
79
-
80
- const flattenObject = (obj, str = '{') => {
81
- Object.keys(obj).forEach(function (key) {
82
- str += `${key}: ${flattenText(obj[key])}, `;
88
+ const concatHTML = useMemo(() => {
89
+ let config = JSON.stringify(props.options, (key, value) => {
90
+ return typeof value === 'function' ? value.toString() : value;
83
91
  });
84
- return `${str.slice(0, str.length - 2)}}`;
85
- };
86
-
87
- let config = JSON.stringify(props.options, (key, value) => {
88
- return typeof value === 'function' ? value.toString() : value;
89
- });
90
-
91
- config = JSON.parse(config);
92
- const concatHTML = `${init}${flattenObject(config)}${end}`.replace(
93
- ': }',
94
- ': {}'
95
- );
92
+ config = JSON.parse(config);
93
+ return `${init}${flattenObject(config)}${end}`.replace(': }', ': {}');
94
+ }, [end, init, props?.options]);
96
95
 
97
96
  return (
98
97
  <WebView
@@ -103,6 +102,7 @@ const Highcharts = (props) => {
103
102
  scalesPageToFit={true}
104
103
  scrollEnabled={false}
105
104
  automaticallyAdjustContentInsets={true}
105
+ ref={props?.setRef}
106
106
  {...props}
107
107
  />
108
108
  );
@@ -149,7 +149,7 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
149
149
  station={station}
150
150
  />
151
151
  );
152
- } else {
152
+ } else if (device.use_default_template) {
153
153
  displays.push(
154
154
  <ItemDevice
155
155
  key={`sensor-${device.id}`}
@@ -150,6 +150,7 @@ describe('test ShortDetail Subunit', () => {
150
150
  station: {},
151
151
  status: null,
152
152
  status2: null,
153
+ use_default_template: true,
153
154
  },
154
155
  ];
155
156
 
@@ -23,7 +23,7 @@ export const useFetchConfigHistory = (
23
23
  endpoint = API.CONFIG.DISPLAY_HISTORY_V3()
24
24
  ) => {
25
25
  const fetchDataDisplayHistory = useCallback(
26
- async (startDate, endDate) => {
26
+ async (startDate, endDate, setProcessing = () => {}) => {
27
27
  if (!configs.length || !startDate || !endDate) {
28
28
  return;
29
29
  }
@@ -33,6 +33,7 @@ export const useFetchConfigHistory = (
33
33
  if (!validConfigs.length) {
34
34
  return;
35
35
  }
36
+ setProcessing(true);
36
37
  validConfigs.forEach((item) => {
37
38
  params.append('configs', item.id);
38
39
  });
@@ -48,6 +49,7 @@ export const useFetchConfigHistory = (
48
49
  params,
49
50
  });
50
51
  await updateConfigChart(success, data, configs, setChartData);
52
+ setProcessing(false);
51
53
  },
52
54
  [configs, endpoint, setChartData]
53
55
  );
@@ -277,3 +277,11 @@ export const BUTTON_TYPE = {
277
277
  TOGGLE_BUTTON: 'toggle_button',
278
278
  PUSH_BUTTON: 'push_button',
279
279
  };
280
+
281
+ export const CHART_TIME = {
282
+ hour: 1,
283
+ day: 24,
284
+ week: 168,
285
+ month: 672,
286
+ year: 12 * 672,
287
+ };
@@ -5,15 +5,22 @@ import DateTimeRangeChange from '../../../commons/DateTimeRangeChange';
5
5
  import moment from 'moment';
6
6
 
7
7
  const ChartWrapper = memo(
8
- ({ children, onChangeDate, showTime, isWidgetOrder }) => {
8
+ ({
9
+ children,
10
+ onChangeDate,
11
+ showTime,
12
+ isWidgetOrder,
13
+ periodDefault,
14
+ setProcessing,
15
+ }) => {
9
16
  const [value, setValue] = useState([
10
- moment().subtract(6, 'days'),
17
+ moment().subtract(periodDefault, 'hour'),
11
18
  moment(),
12
19
  ]);
13
20
 
14
21
  useEffect(() => {
15
- onChangeDate(value[0], value[1]);
16
- }, [onChangeDate, value]);
22
+ onChangeDate(value[0], value[1], setProcessing);
23
+ }, [onChangeDate, setProcessing, value]);
17
24
 
18
25
  const selectStart = (date) => {
19
26
  setValue((state) => [date, state[1]]);
@@ -0,0 +1,138 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import { Colors } from '../../../configs';
4
+ import Text from '../../../commons/Text';
5
+ import Highcharts from '../../../commons/Highcharts';
6
+ import { useConfigGlobalState } from '../../../iot/states';
7
+
8
+ const chartOptions = {
9
+ chart: {
10
+ type: 'pie',
11
+ height: '80%',
12
+ },
13
+ credits: {
14
+ enabled: false,
15
+ },
16
+ exporting: {
17
+ enabled: false,
18
+ },
19
+ title: {
20
+ text: '',
21
+ },
22
+ legend: {
23
+ enabled: true,
24
+ },
25
+ plotOptions: {
26
+ pie: {
27
+ showInLegend: true,
28
+ },
29
+ series: {
30
+ type: 'pie',
31
+ size: '100%',
32
+ innerSize: '50%',
33
+ dataLabels: [
34
+ {
35
+ enabled: true,
36
+ distance: 5,
37
+ connectorWidth: 0,
38
+ style: {
39
+ fontWeight: 'normal',
40
+ },
41
+ },
42
+ {
43
+ enabled: true,
44
+ distance: -30,
45
+ format: '{point.y}',
46
+ style: {
47
+ fontWeight: 'normal',
48
+ },
49
+ },
50
+ ],
51
+ },
52
+ },
53
+ tooltip: {
54
+ format: '<b>{point.name}: {point.y}</b>',
55
+ shared: true,
56
+ },
57
+ series: [
58
+ {
59
+ type: 'pie',
60
+ data: [],
61
+ },
62
+ ],
63
+ };
64
+
65
+ const DonutCharts = ({ item, isWidgetOrder }) => {
66
+ const { configuration, label } = item;
67
+ const { configs = [] } = configuration;
68
+ const [configValues] = useConfigGlobalState('configValues');
69
+ const [highchartsWebviewRef, setHighchartsWebviewRef] = useState(null);
70
+
71
+ const getConfigValue = useCallback(
72
+ (configId) => {
73
+ const value = configValues[configId]?.value;
74
+ return typeof value === 'number' ? value : 0;
75
+ },
76
+ [configValues]
77
+ );
78
+
79
+ useEffect(() => {
80
+ if (!highchartsWebviewRef) {
81
+ return;
82
+ }
83
+ const data = configs.map((config) => ({
84
+ y: getConfigValue(config.id),
85
+ name: config.name,
86
+ color: config.color,
87
+ }));
88
+
89
+ highchartsWebviewRef.injectJavaScript(
90
+ `window.chartObj.series[0].setData(${JSON.stringify(data)})`
91
+ );
92
+ }, [configs, getConfigValue, highchartsWebviewRef]);
93
+
94
+ return (
95
+ <View>
96
+ <View style={styles.titleHistory}>
97
+ <Text type="H3" semibold color={Colors.Gray9}>
98
+ {label}
99
+ </Text>
100
+ </View>
101
+
102
+ <Highcharts
103
+ setRef={setHighchartsWebviewRef}
104
+ options={chartOptions}
105
+ styles={styles.chartStyle}
106
+ webviewStyles={[
107
+ styles.webviewStyle,
108
+ isWidgetOrder && styles.widgetOrderWebview,
109
+ ]}
110
+ />
111
+ </View>
112
+ );
113
+ };
114
+
115
+ const styles = StyleSheet.create({
116
+ chartStyle: {
117
+ backgroundColor: Colors.White,
118
+ flex: 1,
119
+ },
120
+ titleHistory: {
121
+ flexDirection: 'row',
122
+ justifyContent: 'space-between',
123
+ paddingHorizontal: 16,
124
+ },
125
+ webviewStyle: {
126
+ flex: 1,
127
+ minHeight: 200,
128
+ height: 300,
129
+ },
130
+ widgetOrderWebview: {
131
+ minHeight: 200,
132
+ minWidth: 200,
133
+ width: 300,
134
+ height: 250,
135
+ },
136
+ });
137
+
138
+ export default DonutCharts;
@@ -24,6 +24,8 @@ import { DetailHistoryChart } from './DetailHistoryChart';
24
24
  import VisualChart from './VisualChart';
25
25
  import { standardizeCameraScreenSize } from '../../../utils/Utils';
26
26
  import { Device } from '../../../configs';
27
+ import DonutCharts from './DonutChart';
28
+
27
29
  const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
28
30
  Device.screenWidth - 32
29
31
  );
@@ -58,11 +60,11 @@ export const SensorDisplayItem = ({
58
60
  };
59
61
 
60
62
  const getData = useCallback(() => {
61
- if (!item.configuration) {
63
+ if (!configuration) {
62
64
  return;
63
65
  }
64
66
 
65
- const data = (item.configuration.configs || []).map((config) => {
67
+ const data = (configuration.configs || []).map((config) => {
66
68
  const configValue = configValues[config.id]?.value;
67
69
 
68
70
  const configEvaluate = evaluate[config.id] || {};
@@ -86,20 +88,14 @@ export const SensorDisplayItem = ({
86
88
  });
87
89
 
88
90
  return data.filter(Boolean);
89
- }, [
90
- configValues,
91
- evaluate,
92
- evaluateValue,
93
- item.configuration,
94
- value_evaluation,
95
- ]);
91
+ }, [configValues, evaluate, evaluateValue, configuration, value_evaluation]);
96
92
 
97
93
  const getDataCircleMini = useCallback(() => {
98
- if (!item?.configuration?.config?.id) {
94
+ if (!configuration?.config?.id) {
99
95
  return;
100
96
  }
101
97
 
102
- const config = item.configuration.config;
98
+ const config = configuration.config;
103
99
  const configValue = configValues[config.id]?.value;
104
100
  const configEvaluate = evaluate[config.id] || {};
105
101
 
@@ -114,17 +110,11 @@ export const SensorDisplayItem = ({
114
110
  };
115
111
 
116
112
  return [{ ...config, ...value }].filter(Boolean);
117
- }, [
118
- configValues,
119
- evaluate,
120
- evaluateValue,
121
- item.configuration,
122
- value_evaluation,
123
- ]);
113
+ }, [configValues, evaluate, evaluateValue, configuration, value_evaluation]);
124
114
 
125
115
  const doAction = useCallback(
126
- async (action, data) => {
127
- if (processing) {
116
+ async (action, data, interrupted = false) => {
117
+ if (processing && !interrupted) {
128
118
  return;
129
119
  }
130
120
  setProcessing(true);
@@ -187,7 +177,7 @@ export const SensorDisplayItem = ({
187
177
  />
188
178
  );
189
179
  case 'history':
190
- if (item?.configuration?.config === 'power_consumption') {
180
+ if (configuration?.config === 'power_consumption') {
191
181
  return <DetailHistoryChart item={item} sensor={sensor} />;
192
182
  }
193
183
  return (
@@ -254,6 +244,8 @@ export const SensorDisplayItem = ({
254
244
  offsetTitle={offsetTitle}
255
245
  />
256
246
  );
247
+ case 'donut_chart_race':
248
+ return <DonutCharts item={item} isWidgetOrder={isWidgetOrder} />;
257
249
  default:
258
250
  return <ListQualityIndicator data={getData(item)} />;
259
251
  }
@@ -1,4 +1,10 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react';
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
2
8
  import moment from 'moment/moment';
3
9
  import _ from 'lodash';
4
10
 
@@ -8,9 +14,11 @@ import { StyleSheet, View } from 'react-native';
8
14
  import { Colors } from '../../../configs';
9
15
  import ChartAggregationOption from '../../../commons/ChartAggregationOption';
10
16
  import Text from '../../../commons/Text';
11
- import { CHART_GROUP_TYPE } from '../../../configs/Constants';
17
+ import { CHART_GROUP_TYPE, CHART_TIME } from '../../../configs/Constants';
12
18
  import { getDateRangeOfWeek } from '../../../utils/Utils';
13
19
  import Highcharts from '../../../commons/Highcharts';
20
+ import { FullLoading } from '../../../commons';
21
+ import { colorOpacity } from '../../../utils/Converter/color';
14
22
 
15
23
  const groupByTime = (format) => (x) => x[0].format(format);
16
24
 
@@ -129,6 +137,9 @@ const styles = StyleSheet.create({
129
137
  width: 300,
130
138
  height: 250,
131
139
  },
140
+ backgroundLoading: {
141
+ backgroundColor: colorOpacity(Colors.White, 0),
142
+ },
132
143
  });
133
144
 
134
145
  const chartOptions = {
@@ -174,13 +185,16 @@ const VisualChart = ({ item, isDemo = false, isWidgetOrder }) => {
174
185
  const {
175
186
  configs = [],
176
187
  value_type = 'raw',
177
- aggregation_period,
178
- date_format,
179
- show_time,
188
+ aggregation_period = 'day',
189
+ date_format = 'YYYY-MM-DD HH:mm',
190
+ show_time = true,
191
+ type,
180
192
  } = configuration;
193
+
181
194
  const canChooseGroup = value_type !== 'raw';
182
195
  const [chartData, setChartData] = useState(configs);
183
196
  const [options, setOption] = useState(chartOptions);
197
+ const [processing, setProcessing] = useState(false);
184
198
  const [groupBy, setGroupBy] = useState(
185
199
  canChooseGroup ? aggregation_period : null
186
200
  );
@@ -231,7 +245,7 @@ const VisualChart = ({ item, isDemo = false, isWidgetOrder }) => {
231
245
  chart: { ...prev.chart },
232
246
  plotOptions: { ...prev.plotOptions },
233
247
  };
234
- switch (configuration?.type) {
248
+ switch (type) {
235
249
  case CHART_TYPE_ENUM.bar_chart:
236
250
  newOption.chart.type = 'column';
237
251
  newOption.plotOptions.column = {
@@ -281,13 +295,20 @@ const VisualChart = ({ item, isDemo = false, isWidgetOrder }) => {
281
295
  });
282
296
 
283
297
  chartRef.current?.chart?.redraw();
284
- }, [configuration?.type]);
298
+ }, [type]);
285
299
 
286
300
  useEffect(() => {
287
301
  if (!isDemo) {
288
302
  updateChart();
289
303
  }
290
- }, [updateChart, chartData, item?.configuration?.configs?.length, isDemo]);
304
+ }, [updateChart, chartData, configs.length, isDemo]);
305
+
306
+ const getPeriodDefault = useMemo(() => {
307
+ if (value_type === 'raw') {
308
+ return CHART_TIME[aggregation_period];
309
+ }
310
+ return CHART_TIME.week;
311
+ }, [aggregation_period, value_type]);
291
312
 
292
313
  return (
293
314
  <View style={styles.container}>
@@ -305,11 +326,14 @@ const VisualChart = ({ item, isDemo = false, isWidgetOrder }) => {
305
326
  />
306
327
  )}
307
328
  </View>
329
+ {processing && <FullLoading wrapStyle={styles.backgroundLoading} />}
308
330
  <ChartWrapper
309
331
  onChangeDate={fetchDataDisplayHistory}
310
332
  dateFormat={date_format}
311
333
  showTime={show_time}
312
334
  isWidgetOrder={isWidgetOrder}
335
+ periodDefault={getPeriodDefault}
336
+ setProcessing={setProcessing}
313
337
  >
314
338
  <Highcharts
315
339
  options={options}
@@ -12,19 +12,21 @@ const SegmentedRoundChart = memo(({ data }) => {
12
12
  const { id, color, title } = data || {};
13
13
  const [configValues] = useConfigGlobalState('configValues');
14
14
 
15
+ const getValue = configValues[id]?.value ?? '--';
16
+
15
17
  const renderAir = useCallback(() => {
16
18
  return (
17
19
  <SegmentedRoundDisplay
18
20
  filledArcColor={color}
19
- value={configValues[id]?.value}
20
- valueText={configValues[id]?.value || ''}
21
+ value={getValue}
22
+ valueText={getValue}
21
23
  totalValue={500}
22
24
  title={title}
23
25
  style={styles.segment}
24
26
  textHeader={t('text_air_quality_index')}
25
27
  />
26
28
  );
27
- }, [color, configValues, id, t, title]);
29
+ }, [color, getValue, t, title]);
28
30
 
29
31
  return renderAir();
30
32
  });
@@ -13,7 +13,7 @@ const SegmentedRoundChart = memo(({ data }) => {
13
13
  const [configValues] = useConfigGlobalState('configValues');
14
14
 
15
15
  const renderAir = useCallback(() => {
16
- const getValue = configValues?.[id]?.value ?? '--';
16
+ const getValue = configValues[id]?.value ?? '--';
17
17
 
18
18
  return (
19
19
  <SegmentedRoundDisplay
@@ -116,36 +116,6 @@ const WaterQuality = memo(({ summaryDetail }) => {
116
116
  {datas.map((item) => (
117
117
  <Item {...item} key={item.id} />
118
118
  ))}
119
- {/* <Item
120
- title={t('Turbidity')}
121
- value={summaryDetail.tur_value}
122
- color={summaryDetail.tur_color}
123
- des={summaryDetail.tur_status}
124
- svgMain={''}
125
- waterType="turbidity"
126
- />
127
- <Item
128
- title={t('pH')}
129
- value={summaryDetail.ph_value}
130
- color={summaryDetail.ph_color}
131
- des={summaryDetail.ph_status}
132
- svgMain={''}
133
- waterType="ph"
134
- />
135
- <Item
136
- title={t('Chlorine residual')}
137
- value={summaryDetail.clo_value}
138
- color={summaryDetail.clo_color}
139
- des={summaryDetail.clo_status}
140
- svgMain={''}
141
- waterType="clo"
142
- />
143
- <Item
144
- title={t('Water temperature')}
145
- value={summaryDetail.temp_value}
146
- des={''}
147
- svgMain={''}
148
- /> */}
149
119
  </View>
150
120
  </Section>
151
121
  {showBoxHistory && (