Passed
Push — master ( 66539e...e25360 )
by Guangyu
07:54 queued 12s
created

myems-web/src/components/MyEMS/Meter/VirtualMeterBatch.js   A

Complexity

Total Complexity 10
Complexity/F 0

Size

Lines of Code 356
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 311
mnd 10
bc 10
fnc 0
dl 0
loc 356
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import React, { Fragment, useEffect, useState } from 'react';
2
import {
3
  Breadcrumb,
4
  BreadcrumbItem,
5
  Row,
6
  Col,
7
  Card,
8
  CardBody,
9
  Button,
10
  ButtonGroup,
11
  Form,
12
  FormGroup,
13
  Input,
14
  Label,
15
  Spinner,
16
} from 'reactstrap';
17
import Cascader from 'rc-cascader';
18
import moment from 'moment';
19
import loadable from '@loadable/component';
20
import { getCookieValue, createCookie } from '../../../helpers/utils';
21
import withRedirect from '../../../hoc/withRedirect';
22
import { withTranslation } from 'react-i18next';
23
import { toast } from 'react-toastify';
24
import ButtonIcon from '../../common/ButtonIcon';
25
import { APIBaseURL } from '../../../config';
26
import { DateRangePicker } from 'rsuite';
27
import { endOfDay} from 'date-fns';
28
29
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
30
31
const VirtualMeterBatch = ({ setRedirect, setRedirectUrl, t }) => {
32
  let current_moment = moment();
33
  useEffect(() => {
34
    let is_logged_in = getCookieValue('is_logged_in');
35
    let user_name = getCookieValue('user_name');
36
    let user_display_name = getCookieValue('user_display_name');
37
    let user_uuid = getCookieValue('user_uuid');
38
    let token = getCookieValue('token');
39
    if (is_logged_in === null || !is_logged_in) {
40
      setRedirectUrl(`/authentication/basic/login`);
41
      setRedirect(true);
42
    } else {
43
      //update expires time of cookies
44
      createCookie('is_logged_in', true, 1000 * 60 * 60 * 8);
45
      createCookie('user_name', user_name, 1000 * 60 * 60 * 8);
46
      createCookie('user_display_name', user_display_name, 1000 * 60 * 60 * 8);
47
      createCookie('user_uuid', user_uuid, 1000 * 60 * 60 * 8);
48
      createCookie('token', token, 1000 * 60 * 60 * 8);
49
    }
50
  });
51
  // State
52
  //Query From
53
  const [selectedSpaceName, setSelectedSpaceName] = useState(undefined);
54
  const [selectedSpaceID, setSelectedSpaceID] = useState(undefined);
55
  const [meterList, setMeterList] = useState([]);
56
  const [cascaderOptions, setCascaderOptions] = useState(undefined);
57
  const [reportingPeriodDateRange, setReportingPeriodDateRange] = useState([current_moment.clone().startOf('month').toDate(), current_moment.toDate()]);
58
  const dateRangePickerLocale = {
59
    sunday: t('sunday'),
60
    monday: t('monday'),
61
    tuesday: t('tuesday'),
62
    wednesday: t('wednesday'),
63
    thursday: t('thursday'),
64
    friday: t('friday'),
65
    saturday: t('saturday'),
66
    ok: t('ok'),
67
    today: t('today'),
68
    yesterday: t('yesterday'),
69
    hours: t('hours'),
70
    minutes: t('minutes'),
71
    seconds: t('seconds'),
72
    last7Days: t('last7Days')
73
  };
74
  const dateRangePickerStyle = { display: 'block', zIndex: 10};
75
76
  // buttons
77
  const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false);
78
  const [spinnerHidden, setSpinnerHidden] = useState(true);
79
  const [exportButtonHidden, setExportButtonHidden] = useState(true);
80
81
  //Results
82
  const [detailedDataTableColumns, setDetailedDataTableColumns] = useState(
83
    [{dataField: 'id', text: t('ID'), sort: true},
84
    {dataField: 'name', text: t('Name'), sort: true},
85
    {dataField: 'space', text: t('Space'), sort: true}]);
86
  const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
87
  
