Passed
Push — master ( 570acf...bff261 )
by Guangyu
08:10 queued 12s
created

myems-web/src/components/MyEMS/CombinedEquipment/CombinedEquipmentCarbon.js   A

Complexity

Total Complexity 33
Complexity/F 0

Size

Lines of Code 771
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 33
eloc 672
dl 0
loc 771
rs 9.688
c 0
b 0
f 0
mnd 33
bc 33
fnc 0
bpm 0
cpm 0
noi 0
1
import React, { Fragment, useEffect, useState } 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 LineChart from '../common/LineChart';
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 { DateRangePicker } from 'rsuite';
34
import { endOfDay} from 'date-fns';
35
36
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
37
const AssociatedEquipmentTable = loadable(() => import('../common/AssociatedEquipmentTable'));
38
39
const CombinedEquipmentCarbon = ({ setRedirect, setRedirectUrl, t }) => {
40
  let current_moment = moment();
41
  useEffect(() => {
42
    let is_logged_in = getCookieValue('is_logged_in');
43
    let user_name = getCookieValue('user_name');
44
    let user_display_name = getCookieValue('user_display_name');
45
    let user_uuid = getCookieValue('user_uuid');
46
    let token = getCookieValue('token');
47
    if (is_logged_in === null || !is_logged_in) {
48
      setRedirectUrl(`/authentication/basic/login`);
49
      setRedirect(true);
50
    } else {
51
      //update expires time of cookies
52
      createCookie('is_logged_in', true, 1000 * 60 * 60 * 8);
53
      createCookie('user_name', user_name, 1000 * 60 * 60 * 8);
54
      createCookie('user_display_name', user_display_name, 1000 * 60 * 60 * 8);
55
      createCookie('user_uuid', user_uuid, 1000 * 60 * 60 * 8);
56
      createCookie('token', token, 1000 * 60 * 60 * 8);
57
    }
58
  });
59
60
61
  // State
62
  // Query Parameters
63
  const [selectedSpaceName, setSelectedSpaceName] = useState(undefined);
64
  const [selectedSpaceID, setSelectedSpaceID] = useState(undefined);
65
  const [combinedEquipmentList, setCombinedEquipmentList] = useState([]);
66
  const [selectedCombinedEquipment, setSelectedCombinedEquipment] = useState(undefined);
67
  const [comparisonType, setComparisonType] = useState('month-on-month');
68
  const [periodType, setPeriodType] = useState('daily');
69
  const [cascaderOptions, setCascaderOptions] = useState(undefined);
70
  const [basePeriodDateRange, setBasePeriodDateRange] = useState([current_moment.clone().subtract(1, 'months').startOf('month').toDate(), current_moment.clone().subtract(1, 'months').toDate()]);
71
  const [basePeriodDateRangePickerDisabled, setBasePeriodDateRangePickerDisabled] = useState(true);
72
  const [reportingPeriodDateRange, setReportingPeriodDateRange] = useState([current_moment.clone().startOf('month').toDate(), current_moment.toDate()]);
73
  const dateRangePickerLocale = {
74
    sunday: t('sunday'),
75
    monday: t('monday'),
76
    tuesday: t('tuesday'),
77
    wednesday: t('wednesday'),
78
    thursday: t('thursday'),
79
    friday: t('friday'),
80
    saturday: t('saturday'),
81
    ok: t('ok'),
82
    today: t('today'),
83
    yesterday: t('yesterday'),
84
    hours: t('hours'),
85
    minutes: t('minutes'),
86
    seconds: t('seconds'),
87
    last7Days: t('last7Days')
88
  };
89
  const dateRangePickerStyle = { display: 'block', zIndex: 10};
90
91
  // buttons
92
  const [submitButtonDisabled, setSubmitButtonDisabled] = useState(true);
93
  const [spinnerHidden, setSpinnerHidden] = useState(true);
94
  const [exportButtonHidden, setExportButtonHidden] = useState(true);
95
  
96
  //Results
97
  const [timeOfUseShareData, setTimeOfUseShareData] = useState([]);
98
  const [carbonShareData, setCarbonShareData] = useState([]);
99
100
  const [cardSummaryList, setCardSummaryList] = useState([]);
101
  const [combinedEquipmentLineChartLabels, setCombinedEquipmentLineChartLabels] = useState([]);
102
  const [combinedEquipmentLineChartData, setCombinedEquipmentLineChartData] = useState({});
103
  const [combinedEquipmentLineChartOptions, setCombinedEquipmentLineChartOptions] = useState([]);
104
105
  const [parameterLineChartLabels, setParameterLineChartLabels] = useState([]);
106
  const [parameterLineChartData, setParameterLineChartData] = useState({});
107
  const [parameterLineChartOptions, setParameterLineChartOptions] = useState([]);
108
109
  const [detailedDataTableData, setDetailedDataTableData] = useState([]);
110
  const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]);
