Passed
Push — master ( b2a2f7...07fcd7 )
by
unknown
13:12
created

myems-web/src/components/MyEMS/Tenant/TenantComparison.js   B

Complexity

Total Complexity 42
Complexity/F 0

Size

Lines of Code 967
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 42
eloc 826
dl 0
loc 967
rs 8.814
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/Tenant/TenantComparison.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 { getCookieValue, createCookie, checkEmpty } from '../../../helpers/utils';
24
import withRedirect from '../../../hoc/withRedirect';
25
import { withTranslation } from 'react-i18next';
26
import { toast } from 'react-toastify';
27
import ButtonIcon from '../../common/ButtonIcon';
28
import { APIBaseURL, settings } from '../../../config';
29
import { periodTypeOptions } from '../common/PeriodTypeOptions';
30
import MultiTrendChart from '../common/MultiTrendChart';
31
import DateRangePickerWrapper from '../common/DateRangePickerWrapper';
32
import { endOfDay } from 'date-fns';
33
import AppContext from '../../../context/Context';
34
import blankPage from '../../../assets/img/generic/blank-page.png';
35
36
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
37
38
const TenantComparison = ({ setRedirect, setRedirectUrl, t }) => {
39
  let current_moment = moment();
40
  useEffect(() => {
41
    let is_logged_in = getCookieValue('is_logged_in');
42
    let user_name = getCookieValue('user_name');
43
    let user_display_name = getCookieValue('user_display_name');
44
    let user_uuid = getCookieValue('user_uuid');
45
    let token = getCookieValue('token');
46
    if (checkEmpty(is_logged_in) || checkEmpty(token) || checkEmpty(user_uuid) || !is_logged_in) {
47
      setRedirectUrl(`/authentication/basic/login`);
48
      setRedirect(true);
49
    } else {
50
      //update expires time of cookies
51
      createCookie('is_logged_in', true, settings.cookieExpireTime);
52
      createCookie('user_name', user_name, settings.cookieExpireTime);
53
      createCookie('user_display_name', user_display_name, settings.cookieExpireTime);
54
      createCookie('user_uuid', user_uuid, settings.cookieExpireTime);
55
      createCookie('token', token, settings.cookieExpireTime);
56
    }
57
  });
58
59
  useEffect(() => {
60
    let timer = setInterval(() => {
61
      let is_logged_in = getCookieValue('is_logged_in');
62
      if (is_logged_in === null || !is_logged_in) {
63
        setRedirectUrl(`/authentication/basic/login`);
64
        setRedirect(true);
65
      }
66
    }, 1000);
67
    return () => clearInterval(timer);
68
  }, [setRedirect, setRedirectUrl]);
69
70
  // State
71
  //Query Form
72
  const [selectedSpaceName1, setSelectedSpaceName1] = useState(undefined);
73
  const [selectedSpaceName2, setSelectedSpaceName2] = useState(undefined);
74
  const [tenantList1, setTenantList1] = useState([]);
75
  const [tenantList2, setTenantList2] = useState([]);
76
  const [filteredTenantList1, setFilteredTenantList1] = useState([]);
77
  const [filteredTenantList2, setFilteredTenantList2] = useState([]);
78
  const [selectedTenant1, setSelectedTenant1] = useState(undefined);
79
  const [selectedTenant2, setSelectedTenant2] = useState(undefined);
80
  const [energyCategoryList, setEnergyCategoryList] = useState([]);
81
  const [selectedEnergyCategory, setSelectedEnergyCategory] = useState(undefined);
82
  const [periodType, setPeriodType] = useState('daily');
83
  const [cascaderOptions, setCascaderOptions] = useState(undefined);
84
  const [reportingPeriodDateRange, setReportingPeriodDateRange] = useState([
85
    current_moment
86
      .clone()
87
      .startOf('month')
88
      .toDate(),
89
    current_moment.toDate()
90
  ]);
91
  const dateRangePickerLocale = {
92
    sunday: t('sunday'),
93
    monday: t('monday'),
94
    tuesday: t('tuesday'),
95
    wednesday: t('wednesday'),
96
    thursday: t('thursday'),
97
    friday: t('friday'),
98
    saturday: t('saturday'),
99
    ok: t('ok'),
100
    today: t('today'),
101
    yesterday: t('yesterday'),
102
    hours: t('hours'),
103
    minutes: t('minutes'),
104
    seconds: t('seconds'),
105
    last7Days: t('last7Days'),
106
    formattedMonthPattern: 'yyyy-MM-dd'
107
  };
108
  const dateRangePickerStyle = { display: 'block', zIndex: 10 };
109
  const { language } = useContext(AppContext);
110
111
  // buttons
112
  const [submitButtonDisabled, setSubmitButtonDisabled] = useState(true);
113
  const [spinnerHidden, setSpinnerHidden] = useState(true);
114
  const [exportButtonHidden, setExportButtonHidden] = useState(true);
115
  const [resultDataHidden, setResultDataHidden] = useState(true);
116
  //Results
117
  const [tenant1, setTenant1] = useState({
118
    id: undefined,
119
    name: undefined
120
  });
121
  const [tenant2, setTenant2] = useState({
122
    id: undefined,
123
    name: undefined
124
  });
125
  const [energyCategory, setEnergyCategory] = useState({
126
    id: undefined,
127
    name: undefined,
128
    unit_of_measure: undefined
129
  });
130
  const [reportingPeriodEnergyConsumptionInCategory1, setReportingPeriodEnergyConsumptionInCategory1] = useState(0);
131
  const [reportingPeriodEnergyConsumptionInCategory2, setReportingPeriodEnergyConsumptionInCategory2] = useState(0);
132
  const [reportingPeriodEnergyConsumptionInDifference, setReportingPeriodEnergyConsumptionInDifference] = useState(0);
133
  const [tenantLineChartData1, setTenantLineChartData1] = useState({ a0: [] });
134
  const [tenantLineChartData2, setTenantLineChartData2] = useState({ a0: [] });
135
  const [tenantLineChartLabels1, setTenantLineChartLabels1] = useState({ a0: [] });
136
  const [tenantLineChartLabels2, setTenantLineChartLabels2] = useState({ a0: [] });
137
  const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([
138
    { dataField: 'startdatetime', text: t('Datetime'), sort: true }
139
  ]);
140
  const [detailedDataTableData, setDetailedDataTableData] = useState([]);
141
  const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
142
143
  useEffect(() => {
144
    let isResponseOK = false;
145
    fetch(APIBaseURL + '/spaces/tree', {
146
      method: 'GET',
147
      headers: {
148
        'Content-type': 'application/json',
149
        'User-UUID': getCookieValue('user_uuid'),
150
        Token: getCookieValue('token')
151
      },
152
      body: null
153
    })
154
      .then(response => {
155
        if (response.ok) {
156
          isResponseOK = true;
157
        }
158
        return response.json();
159
      })
160
      .then(json => {
161
        if (isResponseOK) {
162
          // rename keys
163
          json = JSON.parse(
164
            JSON.stringify([json])
165
              .split('"id":')
166
              .join('"value":')
167
              .split('"name":')
168
              .join('"label":')
169
          );
170
          setCascaderOptions(json);
171
          setSelectedSpaceName1([json[0]].map(o => o.label));
172
          setSelectedSpaceName2([json[0]].map(o => o.label));
173
          let selectedSpaceID = [json[0]].map(o => o.value);
174
          // get Tenants by root Space ID
175
          let isResponseOK = false;
176
          fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/tenants', {
177
            method: 'GET',
178
            headers: {
179
              'Content-type': 'application/json',
180
              'User-UUID': getCookieValue('user_uuid'),
181
              Token: getCookieValue('token')
182
            },
183
            body: null
184
          })
185
            .then(response => {
186
              if (response.ok) {
187
                isResponseOK = true;
188
              }
189
              return response.json();
190
            })
191
            .then(json => {
192
              if (isResponseOK) {
193
                json = JSON.parse(
194
                  JSON.stringify([json])
195
                    .split('"id":')
196
                    .join('"value":')
197
                    .split('"name":')
198
                    .join('"label":')
199
                );
200
201
                setTenantList1(json[0]);
202
                setTenantList2(json[0]);
203
                setFilteredTenantList1(json[0]);
204
                setFilteredTenantList2(json[0]);
205
                if (json[0].length > 0) {
206
                  setSelectedTenant1(json[0][0].value);
207
                  setSelectedTenant2(json[0][0].value);
208
                } else {
209
                  setSelectedTenant1(undefined);
210
                  setSelectedTenant2(undefined);
211
                }
212
              } else {
213
                toast.error(t(json.description));
214
              }
215
            })
216
            .catch(err => {
217
              console.log(err);
218
            });
219
          // end of get Tenants by root Space ID
220
        } else {
221
          toast.error(t(json.description));
222
        }
223
      })
224
      .catch(err => {
225
        console.log(err);
226
      });
227
228
    // Load energy categories
229
    fetch(APIBaseURL + '/energycategories', {
230
      method: 'GET',
231
      headers: {
232
        'Content-type': 'application/json',
233
        'User-UUID': getCookieValue('user_uuid'),
234
        Token: getCookieValue('token')
235
      },
236
      body: null
237
    })
238
      .then(response => {
239
        if (response.ok) {
240
          isResponseOK = true;
241
        }
242
        return response.json();
243
      })
244
      .then(json => {
245
        if (isResponseOK) {
246
          json = JSON.parse(
247
            JSON.stringify([json])
248
              .split('"id":')
249
              .join('"value":')
250
              .split('"name":')
251
              .join('"label":')
252
          );
253
          setEnergyCategoryList(json[0]);
254
          if (json[0].length > 0) {
255
            setSelectedEnergyCategory(json[0][0].value);
256
            // enable submit button
257
            setSubmitButtonDisabled(false);
258
          } else {
259
            setSelectedEnergyCategory(undefined);
260
            // disable submit button
261
            setSubmitButtonDisabled(true);
262
          }
263
        } else {
264
          toast.error(t(json.description));
265
        }
266
      })
267
      .catch(err => {
268
        console.log(err);
269
      });
270
  }, [t]);