88
  useEffect(() => {
89
    let isResponseOK = false;
90
    fetch(APIBaseURL + '/spaces/tree', {
91
      method: 'GET',
92
      headers: {
93
        "Content-type": "application/json",
94
        "User-UUID": getCookieValue('user_uuid'),
95
        "Token": getCookieValue('token')
96
      },
97
      body: null,
98
99
    }).then(response => {
100
      console.log(response);
101
      if (response.ok) {
102
        isResponseOK = true;
103
      }
104
      return response.json();
105
    }).then(json => {
106
      console.log(json);
107
      if (isResponseOK) {
108
        // rename keys 
109
        json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":'));
110
        setCascaderOptions(json);
111
        // set the default selected space
112
        setSelectedSpaceName([json[0]].map(o => o.label));
113
        setSelectedSpaceID([json[0]].map(o => o.value));
114
115
        setSubmitButtonDisabled(false);
116
        setSpinnerHidden(true);
117
      } else {
118
        toast.error(json.description);
119
      }
120
    }).catch(err => {
121
      console.log(err);
122
    });
123
124
  }, []);
125
126
  const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
127
128
  let onSpaceCascaderChange = (value, selectedOptions) => {
129
    setSelectedSpaceName(selectedOptions.map(o => o.label).join('/'));
130
    setSelectedSpaceID(value[value.length - 1]);
131
    setMeterList([]);
132
    setExportButtonHidden(true);
133
    setSubmitButtonDisabled(false);
134
  };
135
136
  let onReportingPeriodChange = (DateRange) => {
137
    if(DateRange == null) {
138
      setReportingPeriodDateRange([null, null]);
139
    } else {
140
      if (moment(DateRange[1]).format('HH:mm:ss') == '00:00:00') {
141
        // if the user did not change time value, set the default time to the end of day
142
        DateRange[1] = endOfDay(DateRange[1]);
143
      }
144
      setReportingPeriodDateRange([DateRange[0], DateRange[1]]);
145
    }
146
  };
147
148
  let onReportingPeriodClean = event => {
149
    setReportingPeriodDateRange([null, null]);
150
  };
151
152
  // Handler
