Passed
Push — master ( 107ae9...7e7300 )
by Guangyu
12:14 queued 12s
created

myems-web/src/components/MyEMS/Store/StoreEnergyCategory.js   B

Complexity

Total Complexity 42
Complexity/F 0

Size

Lines of Code 915
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 42
eloc 783
dl 0
loc 915
rs 8.857
c 0
b 0
f 0
mnd 42
bc 42
fnc 0
bpm 0
cpm 0
noi 0

How to fix   Complexity   

Complexity

Complex classes like myems-web/src/components/MyEMS/Store/StoreEnergyCategory.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import React, { Fragment, useEffect, useState, useContext } from 'react';
2
import {
3
  Breadcrumb,
4
  BreadcrumbItem,
5
  Row,
6
  Col,
7
  Card,
8
  CardBody,
9
  Button,
10
  ButtonGroup,
11
  Form,
12
  FormGroup,
13
  Input,
14
  Label,
15
  CustomInput,
16
  Spinner
17
} from 'reactstrap';
18
import CountUp from 'react-countup';
19
import moment from 'moment';
20
import loadable from '@loadable/component';
21
import Cascader from 'rc-cascader';
22
import CardSummary from '../common/CardSummary';
23
import MultiTrendChart from '../common/MultiTrendChart';
24
import SharePie from '../common/SharePie';
25
import { getCookieValue, createCookie } from '../../../helpers/utils';
26
import withRedirect from '../../../hoc/withRedirect';
27
import { withTranslation } from 'react-i18next';
28
import { toast } from 'react-toastify';
29
import ButtonIcon from '../../common/ButtonIcon';
30
import { APIBaseURL } from '../../../config';
31
import { periodTypeOptions } from '../common/PeriodTypeOptions';
32
import { comparisonTypeOptions } from '../common/ComparisonTypeOptions';
33
import DateRangePickerWrapper from '../common/DateRangePickerWrapper';
34
import { endOfDay} from 'date-fns';
35
import AppContext from '../../../context/Context';
36
import MultipleLineChart from '../common/MultipleLineChart';
37
38
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
39
40
const StoreEnergyCategory = ({ setRedirect, setRedirectUrl, t }) => {
41
  let current_moment = moment();
42
  useEffect(() => {
43
    let is_logged_in = getCookieValue('is_logged_in');
44
    let user_name = getCookieValue('user_name');
45
    let user_display_name = getCookieValue('user_display_name');
46
    let user_uuid = getCookieValue('user_uuid');
47
    let token = getCookieValue('token');
48
    if (is_logged_in === null || !is_logged_in) {
49
      setRedirectUrl(`/authentication/basic/login`);
50
      setRedirect(true);
51
    } else {
52
      //update expires time of cookies
53
      createCookie('is_logged_in', true, 1000 * 60 * 60 * 8);
54
      createCookie('user_name', user_name, 1000 * 60 * 60 * 8);
55
      createCookie('user_display_name', user_display_name, 1000 * 60 * 60 * 8);
56
      createCookie('user_uuid', user_uuid, 1000 * 60 * 60 * 8);
57
      createCookie('token', token, 1000 * 60 * 60 * 8);
58
    }
59
  });
60
61
62
  // State
63
  // Query Parameters
64
  const [selectedSpaceName, setSelectedSpaceName] = useState(undefined);
65
  const [selectedSpaceID, setSelectedSpaceID] = useState(undefined);
66
  const [storeList, setStoreList] = useState([]);
67
  const [selectedStore, setSelectedStore] = useState(undefined);
68
  const [comparisonType, setComparisonType] = useState('month-on-month');
69
  const [periodType, setPeriodType] = useState('daily');
70
  const [cascaderOptions, setCascaderOptions] = useState(undefined);
71
  const [basePeriodDateRange, setBasePeriodDateRange] = useState([current_moment.clone().subtract(1, 'months').startOf('month').toDate(), current_moment.clone().subtract(1, 'months').toDate()]);
72
  const [basePeriodDateRangePickerDisabled, setBasePeriodDateRangePickerDisabled] = useState(true);
73
  const [reportingPeriodDateRange, setReportingPeriodDateRange] = useState([current_moment.clone().startOf('month').toDate(), current_moment.toDate()]);
74
  const dateRangePickerLocale = {
75
    sunday: t('sunday'),
76
    monday: t('monday'),
77
    tuesday: t('tuesday'),
78
    wednesday: t('wednesday'),
79
    thursday: t('thursday'),
80
    friday: t('friday'),
81
    saturday: t('saturday'),
82
    ok: t('ok'),
83
    today: t('today'),
84
    yesterday: t('yesterday'),
85
    hours: t('hours'),
86
    minutes: t('minutes'),
87
    seconds: t('seconds'),
88
    last7Days: t('last7Days'),
89
    formattedMonthPattern: 'yyyy-MM-dd'
90
  };
91
  const dateRangePickerStyle = { display: 'block', zIndex: 10};
92
  const { language } = useContext(AppContext);
93
94
  // buttons
95
  const [submitButtonDisabled, setSubmitButtonDisabled] = useState(true);
96
  const [spinnerHidden, setSpinnerHidden] = useState(true);
97
  const [exportButtonHidden, setExportButtonHidden] = useState(true);
98
99
  //Results
100
  const [timeOfUseShareData, setTimeOfUseShareData] = useState([]);
101
  const [TCEShareData, setTCEShareData] = useState([]);
102
  const [TCO2EShareData, setTCO2EShareData] = useState([]);
103
104
  const [cardSummaryList, setCardSummaryList] = useState([]);
105
  const [totalInTCE, setTotalInTCE] = useState({});
106
  const [totalInTCO2E, setTotalInTCO2E] = useState({});
107
108
  const [storeBaseAndReportingNames, setStoreBaseAndReportingNames] = useState({"a0":""});
109
  const [storeBaseAndReportingUnits, setStoreBaseAndReportingUnits] = useState({"a0":"()"});
110
111
  const [storeBaseLabels, setStoreBaseLabels] = useState({"a0": []});
112
  const [storeBaseData, setStoreBaseData] = useState({"a0": []});
113
  const [storeBaseSubtotals, setStoreBaseSubtotals] = useState({"a0": (0).toFixed(2)});
114
115
  const [storeReportingLabels, setStoreReportingLabels] = useState({"a0": []});
116
  const [storeReportingData, setStoreReportingData] = useState({"a0": []});
117
  const [storeReportingSubtotals, setStoreReportingSubtotals] = useState({"a0": (0).toFixed(2)});
118
119
  const [storeReportingRates, setStoreReportingRates] = useState({"a0": []});
120
  const [storeReportingOptions, setStoreReportingOptions] = useState([]);
121
122
  const [parameterLineChartLabels, setParameterLineChartLabels] = useState([]);
123
  const [parameterLineChartData, setParameterLineChartData] = useState({});
124
  const [parameterLineChartOptions, setParameterLineChartOptions] = useState([]);
125
126
  const [detailedDataTableData, setDetailedDataTableData] = useState([]);
127
  const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]);