271
272
  const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
273
274
  let onSpaceCascaderChange1 = (value, selectedOptions) => {
275
    setSelectedSpaceName1(selectedOptions.map(o => o.label).join('/'));
276
    let selectedSpaceID = value[value.length - 1];
277
    let isResponseOK = false;
278
    fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/tenants', {
279
      method: 'GET',
280
      headers: {
281
        'Content-type': 'application/json',
282
        'User-UUID': getCookieValue('user_uuid'),
283
        Token: getCookieValue('token')
284
      },
285
      body: null
286
    })
287
      .then(response => {
288
        if (response.ok) {
289
          isResponseOK = true;
290
        }
291
        return response.json();
292
      })
293
      .then(json => {
294
        if (isResponseOK) {
295
          json = JSON.parse(
296
            JSON.stringify([json])
297
              .split('"id":')
298
              .join('"value":')
299
              .split('"name":')
300
              .join('"label":')
301
          );
302
303
          setTenantList1(json[0]);
304
          setFilteredTenantList1(json[0]);
305
          if (json[0].length > 0) {
306
            setSelectedTenant1(json[0][0].value);
307
            // enable submit button
308
            setSubmitButtonDisabled(false);
309
          } else {
310
            setSelectedTenant1(undefined);
311
            // disable submit button
312
            setSubmitButtonDisabled(true);
313
          }
314
        } else {
315
          toast.error(t(json.description));
316
        }
317
      })
