myems-web/src/components/MyEMS/EnergyStoragePowerStation/EnergyStoragePowerStationDetails.js   F
last analyzed

Complexity

Total Complexity 63
Complexity/F 0

Size

Lines of Code 1362
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 63
eloc 1141
dl 0
loc 1362
rs 2.396
c 0
b 0
f 0
mnd 63
bc 63
fnc 0
bpm 0
cpm 0
noi 0

How to fix   Complexity   

Complexity

Complex classes like myems-web/src/components/MyEMS/EnergyStoragePowerStation/EnergyStoragePowerStationDetails.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, useState, useEffect } from 'react';
2
import {
3
  Button,
4
  ButtonGroup,
5
  Card,
6
  CardBody,
7
  Col,
8
  CustomInput,
9
  Form,
10
  FormGroup,
11
  Input,
12
  Row,
13
  Table,
14
  Spinner,
15
  Nav,
16
  NavItem,
17
  NavLink,
18
  TabContent,
19
  TabPane
20
} from 'reactstrap';
21
import Cascader from 'rc-cascader';
22
import MultipleLineChart from '../common/MultipleLineChart';
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 { v4 as uuidv4 } from 'uuid';
28
import { APIBaseURL, settings } from '../../../config';
29
import useInterval from '../../../hooks/useInterval';
30
import { useLocation } from 'react-router-dom';
31
import { isIterableArray } from '../../../helpers/utils';
32
import classNames from 'classnames';
33
import ScheduleDetails from './ScheduleDetails';
34
import DetailsCard from './DetailsCard';
35
import CommandDetails from './CommandDetails';
36
import DeviceStatusDetails from './DeviceStatusDetails';
37
import blankPage from '../../../assets/img/generic/blank-page.png';
38
import PinModal from './PinModal';
39
40
const EnergyStoragePowerStationDetails = ({ setRedirect, setRedirectUrl, t }) => {
41
  const location = useLocation();
42
  const uuid = location.search.split('=')[1];
43
  const energyStoragePowerStationUUID = location.search.split('=')[1];
44
  const [isOpenPinModal, setIsOpenPinModal] = useState(false);
45
46
  useEffect(() => {
47
    let is_logged_in = getCookieValue('is_logged_in');
48
    let user_name = getCookieValue('user_name');
49
    let user_display_name = getCookieValue('user_display_name');
50
    let user_uuid = getCookieValue('user_uuid');
51
    let token = getCookieValue('token');
52
    if (checkEmpty(is_logged_in) || checkEmpty(token) || checkEmpty(user_uuid) || !is_logged_in) {
53
      setRedirectUrl(`/authentication/basic/login`);
54
      setRedirect(true);
55
    } else {
56
      //update expires time of cookies
57
      createCookie('is_logged_in', true, settings.cookieExpireTime);
58
      createCookie('user_name', user_name, settings.cookieExpireTime);
59
      createCookie('user_display_name', user_display_name, settings.cookieExpireTime);
60
      createCookie('user_uuid', user_uuid, settings.cookieExpireTime);
61
      createCookie('token', token, settings.cookieExpireTime);
62
    }
63
  });
64
65
  useEffect(() => {
66
    let timer = setInterval(() => {
67
      let is_logged_in = getCookieValue('is_logged_in');
68
      if (is_logged_in === null || !is_logged_in) {
69
        setRedirectUrl(`/authentication/basic/login`);
70
        setRedirect(true);
71
      }
72
    }, 1000);
73
    return () => clearInterval(timer);
74
  }, [setRedirect, setRedirectUrl]);
75
76
  const [activeTabLeft, setActiveTabLeft] = useState('1');
77
  const toggleTabLeft = tab => {
78
    if (activeTabLeft !== tab) setActiveTabLeft(tab);
79
  };
80
81
  const [activeTabRight, setActiveTabRight] = useState('1');
82
  const toggleTabRight = tab => {
83
    if (activeTabRight !== tab) setActiveTabRight(tab);
84
  };
85
86
  const [activeTabBottom, setActiveTabBottom] = useState('1');
87
88
  // State
89
  const [selectedSpaceName, setSelectedSpaceName] = useState(undefined);
90
  const [stationList, setStationList] = useState([]);
91
  const [filteredStationList, setFilteredStationList] = useState([]);
92
  const [selectedStation, setSelectedStation] = useState(undefined);
93
  const [cascaderOptions, setCascaderOptions] = useState(undefined);
94
95
  // buttons
96
  const [spinnerHidden, setSpinnerHidden] = useState(true);
97
  const [spaceCascaderHidden, setSpaceCascaderHidden] = useState(false);
98
  const [resultDataHidden, setResultDataHidden] = useState(true);
99
100
  //Results
101
  const [energyStoragePowerStationName, setEnergyStoragePowerStationName] = useState();
102
  const [energyStoragePowerStationAddress, setEnergyStoragePowerStationAddress] = useState();
103
  const [energyStoragePowerStationRatedCapacity, setEnergyStoragePowerStationRatedCapacity] = useState();
104
  const [energyStoragePowerStationRatedPower, setEnergyStoragePowerStationRatedPower] = useState();
105
  const [energyStoragePowerStationSVG, setEnergyStoragePowerStationSVG] = useState();
106
  const [gatewayStatus, setGatewayStatus] = useState();
107
  const [PCSStatus, setPCSStatus] = useState();
108
  const [BMSStatus, setBMSStatus] = useState();
109
110
  const [todayChargeEnergyValue, setTodayChargeEnergyValue] = useState();
111
  const [todayDischargeEnergyValue, setTodayDischargeEnergyValue] = useState();
112
  const [totalChargeEnergyValue, setTotalChargeEnergyValue] = useState();
113
  const [totalDischargeEnergyValue, setTotalDischargeEnergyValue] = useState();
114
  const [totalEfficiency, setTotalEfficiency] = useState();
115
116
  const [todayChargeRevenueValue, setTodayChargeRevenueValue] = useState();
117
  const [todayDischargeRevenueValue, setTodayDischargeRevenueValue] = useState();
118
  const [totalChargeRevenueValue, setTotalChargeRevenueValue] = useState();
119
  const [totalDischargeRevenueValue, setTotalDischargeRevenueValue] = useState();
120
121
  const [scheduleXaxisData, setScheduleXaxisData] = useState();
122
  const [scheduleSeriesName, setScheduleSeriesName] = useState();
123
  const [scheduleSeriesData, setScheduleSeriesData] = useState();
124
  const [scheduleMarkAreaData, setScheduleMarkAreaData] = useState();
125
126
  const [parameterLineChartLabels, setParameterLineChartLabels] = useState([]);
127
  const [parameterLineChartData, setParameterLineChartData] = useState({});
128
  const [parameterLineChartOptions, setParameterLineChartOptions] = useState([]);
129
130
  const [BMSDetailsList, setBMSDetailsList] = useState([]);
131
  const [firecontrolDetailsList, setFirecontrolDetailsList] = useState([]);
132
  const [HVACDetailsList, setHVACDetailsList] = useState([]);
133
  const [DCDCDetailsList, setDCDCDetailsList] = useState([]);
134
  const [PCSDetailsList, setPCSDetailsList] = useState([]);
135
  const [ESSMeterDetailsList, setESSMeterDetailsList] = useState([]);
136
  const [gridDetailsList, setGridDetailsList] = useState([]);
137
  const [loadDetailsList, setLoadDetailsList] = useState([]);
138
  const [STSDetailsList, setSTSDetailsList] = useState([]);
139
  const [commandDetailsList, setCommandDetailsList] = useState([]);
140
141
  useEffect(() => {
142
    if (uuid === null || !uuid) {
143
      let isResponseOK = false;
144
      setSpaceCascaderHidden(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
            setSelectedSpaceName([json[0]].map(o => o.label));
172
            let selectedSpaceID = [json[0]].map(o => o.value);
173
            // get Energy Storage Power Stations by root Space ID
174
            let isResponseOK = false;
175
            fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/energystoragepowerstations', {
176
              method: 'GET',
177
              headers: {
178
                'Content-type': 'application/json',
179
                'User-UUID': getCookieValue('user_uuid'),
180
                Token: getCookieValue('token')
181
              },
182
              body: null
183
            })
184
              .then(response => {
185
                if (response.ok) {
186
                  isResponseOK = true;
187
                }
188
                return response.json();
189
              })
190
              .then(json => {
191
                if (isResponseOK) {
192
                  json = JSON.parse(
193
                    JSON.stringify([json])
194
                      .split('"id":')
195
                      .join('"value":')
196
                      .split('"name":')
197
                      .join('"label":')
198
                  );
199
                  setStationList(json[0]);
200
                  setFilteredStationList(json[0]);
201
                  if (json[0].length > 0) {
202
                    // select the first station
203
                    let stationID = json[0][0].value;
204
                    setSelectedStation(stationID);
205
                    // automatically submit with the first station
206
                    loadData(APIBaseURL + '/reports/energystoragepowerstationdetails?id=' + stationID);
207
                  } else {
208
                    setSelectedStation(undefined);
209
                  }
210
                } else {
211
                  toast.error(t(json.description));
212
                }
213
              })
214
              .catch(err => {
215
                console.log(err);
216
              });
217
            // end of get Energy Storage Power Stations by root Space ID
218
          } else {
219
            toast.error(t(json.description));
220
          }
221
        })
