diff --git a/client/package.json b/client/package.json index 26300b5..4aa04dc 100644 --- a/client/package.json +++ b/client/package.json @@ -5,6 +5,7 @@ "dependencies": { "axios": "^0.18.0", "fuse.js": "^3.4.5", + "moment": "^2.24.0", "react": "^16.8.6", "react-dom": "^16.8.6", "react-redux": "^7.0.3", diff --git a/client/src/components/DateRangePicker/index.js b/client/src/components/DateRangePicker/index.js new file mode 100644 index 0000000..442a700 --- /dev/null +++ b/client/src/components/DateRangePicker/index.js @@ -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 ( +
+ + + + + { error && + + Wrong date +

{startDateLabel} has to be before {endDateLabel}

+
+ } + {buttonLabel} +
+ ); + } +} + +export default DateRangePicker; diff --git a/client/src/constants/constants.js b/client/src/constants/constants.js new file mode 100644 index 0000000..ed5633b --- /dev/null +++ b/client/src/constants/constants.js @@ -0,0 +1 @@ +export const defaultDateFormat = 'YYYY-MM-DD'; diff --git a/client/src/scenes/IncidentsReport/index.js b/client/src/scenes/IncidentsReport/index.js index 09a76cb..d12cd01 100644 --- a/client/src/scenes/IncidentsReport/index.js +++ b/client/src/scenes/IncidentsReport/index.js @@ -1,19 +1,20 @@ import React, { Component } from 'react'; 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 'react-table/react-table.css'; import MainMenu from '../../components/MainMenu'; +import DateRangePicker from '../../components/DateRangePicker'; + import { fetchIncidents } from '../../store/actions'; import { incidentsReportHeaderTitles } from '../../constants/menuItems'; import { incidentDescriptions, incidentLevelDescriptions, UNSCHEDULED_INCIDENT, UNLOCKED_INCIDENT } from '../../constants/enums'; class IncidentsReport extends Component { - - componentDidMount() { + onDatesUpdate(dateRange) { const { fetchIncidents } = this.props; - fetchIncidents(); + fetchIncidents(dateRange); } render () { @@ -56,6 +57,9 @@ class IncidentsReport extends Component { case UNSCHEDULED_INCIDENT: cellValue = `${timeIntervalsToCharge} x 5 min`; break; + default: + cellValue = ''; + break; } break; @@ -82,6 +86,8 @@ class IncidentsReport extends Component {

Incidents Report


+ +
{ !pendingIncidents && incidents && diff --git a/client/src/store/actions/integrationActions.js b/client/src/store/actions/integrationActions.js index 599573f..395186f 100644 --- a/client/src/store/actions/integrationActions.js +++ b/client/src/store/actions/integrationActions.js @@ -36,9 +36,11 @@ export const addNewMapping = (dispatch, mapping) => { }); }; -export const fetchIncidents = (dispatch) => { +export const fetchIncidents = (dispatch, dateRange) => { dispatch({type: FETCH_INCIDENTS_PENDING}); - API.get('integration/report/allIncidents') + API.get('integration/report/allIncidents', { + dateRange + }) .then(response => { dispatch({type: FETCH_INCIDENTS_SUCCESS, payload: response.data}); }) diff --git a/client/yarn.lock b/client/yarn.lock index dd8a44d..caa1ce2 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -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: 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: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"