318
      .catch(err => {
319
        console.log(err);
320
      });
321
  };
322
323
  let onSpaceCascaderChange2 = (value, selectedOptions) => {
324
    setSelectedSpaceName2(selectedOptions.map(o => o.label).join('/'));
325
    let selectedSpaceID = value[value.length - 1];
326
    let isResponseOK = false;
327
    fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/tenants', {
328
      method: 'GET',
329
      headers: {
330
        'Content-type': 'application/json',
331
        'User-UUID': getCookieValue('user_uuid'),
332
        Token: getCookieValue('token')
333
      },
334
      body: null
335
    })
336
      .then(response => {
337
        if (response.ok) {
338
          isResponseOK = true;
339
        }
340
        return response.json();
341
      })
342
      .then(json => {
343
        if (isResponseOK) {
344
          json = JSON.parse(
345
            JSON.stringify([json])
346
              .split('"id":')
347
              .join('"value":')
348
              .split('"name":')
349
              .join('"label":')
350
          );
351
352
          setTenantList2(json[0]);
353
          setFilteredTenantList2(json[0]);
354
          if (json[0].length > 0) {
355
            setSelectedTenant2(json[0][0].value);
356
            // enable submit button
357
            setSubmitButtonDisabled(false);
358
          } else {
359
            setSelectedTenant2(undefined);
360
            // disable submit button
361
            setSubmitButtonDisabled(true);
362
          }
363
        } else {
364
          toast.error(t(json.description));
365
        }
366
      })
367
      .catch(err => {
368
        console.log(err);
369
      });
370
  };