111
  
112
  const [associatedEquipmentTableData, setAssociatedEquipmentTableData] = useState([]);
113
  const [associatedEquipmentTableColumns, setAssociatedEquipmentTableColumns] = useState([{dataField: 'name', text: t('Associated Equipment'), sort: true }]);
114
  
115
  const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
116
  
117
  useEffect(() => {
118
    let isResponseOK = false;
119
    fetch(APIBaseURL + '/spaces/tree', {
120
      method: 'GET',
121
      headers: {
122
        "Content-type": "application/json",
123
        "User-UUID": getCookieValue('user_uuid'),
124
        "Token": getCookieValue('token')
125
      },
126
      body: null,
127
128
    }).then(response => {
129
      console.log(response);
130
      if (response.ok) {
131
        isResponseOK = true;
132
      }
133
      return response.json();
134
    }).then(json => {
135
      console.log(json);
136
      if (isResponseOK) {
137
        // rename keys 
138
        json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
139
        setCascaderOptions(json);
140
        setSelectedSpaceName([json[0]].map(o => o.label));
141
        setSelectedSpaceID([json[0]].map(o => o.value));
142
        // get Combined Equipments by root Space ID
143
        let isResponseOK = false;
144
        fetch(APIBaseURL + '/spaces/' + [json[0]].map(o => o.value) + '/combinedequipments', {
145
          method: 'GET',
146
          headers: {
147
            "Content-type": "application/json",
148
            "User-UUID": getCookieValue('user_uuid'),
149
            "Token": getCookieValue('token')
150
          },
151
          body: null,
152
153
        }).then(response => {
154
          if (response.ok) {
155
            isResponseOK = true;
156
          }
157
          return response.json();
158
        }).then(json => {
159
          if (isResponseOK) {
160
            json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
161
            console.log(json);
162
            setCombinedEquipmentList(json[0]);
163
            if (json[0].length > 0) {
164
              setSelectedCombinedEquipment(json[0][0].value);
165
              // enable submit button
166
              setSubmitButtonDisabled(false);
167
            } else {
168
              setSelectedCombinedEquipment(undefined);
169
              // disable submit button
170
              setSubmitButtonDisabled(true);
171
            }
172
          } else {
173
            toast.error(json.description)
174
          }
175
        }).catch(err => {
176
          console.log(err);
177
        });
178
        // end of get Combined Equipments by root Space ID
179
      } else {
180
        toast.error(json.description);
181
      }
182
    }).catch(err => {
183
      console.log(err);
184
    });
185
186
  }, []);
187
188
  const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