222
        .catch(err => {
223
          console.log(err);
224
        });
225
    } else {
226
      setSpaceCascaderHidden(true);
227
      loadData(APIBaseURL + '/reports/energystoragepowerstationdetails?uuid=' + energyStoragePowerStationUUID);
228
    }
229
  }, [energyStoragePowerStationUUID]);
230
231
  const loadData = url => {
232
    // show spinner
233
    setSpinnerHidden(false);
234
    // hide result data
235
    setResultDataHidden(true);
236
237
    let isResponseOK = false;
238
    fetch(url, {
239
      method: 'GET',
240
      headers: {
241
        'Content-type': 'application/json',
242
        'User-UUID': getCookieValue('user_uuid'),
243
        Token: getCookieValue('token')
244
      },
245
      body: null
246
    })
247
      .then(response => {
248
        if (response.ok) {
249
          isResponseOK = true;
250
        }
251
        return response.json();
252
      })
253
      .then(json => {
254
        if (isResponseOK) {
255
          if (uuid !== null && uuid) {
256
            setFilteredStationList([
257
              { id: json['energy_storage_power_station']['id'], label: json['energy_storage_power_station']['name'] }
258
            ]);
259
            setSelectedStation(json['energy_storage_power_station']['id']);
260
          }
261
          setEnergyStoragePowerStationName(json['energy_storage_power_station']['name']);
262
          setEnergyStoragePowerStationAddress(json['energy_storage_power_station']['address']);
263
          setEnergyStoragePowerStationRatedCapacity(json['energy_storage_power_station']['rated_capacity']);
264
          setEnergyStoragePowerStationRatedPower(json['energy_storage_power_station']['rated_power']);
265
          setEnergyStoragePowerStationSVG({ __html: json['energy_storage_power_station']['svg'] });
266
267
          setGatewayStatus(json['energy_storage_power_station']['is_online']);
268
          setPCSStatus(json['energy_storage_power_station']['pcs_run_state']);
269
          setBMSStatus(json['energy_storage_power_station']['battery_operating_state']);
270
271
          setTodayChargeEnergyValue(json['energy_indicators']['today_charge_energy_value']);
272
          setTodayDischargeEnergyValue(json['energy_indicators']['today_discharge_energy_value']);
273
          setTotalChargeEnergyValue(json['energy_indicators']['total_charge_energy_value']);
274
          setTotalDischargeEnergyValue(json['energy_indicators']['total_discharge_energy_value']);
275
276
          if (json['energy_indicators']['total_charge_energy_value'] > 0) {
277
            setTotalEfficiency(
278
              (
279
                (100 * json['energy_indicators']['total_discharge_energy_value']) /
280
                json['energy_indicators']['total_charge_energy_value']
281
              ).toFixed(2)
282
            );
283
          } else {
284
            setTotalEfficiency(0);
285
          }
286
287
          setTodayChargeRevenueValue(json['revenue_indicators']['today_charge_revenue_value']);
288
          setTodayDischargeRevenueValue(json['revenue_indicators']['today_discharge_revenue_value']);
289
          setTotalChargeRevenueValue(json['revenue_indicators']['total_charge_revenue_value']);
290
          setTotalDischargeRevenueValue(json['revenue_indicators']['total_discharge_revenue_value']);
291
292
          let timestamps = {};
293
          json['parameters']['timestamps'].forEach((currentValue, index) => {
294
            timestamps['a' + index] = currentValue;
295
          });
296
          setParameterLineChartLabels(timestamps);
297
298
          let values = {};
299
          json['parameters']['values'].forEach((currentValue, index) => {
300
            values['a' + index] = currentValue;
301
          });
302
          setParameterLineChartData(values);
303
304
          let names = [];
305
          json['parameters']['names'].forEach((currentValue, index) => {
306
            names.push({ value: 'a' + index, label: currentValue });
307
          });
308
          setParameterLineChartOptions(names);
309
          // hide spinner
310
          setSpinnerHidden(true);
311
          // show result data
312
          setResultDataHidden(false);
313
        } else {
314
          toast.error(t(json.description));
315
          // hide spinner
316
          setSpinnerHidden(true);
317
        }
318
      })
319
      .catch(err => {
320
        console.log(err);
321
      });
322
  };