371
372
  const onSearchTenant1 = ({ target }) => {
373
    const keyword = target.value.toLowerCase();
374
    const filteredResult = tenantList1.filter(tenant => tenant.label.toLowerCase().includes(keyword));
375
    setFilteredTenantList1(keyword.length ? filteredResult : tenantList1);
376
    if (filteredResult.length > 0) {
377
      setSelectedTenant1(filteredResult[0].value);
378
      // enable submit button
379
      setSubmitButtonDisabled(false);
380
    } else {
381
      setSelectedTenant1(undefined);
382
      // disable submit button
383
      setSubmitButtonDisabled(true);
384
    }
385
    let customInputTarget = document.getElementById('tenantSelect1');
386
    customInputTarget.value = filteredResult[0].value;
387
  };
388
389
  const onSearchTenant2 = ({ target }) => {
390
    const keyword = target.value.toLowerCase();
391
    const filteredResult = tenantList2.filter(tenant => tenant.label.toLowerCase().includes(keyword));
392
    setFilteredTenantList2(keyword.length ? filteredResult : tenantList2);
393
    if (filteredResult.length > 0) {
394
      setSelectedTenant2(filteredResult[0].value);
395
      // enable submit button
396
      setSubmitButtonDisabled(false);
397
    } else {
398
      setSelectedTenant2(undefined);
399
      // disable submit button
400
      setSubmitButtonDisabled(true);
401
    }
402
    let customInputTarget = document.getElementById('tenantSelect2');
403
    customInputTarget.value = filteredResult[0].value;
404
  };
405
406
  // Callback fired when value changed
407
  let onReportingPeriodChange = DateRange => {
408
    if (DateRange == null) {
409
      setReportingPeriodDateRange([null, null]);
410
    } else {
411
      if (moment(DateRange[1]).format('HH:mm:ss') === '00:00:00') {
412
        // if the user did not change time value, set the default time to the end of day
413
        DateRange[1] = endOfDay(DateRange[1]);
414
      }
415
      setReportingPeriodDateRange([DateRange[0], DateRange[1]]);
416
      const dateDifferenceInSeconds = moment(DateRange[1]).valueOf() / 1000 - moment(DateRange[0]).valueOf() / 1000;
417
      if (periodType === 'hourly') {
418
        if (dateDifferenceInSeconds > 3 * 365 * 24 * 60 * 60) {
419
          // more than 3 years
420
          setPeriodType('yearly');
421
          document.getElementById('periodType').value = 'yearly';
422
        } else if (dateDifferenceInSeconds > 6 * 30 * 24 * 60 * 60) {
423
          // more than 6 months
424
          setPeriodType('monthly');
425
          document.getElementById('periodType').value = 'monthly';
426
        } else if (dateDifferenceInSeconds > 30 * 24 * 60 * 60) {
427
          // more than 30 days
428
          setPeriodType('daily');
429
          document.getElementById('periodType').value = 'daily';
430
        }
431
      } else if (periodType === 'daily') {
432
        if (dateDifferenceInSeconds >= 3 * 365 * 24 * 60 * 60) {
433
          // more than 3 years
434
          setPeriodType('yearly');
435
          document.getElementById('periodType').value = 'yearly';
436
        } else if (dateDifferenceInSeconds >= 6 * 30 * 24 * 60 * 60) {
437
          // more than 6 months
438
          setPeriodType('monthly');
439
          document.getElementById('periodType').value = 'monthly';
440
        }
441
      } else if (periodType === 'monthly') {
442
        if (dateDifferenceInSeconds >= 3 * 365 * 24 * 60 * 60) {
443
          // more than 3 years
444
          setPeriodType('yearly');
445
          document.getElementById('periodType').value = 'yearly';
446
        }
447
      }
448
    }
449
  };
450
451
  // Callback fired when value clean
452
  let onReportingPeriodClean = event => {
453
    setReportingPeriodDateRange([null, null]);
454
  };
455
456
  // Handler