128
  const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
129
130
  useEffect(() => {
131
    let isResponseOK = false;
132
    fetch(APIBaseURL + '/spaces/tree', {
133
      method: 'GET',
134
      headers: {
135
        "Content-type": "application/json",
136
        "User-UUID": getCookieValue('user_uuid'),
137
        "Token": getCookieValue('token')
138
      },
139
      body: null,
140
141
    }).then(response => {
142
      console.log(response);
143
      if (response.ok) {
144
        isResponseOK = true;
145
      }
146
      return response.json();
147
    }).then(json => {
148
      console.log(json);
149
      if (isResponseOK) {
150
        // rename keys 
151
        json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
152
        setCascaderOptions(json);
153
        setSelectedSpaceName([json[0]].map(o => o.label));
154
        setSelectedSpaceID([json[0]].map(o => o.value));
155
        // get Stores by root Space ID
156
        let isResponseOK = false;
157
        fetch(APIBaseURL + '/spaces/' + [json[0]].map(o => o.value) + '/stores', {
158
          method: 'GET',
159
          headers: {
160
            "Content-type": "application/json",
161
            "User-UUID": getCookieValue('user_uuid'),
162
            "Token": getCookieValue('token')
163
          },
164
          body: null,
165
166
        }).then(response => {
167
          if (response.ok) {
168
            isResponseOK = true;
169
          }
170
          return response.json();
171
        }).then(json => {
172
          if (isResponseOK) {
173
            json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
174
            console.log(json);
175
            setStoreList(json[0]);
176
            if (json[0].length > 0) {
177
              setSelectedStore(json[0][0].value);
178
              // enable submit button
179
              setSubmitButtonDisabled(false);
180
            } else {
181
              setSelectedStore(undefined);
182
              // disable submit button
183
              setSubmitButtonDisabled(true);
184
            }
185
          } else {
186
            toast.error(t(json.description))
187
          }
188
        }).catch(err => {
189
          console.log(err);
190
        });
191
        // end of get Stores by root Space ID
192
      } else {
193
        toast.error(t(json.description));
194
      }
195
    }).catch(err => {
196
      console.log(err);
197
    });
198
199
  }, []);
200
201
  const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
202
203
  let onSpaceCascaderChange = (value, selectedOptions) => {
204
    setSelectedSpaceName(selectedOptions.map(o => o.label).join('/'));
205
    setSelectedSpaceID(value[value.length - 1]);
206
207
    let isResponseOK = false;
208
    fetch(APIBaseURL + '/spaces/' + value[value.length - 1] + '/stores', {
209
      method: 'GET',
210
      headers: {
211
        "Content-type": "application/json",
212
        "User-UUID": getCookieValue('user_uuid'),
213
        "Token": getCookieValue('token')
214
      },
215
      body: null,
216
217
    }).then(response => {
218
      if (response.ok) {
219
        isResponseOK = true;
220
      }
221
      return response.json();
222
    }).then(json => {
223
      if (isResponseOK) {
224
        json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
225
        console.log(json)
226
        setStoreList(json[0]);
227
        if (json[0].length > 0) {
228
          setSelectedStore(json[0][0].value);
229
          // enable submit button
230
          setSubmitButtonDisabled(false);
231
        } else {
232
          setSelectedStore(undefined);
233
          // disable submit button
234
          setSubmitButtonDisabled(true);
235
        }
236
      } else {
237
        toast.error(t(json.description))
238
      }
239
    }).catch(err => {
240
      console.log(err);
241
    });
242
  }