323
  const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
324
325
  let onSpaceCascaderChange = (value, selectedOptions) => {
326
    setSelectedSpaceName(selectedOptions.map(o => o.label).join('/'));
327
    let selectedSpaceID = value[value.length - 1];
328
    let isResponseOK = false;
329
    fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/energystoragepowerstations', {
330
      method: 'GET',
331
      headers: {
332
        'Content-type': 'application/json',
333
        'User-UUID': getCookieValue('user_uuid'),
334
        Token: getCookieValue('token')
335
      },
336
      body: null
337
    })
338
      .then(response => {
339
        if (response.ok) {
340
          isResponseOK = true;
341
        }
342
        return response.json();
343
      })
344
      .then(json => {
345
        if (isResponseOK) {
346
          json = JSON.parse(
347
            JSON.stringify([json])
348
              .split('"id":')
349
              .join('"value":')
350
              .split('"name":')
351
              .join('"label":')
352
          );
353
          setStationList(json[0]);
354
          setFilteredStationList(json[0]);
355
          if (json[0].length > 0) {
356
            setSelectedStation(json[0][0].value);
357
            loadData(APIBaseURL + '/reports/energystoragepowerstationdetails?id=' + json[0][0].value);
358
          } else {
359
            setSelectedStation(undefined);
360
          }
361
        } else {
362
          toast.error(t(json.description));
363
        }
364
      })
365
      .catch(err => {
366
        console.log(err);
367
      });
368
  };
369
370
  let onStationChange = ({ target }) => {
371
    setSelectedStation(target.value);
372
    loadData(APIBaseURL + '/reports/energystoragepowerstationdetails?id=' + target.value);
373
  };
374
375
  const refreshSVGData = () => {
376
    let isResponseOK = false;
377
    fetch(APIBaseURL + '/reports/pointrealtime', {
378
      method: 'GET',
379
      headers: {
380
        'Content-type': 'application/json',
381
        'User-UUID': getCookieValue('user_uuid'),
382
        Token: getCookieValue('token')
383
      },
384
      body: null
385
    })
386
      .then(response => {
387
        if (response.ok) {
388
          isResponseOK = true;
389
        }
390
        return response.json();
391
      })
392
      .then(json => {
393
        if (isResponseOK) {
394
          json.forEach(currentPoint => {
395
            let textElement = document.getElementById('PT' + currentPoint['point_id']);
396
            if (textElement) {
397
              textElement.textContent = parseFloat(currentPoint['value']).toFixed(2);
398
            }
399
            let circleElement = document.getElementById('CIRCLE' + currentPoint['point_id']);
400
            if (circleElement) {
401
              if (currentPoint['value'] > 0) {
402
                circleElement.className.baseVal = 'flow';
403
              } else if (currentPoint['value'] < 0) {
404
                circleElement.className.baseVal = 'flow-reverse';
405
              } else {
406
                circleElement.className.baseVal = '';
407
              }
408
            }
409
          });
410
        }
411
      })
412
      .catch(err => {
413
        console.log(err);
414
      });
415
  };
416
417
  useInterval(() => {
418
    refreshSVGData();
419
  }, 1000 * 10);
420
421
422
  const refreshTabBottomData = () => {
423
    if(activeTabBottom == '1') {
424
      // null
425
    } else if (activeTabBottom == '2') {
426
      fetchScheduleDetails();
427
    } else if (activeTabBottom == '3') {
428
      // null
429
    } else if (activeTabBottom == '4') {
430
      fetchDCDCDetails()
431
    } else if (activeTabBottom == '5') {
432
      fetchPCSDetails();
433
    } else if (activeTabBottom == '6') {
434
      fetchBMSDetails();
435
    } else if (activeTabBottom == '7') {
436
      fetchESSMeterDetails();
437
    } else if (activeTabBottom == '8') {
438
      fetchGridDetails();
439
    } else if (activeTabBottom == '9') {
440
      fetchLoadDetails();
441
    } else if (activeTabBottom == '10') {
442
      fetchHVACDetails();
443
    } else if (activeTabBottom == '11') {
444
      fetchFireControlDetails();
445
    } else if (activeTabBottom == '12') {
446
      fetchSTSDetails();
447
    } else if (activeTabBottom == '13') {
448
      fetchCommandDetails();
449
    }
450
451
  };
452
453
  useInterval(() => {
454
    refreshTabBottomData();
455
  }, 1000 * 60);
456
457
458
  // Schedule