457
  const handleSubmit = e => {
458
    e.preventDefault();
459
    // disable submit button
460
    setSubmitButtonDisabled(true);
461
    // show spinner
462
    setSpinnerHidden(false);
463
    // hide export button
464
    setExportButtonHidden(true);
465
    // hide result data
466
    setResultDataHidden(true);
467
468
    // Reinitialize tables
469
    setDetailedDataTableData([]);
470
471
    let isResponseOK = false;
472
    fetch(
473
      APIBaseURL +
474
        '/reports/tenantcomparison?' +
475
        'tenantid1=' +
476
        selectedTenant1 +
477
        '&tenantid2=' +
478
        selectedTenant2 +
479
        '&energycategoryid=' +
480
        selectedEnergyCategory +
481
        '&periodtype=' +
482
        periodType +
483
        '&reportingperiodstartdatetime=' +
484
        moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') +
485
        '&reportingperiodenddatetime=' +
486
        moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss') +
487
        '&language=' +
488
        language,
489
      {
490
        method: 'GET',
491
        headers: {
492
          'Content-type': 'application/json',
493
          'User-UUID': getCookieValue('user_uuid'),
494
          Token: getCookieValue('token')
495
        },
496
        body: null
497
      }
498
    )
499
      .then(response => {
500
        if (response.ok) {
501
          isResponseOK = true;
502
        }
503
        return response.json();
504
      })
505
      .then(json => {
506
        if (isResponseOK) {
507
          setTenant1({
508
            id: json['tenant1']['id'],
509
            name: json['tenant1']['name']
510
          });
511
          setTenant2({
512
            id: json['tenant2']['id'],
513
            name: json['tenant2']['name']
514
          });
515
          setEnergyCategory({
516
            id: json['energy_category']['id'],
517
            name: json['energy_category']['name'],
518
            unit_of_measure: json['energy_category']['unit_of_measure']
519
          });
520
          setReportingPeriodEnergyConsumptionInCategory1(json['reporting_period1']['total_in_category']);
521
          setReportingPeriodEnergyConsumptionInCategory2(json['reporting_period2']['total_in_category']);
522
          setReportingPeriodEnergyConsumptionInDifference(json['diff']['total_in_category']);
523
524
525
          let timestamps1 = {};
526
          timestamps1['a0'] = json['reporting_period1']['timestamps'];
527
          setTenantLineChartLabels1(timestamps1);
528
529
          let timestamps2 = {};
530
          timestamps2['a0'] = json['reporting_period2']['timestamps'];
531
          setTenantLineChartLabels2(timestamps2);
532
533
          let values1 = { a0: [] };
534
          json['reporting_period1']['values'].forEach((currentValue, index) => {
535
            values1['a0'][index] = currentValue === null ? null : currentValue.toFixed(2);
536
          });
537
          setTenantLineChartData1(values1);
538
539
          let values2 = { a0: [] };
540
          json['reporting_period2']['values'].forEach((currentValue, index) => {
541
            values2['a0'][index] = currentValue === null ? null : currentValue.toFixed(2);
542
          });
543
          setTenantLineChartData2(values2);
544
545
          setDetailedDataTableColumns([
546
            {
547
              dataField: 'startdatetime',
548
              text: t('Datetime'),
549
              sort: true
550
            },
551
            {
552
              dataField: 'a0',
553
              text:
554
                json['tenant1']['name'] +
555
                ' ' +
556
                json['energy_category']['name'] +
557
                ' (' +
558
                json['energy_category']['unit_of_measure'] +
559
                ')',
560
              sort: true,
561
              formatter: function(decimalValue) {
562
                if (typeof decimalValue === 'number') {
563
                  return decimalValue.toFixed(2);
564
                } else {
565
                  return null;
566
                }
567
              }
568
            },
569
            {
570
              dataField: 'a1',
571
              text:
572
                json['tenant2']['name'] +
573
                ' ' +
574
                json['energy_category']['name'] +
575
                ' (' +
576
                json['energy_category']['unit_of_measure'] +
577
                ')',
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
              dataField: 'a2',
589
              text: t('Reporting Period Difference CATEGORY UNIT', {
590
                CATEGORY: json['energy_category']['name'],
591
                UNIT: '(' + json['energy_category']['unit_of_measure'] + ')'
592
              }),
593
              sort: true,
594
              formatter: function(decimalValue) {
595
                if (typeof decimalValue === 'number') {
596
                  return decimalValue.toFixed(2);
597
                } else {
598
                  return null;
599
                }
600
              }
601
            }
602
          ]);
603
604
          let detailed_value_list = [];
605
          json['reporting_period1']['timestamps'].forEach((currentTimestamp, timestampIndex) => {
606
            let detailed_value = {};
607
            detailed_value['id'] = timestampIndex;
608
            detailed_value['startdatetime'] = currentTimestamp;
609
            detailed_value['a0'] = json['reporting_period1']['values'][timestampIndex];
610
            detailed_value['a1'] = json['reporting_period2']['values'][timestampIndex];
611
            detailed_value['a2'] = json['diff']['values'][timestampIndex];
612
            detailed_value_list.push(detailed_value);
613
          });
614
615
          let detailed_value = {};
616
          detailed_value['id'] = detailed_value_list.length;
617
          detailed_value['startdatetime'] = t('Total');
618
          detailed_value['a0'] = json['reporting_period1']['total_in_category'];
619
          detailed_value['a1'] = json['reporting_period2']['total_in_category'];
620
          detailed_value['a2'] = json['diff']['total_in_category'];
621
          detailed_value_list.push(detailed_value);
622
          setTimeout(() => {
623
            setDetailedDataTableData(detailed_value_list);
624
          }, 0);
625
626
          setExcelBytesBase64(json['excel_bytes_base64']);
627
628
          // enable submit button
629
          setSubmitButtonDisabled(false);
630
          // hide spinner
631
          setSpinnerHidden(true);
632
          // show export button
633
          setExportButtonHidden(false);
634
          // show result data
635
          setResultDataHidden(false);
636
        } else {
637
          toast.error(t(json.description));
638
          setSpinnerHidden(true);
639
          setSubmitButtonDisabled(false);
640
        }
641
      })
642
      .catch(err => {
643
        console.log(err);
644
      });
645
  };