243
244
245
  let onComparisonTypeChange = ({ target }) => {
246
    console.log(target.value);
247
    setComparisonType(target.value);
248
    if (target.value === 'year-over-year') {
249
      setBasePeriodDateRangePickerDisabled(true);
250
      setBasePeriodDateRange([moment(reportingPeriodDateRange[0]).subtract(1, 'years').toDate(),
251
        moment(reportingPeriodDateRange[1]).subtract(1, 'years').toDate()]);
252
    } else if (target.value === 'month-on-month') {
253
      setBasePeriodDateRangePickerDisabled(true);
254
      setBasePeriodDateRange([moment(reportingPeriodDateRange[0]).subtract(1, 'months').toDate(),
255
        moment(reportingPeriodDateRange[1]).subtract(1, 'months').toDate()]);
256
    } else if (target.value === 'free-comparison') {
257
      setBasePeriodDateRangePickerDisabled(false);
258
    } else if (target.value === 'none-comparison') {
259
      setBasePeriodDateRange([null, null]);
260
      setBasePeriodDateRangePickerDisabled(true);
261
    }
262
  };
263
264
  // Callback fired when value changed
265
  let onBasePeriodChange = (DateRange) => {
266
    if(DateRange == null) {
267
      setBasePeriodDateRange([null, null]);
268
    } else {
269
      if (moment(DateRange[1]).format('HH:mm:ss') == '00:00:00') {
270
        // if the user did not change time value, set the default time to the end of day
271
        DateRange[1] = endOfDay(DateRange[1]);
272
      }
273
      setBasePeriodDateRange([DateRange[0], DateRange[1]]);
274
    }
275
  };
276
277
  // Callback fired when value changed
278
  let onReportingPeriodChange = (DateRange) => {
279
    if(DateRange == null) {
280
      setReportingPeriodDateRange([null, null]);
281
    } else {
282
      if (moment(DateRange[1]).format('HH:mm:ss') == '00:00:00') {
283
        // if the user did not change time value, set the default time to the end of day
284
        DateRange[1] = endOfDay(DateRange[1]);
285
      }
286
      setReportingPeriodDateRange([DateRange[0], DateRange[1]]);
287
      if (comparisonType === 'year-over-year') {
288
        setBasePeriodDateRange([moment(DateRange[0]).clone().subtract(1, 'years').toDate(), moment(DateRange[1]).clone().subtract(1, 'years').toDate()]);
289
      } else if (comparisonType === 'month-on-month') {
290
        setBasePeriodDateRange([moment(DateRange[0]).clone().subtract(1, 'months').toDate(), moment(DateRange[1]).clone().subtract(1, 'months').toDate()]);
291
      }
292
    }
293
  };
294
295
  // Callback fired when value clean
296
  let onBasePeriodClean = event => {
297
    setBasePeriodDateRange([null, null]);
298
  };
299
300
  // Callback fired when value clean
301
  let onReportingPeriodClean = event => {
302
    setReportingPeriodDateRange([null, null]);
303
  };
304
305
  const isBasePeriodTimestampExists = (base_period_data) => {
306
    const timestamps = base_period_data['timestamps'];
307
308
    if (timestamps.length === 0) {
309
      return false;
310
    }
311
312
    for (let i = 0; i < timestamps.length; i++) {
313
      if (timestamps[i].length > 0) {
314
        return true;
315
      }
316
    }
317
    return false
318
  }
319
320
  // Handler