459
  const fetchScheduleDetails = () => {
460
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/schedule';
461
    let isResponseOK = false;
462
    fetch(url, {
463
      method: 'GET',
464
      headers: {
465
        'Content-type': 'application/json',
466
        'User-UUID': getCookieValue('user_uuid'),
467
        Token: getCookieValue('token')
468
      },
469
      body: null
470
    })
471
      .then(response => {
472
        if (response.ok) {
473
          isResponseOK = true;
474
        }
475
        return response.json();
476
      })
477
      .then(json => {
478
        if (isResponseOK) {
479
          setScheduleXaxisData([
480
            '00:00:00',
481
            '00:30:00',
482
            '01:00:00',
483
            '01:30:00',
484
            '02:00:00',
485
            '02:30:00',
486
            '03:00:00',
487
            '03:30:00',
488
            '04:00:00',
489
            '04:30:00',
490
            '05:00:00',
491
            '05:30:00',
492
            '06:00:00',
493
            '06:30:00',
494
            '07:00:00',
495
            '07:30:00',
496
            '08:00:00',
497
            '08:30:00',
498
            '09:00:00',
499
            '09:30:00',
500
            '10:00:00',
501
            '10:30:00',
502
            '11:00:00',
503
            '11:30:00',
504
            '12:00:00',
505
            '12:30:00',
506
            '13:00:00',
507
            '13:30:00',
508
            '14:00:00',
509
            '14:30:00',
510
            '15:00:00',
511
            '15:30:00',
512
            '16:00:00',
513
            '16:30:00',
514
            '17:00:00',
515
            '17:30:00',
516
            '18:00:00',
517
            '18:30:00',
518
            '19:00:00',
519
            '19:30:00',
520
            '20:00:00',
521
            '20:30:00',
522
            '21:00:00',
523
            '21:30:00',
524
            '22:00:00',
525
            '22:30:00',
526
            '23:00:00',
527
            '23:30:00',
528
            '23:59:59'
529
          ]);
530
          setScheduleSeriesName('Power');
531
          setScheduleSeriesData(json['schedule']['series_data']);
532
          let schedule_mark_area_data = [];
533
          json['schedule']['schedule_list'].forEach((schedule_item, index) => {
534
            schedule_mark_area_data.push([
535
              { name: t(schedule_item['peak_type']), xAxis: schedule_item['start_time_of_day'] },
536
              { xAxis: schedule_item['end_time_of_day'] }
537
            ]);
538
          });
539
          setScheduleMarkAreaData(schedule_mark_area_data);
540
        } else {
541
          toast.error(t(json.description));
542
        }
543
      })
544
      .catch(err => {
545
        console.log(err);
546
      });
547
  };
548
549
  // DCDC
550
  const fetchDCDCDetails = () => {
551
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/dcdc';
552
    let isResponseOK = false;
553
    fetch(url, {
554
      method: 'GET',
555
      headers: {
556
        'Content-type': 'application/json',
557
        'User-UUID': getCookieValue('user_uuid'),
558
        Token: getCookieValue('token')
559
      },
560
      body: null
561
    })
562
      .then(response => {
563
        if (response.ok) {
564
          isResponseOK = true;
565
        }
566
        return response.json();
567
      })
568
      .then(json => {
569
        if (isResponseOK) {
570
          setDCDCDetailsList(json);
571
        } else {
572
          toast.error(t(json.description));
573
        }
574
      })
575
      .catch(err => {
576
        console.log(err);
577
      });
578
  };
579
  // PCS
580
  const fetchPCSDetails = () => {
581
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/pcs';
582
    let isResponseOK = false;
583
    fetch(url, {
584
      method: 'GET',
585
      headers: {
586
        'Content-type': 'application/json',
587
        'User-UUID': getCookieValue('user_uuid'),
588
        Token: getCookieValue('token')
589
      },
590
      body: null
591
    })
592
      .then(response => {
593
        if (response.ok) {
594
          isResponseOK = true;
595
        }
596
        return response.json();
597
      })
598
      .then(json => {
599
        if (isResponseOK) {
600
          setPCSDetailsList(json);
601
        } else {
602
          toast.error(t(json.description));
603
        }
604
      })
605
      .catch(err => {
606
        console.log(err);
607
      });
608
  };
609
  // BMS
610
  const fetchBMSDetails = () => {
611
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/bms';
612
    let isResponseOK = false;
613
    fetch(url, {
614
      method: 'GET',
615
      headers: {
616
        'Content-type': 'application/json',
617
        'User-UUID': getCookieValue('user_uuid'),
618
        Token: getCookieValue('token')
619
      },
620
      body: null
621
    })
622
      .then(response => {
623
        if (response.ok) {
624
          isResponseOK = true;
625
        }
626
        return response.json();
627
      })
628
      .then(json => {
629
        if (isResponseOK) {
630
          setBMSDetailsList(json);
631
        } else {
632
          toast.error(t(json.description));
633
        }
634
      })
635
      .catch(err => {
636
        console.log(err);
637
      });
638
  };
639
  // Grids
640
  const fetchGridDetails = () => {
641
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/grid';
642
    let isResponseOK = false;
643
    fetch(url, {
644
      method: 'GET',
645
      headers: {
646
        'Content-type': 'application/json',
647
        'User-UUID': getCookieValue('user_uuid'),
648
        Token: getCookieValue('token')
649
      },
650
      body: null
651
    })
652
      .then(response => {
653
        if (response.ok) {
654
          isResponseOK = true;
655
        }
656
        return response.json();
657
      })
658
      .then(json => {
659
        if (isResponseOK) {
660
          setGridDetailsList(json);
661
        } else {
662
          toast.error(t(json.description));
663
        }
664
      })
665
      .catch(err => {
666
        console.log(err);
667
      });
668
  };
669
  // Loads