189
190
  let onSpaceCascaderChange = (value, selectedOptions) => {
191
    setSelectedSpaceName(selectedOptions.map(o => o.label).join('/'));
192
    setSelectedSpaceID(value[value.length - 1]);
193
194
    let isResponseOK = false;
195
    fetch(APIBaseURL + '/spaces/' + value[value.length - 1] + '/combinedequipments', {
196
      method: 'GET',
197
      headers: {
198
        "Content-type": "application/json",
199
        "User-UUID": getCookieValue('user_uuid'),
200
        "Token": getCookieValue('token')
201
      },
202
      body: null,
203
204
    }).then(response => {
205
      if (response.ok) {
206
        isResponseOK = true;
207
      }
208
      return response.json();
209
    }).then(json => {
210
      if (isResponseOK) {
211
        json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
212
        console.log(json)
213
        setCombinedEquipmentList(json[0]);
214
        if (json[0].length > 0) {
215
          setSelectedCombinedEquipment(json[0][0].value);
216
          // enable submit button
217
          setSubmitButtonDisabled(false);
218
        } else {
219
          setSelectedCombinedEquipment(undefined);
220
          // disable submit button
221
          setSubmitButtonDisabled(true);
222
        }
223
      } else {
224
        toast.error(json.description)
225
      }
226
    }).catch(err => {
227
      console.log(err);
228
    });
229
  }
230
231
232
  let onComparisonTypeChange = ({ target }) => {
233
    console.log(target.value);
234
    setComparisonType(target.value);
235
    if (target.value === 'year-over-year') {
236
      setBasePeriodDateRangePickerDisabled(true);
237
      setBasePeriodDateRange([moment(reportingPeriodDateRange[0]).subtract(1, 'years').toDate(),
238
        moment(reportingPeriodDateRange[1]).subtract(1, 'years').toDate()]);
239
    } else if (target.value === 'month-on-month') {
240
      setBasePeriodDateRangePickerDisabled(true);
241
      setBasePeriodDateRange([moment(reportingPeriodDateRange[0]).subtract(1, 'months').toDate(),
242
        moment(reportingPeriodDateRange[1]).subtract(1, 'months').toDate()]);
243
    } else if (target.value === 'free-comparison') {
244
      setBasePeriodDateRangePickerDisabled(false);
245
    } else if (target.value === 'none-comparison') {
246
      setBasePeriodDateRange([null, null]);
247
      setBasePeriodDateRangePickerDisabled(true);
248
    }
249
  };
250
251
  // Callback fired when value changed
252
  let onBasePeriodChange = (DateRange) => {
253
    if(DateRange == null) {
254
      setBasePeriodDateRange([null, null]);
255
    } else {
256
      if (moment(DateRange[1]).format('HH:mm:ss') == '00:00:00') {
257
        // if the user did not change time value, set the default time to the end of day
258
        DateRange[1] = endOfDay(DateRange[1]);
259
      }
260
      setBasePeriodDateRange([DateRange[0], DateRange[1]]);
261
    }
262
  };
263
264
  // Callback fired when value changed