153
  const handleSubmit = e => {
154
    e.preventDefault();
155
    console.log('handleSubmit');
156
    console.log(selectedSpaceID);
157
    console.log(moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss'))
158
    console.log(moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss'));
159
160
    // disable submit button
161
    setSubmitButtonDisabled(true);
162
    // show spinner
163
    setSpinnerHidden(false);
164
    // hide export button
165
    setExportButtonHidden(true)
166
 
167
    // Reinitialize tables
168
    setMeterList([]);
169
    
170
    let isResponseOK = false;
171
    fetch(APIBaseURL + '/reports/virtualmeterbatch?' +
172
      'spaceid=' + selectedSpaceID +
173
      '&reportingperiodstartdatetime=' + moment(reportingPeriodDateRange[0]).format('YYYY-MM-DDTHH:mm:ss') +
174
      '&reportingperiodenddatetime=' + moment(reportingPeriodDateRange[1]).format('YYYY-MM-DDTHH:mm:ss'), {
175
      method: 'GET',
176
      headers: {
177
        "Content-type": "application/json",
178
        "User-UUID": getCookieValue('user_uuid'),
179
        "Token": getCookieValue('token')
180
      },
181
      body: null,
182
183
    }).then(response => {
184
      if (response.ok) {
185
        isResponseOK = true;
186
      };
187
      return response.json();
188
    }).then(json => {
189
      if (isResponseOK) {
190
        console.log(json)
191
        let meters = [];
192
        if (json['virtual_meters'].length > 0) {
193
          json['virtual_meters'].forEach((currentMeter, index) => {
194
            let detailed_value = {};
195
            detailed_value['id'] = currentMeter['id'];
196
            detailed_value['name'] = currentMeter['virtual_meter_name'];
197
            detailed_value['space'] = currentMeter['space_name'];
198
            detailed_value['costcenter'] = currentMeter['cost_center_name'];
199
            currentMeter['values'].forEach((currentValue, energyCategoryIndex) => {
200
              if (typeof currentValue === 'number') {
201
                detailed_value['a' + energyCategoryIndex] = currentValue;
202
              } else {
203
                detailed_value['a' + energyCategoryIndex] = null;
204
              }
205
              
206
            });
207
            meters.push(detailed_value);
208
          });
209
        };
210
211
        setMeterList(meters);
212
213
        let detailed_column_list = [];
214
        detailed_column_list.push({
215
          dataField: 'id',
216
          text: t('ID'),
217
          sort: true
218
        });
219
        detailed_column_list.push({
220
          dataField: 'name',
221
          text: t('Name'),
222
          sort: true
223
        });
224
        detailed_column_list.push({
225
          dataField: 'space',
226
          text: t('Space'),
227
          sort: true
228
        });
229
        json['energycategories'].forEach((currentValue, index) => {
230
          detailed_column_list.push({
231
            dataField: 'a' + index,
232
            text: currentValue['name'] + ' (' + currentValue['unit_of_measure'] + ')',
233
            sort: true,
234
            formatter: function (decimalValue) {
235
              if (typeof decimalValue === 'number') {
236
                return decimalValue.toFixed(2);
237
              } else {
238
                return null;
239
              }
240
            }
241
          })
242
        });
243
        setDetailedDataTableColumns(detailed_column_list);
244
245
        setExcelBytesBase64(json['excel_bytes_base64']);
246
247
        // enable submit button
248
        setSubmitButtonDisabled(false);
249
        // hide spinner
250
        setSpinnerHidden(true);
251
        // show export button
252
        setExportButtonHidden(false);
253
      } else {
254
        toast.error(json.description)
255
      }
256
    }).catch(err => {
257
      console.log(err);
258
    });
259
  };
260
261
  const handleExport = e => {
262
    e.preventDefault();
263
    const mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
264
    const fileName = 'virtualmeterbatch.xlsx'
265
    var fileUrl = "data:" + mimeType + ";base64," + excelBytesBase64;
266
    fetch(fileUrl)
267
        .then(response => response.blob())
268
        .then(blob => {
269
            var link = window.document.createElement("a");
270
            link.href = window.URL.createObjectURL(blob, { type: mimeType });
271
            link.download = fileName;
272
            document.body.appendChild(link);
273
            link.click();
274
            document.body.removeChild(link);
275
        });
276
  };
277
  
278
279
280
  return (
281
    <Fragment>
282
      <div>
283
        <Breadcrumb>
284
          <BreadcrumbItem>{t('Meter Data')}</BreadcrumbItem><BreadcrumbItem active>{t('Virtual Meter Batch Analysis')}</BreadcrumbItem>
285
        </Breadcrumb>
286
      </div>
287
      <Card className="bg-light mb-3">
288
        <CardBody className="p-3">
289
          <Form onSubmit={handleSubmit}>
290
            <Row form>
291
              <Col xs={6} sm={3}>
292
                <FormGroup className="form-group">
293
                  <Label className={labelClasses} for="space">
294
                    {t('Space')}
295
                  </Label>
296
                  <br />
297
                  <Cascader options={cascaderOptions}
298
                    onChange={onSpaceCascaderChange}
299
                    changeOnSelect
300
                    expandTrigger="hover">
301
                    <Input value={selectedSpaceName || ''} readOnly />
302
                  </Cascader>
303
                </FormGroup>
304
              </Col>
305
              <Col xs={6} sm={3}>
306
                <FormGroup className="form-group">
307
                  <Label className={labelClasses} for="reportingPeriodDateRangePicker">{t('Reporting Period')}</Label>
308
                  <br/>
309
                  <DateRangePicker
310
                    id='reportingPeriodDateRangePicker'
311
                    format="yyyy-MM-dd HH:mm:ss"
312
                    value={reportingPeriodDateRange}
313
                    onChange={onReportingPeriodChange}
314
                    size="md"
315
                    style={dateRangePickerStyle}
316
                    onClean={onReportingPeriodClean}
317
                    locale={dateRangePickerLocale}
318
                    placeholder={t("Select Date Range")}
319
                  />
320
                </FormGroup>
321
              </Col>
322
              <Col xs="auto">
323
                <FormGroup>
324
                  <br></br>
325
                  <ButtonGroup id="submit">
326
                    <Button color="success" disabled={submitButtonDisabled} >{t('Submit')}</Button>
327
                  </ButtonGroup>
328
                </FormGroup>
329
              </Col>
330
              <Col xs="auto">
331
                <FormGroup>
332
                  <br></br>
333
                  <Spinner color="primary" hidden={spinnerHidden}  />
334
                </FormGroup>
335
              </Col>
336
              <Col xs="auto">
337
                  <br></br>
338
                  <ButtonIcon icon="external-link-alt" transform="shrink-3 down-2" color="falcon-default" 
339
                  hidden={exportButtonHidden}
340
                  onClick={handleExport} >
341
                    {t('Export')}
342
                  </ButtonIcon>
343
              </Col>
344
            </Row>
345
          </Form>
346
        </CardBody>
347
      </Card>
348
      <DetailedDataTable data={meterList} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
349
      </DetailedDataTable>
350
351
    </Fragment>
352
  );
353
};
354
355
export default withTranslation()(withRedirect(VirtualMeterBatch));
356