add date range picker to the incidents screen
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"fuse.js": "^3.4.5",
|
"fuse.js": "^3.4.5",
|
||||||
|
"moment": "^2.24.0",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-redux": "^7.0.3",
|
"react-redux": "^7.0.3",
|
||||||
|
|||||||
114
client/src/components/DateRangePicker/index.js
Normal file
114
client/src/components/DateRangePicker/index.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
import { Form, Message } from 'semantic-ui-react';
|
||||||
|
|
||||||
|
import { defaultDateFormat } from '../../constants/constants';
|
||||||
|
|
||||||
|
class DateRangePicker extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
const initialStartDate = props.startDate ? moment(props.startDate, defaultDateFormat) : moment().startOf('month');
|
||||||
|
let initialEndDate = props.endDate ? moment(props.endDate, defaultDateFormat) : moment();
|
||||||
|
|
||||||
|
if (initialStartDate > initialEndDate){
|
||||||
|
initialEndDate = initialStartDate.add(1, 'day');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
startDate: initialStartDate,
|
||||||
|
endDate: initialEndDate,
|
||||||
|
error: null,
|
||||||
|
startDateLabel: props.startDateLabel || 'Start date',
|
||||||
|
endDateLabel: props.endDateLabel || 'End date',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onStartDateChange(event) {
|
||||||
|
const { endDate, startDateLabel, endDateLabel } = this.state;
|
||||||
|
|
||||||
|
const newStartDate = moment(event.target.value, defaultDateFormat);
|
||||||
|
if (newStartDate > endDate){
|
||||||
|
this.setState({
|
||||||
|
error: `${startDateLabel} cannot be after ${endDateLabel}`
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({startDate: newStartDate, error: null});
|
||||||
|
}
|
||||||
|
|
||||||
|
onEndDateChange(event) {
|
||||||
|
const { startDate, startDateLabel, endDateLabel } = this.state;
|
||||||
|
|
||||||
|
const newEndDate = moment(event.target.value, defaultDateFormat);
|
||||||
|
if (newEndDate < startDate){
|
||||||
|
this.setState({
|
||||||
|
error: `${startDateLabel} cannot be after ${endDateLabel}`
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({endDate: newEndDate, error: null});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDismiss() {
|
||||||
|
this.setState({error: null});
|
||||||
|
}
|
||||||
|
|
||||||
|
onButtonClick() {
|
||||||
|
const { onDatesUpdate } = this.props;
|
||||||
|
const { startDate, endDate } = this.state;
|
||||||
|
|
||||||
|
if (onDatesUpdate){
|
||||||
|
onDatesUpdate({
|
||||||
|
startDate: startDate.format(defaultDateFormat),
|
||||||
|
endDate: endDate.format(defaultDateFormat),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.onButtonClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { startDate, endDate, error, startDateLabel, endDateLabel } = this.state;
|
||||||
|
|
||||||
|
const buttonLabel = this.props.buttonLabel || 'Save';
|
||||||
|
|
||||||
|
const startDateValue = startDate.format(defaultDateFormat);
|
||||||
|
const endDateValue = endDate.format(defaultDateFormat);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form>
|
||||||
|
<Form.Group widths="equal">
|
||||||
|
<Form.Input
|
||||||
|
fluid
|
||||||
|
required
|
||||||
|
label={startDateLabel}
|
||||||
|
type="date"
|
||||||
|
value={startDateValue}
|
||||||
|
onChange={this.onStartDateChange.bind(this)}
|
||||||
|
/>
|
||||||
|
<Form.Input
|
||||||
|
fluid
|
||||||
|
required
|
||||||
|
label={endDateLabel}
|
||||||
|
type="date"
|
||||||
|
value={endDateValue}
|
||||||
|
onChange={this.onEndDateChange.bind(this)}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
{ error &&
|
||||||
|
<Message color="orange" onDismiss={this.onDismiss.bind(this)}>
|
||||||
|
<Message.Header>Wrong date</Message.Header>
|
||||||
|
<p><b>{startDateLabel}</b> has to be before <b>{endDateLabel}</b></p>
|
||||||
|
</Message>
|
||||||
|
}
|
||||||
|
<Form.Button onClick={this.onButtonClick.bind(this)}>{buttonLabel}</Form.Button>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DateRangePicker;
|
||||||
1
client/src/constants/constants.js
Normal file
1
client/src/constants/constants.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const defaultDateFormat = 'YYYY-MM-DD';
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Container, Loader } from 'semantic-ui-react';
|
import {Container, Loader} from 'semantic-ui-react';
|
||||||
import ReactTable from 'react-table';
|
import ReactTable from 'react-table';
|
||||||
import 'react-table/react-table.css';
|
import 'react-table/react-table.css';
|
||||||
|
|
||||||
import MainMenu from '../../components/MainMenu';
|
import MainMenu from '../../components/MainMenu';
|
||||||
|
import DateRangePicker from '../../components/DateRangePicker';
|
||||||
|
|
||||||
import { fetchIncidents } from '../../store/actions';
|
import { fetchIncidents } from '../../store/actions';
|
||||||
import { incidentsReportHeaderTitles } from '../../constants/menuItems';
|
import { incidentsReportHeaderTitles } from '../../constants/menuItems';
|
||||||
import { incidentDescriptions, incidentLevelDescriptions, UNSCHEDULED_INCIDENT, UNLOCKED_INCIDENT } from '../../constants/enums';
|
import { incidentDescriptions, incidentLevelDescriptions, UNSCHEDULED_INCIDENT, UNLOCKED_INCIDENT } from '../../constants/enums';
|
||||||
|
|
||||||
class IncidentsReport extends Component {
|
class IncidentsReport extends Component {
|
||||||
|
onDatesUpdate(dateRange) {
|
||||||
componentDidMount() {
|
|
||||||
const { fetchIncidents } = this.props;
|
const { fetchIncidents } = this.props;
|
||||||
fetchIncidents();
|
fetchIncidents(dateRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@@ -56,6 +57,9 @@ class IncidentsReport extends Component {
|
|||||||
case UNSCHEDULED_INCIDENT:
|
case UNSCHEDULED_INCIDENT:
|
||||||
cellValue = `${timeIntervalsToCharge} x 5 min`;
|
cellValue = `${timeIntervalsToCharge} x 5 min`;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
cellValue = '';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -82,6 +86,8 @@ class IncidentsReport extends Component {
|
|||||||
<MainMenu/>
|
<MainMenu/>
|
||||||
<h3>Incidents Report</h3>
|
<h3>Incidents Report</h3>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
<DateRangePicker buttonLabel="Show report" onDatesUpdate={this.onDatesUpdate.bind(this)} />
|
||||||
|
<br/>
|
||||||
<Loader active={pendingIncidents} />
|
<Loader active={pendingIncidents} />
|
||||||
{
|
{
|
||||||
!pendingIncidents && incidents &&
|
!pendingIncidents && incidents &&
|
||||||
|
|||||||
@@ -36,9 +36,11 @@ export const addNewMapping = (dispatch, mapping) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchIncidents = (dispatch) => {
|
export const fetchIncidents = (dispatch, dateRange) => {
|
||||||
dispatch({type: FETCH_INCIDENTS_PENDING});
|
dispatch({type: FETCH_INCIDENTS_PENDING});
|
||||||
API.get('integration/report/allIncidents')
|
API.get('integration/report/allIncidents', {
|
||||||
|
dateRange
|
||||||
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
dispatch({type: FETCH_INCIDENTS_SUCCESS, payload: response.data});
|
dispatch({type: FETCH_INCIDENTS_SUCCESS, payload: response.data});
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5478,6 +5478,10 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimist "0.0.8"
|
minimist "0.0.8"
|
||||||
|
|
||||||
|
moment@^2.24.0:
|
||||||
|
version "2.24.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||||
|
|
||||||
move-concurrently@^1.0.1:
|
move-concurrently@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||||
|
|||||||
Reference in New Issue
Block a user