265
  let onReportingPeriodChange = (DateRange) => {
266
    if(DateRange == null) {
267
      setReportingPeriodDateRange([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
      setReportingPeriodDateRange([DateRange[0], DateRange[1]]);
274
      if (comparisonType === 'year-over-year') {
275
        setBasePeriodDateRange([moment(DateRange[0]).clone().subtract(1, 'years').toDate(), moment(DateRange[1]).clone().subtract(1, 'years').toDate()]);
276
      } else if (comparisonType === 'month-on-month') {
277
        setBasePeriodDateRange([moment(DateRange[0]).clone().subtract(1, 'months').toDate(), moment(DateRange[1]).clone().subtract(1, 'months').toDate()]);
278
      }
279
    }
280
  };
281
282
  // Callback fired when value clean
283
  let onBasePeriodClean = event => {
284
    setBasePeriodDateRange([null, null]);
285
  };
286
287
  // Callback fired when value clean
288
  let onReportingPeriodClean = event => {
289
    setReportingPeriodDateRange([null, null]);
290
  };
291
292
  // Handler
293
  const handleSubmit = e => {
294
    e.preventDefault();
295
    console.log('handleSubmit');
296
    console.log(selectedSpaceID);
297
    console.log(selectedCombinedEquipment);
298
    console.log(comparisonType);
299
    console.log(periodType);
300
    console.log(basePeriodDateRange[0] != null ? moment(basePeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') : null)
301
    console.log(basePeriodDateRange[1] != null ? moment(basePeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') : null)
302
    console.log(moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss'))
303
    console.log(moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss'));
304
305
    // disable submit button
306
    setSubmitButtonDisabled(true);
307
    // show spinner
308
    setSpinnerHidden(false);
309
    // hide export button
310
    setExportButtonHidden(true)
311
312
    // Reinitialize tables
313
    setDetailedDataTableData([]);
314
    setAssociatedEquipmentTableData([]);
315
    
316
    let isResponseOK = false;
317
    fetch(APIBaseURL + '/reports/combinedequipmentcarbon?' +
318
      'combinedequipmentid=' + selectedCombinedEquipment +
319
      '&periodtype=' + periodType +
320
      '&baseperiodstartdatetime=' + (basePeriodDateRange[0] != null ? moment(basePeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') : '') +
321
      '&baseperiodenddatetime=' + (basePeriodDateRange[1] != null ? moment(basePeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') : '') +
322
      '&reportingperiodstartdatetime=' + moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') +
323
      '&reportingperiodenddatetime=' + moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss'), {
324
      method: 'GET',
325
      headers: {
326
        "Content-type": "application/json",
327
        "User-UUID": getCookieValue('user_uuid'),
328
        "Token": getCookieValue('token')
329
      },
330
      body: null,
331
332
    }).then(response => {
333
      if (response.ok) {
334
        isResponseOK = true;
335
      };
336
      return response.json();
337
    }).then(json => {
338
      if (isResponseOK) {
339
        console.log(json)
340
341
        let cardSummaryList = []
342
        json['reporting_period']['names'].forEach((currentValue, index) => {
343
          let cardSummaryItem = {}
344
          cardSummaryItem['name'] = json['reporting_period']['names'][index];
345
          cardSummaryItem['unit'] = json['reporting_period']['units'][index];
346
          cardSummaryItem['subtotal'] = json['reporting_period']['subtotals'][index];
347
          cardSummaryItem['increment_rate'] = parseFloat(json['reporting_period']['increment_rates'][index] * 100).toFixed(2) + "%";
348
          cardSummaryList.push(cardSummaryItem);
349
        });
350
        let cardSummaryItem = {}
351
        cardSummaryItem['name'] = t('Total');
352
        cardSummaryItem['unit'] = json['reporting_period']['total_unit'];
353
        cardSummaryItem['subtotal'] = json['reporting_period']['total'];
354
        cardSummaryItem['increment_rate'] = parseFloat(json['reporting_period']['total_increment_rate'] * 100).toFixed(2) + "%";
355
        cardSummaryList.push(cardSummaryItem);
356
        setCardSummaryList(cardSummaryList);
357
358
        let timeOfUseArray = [];
359
        json['reporting_period']['energy_category_ids'].forEach((currentValue, index) => {
360
          if(currentValue === 1) {
361
            // energy_category_id 1 electricity
362
            let timeOfUseItem = {}
363
            timeOfUseItem['id'] = 1;
364
            timeOfUseItem['name'] =  t('Top-Peak');
365
            timeOfUseItem['value'] = json['reporting_period']['toppeaks'][index];
366
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
367
            timeOfUseArray.push(timeOfUseItem);
368
            
369
            timeOfUseItem = {}
370
            timeOfUseItem['id'] = 2;
371
            timeOfUseItem['name'] =  t('On-Peak');
372
            timeOfUseItem['value'] = json['reporting_period']['onpeaks'][index];
373
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
374
            timeOfUseArray.push(timeOfUseItem);
375
376
            timeOfUseItem = {}
377
            timeOfUseItem['id'] = 3;
378
            timeOfUseItem['name'] =  t('Mid-Peak');
379
            timeOfUseItem['value'] = json['reporting_period']['midpeaks'][index];
380
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
381
            timeOfUseArray.push(timeOfUseItem);
382
383
            timeOfUseItem = {}
384
            timeOfUseItem['id'] = 4;
385
            timeOfUseItem['name'] =  t('Off-Peak');
386
            timeOfUseItem['value'] = json['reporting_period']['offpeaks'][index];
387
            timeOfUseItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
388
            timeOfUseArray.push(timeOfUseItem);
389
          }
390
        });
391
        setTimeOfUseShareData(timeOfUseArray);
392
393
        let carbonDataArray = [];
394
        json['reporting_period']['names'].forEach((currentValue, index) => {
395
          let carbonDataItem = {}
396
          carbonDataItem['id'] = index;
397
          carbonDataItem['name'] = currentValue;
398
          carbonDataItem['value'] = json['reporting_period']['subtotals'][index];
399
          carbonDataItem['color'] = "#"+((1<<24)*Math.random()|0).toString(16);
400
          carbonDataArray.push(carbonDataItem);
401
        });
402
        setCarbonShareData(carbonDataArray);
403
404
        let timestamps = {}
405
        json['reporting_period']['timestamps'].forEach((currentValue, index) => {
406
          timestamps['a' + index] = currentValue;
407
        });
408
        setCombinedEquipmentLineChartLabels(timestamps);
409
410
        let values = {}
411
        json['reporting_period']['values'].forEach((currentValue, index) => {
412
          values['a' + index] = currentValue;
413
        });
414
        setCombinedEquipmentLineChartData(values);
415
        
416
        let names = Array();
417
        json['reporting_period']['names'].forEach((currentValue, index) => {
418
          let unit = json['reporting_period']['units'][index];
419
          names.push({ 'value': 'a' + index, 'label': currentValue + ' (' + unit + ')'});
420
        });
421
        setCombinedEquipmentLineChartOptions(names);
422
423
        timestamps = {}
424
        json['parameters']['timestamps'].forEach((currentValue, index) => {
425
          timestamps['a' + index] = currentValue;
426
        });
427
        setParameterLineChartLabels(timestamps);
428
429
        values = {}
430
        json['parameters']['values'].forEach((currentValue, index) => {
431
          values['a' + index] = currentValue;
432
        });
433
        setParameterLineChartData(values);
434
      
435
        names = Array();
436
        json['parameters']['names'].forEach((currentValue, index) => {
437
          if (currentValue.startsWith('TARIFF-')) {
438
            currentValue = t('Tariff') + currentValue.replace('TARIFF-', '-');
439
          }
440
          
441
          names.push({ 'value': 'a' + index, 'label': currentValue });
442
        });
443
        setParameterLineChartOptions(names);
444
445
        let detailed_value_list = [];
446
        if (json['reporting_period']['timestamps'].length > 0) {
447
          json['reporting_period']['timestamps'][0].forEach((currentTimestamp, timestampIndex) => {
448
            let detailed_value = {};
449
            detailed_value['id'] = timestampIndex;
450
            detailed_value['startdatetime'] = currentTimestamp;
451
            let total_current_timstamp = 0.0;
452
            json['reporting_period']['values'].forEach((currentValue, energyCategoryIndex) => {
453
              detailed_value['a' + energyCategoryIndex] = json['reporting_period']['values'][energyCategoryIndex][timestampIndex];
454
              total_current_timstamp += json['reporting_period']['values'][energyCategoryIndex][timestampIndex];
455
            });
456
            detailed_value['total'] = total_current_timstamp;
457
            detailed_value_list.push(detailed_value);
458
          });
459
        };
460
461
        let detailed_value = {};
462
        detailed_value['id'] = detailed_value_list.length;
463
        detailed_value['startdatetime'] = t('Subtotal');
464
        let total_of_subtotals = 0.0;
465
        json['reporting_period']['subtotals'].forEach((currentValue, index) => {
466
            detailed_value['a' + index] = currentValue;
467
            total_of_subtotals += currentValue
468
          });
469
        detailed_value['total'] = total_of_subtotals;
470
        detailed_value_list.push(detailed_value);
471
        setDetailedDataTableData(detailed_value_list);
472
        
473
        let detailed_column_list = [];
474
        detailed_column_list.push({
475
          dataField: 'startdatetime',
476
          text: t('Datetime'),
477
          sort: true
478
        });
479
        json['reporting_period']['names'].forEach((currentValue, index) => {
480
          let unit = json['reporting_period']['units'][index];
481
          detailed_column_list.push({
482
            dataField: 'a' + index,
483
            text: currentValue + ' (' + unit + ')',
484
            sort: true,
485
            formatter: function (decimalValue) {
486
              if (typeof decimalValue === 'number') {
487
                return decimalValue.toFixed(2);
488
              } else {
489
                return null;
490
              }
491
            }
492
          });
493
        });
494
        detailed_column_list.push({
495
          dataField: 'total',
496
          text: t('Total') + ' (' + json['reporting_period']['total_unit'] + ')',
497
          sort: true,
498
          formatter: function (decimalValue) {
499
            if (typeof decimalValue === 'number') {
500
              return decimalValue.toFixed(2);
501
            } else {
502
              return null;
503
            }
504
          }
505
        });
506
        setDetailedDataTableColumns(detailed_column_list);
507
        
508
        let associated_equipment_value_list = [];
509
        if (json['associated_equipment']['associated_equipment_names_array'].length > 0) {
510
          json['associated_equipment']['associated_equipment_names_array'][0].forEach((currentEquipmentName, equipmentIndex) => {
511
            let associated_equipment_value = {};
512
            associated_equipment_value['id'] = equipmentIndex;
513
            associated_equipment_value['name'] = currentEquipmentName;
514
            let total = 0.0;
515
            json['associated_equipment']['energy_category_names'].forEach((currentValue, energyCategoryIndex) => {
516
              associated_equipment_value['a' + energyCategoryIndex] = json['associated_equipment']['subtotals_array'][energyCategoryIndex][equipmentIndex];
517
              total += json['associated_equipment']['subtotals_array'][energyCategoryIndex][equipmentIndex]
518
            });
519
            associated_equipment_value['total'] = total;
520
            associated_equipment_value_list.push(associated_equipment_value);
521
          });
522
        };
523
524
        setAssociatedEquipmentTableData(associated_equipment_value_list);
525
526
        let associated_equipment_column_list = [];
527
        associated_equipment_column_list.push({
528
          dataField: 'name',
529
          text: t('Associated Equipment'),
530
          sort: true
531
        });
532
        json['associated_equipment']['energy_category_names'].forEach((currentValue, index) => {
533
          let unit = json['associated_equipment']['units'][index];
534
          associated_equipment_column_list.push({
535
            dataField: 'a' + index,
536
            text: currentValue + ' (' + unit + ')',
537
            sort: true,
538
            formatter: function (decimalValue) {
539
              if (typeof decimalValue === 'number') {
540
                return decimalValue.toFixed(2);
541
              } else {
542
                return null;
543
              }
544
            }
545
          });
546
        });
547
        associated_equipment_column_list.push({
548
          dataField: 'total',
549
          text: t('Total') + ' (' + json['associated_equipment']['total_unit'] + ')',
550
          sort: true,
551
          formatter: function (decimalValue) {
552
            if (typeof decimalValue === 'number') {
553
              return decimalValue.toFixed(2);
554
            } else {
555
              return null;
556
            }
557
          }
558
        });
559
560
        setAssociatedEquipmentTableColumns(associated_equipment_column_list);
561
        
562
        setExcelBytesBase64(json['excel_bytes_base64']);
563
564
        // enable submit button
565
        setSubmitButtonDisabled(false);
566
        // hide spinner
567
        setSpinnerHidden(true);
568
        // show export button
569
        setExportButtonHidden(false);
570
      } else {
571
        toast.error(json.description)
572
      }
573
    }).catch(err => {
574
      console.log(err);
575
    });
576
  };
577
578
  const handleExport = e => {
579
    e.preventDefault();
580
    const mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
581
    const fileName = 'combinedequipmentcarbon.xlsx'
582
    var fileUrl = "data:" + mimeType + ";base64," + excelBytesBase64;
583
    fetch(fileUrl)
584
        .then(response => response.blob())
585
        .then(blob => {
586
            var link = window.document.createElement("a");
587
            link.href = window.URL.createObjectURL(blob, { type: mimeType });
588
            link.download = fileName;
589
            document.body.appendChild(link);
590
            link.click();
591
            document.body.removeChild(link);
592
        });
593
  };
594
595
  return (
596
    <Fragment>
597
      <div>
598
        <Breadcrumb>
599
          <BreadcrumbItem>{t('Combined Equipment Data')}</BreadcrumbItem><BreadcrumbItem active>{t('Carbon')}</BreadcrumbItem>
600
        </Breadcrumb>
601
      </div>
602
      <Card className="bg-light mb-3">
603
        <CardBody className="p-3">
604
          <Form onSubmit={handleSubmit}>
605
            <Row form>
606
              <Col xs={6} sm={3}>
607
                <FormGroup className="form-group">
608
                  <Label className={labelClasses} for="space">
609
                    {t('Space')}
610
                  </Label>
611
                  <br />
612
                  <Cascader options={cascaderOptions}
613
                    onChange={onSpaceCascaderChange}
614
                    changeOnSelect
615
                    expandTrigger="hover">
616
                    <Input value={selectedSpaceName || ''} readOnly />
617
                  </Cascader>
618
                </FormGroup>
619
              </Col>
620
              <Col xs="auto">
621
                <FormGroup>
622
                  <Label className={labelClasses} for="combinedEquipmentSelect">
623
                    {t('Combined Equipment')}
624
                  </Label>
625
                  <CustomInput type="select" id="combinedEquipmentSelect" name="combinedEquipmentSelect" onChange={({ target }) => setSelectedCombinedEquipment(target.value)}
626
                  >
627
                    {combinedEquipmentList.map((combinedEquipment, index) => (
628
                      <option value={combinedEquipment.value} key={combinedEquipment.value}>
629
                        {combinedEquipment.label}
630
                      </option>
631
                    ))}
632
                  </CustomInput>
633
                </FormGroup>
634
              </Col>
635
              <Col xs="auto">
636
                <FormGroup>
637
                  <Label className={labelClasses} for="comparisonType">
638
                    {t('Comparison Types')}
639
                  </Label>
640
                  <CustomInput type="select" id="comparisonType" name="comparisonType"
641
                    defaultValue="month-on-month"
642
                    onChange={onComparisonTypeChange}
643
                  >
644
                    {comparisonTypeOptions.map((comparisonType, index) => (
645
                      <option value={comparisonType.value} key={comparisonType.value} >
646
                        {t(comparisonType.label)}
647
                      </option>
648
                    ))}
649
                  </CustomInput>
650
                </FormGroup>
651
              </Col>
652
              <Col xs="auto">
653
                <FormGroup>
654
                  <Label className={labelClasses} for="periodType">
655
                    {t('Period Types')}
656
                  </Label>
657
                  <CustomInput type="select" id="periodType" name="periodType" defaultValue="daily" onChange={({ target }) => setPeriodType(target.value)}
658
                  >
659
                    {periodTypeOptions.map((periodType, index) => (
660
                      <option value={periodType.value} key={periodType.value} >
661
                        {t(periodType.label)}
662
                      </option>
663
                    ))}
664
                  </CustomInput>
665
                </FormGroup>
666
              </Col>
667
              <Col xs={6} sm={3}>
668
                <FormGroup className="form-group">
669
                  <Label className={labelClasses} for="basePeriodDateRangePicker">{t('Base Period')}{t('(Optional)')}</Label>
670
                  <DateRangePicker 
671
                    id='basePeriodDateRangePicker'
672
                    readOnly={basePeriodDateRangePickerDisabled}
673
                    format="yyyy-MM-dd HH:mm:ss"
674
                    value={basePeriodDateRange}
675
                    onChange={onBasePeriodChange}
676
                    size="md"
677
                    style={dateRangePickerStyle}
678
                    onClean={onBasePeriodClean}
679
                    locale={dateRangePickerLocale}
680
                    placeholder={t("Select Date Range")}
681
                   />
682
                </FormGroup>
683
              </Col>
684
              <Col xs={6} sm={3}>
685
                <FormGroup className="form-group">
686
                  <Label className={labelClasses} for="reportingPeriodDateRangePicker">{t('Reporting Period')}</Label>
687
                  <br/>
688
                  <DateRangePicker
689
                    id='reportingPeriodDateRangePicker'
690
                    format="yyyy-MM-dd HH:mm:ss"
691
                    value={reportingPeriodDateRange}
692
                    onChange={onReportingPeriodChange}
693
                    size="md"
694
                    style={dateRangePickerStyle}
695
                    onClean={onReportingPeriodClean}
696
                    locale={dateRangePickerLocale}
697
                    placeholder={t("Select Date Range")}
698
                  />
699
                </FormGroup>
700
              </Col>
701
              <Col xs="auto">
702
                <FormGroup>
703
                  <br></br>
704
                  <ButtonGroup id="submit">
705
                    <Button color="success" disabled={submitButtonDisabled} >{t('Submit')}</Button>
706
                  </ButtonGroup>
707
                </FormGroup>
708
              </Col>
709
              <Col xs="auto">
710
                <FormGroup>
711
                  <br></br>
712
                  <Spinner color="primary" hidden={spinnerHidden}  />
713
                </FormGroup>
714
              </Col>
715
              <Col xs="auto">
716
                  <br></br>
717
                  <ButtonIcon icon="external-link-alt" transform="shrink-3 down-2" color="falcon-default" 
718
                  hidden={exportButtonHidden}
719
                  onClick={handleExport} >
720
                    {t('Export')}
721
                  </ButtonIcon>
722
              </Col>
723
            </Row>
724
          </Form>
725
        </CardBody>
726
      </Card>
727
      <div className="card-deck">
728
        {cardSummaryList.map(cardSummaryItem => (
729
          <CardSummary key={cardSummaryItem['name']}
730
            rate={cardSummaryItem['increment_rate']}
731
            title={t('Reporting Period Carbon Dioxide Emissions CATEGORY UNIT', { 'CATEGORY': cardSummaryItem['name'], 'UNIT': '(' + cardSummaryItem['unit'] + ')' })}
732
            color="success" >
733
            {cardSummaryItem['subtotal'] && <CountUp end={cardSummaryItem['subtotal']} duration={2} prefix="" separator="," decimal="." decimals={2} />}
734
          </CardSummary>
735
        ))}
736
      </div>
737
      <Row noGutters>
738
        <Col className="mb-3 pr-lg-2 mb-3">
739
          <SharePie data={timeOfUseShareData} title={t('Electricity Carbon Dioxide Emissions by Time-Of-Use')} />
740
        </Col>
741
        <Col className="mb-3 pr-lg-2 mb-3">
742
          <SharePie data={carbonShareData} title={t('Carbon Dioxide Emissions by Energy Category')} />
743
        </Col>
744
      </Row>
745
      <LineChart reportingTitle={t('Reporting Period Carbon Dioxide Emissions CATEGORY VALUE UNIT', { 'CATEGORY': null, 'VALUE': null, 'UNIT': null })}
746
        baseTitle=''
747
        labels={combinedEquipmentLineChartLabels}
748
        data={combinedEquipmentLineChartData}
749
        options={combinedEquipmentLineChartOptions}>
750
      </LineChart>
751
752
      <LineChart reportingTitle={t('Related Parameters')}
753
        baseTitle=''
754
        labels={parameterLineChartLabels}
755
        data={parameterLineChartData}
756
        options={parameterLineChartOptions}>
757
      </LineChart>
758
759
      <br />
760
      <DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
761
      </DetailedDataTable>
762
      <br />
763
      <AssociatedEquipmentTable data={associatedEquipmentTableData} title={t('Associated Equipment Data')} columns={associatedEquipmentTableColumns}>
764
      </AssociatedEquipmentTable>
765
766
    </Fragment>
767
  );
768
};
769
770
export default withTranslation()(withRedirect(CombinedEquipmentCarbon));
771