670
  const fetchLoadDetails = () => {
671
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/load';
672
    let isResponseOK = false;
673
    fetch(url, {
674
      method: 'GET',
675
      headers: {
676
        'Content-type': 'application/json',
677
        'User-UUID': getCookieValue('user_uuid'),
678
        Token: getCookieValue('token')
679
      },
680
      body: null
681
    })
682
      .then(response => {
683
        if (response.ok) {
684
          isResponseOK = true;
685
        }
686
        return response.json();
687
      })
688
      .then(json => {
689
        if (isResponseOK) {
690
          setLoadDetailsList(json);
691
        } else {
692
          toast.error(t(json.description));
693
        }
694
      })
695
      .catch(err => {
696
        console.log(err);
697
      });
698
  };
699
700
  // ESS Meters
701
  const fetchESSMeterDetails = () => {
702
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/meter';
703
    let isResponseOK = false;
704
    fetch(url, {
705
      method: 'GET',
706
      headers: {
707
        'Content-type': 'application/json',
708
        'User-UUID': getCookieValue('user_uuid'),
709
        Token: getCookieValue('token')
710
      },
711
      body: null
712
    })
713
      .then(response => {
714
        if (response.ok) {
715
          isResponseOK = true;
716
        }
717
        return response.json();
718
      })
719
      .then(json => {
720
        if (isResponseOK) {
721
          setESSMeterDetailsList(json);
722
        } else {
723
          toast.error(t(json.description));
724
        }
725
      })
726
      .catch(err => {
727
        console.log(err);
728
      });
729
  };
730
  // HVAC
731
  const fetchHVACDetails = () => {
732
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/hvac';
733
    let isResponseOK = false;
734
    fetch(url, {
735
      method: 'GET',
736
      headers: {
737
        'Content-type': 'application/json',
738
        'User-UUID': getCookieValue('user_uuid'),
739
        Token: getCookieValue('token')
740
      },
741
      body: null
742
    })
743
      .then(response => {
744
        if (response.ok) {
745
          isResponseOK = true;
746
        }
747
        return response.json();
748
      })
749
      .then(json => {
750
        if (isResponseOK) {
751
          setHVACDetailsList(json);
752
        } else {
753
          toast.error(t(json.description));
754
        }
755
      })
756
      .catch(err => {
757
        console.log(err);
758
      });
759
  };
760
  // Fire Control
761
  const fetchFireControlDetails = () => {
762
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/firecontrol';
763
    let isResponseOK = false;
764
    fetch(url, {
765
      method: 'GET',
766
      headers: {
767
        'Content-type': 'application/json',
768
        'User-UUID': getCookieValue('user_uuid'),
769
        Token: getCookieValue('token')
770
      },
771
      body: null
772
    })
773
      .then(response => {
774
        if (response.ok) {
775
          isResponseOK = true;
776
        }
777
        return response.json();
778
      })
779
      .then(json => {
780
        if (isResponseOK) {
781
          setFirecontrolDetailsList(json);
782
        } else {
783
          toast.error(t(json.description));
784
        }
785
      })
786
      .catch(err => {
787
        console.log(err);
788
      });
789
  };
790
791
  // STS
792
  const fetchSTSDetails = () => {
793
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/sts';
794
    let isResponseOK = false;
795
    fetch(url, {
796
      method: 'GET',
797
      headers: {
798
        'Content-type': 'application/json',
799
        'User-UUID': getCookieValue('user_uuid'),
800
        Token: getCookieValue('token')
801
      },
802
      body: null
803
    })
804
      .then(response => {
805
        if (response.ok) {
806
          isResponseOK = true;
807
        }
808
        return response.json();
809
      })
810
      .then(json => {
811
        if (isResponseOK) {
812
          setSTSDetailsList(json);
813
        } else {
814
          toast.error(t(json.description));
815
        }
816
      })
817
      .catch(err => {
818
        console.log(err);
819
      });
820
  };
821
  // Command
822
  const fetchCommandDetails = () => {
823
    let url = APIBaseURL + '/reports/energystoragepowerstationdetails/' + selectedStation + '/command';
824
    let isResponseOK = false;
825
    fetch(url, {
826
      method: 'GET',
827
      headers: {
828
        'Content-type': 'application/json',
829
        'User-UUID': getCookieValue('user_uuid'),
830
        Token: getCookieValue('token')
831
      },
832
      body: null
833
    })
834
      .then(response => {
835
        if (response.ok) {
836
          isResponseOK = true;
837
        }
838
        return response.json();
839
      })
840
      .then(json => {
841
        if (isResponseOK) {
842
          setCommandDetailsList(json);
843
        } else {
844
          toast.error(t(json.description));
845
        }
846
      })
847
      .catch(err => {
848
        console.log(err);
849
      });
850
  };