646
647
  const handleExport = e => {
648
    e.preventDefault();
649
    const mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
650
    const fileName = 'tenantcomparison.xlsx';
651
    var fileUrl = 'data:' + mimeType + ';base64,' + excelBytesBase64;
652
    fetch(fileUrl)
653
      .then(response => response.blob())
654
      .then(blob => {
655
        var link = window.document.createElement('a');
656
        link.href = window.URL.createObjectURL(blob, { type: mimeType });
657
        link.download = fileName;
658
        document.body.appendChild(link);
659
        link.click();
660
        document.body.removeChild(link);
661
      });
662
  };
663
664
  return (
665
    <Fragment>
666
      <div>
667
        <Breadcrumb>
668
          <BreadcrumbItem>{t('Tenant Data')}</BreadcrumbItem>
669
          <BreadcrumbItem active>{t('Tenant Comparison')}</BreadcrumbItem>
670
        </Breadcrumb>
671
      </div>
672
      <Card className="bg-light mb-3">
673
        <CardBody className="p-3">
674
          <Form onSubmit={handleSubmit}>
675
            <Row form>
676
              <Col xs={6} sm={3}>
677
                <FormGroup className="form-group">
678
                  <Label className={labelClasses} for="space">
679
                    {t('Space')}1
680
                  </Label>
681
                  <br />
682
                  <Cascader
683
                    options={cascaderOptions}
684
                    onChange={onSpaceCascaderChange1}
685
                    changeOnSelect
686
                    expandTrigger="hover"
687
                  >
688
                    <Input bsSize="sm" value={selectedSpaceName1 || ''} readOnly />
689
                  </Cascader>
690
                </FormGroup>
691
              </Col>
692
              <Col xs="auto">
693
                <FormGroup>
694
                  <Label className={labelClasses} for="tenantSelect1">
695
                    {t('Tenant')}1
696
                  </Label>
697
698
                  <Form inline>
699
                    <Input placeholder={t('Search')} bsSize="sm" onChange={onSearchTenant1} />
700
                    <CustomInput
701
                      type="select"
702
                      id="tenantSelect1"
703
                      name="tenantSelect1"
704
                      bsSize="sm"
705
                      onChange={({ target }) => setSelectedTenant1(target.value)}
706
                    >
707
                      {filteredTenantList1.map((tenant, index) => (
708
                        <option value={tenant.value} key={tenant.value}>
709
                          {tenant.label}
710
                        </option>
711
                      ))}
712
                    </CustomInput>
713
                  </Form>
714
                </FormGroup>
715
              </Col>
716
            </Row>
717
            <Row form>
718
              <Col xs={6} sm={3}>
719
                <FormGroup className="form-group">
720
                  <Label className={labelClasses} for="space">
721
                    {t('Space')}2
722
                  </Label>
723
                  <br />
724
                  <Cascader
725
                    options={cascaderOptions}
726
                    onChange={onSpaceCascaderChange2}
727
                    changeOnSelect
728
                    expandTrigger="hover"
729
                  >
730
                    <Input value={selectedSpaceName2 || ''} readOnly />
731
                  </Cascader>
732
                </FormGroup>
733
              </Col>
734
              <Col xs="auto">
735
                <FormGroup>
736
                  <Label className={labelClasses} for="tenantSelect2">
737
                    {t('Tenant')}2
738
                  </Label>
739
740
                  <Form inline>
741
                    <Input placeholder={t('Search')} bsSize="sm" onChange={onSearchTenant2} />
742
                    <CustomInput
743
                      type="select"
744
                      id="tenantSelect2"
745
                      name="tenantSelect2"
746
                      bsSize="sm"
747
                      onChange={({ target }) => setSelectedTenant2(target.value)}
748
                    >
749
                      {filteredTenantList2.map((tenant, index) => (
750
                        <option value={tenant.value} key={tenant.value}>
751
                          {tenant.label}
752
                        </option>
753
                      ))}
754
                    </CustomInput>
755
                  </Form>
756
                </FormGroup>
757
              </Col>
758
            </Row>
759
            <Row>
760
              <Col xs="auto">
761
                <FormGroup>
762
                  <Label className={labelClasses} for="energyCategorySelect">
763
                    {t('Energy Category')}
764
                  </Label>
765
                  <CustomInput
766
                    type="select"
767
                    id="energyCategorySelect"
768
                    name="energyCategorySelect"
769
                    bsSize="sm"
770
                    onChange={({ target }) => setSelectedEnergyCategory(target.value)}
771
                  >
772
                    {energyCategoryList.map((energyCategory, index) => (
773
                      <option value={energyCategory.value} key={energyCategory.value}>
774
                        {energyCategory.label}
775
                      </option>
776
                    ))}
777
                  </CustomInput>
778
                </FormGroup>
779
              </Col>
780
              <Col xs="auto">
781
                <FormGroup>
782
                  <Label className={labelClasses} for="periodType">
783
                    {t('Period Types')}
784
                  </Label>
785
                  <CustomInput
786
                    type="select"
787
                    id="periodType"
788
                    name="periodType"
789
                    bsSize="sm"
790
                    defaultValue="daily"
791
                    onChange={({ target }) => setPeriodType(target.value)}
792
                  >
793
                    {periodTypeOptions.map((periodType, index) => (
794
                      <option value={periodType.value} key={periodType.value}>
795
                        {t(periodType.label)}
796
                      </option>
797
                    ))}
798
                  </CustomInput>
799
                </FormGroup>
800
              </Col>
801
802
              <Col xs={6} sm={3}>
803
                <FormGroup className="form-group">
804
                  <Label className={labelClasses} for="reportingPeriodDateRangePicker">
805
                    {t('Reporting Period')}
806
                  </Label>
807
                  <br />
808
                  <DateRangePickerWrapper
809
                    id="reportingPeriodDateRangePicker"
810
                    format="yyyy-MM-dd HH:mm:ss"
811
                    value={reportingPeriodDateRange}
812
                    onChange={onReportingPeriodChange}
813
                    size="sm"
814
                    style={dateRangePickerStyle}
815
                    onClean={onReportingPeriodClean}
816
                    locale={dateRangePickerLocale}
817
                    placeholder={t('Select Date Range')}
818
                  />
819
                </FormGroup>
820
              </Col>
821
              <Col xs="auto">
822
                <FormGroup>
823
                  <br />
824
                  <ButtonGroup id="submit">
825
                    <Button size="sm" color="success" disabled={submitButtonDisabled}>
826
                      {t('Submit')}
827
                    </Button>
828
                  </ButtonGroup>
829
                </FormGroup>
830
              </Col>
831
              <Col xs="auto">
832
                <FormGroup>
833
                  <br />
834
                  <Spinner color="primary" hidden={spinnerHidden} />
835
                </FormGroup>
836
              </Col>
837
              <Col xs="auto">
838
                <br />
839
                <ButtonIcon
840
                  icon="external-link-alt"
841
                  transform="shrink-3 down-2"
842
                  color="falcon-default"
843
                  size="sm"
844
                  hidden={exportButtonHidden}
845
                  onClick={handleExport}
846
                >
847
                  {t('Export')}
848
                </ButtonIcon>
849
              </Col>
850
            </Row>
851
          </Form>
852
        </CardBody>
853
      </Card>
854
      <div className="blank-page-image-container" style={{ visibility: resultDataHidden ? 'visible' : 'hidden', display: resultDataHidden ? '' : 'none' }}>
855
        <img className="img-fluid" src={blankPage} alt="" />
856
      </div>
857
      <div style={{ visibility: resultDataHidden ? 'hidden' : 'visible', display: resultDataHidden ? 'none' : '' }}>
858
        <div className="card-deck">
859
          <CardSummary
860
            id="cardSummary1"
861
            title={t('TENANT CATEGORY VALUE UNIT', {
862
              TENANT: tenant1['name'],
863
              CATEGORY: energyCategory['name'],
864
              UNIT: '(' + energyCategory['unit_of_measure'] + ')'
865
            })}
866
            color="success"
867
          >
868
            <CountUp
869
              end={reportingPeriodEnergyConsumptionInCategory1}
870
              duration={2}
871
              prefix=""
872
              separator=","
873
              decimals={2}
874
              decimal="."
875
            />
876
          </CardSummary>
877
          <CardSummary
878
            id="cardSummary2"
879
            title={t('TENANT CATEGORY VALUE UNIT', {
880
              TENANT: tenant2['name'],
881
              CATEGORY: energyCategory['name'],
882
              UNIT: '(' + energyCategory['unit_of_measure'] + ')'
883
            })}
884
            color="success"
885
          >
886
            <CountUp
887
              end={reportingPeriodEnergyConsumptionInCategory2}
888
              duration={2}
889
              prefix=""
890
              separator=","
891
              decimals={2}
892
              decimal="."
893
            />
894
          </CardSummary>
895
          <CardSummary
896
            id="cardSummary3"
897
            title={t('Reporting Period Difference CATEGORY UNIT', {
898
              CATEGORY: energyCategory['name'],
899
              UNIT: '(' + energyCategory['unit_of_measure'] + ')'
900
            })}
901
            color="success"
902
          >
903
            <CountUp
904
              end={reportingPeriodEnergyConsumptionInDifference}
905
              duration={2}
906
              prefix=""
907
              separator=","
908
              decimals={2}
909
              decimal="."
910
            />
911
          </CardSummary>
912
        </div>
913
914
        <MultiTrendChart
915
          baseTitle={{
916
            name: 'TENANT CATEGORY VALUE UNIT',
917
            substitute: ['TENANT', 'CATEGORY', 'VALUE', 'UNIT'],
918
            TENANT: { a0: tenant1['name'] },
919
            CATEGORY: { a0: energyCategory['name'] },
920
            VALUE: { a0: reportingPeriodEnergyConsumptionInCategory1.toFixed(2) },
921
            UNIT: { a0: '(' + energyCategory['unit_of_measure'] + ')' }
922
          }}
923
          reportingTitle={{
924
            name: 'TENANT CATEGORY VALUE UNIT',
925
            substitute: ['TENANT', 'CATEGORY', 'VALUE', 'UNIT'],
926
            TENANT: { a0: tenant2['name'] },
927
            CATEGORY: { a0: energyCategory['name'] },
928
            VALUE: { a0: reportingPeriodEnergyConsumptionInCategory2.toFixed(2) },
929
            UNIT: { a0: '(' + energyCategory['unit_of_measure'] + ')' }
930
          }}
931
          baseTooltipTitle={{
932
            name: 'TENANT CATEGORY VALUE UNIT',
933
            substitute: ['TENANT', 'CATEGORY', 'VALUE', 'UNIT'],
934
            TENANT: { a0: tenant1['name'] },
935
            CATEGORY: { a0: energyCategory['name'] },
936
            VALUE: null,
937
            UNIT: { a0: '(' + energyCategory['unit_of_measure'] + ')' }
938
          }}
939
          reportingTooltipTitle={{
940
            name: 'TENANT CATEGORY VALUE UNIT',
941
            substitute: ['TENANT', 'CATEGORY', 'VALUE', 'UNIT'],
942
            TENANT: { a0: tenant2['name'] },
943
            CATEGORY: { a0: energyCategory['name'] },
944
            VALUE: null,
945
            UNIT: { a0: '(' + energyCategory['unit_of_measure'] + ')' }
946
          }}
947
          baseLabels={tenantLineChartLabels1}
948
          baseData={tenantLineChartData1}
949
          reportingLabels={tenantLineChartLabels2}
950
          reportingData={tenantLineChartData2}
951
          rates={{ a0: [] }}
952
        />
953
954
        <br />
955
        <DetailedDataTable
956
          data={detailedDataTableData}
957
          title={t('Detailed Data')}
958
          columns={detailedDataTableColumns}
959
          pagesize={50}
960
        />
961
      </div>
962
    </Fragment>
963
  );
964
};
965
966
export default withTranslation()(withRedirect(TenantComparison));
967