321
  const handleSubmit = e => {
322
    e.preventDefault();
323
    console.log('handleSubmit');
324
    console.log(selectedSpaceID);
325
    console.log(selectedStore);
326
    console.log(comparisonType);
327
    console.log(periodType);
328
    console.log(basePeriodDateRange[0] != null ? moment(basePeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') : null)
329
    console.log(basePeriodDateRange[1] != null ? moment(basePeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') : null)
330
    console.log(moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss'))
331
    console.log(moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss'));
332
333
    // disable submit button
334
    setSubmitButtonDisabled(true);
335
    // show spinner
336
    setSpinnerHidden(false);
337
    // hide export button
338
    setExportButtonHidden(true)
339
340
    // Reinitialize tables
341
    setDetailedDataTableData([]);
342
    
343
    let isResponseOK = false;
344
    fetch(APIBaseURL + '/reports/storeenergycategory?' +
345
      'storeid=' + selectedStore +
346
      '&periodtype=' + periodType +
347
      '&baseperiodstartdatetime=' + (basePeriodDateRange[0] != null ? moment(basePeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') : '') +
348
      '&baseperiodenddatetime=' + (basePeriodDateRange[1] != null ? moment(basePeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') : '') +
349
      '&reportingperiodstartdatetime=' + moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') +
350
      '&reportingperiodenddatetime=' + moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') + 
351
      '&language=' + language, {
352
      method: 'GET',
353
      headers: {
354
        "Content-type": "application/json",
355
        "User-UUID": getCookieValue('user_uuid'),
356
        "Token": getCookieValue('token')
357
      },
358
      body: null,
359
360
    }).then(response => {
361
      if (response.ok) {
362
        isResponseOK = true;
363
      };
364
      return response.json();
365
    }).then(json => {
366
      if (isResponseOK) {
367
        console.log(json);
368
369
        let cardSummaryArray = []
370
        json['reporting_period']['names'].forEach((currentValue, index) => {
371
          let cardSummaryItem = {}
372
          cardSummaryItem['name'] = json['reporting_period']['names'][index];
373
          cardSummaryItem['unit'] = json['reporting_period']['units'][index];
374
          cardSummaryItem['subtotal'] = json['reporting_period']['subtotals'][index];
375
          cardSummaryItem['increment_rate'] = parseFloat(json['reporting_period']['increment_rates'][index] * 100).toFixed(2) + "%";
376
          cardSummaryItem['subtotal_per_unit_area'] = json['reporting_period']['subtotals_per_unit_area'][index];
377
          cardSummaryArray.push(cardSummaryItem);
378
        });
379
        setCardSummaryList(cardSummaryArray);
380
        
381
        let timeOfUseArray = [];
382
        json['reporting_period']['energy_category_ids'].forEach((currentValue, index) => {
383
          if(currentValue === 1) {
384
            // energy_category_id 1 electricity
385
            let timeOfUseItem = {}
386
            timeOfUseItem['id'] = 1;
387
            timeOfUseItem['name'] =  t('Top-Peak');
388
            timeOfUseItem['value'] = json['reporting_period']['toppeaks'][index];
389
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
390
            timeOfUseArray.push(timeOfUseItem);
391
            
392
            timeOfUseItem = {}
393
            timeOfUseItem['id'] = 2;
394
            timeOfUseItem['name'] =  t('On-Peak');
395
            timeOfUseItem['value'] = json['reporting_period']['onpeaks'][index];
396
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
397
            timeOfUseArray.push(timeOfUseItem);
398
399
            timeOfUseItem = {}
400
            timeOfUseItem['id'] = 3;
401
            timeOfUseItem['name'] =  t('Mid-Peak');
402
            timeOfUseItem['value'] = json['reporting_period']['midpeaks'][index];
403
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
404
            timeOfUseArray.push(timeOfUseItem);
405
406
            timeOfUseItem = {}
407
            timeOfUseItem['id'] = 4;
408
            timeOfUseItem['name'] =  t('Off-Peak');
409
            timeOfUseItem['value'] = json['reporting_period']['offpeaks'][index];
410
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
411
            timeOfUseArray.push(timeOfUseItem);
412
          }
413
        });
414
        setTimeOfUseShareData(timeOfUseArray);
415
416
        
417
        let totalInTCE = {}; 
418
        totalInTCE['value'] = json['reporting_period']['total_in_kgce'] / 1000; // convert from kg to t
419
        totalInTCE['increment_rate'] = parseFloat(json['reporting_period']['increment_rate_in_kgce'] * 100).toFixed(2) + "%";
420
        totalInTCE['value_per_unit_area'] = json['reporting_period']['total_in_kgce_per_unit_area'] / 1000; // convert from kg to t
421
        setTotalInTCE(totalInTCE);
422
423
        let totalInTCO2E = {}; 
424
        totalInTCO2E['value'] = json['reporting_period']['total_in_kgco2e'] / 1000; // convert from kg to t
425
        totalInTCO2E['increment_rate'] = parseFloat(json['reporting_period']['increment_rate_in_kgco2e'] * 100).toFixed(2) + "%";
426
        totalInTCO2E['value_per_unit_area'] = json['reporting_period']['total_in_kgco2e_per_unit_area'] / 1000; // convert from kg to t
427
        setTotalInTCO2E(totalInTCO2E);
428
429
        let TCEDataArray = [];
430
        json['reporting_period']['names'].forEach((currentValue, index) => {
431
          let TCEDataItem = {}
432
          TCEDataItem['id'] = index;
433
          TCEDataItem['name'] = currentValue;
434
          TCEDataItem['value'] = json['reporting_period']['subtotals_in_kgce'][index] / 1000; // convert from kg to t
435
          TCEDataItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
436
          TCEDataArray.push(TCEDataItem);
437
        });
438
        setTCEShareData(TCEDataArray);
439
440
        let TCO2EDataArray = [];
441
        json['reporting_period']['names'].forEach((currentValue, index) => {
442
          let TCO2EDataItem = {}
443
          TCO2EDataItem['id'] = index;
444
          TCO2EDataItem['name'] = currentValue;
445
          TCO2EDataItem['value'] = json['reporting_period']['subtotals_in_kgco2e'][index] / 1000; // convert from kg to t
446
          TCO2EDataItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
447
          TCO2EDataArray.push(TCO2EDataItem);
448
        });
449
        setTCO2EShareData(TCO2EDataArray);
450
451
        let base_timestamps = {}
452
        json['base_period']['timestamps'].forEach((currentValue, index) => {
453
          base_timestamps['a' + index] = currentValue;
454
        });
455
        setStoreBaseLabels(base_timestamps)
456
457
        let base_values = {}
458
        json['base_period']['values'].forEach((currentValue, index) => {
459
          base_values['a' + index] = currentValue;
460
        });
461
        setStoreBaseData(base_values)
462
463
        /*
464
        * Tip:
465
        *     base_names === reporting_names
466
        *     base_units === reporting_units
467
        * */
468
469
        let base_and_reporting_names = {}
470
        json['reporting_period']['names'].forEach((currentValue, index) => {
471
          base_and_reporting_names['a' + index] = currentValue;
472
        });
473
        setStoreBaseAndReportingNames(base_and_reporting_names)
474
475
        let base_and_reporting_units = {}
476
        json['reporting_period']['units'].forEach((currentValue, index) => {
477
          base_and_reporting_units['a' + index] = "("+currentValue+")";
478
        });
479
        setStoreBaseAndReportingUnits(base_and_reporting_units)
480
481
        let base_subtotals = {}
482
        json['base_period']['subtotals'].forEach((currentValue, index) => {
483
          base_subtotals['a' + index] = currentValue.toFixed(2);
484
        });
485
        setStoreBaseSubtotals(base_subtotals)
486
487
        let reporting_timestamps = {}
488
        json['reporting_period']['timestamps'].forEach((currentValue, index) => {
489
          reporting_timestamps['a' + index] = currentValue;
490
        });
491
        setStoreReportingLabels(reporting_timestamps);
492
493
        let reporting_values = {}
494
        json['reporting_period']['values'].forEach((currentValue, index) => {
495
          reporting_values['a' + index] = currentValue;
496
        });
497
        setStoreReportingData(reporting_values);
498
499
        let reporting_subtotals = {}
500
        json['reporting_period']['subtotals'].forEach((currentValue, index) => {
501
          reporting_subtotals['a' + index] = currentValue.toFixed(2);
502
        });
503
        setStoreReportingSubtotals(reporting_subtotals);
504
505
        let rates = {}
506
        json['reporting_period']['rates'].forEach((currentValue, index) => {
507
          let currentRate = Array();
508
          currentValue.forEach((rate) => {
509
            currentRate.push(rate ? parseFloat(rate * 100).toFixed(2) : '0.00');
510
          });
511
          rates['a' + index] = currentRate;
512
        });
513
        setStoreReportingRates(rates)
514
515
        let options = Array();
516
        json['reporting_period']['names'].forEach((currentValue, index) => {
517
          let unit = json['reporting_period']['units'][index];
518
          options.push({ 'value': 'a' + index, 'label': currentValue + ' (' + unit + ')'});
519
        });
520
        setStoreReportingOptions(options);
521
522
        let timestamps = {}
523
        json['parameters']['timestamps'].forEach((currentValue, index) => {
524
          timestamps['a' + index] = currentValue;
525
        });
526
        setParameterLineChartLabels(timestamps);
527
528
        let values = {}
529
        json['parameters']['values'].forEach((currentValue, index) => {
530
          values['a' + index] = currentValue;
531
        });
532
        setParameterLineChartData(values);
533
      
534
        let names = Array();
535
        json['parameters']['names'].forEach((currentValue, index) => {
536
          
537
          names.push({ 'value': 'a' + index, 'label': currentValue });
538
        });
539
        setParameterLineChartOptions(names);
540
541
        if(!isBasePeriodTimestampExists(json['base_period'])) {
542
          let detailed_value_list = [];
543
          if (json['reporting_period']['timestamps'].length > 0) {
544
            json['reporting_period']['timestamps'][0].forEach((currentTimestamp, timestampIndex) => {
545
              let detailed_value = {};
546
              detailed_value['id'] = timestampIndex;
547
              detailed_value['startdatetime'] = currentTimestamp;
548
              json['reporting_period']['values'].forEach((currentValue, energyCategoryIndex) => {
549
                detailed_value['a' + energyCategoryIndex] = json['reporting_period']['values'][energyCategoryIndex][timestampIndex];
550
              });
551
              detailed_value_list.push(detailed_value);
552
            });
553
          }
554
          ;
555
556
          let detailed_value = {};
557
          detailed_value['id'] = detailed_value_list.length;
558
          detailed_value['startdatetime'] = t('Subtotal');
559
          json['reporting_period']['subtotals'].forEach((currentValue, index) => {
560
            detailed_value['a' + index] = currentValue;
561
          });
562
          detailed_value_list.push(detailed_value);
563
          setTimeout(() => {
564
            setDetailedDataTableData(detailed_value_list);
565
          }, 0)
566
567
          let detailed_column_list = [];
568
          detailed_column_list.push({
569
            dataField: 'startdatetime',
570
            text: t('Datetime'),
571
            sort: true
572
          });
573
          json['reporting_period']['names'].forEach((currentValue, index) => {
574
            let unit = json['reporting_period']['units'][index];
575
            detailed_column_list.push({
576
              dataField: 'a' + index,
577
              text: currentValue + ' (' + unit + ')',
578
              sort: true,
579
              formatter: function (decimalValue) {
580
                if (typeof decimalValue === 'number') {
581
                  return decimalValue.toFixed(2);
582
                } else {
583
                  return null;
584
                }
585
              }
586
            });
587
          });
588
          setDetailedDataTableColumns(detailed_column_list);
589
        }else {
590
          /*
591
          * Tip:
592
          *     json['base_period']['names'] ===  json['reporting_period']['names']
593
          *     json['base_period']['units'] ===  json['reporting_period']['units']
594
          * */
595
          let detailed_column_list = [];
596
          detailed_column_list.push({
597
            dataField: 'basePeriodDatetime',
598
            text: t('Base Period') + ' - ' + t('Datetime'),
599
            sort: true
600
          })
601
602
          json['base_period']['names'].forEach((currentValue, index) => {
603
            let unit = json['base_period']['units'][index];
604
            detailed_column_list.push({
605
              dataField: 'a' + index,
606
              text: t('Base Period') + ' - ' + currentValue + ' (' + unit + ')',
607
              sort: true,
608
              formatter: function (decimalValue) {
609
                if (typeof decimalValue === 'number') {
610
                  return decimalValue.toFixed(2);
611
                } else {
612
                  return null;
613
                }
614
              }
615
            })
616
          });
617
618
          detailed_column_list.push({
619
            dataField: 'reportingPeriodDatetime',
620
            text: t('Reporting Period') + ' - ' + t('Datetime'),
621
            sort: true
622
          })
623
624
          json['reporting_period']['names'].forEach((currentValue, index) => {
625
            let unit = json['reporting_period']['units'][index];
626
            detailed_column_list.push({
627
              dataField: 'b' + index,
628
              text: t('Reporting Period') + ' - ' + currentValue + ' (' + unit + ')',
629
              sort: true,
630
              formatter: function (decimalValue) {
631
                if (typeof decimalValue === 'number') {
632
                  return decimalValue.toFixed(2);
633
                } else {
634
                  return null;
635
                }
636
              }
637
            })
638
          });
639
          setDetailedDataTableColumns(detailed_column_list);
640
641
          let detailed_value_list = [];
642
          if (json['base_period']['timestamps'].length > 0 || json['reporting_period']['timestamps'].length > 0) {
643
            const max_timestamps_length = json['base_period']['timestamps'][0].length >= json['reporting_period']['timestamps'][0].length?
644
                json['base_period']['timestamps'][0].length : json['reporting_period']['timestamps'][0].length;
645
            for (let index = 0; index < max_timestamps_length; index++) {
646
              let detailed_value = {};
647
              detailed_value['id'] = index;
648
              detailed_value['basePeriodDatetime'] = index < json['base_period']['timestamps'][0].length? json['base_period']['timestamps'][0][index] : null;
649
              json['base_period']['values'].forEach((currentValue, energyCategoryIndex) => {
650
                detailed_value['a' + energyCategoryIndex] = index < json['base_period']['values'][energyCategoryIndex].length? json['base_period']['values'][energyCategoryIndex][index] : null;
651
              });
652
              detailed_value['reportingPeriodDatetime'] = index < json['reporting_period']['timestamps'][0].length? json['reporting_period']['timestamps'][0][index] : null;
653
              json['reporting_period']['values'].forEach((currentValue, energyCategoryIndex) => {
654
                detailed_value['b' + energyCategoryIndex] = index < json['reporting_period']['values'][energyCategoryIndex].length? json['reporting_period']['values'][energyCategoryIndex][index] : null;
655
              });
656
              detailed_value_list.push(detailed_value);
657
            }
658
659
            let detailed_value = {};
660
            detailed_value['id'] = detailed_value_list.length;
661
            detailed_value['basePeriodDatetime'] = t('Subtotal');
662
            json['base_period']['subtotals'].forEach((currentValue, index) => {
663
              detailed_value['a' + index] = currentValue;
664
            });
665
            detailed_value['reportingPeriodDatetime'] = t('Subtotal');
666
            json['reporting_period']['subtotals'].forEach((currentValue, index) => {
667
              detailed_value['b' + index] = currentValue;
668
            });
669
            detailed_value_list.push(detailed_value);
670
            setTimeout( () => {
671
              setDetailedDataTableData(detailed_value_list);
672
            }, 0)
673
          }
674
        }
675
        
676
        setExcelBytesBase64(json['excel_bytes_base64']);
677
678
        // enable submit button
679
        setSubmitButtonDisabled(false);
680
        // hide spinner
681
        setSpinnerHidden(true);
682
        // show export button
683
        setExportButtonHidden(false)
684
685
      } else {
686
        toast.error(t(json.description))
687
      }
688
    }).catch(err => {
689
      console.log(err);
690
    });
691
  };
692
693
  const handleExport = e => {
694
    e.preventDefault();
695
    const mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
696
    const fileName = 'storeenergycategory.xlsx'
697
    var fileUrl = "data:" + mimeType + ";base64," + excelBytesBase64;
698
    fetch(fileUrl)
699
        .then(response => response.blob())
700
        .then(blob => {
701
            var link = window.document.createElement("a");
702
            link.href = window.URL.createObjectURL(blob, { type: mimeType });
703
            link.download = fileName;
704
            document.body.appendChild(link);
705
            link.click();
706
            document.body.removeChild(link);
707
        });
708
  };
709
  
710
711
712
  return (
713
    <Fragment>
714
      <div>
715
        <Breadcrumb>
716
          <BreadcrumbItem>{t('Store Data')}</BreadcrumbItem><BreadcrumbItem active>{t('Energy Category Data')}</BreadcrumbItem>
717
        </Breadcrumb>
718
      </div>
719
      <Card className="bg-light mb-3">
720
        <CardBody className="p-3">
721
          <Form onSubmit={handleSubmit}>
722
            <Row form>
723
              <Col xs={6} sm={3}>
724
                <FormGroup className="form-group">
725
                  <Label className={labelClasses} for="space">
726
                    {t('Space')}
727
                  </Label>
728
                  <br />
729
                  <Cascader options={cascaderOptions}
730
                    onChange={onSpaceCascaderChange}
731
                    changeOnSelect
732
                    expandTrigger="hover">
733
                    <Input value={selectedSpaceName || ''} readOnly />
734
                  </Cascader>
735
                </FormGroup>
736
              </Col>
737
              <Col xs="auto">
738
                <FormGroup>
739
                  <Label className={labelClasses} for="storeSelect">
740
                    {t('Store')}
741
                  </Label>
742
                  <CustomInput type="select" id="storeSelect" name="storeSelect" onChange={({ target }) => setSelectedStore(target.value)}
743
                  >
744
                    {storeList.map((store, index) => (
745
                      <option value={store.value} key={store.value}>
746
                        {store.label}
747
                      </option>
748
                    ))}
749
                  </CustomInput>
750
                </FormGroup>
751
              </Col>
752
              <Col xs="auto">
753
                <FormGroup>
754
                  <Label className={labelClasses} for="comparisonType">
755
                    {t('Comparison Types')}
756
                  </Label>
757
                  <CustomInput type="select" id="comparisonType" name="comparisonType"
758
                    defaultValue="month-on-month"
759
                    onChange={onComparisonTypeChange}
760
                  >
761
                    {comparisonTypeOptions.map((comparisonType, index) => (
762
                      <option value={comparisonType.value} key={comparisonType.value} >
763
                        {t(comparisonType.label)}
764
                      </option>
765
                    ))}
766
                  </CustomInput>
767
                </FormGroup>
768
              </Col>
769
              <Col xs="auto">
770
                <FormGroup>
771
                  <Label className={labelClasses} for="periodType">
772
                    {t('Period Types')}
773
                  </Label>
774
                  <CustomInput type="select" id="periodType" name="periodType" defaultValue="daily" onChange={({ target }) => setPeriodType(target.value)}
775
                  >
776
                    {periodTypeOptions.map((periodType, index) => (
777
                      <option value={periodType.value} key={periodType.value} >
778
                        {t(periodType.label)}
779
                      </option>
780
                    ))}
781
                  </CustomInput>
782
                </FormGroup>
783
              </Col>
784
              <Col xs={6} sm={3}>
785
                <FormGroup className="form-group">
786
                  <Label className={labelClasses} for="basePeriodDateRangePicker">{t('Base Period')}{t('(Optional)')}</Label>
787
                  <DateRangePickerWrapper 
788
                    id='basePeriodDateRangePicker'
789
                    disabled={basePeriodDateRangePickerDisabled}
790
                    format="yyyy-MM-dd HH:mm:ss"
791
                    value={basePeriodDateRange}
792
                    onChange={onBasePeriodChange}
793
                    size="md"
794
                    style={dateRangePickerStyle}
795
                    onClean={onBasePeriodClean}
796
                    locale={dateRangePickerLocale}
797
                    placeholder={t("Select Date Range")}
798
                   />
799
                </FormGroup>
800
              </Col>
801
              <Col xs={6} sm={3}>
802
                <FormGroup className="form-group">
803
                  <Label className={labelClasses} for="reportingPeriodDateRangePicker">{t('Reporting Period')}</Label>
804
                  <br/>
805
                  <DateRangePickerWrapper
806
                    id='reportingPeriodDateRangePicker'
807
                    format="yyyy-MM-dd HH:mm:ss"
808
                    value={reportingPeriodDateRange}
809
                    onChange={onReportingPeriodChange}
810
                    size="md"
811
                    style={dateRangePickerStyle}
812
                    onClean={onReportingPeriodClean}
813
                    locale={dateRangePickerLocale}
814
                    placeholder={t("Select Date Range")}
815
                  />
816
                </FormGroup>
817
              </Col>
818
              <Col xs="auto">
819
                <FormGroup>
820
                  <br></br>
821
                  <ButtonGroup id="submit">
822
                    <Button color="success" disabled={submitButtonDisabled} >{t('Submit')}</Button>
823
                  </ButtonGroup>
824
                </FormGroup>
825
              </Col>
826
              <Col xs="auto">
827
                <FormGroup>
828
                  <br></br>
829
                  <Spinner color="primary" hidden={spinnerHidden}  />
830
                </FormGroup>
831
              </Col>
832
              <Col xs="auto">
833
                  <br></br>
834
                  <ButtonIcon icon="external-link-alt" transform="shrink-3 down-2" color="falcon-default" 
835
                  hidden={exportButtonHidden}
836
                  onClick={handleExport} >
837
                    {t('Export')}
838
                  </ButtonIcon>
839
              </Col>
840
            </Row>
841
          </Form>
842
        </CardBody>
843
      </Card>
844
      <div className="card-deck">
845
        {cardSummaryList.map(cardSummaryItem => (
846
          <CardSummary key={cardSummaryItem['name']}
847
            rate={cardSummaryItem['increment_rate']}
848
            title={t('Reporting Period Consumption CATEGORY UNIT', { 'CATEGORY': cardSummaryItem['name'], 'UNIT': '(' + cardSummaryItem['unit'] + ')' })}
849
            color="success" 
850
            footnote={t('Per Unit Area')} 
851
            footvalue={cardSummaryItem['subtotal_per_unit_area']}
852
            footunit={"(" + cardSummaryItem['unit'] + "/M²)"} >
853
            {cardSummaryItem['subtotal'] && <CountUp end={cardSummaryItem['subtotal']} duration={2} prefix="" separator="," decimal="." decimals={2} />}
854
          </CardSummary>
855
        ))}
856
       
857
        <CardSummary 
858
          rate={totalInTCE['increment_rate'] || ''} 
859
          title={t('Reporting Period Consumption CATEGORY UNIT', { 'CATEGORY': t('Ton of Standard Coal'), 'UNIT': '(TCE)' })}
860
          color="warning" 
861
          footnote={t('Per Unit Area')} 
862
          footvalue={totalInTCE['value_per_unit_area']} 
863
          footunit="(TCE/M²)">
864
          {totalInTCE['value'] && <CountUp end={totalInTCE['value']} duration={2} prefix="" separator="," decimal="." decimals={2} />}
865
        </CardSummary>
866
        <CardSummary 
867
          rate={totalInTCO2E['increment_rate'] || ''} 
868
          title={t('Reporting Period Consumption CATEGORY UNIT', { 'CATEGORY': t('Ton of Carbon Dioxide Emissions'), 'UNIT': '(TCO2E)' })}
869
          color="warning" 
870
          footnote={t('Per Unit Area')} 
871
          footvalue={totalInTCO2E['value_per_unit_area']} 
872
          footunit="(TCO2E/M²)">
873
          {totalInTCO2E['value'] && <CountUp end={totalInTCO2E['value']} duration={2} prefix="" separator="," decimal="." decimals={2} />}
874
        </CardSummary>
875
      </div>
876
      <Row noGutters>
877
        <Col className="mb-3 pr-lg-2 mb-3">
878
          <SharePie data={timeOfUseShareData} title={t('Electricity Consumption by Time-Of-Use')} />
879
        </Col>
880
        <Col className="mb-3 pr-lg-2 mb-3">
881
          <SharePie data={TCEShareData} title={t('Ton of Standard Coal by Energy Category')} />
882
        </Col>
883
        <Col className="mb-3 pr-lg-2 mb-3">
884
          <SharePie data={TCO2EShareData} title={t('Ton of Carbon Dioxide Emissions by Energy Category')} />
885
        </Col>
886
      </Row>
887
888
      <MultiTrendChart reportingTitle = {{"name": "Reporting Period Consumption CATEGORY VALUE UNIT", "substitute": ["CATEGORY", "VALUE", "UNIT"], "CATEGORY": storeBaseAndReportingNames, "VALUE": storeReportingSubtotals, "UNIT": storeBaseAndReportingUnits}}
889
        baseTitle = {{"name": "Base Period Consumption CATEGORY VALUE UNIT", "substitute": ["CATEGORY", "VALUE", "UNIT"], "CATEGORY": storeBaseAndReportingNames, "VALUE": storeBaseSubtotals, "UNIT": storeBaseAndReportingUnits}}
890
        reportingTooltipTitle = {{"name": "Reporting Period Consumption CATEGORY VALUE UNIT", "substitute": ["CATEGORY", "VALUE", "UNIT"], "CATEGORY": storeBaseAndReportingNames, "VALUE": null, "UNIT": storeBaseAndReportingUnits}}
891
        baseTooltipTitle = {{"name": "Base Period Consumption CATEGORY VALUE UNIT", "substitute": ["CATEGORY", "VALUE", "UNIT"], "CATEGORY": storeBaseAndReportingNames, "VALUE": null, "UNIT": storeBaseAndReportingUnits}}
892
        reportingLabels={storeReportingLabels}
893
        reportingData={storeReportingData}
894
        baseLabels={storeBaseLabels}
895
        baseData={storeBaseData}
896
        rates={storeReportingRates}
897
        options={storeReportingOptions}>
898
      </MultiTrendChart>
899
900
      <MultipleLineChart reportingTitle={t('Related Parameters')}
901
        baseTitle=''
902
        labels={parameterLineChartLabels}
903
        data={parameterLineChartData}
904
        options={parameterLineChartOptions}>
905
      </MultipleLineChart>
906
      <br />
907
      <DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
908
      </DetailedDataTable>
909
910
    </Fragment>
911
  );
912
};
913
914
export default withTranslation()(withRedirect(StoreEnergyCategory));
915