851
852
  return (
853
    <Fragment>
854
      <Form>
855
        <Row form>
856
          <Col xs={6} sm={3} hidden={spaceCascaderHidden}>
857
            <FormGroup className="form-group">
858
              <Cascader options={cascaderOptions} onChange={onSpaceCascaderChange} changeOnSelect expandTrigger="hover">
859
                <Input bsSize="sm" value={selectedSpaceName || ''} readOnly />
860
              </Cascader>
861
            </FormGroup>
862
          </Col>
863
          <Col xs="auto">
864
            <FormGroup>
865
              <Form inline>
866
                <CustomInput
867
                  type="select"
868
                  id="stationSelect"
869
                  name="stationSelect"
870
                  bsSize="sm"
871
                  onChange={onStationChange}
872
                >
873
                  {filteredStationList.map((station, index) => (
874
                    <option value={station.value} key={index}>
875
                      {station.label}
876
                    </option>
877
                  ))}
878
                </CustomInput>
879
              </Form>
880
            </FormGroup>
881
          </Col>
882
          <Col xs="auto">
883
            <FormGroup>
884
              <Spinner color="primary" hidden={spinnerHidden} />
885
            </FormGroup>
886
          </Col>
887
          <Col xs="auto">
888
            <FormGroup>
889
              <Button tag={'a'} href="./details" target="_blank" color="primary" bsSize="sm" hidden={!spaceCascaderHidden}  > 更多  </Button>
890
            </FormGroup>
891
          </Col>
892
        </Row>
893
      </Form>
894
      <div style={{ visibility: resultDataHidden ? 'visible' : 'hidden', display: resultDataHidden ? '' : 'none' }}>
895
        <img className="img-fluid" src={blankPage} alt="" />
896
      </div>
897
      <div style={{ visibility: resultDataHidden ? 'hidden' : 'visible', display: resultDataHidden ? 'none' : '' }}>
898
        <Row noGutters>
899
          <Col lg="3" className="pr-lg-2">
900
            <Nav tabs>
901
              <NavItem className="cursor-pointer">
902
                <NavLink
903
                  className={classNames({ active: activeTabLeft === '1' })}
904
                  onClick={() => {
905
                    toggleTabLeft('1');
906
                  }}
907
                >
908
                  <h6>{t('Energy Indicator')}</h6>
909
                </NavLink>
910
              </NavItem>
911
              <NavItem className="cursor-pointer">
912
                <NavLink
913
                  className={classNames({ active: activeTabLeft === '2' })}
914
                  onClick={() => {
915
                    toggleTabLeft('2');
916
                  }}
917
                >
918
                  <h6>{t('Revenue Indicator')}</h6>
919
                </NavLink>
920
              </NavItem>
921
              {/* <NavItem className="cursor-pointer">
922
                <NavLink
923
                  className={classNames({ active: activeTabLeft === '3' })}
924
                  onClick={() => {
925
                    toggleTabLeft('3');
926
                  }}
927
                >
928
                  <h6>{t('Carbon Indicator')}</h6>
929
                </NavLink>
930
              </NavItem> */}
931
            </Nav>
932
            <TabContent activeTab={activeTabLeft}>
933
              <TabPane tabId="1">
934
                <Card className="mb-3 fs--1">
935
                  <Fragment>
936
                    <CardBody className="pt-0">
937
                      <Table borderless className="fs--1 mb-0">
938
                        <tbody>
939
                          <tr className="border-bottom">
940
                            <th className="pl-0">{t("Today's Charge")}</th>
941
                            <th className="pr-0 text-right">{todayChargeEnergyValue} kWh</th>
942
                          </tr>
943
                          <tr className="border-bottom">
944
                            <th className="pl-0">{t("Today's Discharge")}</th>
945
                            <th className="pr-0 text-right ">{todayDischargeEnergyValue} kWh</th>
946
                          </tr>
947
                          <tr className="border-bottom">
948
                            <th className="pl-0 pb-0">{t('Total Charge')}</th>
949
                            <th className="pr-0 text-right">{totalChargeEnergyValue} kWh</th>
950
                          </tr>
951
                          <tr className="border-bottom">
952
                            <th className="pl-0 pb-0">{t('Total Discharge')}</th>
953
                            <th className="pr-0 text-right">{totalDischargeEnergyValue} kWh</th>
954
                          </tr>
955
                          <tr className="border-bottom">
956
                            <th className="pl-0 pb-0">{t('Total Efficiency')}</th>
957
                            <th className="pr-0 text-right">{totalEfficiency}%</th>
958
                          </tr>
959
                          <tr className="border-bottom">
960
                            <th className="pl-0 pb-0">{t('Discharge Achievement Rate')}</th>
961
                            <th className="pr-0 text-right">
962
                              {((100 * todayDischargeEnergyValue) / energyStoragePowerStationRatedCapacity).toFixed(2)}%
963
                            </th>
964
                          </tr>
965
                        </tbody>
966
                      </Table>
967
                    </CardBody>
968
                  </Fragment>
969
                </Card>
970
              </TabPane>
971
              <TabPane tabId="2">
972
                <Card className="mb-3 fs--1">
973
                  <Fragment>
974
                    <CardBody className="pt-0">
975
                      <Table borderless className="fs--1 mb-0">
976
                        <tbody>
977
                          <tr className="border-bottom">
978
                            <th className="pl-0">{t("Today's Cost")}</th>
979
                            <th className="pr-0 text-right">{todayChargeRevenueValue} 元</th>
980
                          </tr>
981
                          <tr className="border-bottom">
982
                            <th className="pl-0">{t("Today's Income")}</th>
983
                            <th className="pr-0 text-right ">{todayDischargeRevenueValue} 元</th>
984
                          </tr>
985
                          <tr className="border-bottom">
986
                            <th className="pl-0 pb-0">{t('Total Cost')}</th>
987
                            <th className="pr-0 text-right">{totalChargeRevenueValue} 元</th>
988
                          </tr>
989
                          <tr className="border-bottom">
990
                            <th className="pl-0 pb-0">{t('Total Income')}</th>
991
                            <th className="pr-0 text-right">{totalDischargeRevenueValue} 元</th>
992
                          </tr>
993
                          <tr className="border-bottom">
994
                            <th className="pl-0 pb-0">{t("Today's Revenue")}</th>
995
                            <th className="pr-0 text-right">
996
                              {(todayDischargeRevenueValue - todayChargeRevenueValue).toFixed(2)} 元
997
                            </th>
998
                          </tr>
999
                          <tr className="border-bottom">
1000
                            <th className="pl-0 pb-0">{t('Total Revenue')}</th>
1001
                            <th className="pr-0 text-right">
1002
                              {(totalDischargeRevenueValue - totalChargeRevenueValue).toFixed(2)} 元
1003
                            </th>
1004
                          </tr>
1005
                        </tbody>
1006
                      </Table>
1007
                    </CardBody>
1008
                  </Fragment>
1009
                </Card>
1010
              </TabPane>
1011
            </TabContent>
1012
          </Col>
1013
          <Col lg="6" className="pr-lg-2" key={uuidv4()}>
1014
            <div dangerouslySetInnerHTML={energyStoragePowerStationSVG} />
1015
          </Col>
1016
          <Col lg="3" className="pr-lg-2">
1017
            <Nav tabs>
1018
              <NavItem className="cursor-pointer">
1019
                <NavLink
1020
                  className={classNames({ active: activeTabRight === '1' })}
1021
                  onClick={() => {
1022
                    toggleTabRight('1');
1023
                  }}
1024
                >
1025
                  <h6>{t('Device Status')}</h6>
1026
                </NavLink>
1027
              </NavItem>
1028
              <NavItem className="cursor-pointer">
1029
                <NavLink
1030
                  className={classNames({ active: activeTabRight === '2' })}
1031
                  onClick={() => {
1032
                    toggleTabRight('2');
1033
                  }}
1034
                >
1035
                  <h6>{t('Basic Information')}</h6>
1036
                </NavLink>
1037
              </NavItem>
1038
            </Nav>
1039
            <TabContent activeTab={activeTabRight}>
1040
              <TabPane tabId="1">
1041
                <DeviceStatusDetails
1042
                  id={selectedStation}
1043
                  isOnline={gatewayStatus}
1044
                  PCSRunState={PCSStatus}
1045
                  batteryOperatingState={BMSStatus}
1046
                />
1047
              </TabPane>
1048
              <TabPane tabId="2">
1049
                <Card className="mb-3 fs--1">
1050
                  <Fragment>
1051
                    <CardBody className="pt-0">
1052
                      <Table borderless className="fs--1 mb-0">
1053
                        <tbody>
1054
                          <tr className="border-bottom">
1055
                            <th className="pl-0">{t('Name')}</th>
1056
                            <th className="pr-0 text-right">{energyStoragePowerStationName}</th>
1057
                          </tr>
1058
                          <tr className="border-bottom">
1059
                            <th className="pl-0">{t('Address')}</th>
1060
                            <th className="pr-0 text-right ">{energyStoragePowerStationAddress}</th>
1061
                          </tr>
1062
                          <tr className="border-bottom">
1063
                            <th className="pl-0 pb-0">{t('Rated Capacity')} </th>
1064
                            <th className="pr-0 text-right">{energyStoragePowerStationRatedCapacity} kWh</th>
1065
                          </tr>
1066
                          <tr className="border-bottom">
1067
                            <th className="pl-0 pb-0">{t('Rated Power')} </th>
1068
                            <th className="pr-0 text-right">{energyStoragePowerStationRatedPower} kW</th>
1069
                          </tr>
1070
                        </tbody>
1071
                      </Table>
1072
                    </CardBody>
1073
                  </Fragment>
1074
                </Card>
1075
              </TabPane>
1076
            </TabContent>
1077
          </Col>
1078
        </Row>
1079
1080
        <Nav tabs>
1081
          <NavItem className="cursor-pointer">
1082
            <NavLink
1083
              className={classNames({ active: activeTabBottom === '1' })}
1084
              onClick={() => {
1085
                setActiveTabBottom('1');
1086
              }}
1087
            >
1088
              <h6>{t('Operating Characteristic Curve')}</h6>
1089
            </NavLink>
1090
          </NavItem>
1091
          <NavItem className="cursor-pointer">
1092
            <NavLink
1093
              className={classNames({ active: activeTabBottom === '2' })}
1094
              onClick={() => {
1095
                setActiveTabBottom('2');
1096
                fetchScheduleDetails();
1097
              }}
1098
            >
1099
              <h6>{t('Strategy Management')}</h6>
1100
            </NavLink>
1101
          </NavItem>
1102
          <NavItem className="cursor-pointer">
1103
            <NavLink
1104
              className={classNames({ active: activeTabBottom === '3' })}
1105
              onClick={() => {
1106
                setActiveTabBottom('3');
1107
              }}
1108
            >
1109
              <h6>{t('Fault Alarms')}</h6>
1110
            </NavLink>
1111
          </NavItem>
1112
1113
          <NavItem className="cursor-pointer">
1114
            <NavLink
1115
              className={classNames({ active: activeTabBottom === '4' })}
1116
              onClick={() => {
1117
                setActiveTabBottom('4');
1118
                fetchDCDCDetails();
1119
              }}
1120
            >
1121
              <h6>{t('DCDC')}</h6>
1122
            </NavLink>
1123
          </NavItem>
1124
1125
          <NavItem className="cursor-pointer">
1126
            <NavLink
1127
              className={classNames({ active: activeTabBottom === '5' })}
1128
              onClick={() => {
1129
                setActiveTabBottom('5');
1130
                fetchPCSDetails();
1131
              }}
1132
            >
1133
              <h6>{t('PCS')}</h6>
1134
            </NavLink>
1135
          </NavItem>
1136
1137
          <NavItem className="cursor-pointer">
1138
            <NavLink
1139
              className={classNames({ active: activeTabBottom === '6' })}
1140
              onClick={() => {
1141
                setActiveTabBottom('6');
1142
                fetchBMSDetails();
1143
              }}
1144
            >
1145
              <h6>{t('BMS')}</h6>
1146
            </NavLink>
1147
          </NavItem>
1148
          <NavItem className="cursor-pointer">
1149
            <NavLink
1150
              className={classNames({ active: activeTabBottom === '7' })}
1151
              onClick={() => {
1152
                setActiveTabBottom('7');
1153
                fetchESSMeterDetails();
1154
              }}
1155
            >
1156
              <h6>{t('ESS Meter')}</h6>
1157
            </NavLink>
1158
          </NavItem>
1159
          <NavItem className="cursor-pointer">
1160
            <NavLink
1161
              className={classNames({ active: activeTabBottom === '8' })}
1162
              onClick={() => {
1163
                setActiveTabBottom('7');
1164
                fetchGridDetails();
1165
              }}
1166
            >
1167
              <h6>{t('Grid Meter')}</h6>
1168
            </NavLink>
1169
          </NavItem>
1170
          <NavItem className="cursor-pointer">
1171
            <NavLink
1172
              className={classNames({ active: activeTabBottom === '9' })}
1173
              onClick={() => {
1174
                setActiveTabBottom('8');
1175
                fetchLoadDetails();
1176
              }}
1177
            >
1178
              <h6>{t('Load Meter')}</h6>
1179
            </NavLink>
1180
          </NavItem>
1181
1182
          <NavItem className="cursor-pointer">
1183
            <NavLink
1184
              className={classNames({ active: activeTabBottom === '10' })}
1185
              onClick={() => {
1186
                setActiveTabBottom('9');
1187
                fetchHVACDetails();
1188
              }}
1189
            >
1190
              <h6>{t('HVAC')}</h6>
1191
            </NavLink>
1192
          </NavItem>
1193
1194
          <NavItem className="cursor-pointer">
1195
            <NavLink
1196
              className={classNames({ active: activeTabBottom === '11' })}
1197
              onClick={() => {
1198
                setActiveTabBottom('10');
1199
                fetchFireControlDetails();
1200
              }}
1201
            >
1202
              <h6>{t('Fire Control')}</h6>
1203
            </NavLink>
1204
          </NavItem>
1205
1206
          <NavItem className="cursor-pointer">
1207
            <NavLink
1208
              className={classNames({ active: activeTabBottom === '12' })}
1209
              onClick={() => {
1210
                setActiveTabBottom('12');
1211
                fetchSTSDetails();
1212
              }}
1213
            >
1214
              <h6>{t('STS')}</h6>
1215
            </NavLink>
1216
          </NavItem>
1217
1218
          <NavItem className="cursor-pointer">
1219
            <NavLink
1220
              className={classNames({ active: activeTabBottom === '13' })}
1221
              onClick={() => {
1222
                let is_pin_valid = getCookieValue('is_pin_valid');
1223
                if (is_pin_valid) {
1224
                  setActiveTabBottom('12');
1225
                  fetchCommandDetails();
1226
                } else {
1227
                  setIsOpenPinModal(true);
1228
                }
1229
              }}
1230
            >
1231
              <h6>{t('Run Commands')}</h6>
1232
            </NavLink>
1233
          </NavItem>
1234
        </Nav>
1235
        <TabContent activeTab={activeTabBottom}>
1236
          <TabPane tabId="1">
1237
            <MultipleLineChart
1238
              reportingTitle=""
1239
              baseTitle=""
1240
              labels={parameterLineChartLabels}
1241
              data={parameterLineChartData}
1242
              options={parameterLineChartOptions}
1243
            />
1244
          </TabPane>
1245
          <TabPane tabId="2">
1246
            <ScheduleDetails
1247
              xaxisData={scheduleXaxisData}
1248
              seriesName={scheduleSeriesName}
1249
              seriesData={scheduleSeriesData}
1250
              markAreaData={scheduleMarkAreaData}
1251
            />
1252
          </TabPane>
1253
          <TabPane tabId="3">
1254
            <Card className="mb-3 fs--1">
1255
              <CardBody className="bg-light">
1256
                <Table striped className="border-bottom">
1257
                  <thead>
1258
                    <tr>
1259
                      <th>#</th>
1260
                      <th>主题</th>
1261
                      <th>内容</th>
1262
                      <th>创建时间</th>
1263
                      <th>开始时间</th>
1264
                      <th>结束时间</th>
1265
                      <th>状态</th>
1266
                      <th>更新时间</th>
1267
                    </tr>
1268
                  </thead>
1269
                  <tbody>
1270
                    <tr>
1271
                      <th scope="row">1</th>
1272
                      <td />
1273
                      <td />
1274
                      <td />
1275
                      <td />
1276
                      <td />
1277
                      <td />
1278
                      <td />
1279
                    </tr>
1280
                    <tr>
1281
                      <th scope="row">2</th>
1282
                      <td />
1283
                      <td />
1284
                      <td />
1285
                      <td />
1286
                      <td />
1287
                      <td />
1288
                      <td />
1289
                    </tr>
1290
                    <tr>
1291
                      <th scope="row">3</th>
1292
                      <td />
1293
                      <td />
1294
                      <td />
1295
                      <td />
1296
                      <td />
1297
                      <td />
1298
                      <td />
1299
                    </tr>
1300
                    <tr>
1301
                      <th scope="row">4</th>
1302
                      <td />
1303
                      <td />
1304
                      <td />
1305
                      <td />
1306
                      <td />
1307
                      <td />
1308
                      <td />
1309
                    </tr>
1310
                  </tbody>
1311
                </Table>
1312
              </CardBody>
1313
            </Card>
1314
          </TabPane>
1315
          {<TabPane tabId="4">
1316
            {isIterableArray(DCDCDetailsList) && DCDCDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />) }
1317
          </TabPane>}
1318
          <TabPane tabId="5">
1319
            {isIterableArray(PCSDetailsList) &&
1320
              PCSDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1321
          </TabPane>
1322
          <TabPane tabId="6">
1323
            {isIterableArray(BMSDetailsList) &&
1324
              BMSDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1325
          </TabPane>
1326
          <TabPane tabId="7">
1327
            {isIterableArray(ESSMeterDetailsList) &&
1328
              ESSMeterDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1329
          </TabPane>
1330
          <TabPane tabId="8">
1331
            {isIterableArray(gridDetailsList) &&
1332
              gridDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1333
          </TabPane>
1334
          <TabPane tabId="9">
1335
            {isIterableArray(loadDetailsList) &&
1336
              loadDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1337
          </TabPane>
1338
          <TabPane tabId="10">
1339
            {isIterableArray(HVACDetailsList) &&
1340
              HVACDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1341
          </TabPane>
1342
          <TabPane tabId="11">
1343
            {isIterableArray(firecontrolDetailsList) &&
1344
              firecontrolDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />)}
1345
          </TabPane>
1346
          {<TabPane tabId="12">
1347
            {isIterableArray(STSDetailsList) && STSDetailsList.map(({ id, ...rest }) => <DetailsCard key={id} id={id} {...rest} />) }
1348
          </TabPane> }
1349
          <TabPane tabId="13">
1350
            {isIterableArray(commandDetailsList) &&
1351
              commandDetailsList.map(({ id, ...rest }) => <CommandDetails key={id} id={id} {...rest} />)}
1352
          </TabPane>
1353
        </TabContent>
1354
      </div>
1355
1356
      <PinModal isOpenPinModal={isOpenPinModal} setIsOpenPinModal={setIsOpenPinModal} />
1357
    </Fragment>
1358
  );
1359
};
1360
1361
export default withTranslation()(withRedirect(EnergyStoragePowerStationDetails));
1362