diff --git a/client/src/constants/enums.js b/client/src/constants/enums.js new file mode 100644 index 0000000..a6da2d0 --- /dev/null +++ b/client/src/constants/enums.js @@ -0,0 +1,17 @@ + +export const UNLOCKED_INCIDENT = 2; +export const UNSCHEDULED_INCIDENT = 3; + +export const incidentDescriptions = {}; +incidentDescriptions[UNLOCKED_INCIDENT] = 'User left door unlocked'; +incidentDescriptions[UNSCHEDULED_INCIDENT] = 'Unscheduled use'; + +export const incidentLevelDescriptions = { + UNLOCKED_0: 'First month', + UNLOCKED_1: 'Second month', + UNLOCKED_2: 'Third month', + UNLOCKED_3: 'Fourth month', + UNLOCKED_4: 'Fifth month', + UNLOCKED_5: 'Sixth month', + +}; diff --git a/client/src/constants/menuItems.js b/client/src/constants/menuItems.js index cd4f3d2..8a910e3 100644 --- a/client/src/constants/menuItems.js +++ b/client/src/constants/menuItems.js @@ -1,5 +1,6 @@ -import UploadDLockData from "../scenes/UploadDLockData"; -import Home from "../scenes/Home"; +import UploadDLockData from '../scenes/UploadDLockData'; +import Home from '../scenes/Home'; +import IncidentsReport from '../scenes/IncidentsReport'; export const mainMenuItems = [ { @@ -8,6 +9,12 @@ export const mainMenuItems = [ url: '/', component: Home, }, + { + id: 'report', + title: 'Incidents Report', + url: '/incidents-report', + component: IncidentsReport, + }, { id: 'uploadDLockData', title: 'DLock', @@ -15,3 +22,14 @@ export const mainMenuItems = [ component: UploadDLockData, }, ]; + +export const incidentsReportHeaderTitles = { + officeName: 'Office', + resourceName: 'Room', + bookingStart: 'Reservation Start', + bookingEnd: 'Reservation End', + memberName: 'Member Name', + incidentType: 'Incident Type', + feeDescription: 'Fee description', + totalChargeFee: 'Total Fee', +}; diff --git a/client/src/scenes/IncidentsReport/index.js b/client/src/scenes/IncidentsReport/index.js new file mode 100644 index 0000000..defc361 --- /dev/null +++ b/client/src/scenes/IncidentsReport/index.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { Container, Loader } from 'semantic-ui-react'; +import ReactTable from 'react-table'; +import 'react-table/react-table.css'; + +import MainMenu from '../../components/MainMenu'; +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() { + const { fetchIncidents } = this.props; + fetchIncidents(); + } + + render () { + const { pendingIncidents, incidents } = this.props; + + const columns = []; + if (incidents && incidents.length > 0){ + const incidentHeaders = Object.keys(incidentsReportHeaderTitles); + + incidentHeaders.forEach((header) => { + const columnTitle = incidentsReportHeaderTitles[header]; + + if (columnTitle){ + columns.push({ + Header: incidentsReportHeaderTitles[header], + accessor: header, + Cell: props => { + let cellValue; + + switch (props.column.id) { + case 'incidentType': + cellValue = incidentDescriptions[props.value]; + break; + case 'incidentLevel': + cellValue = incidentLevelDescriptions[props.value]; + break; + + case 'feeDescription': + const { incidentType, incidentLevel, timeIntervalsToCharge } = props.row['_original']; + switch (incidentType) { + case UNLOCKED_INCIDENT: + cellValue = `${incidentLevelDescriptions[incidentLevel]}`; + break; + case UNSCHEDULED_INCIDENT: + cellValue = `${timeIntervalsToCharge} x 5 min`; + break; + } + break; + + case 'totalChargeFee': + const totalFee = props.value ? props.value : props.row['_original'].incidentPrice; + cellValue = `$ ${totalFee}`; + break; + + default: + cellValue = props.value; + } + + return {cellValue} + } + }); + } + }); + } + + return ( + + +

Incidents Report

+
+ + { + !pendingIncidents && incidents && + + } +
+ ); + } +} + +const mapStateToProps = (state) => ({ + pendingIncidents: state.incidentsReport.pending, + incidents: state.incidentsReport.result, +}); + +const mapDispatchToProps = (dispatch) => ({ + fetchIncidents: () => fetchIncidents(dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(IncidentsReport); diff --git a/client/src/store/actions/integrationActions.js b/client/src/store/actions/integrationActions.js index b61b58b..599573f 100644 --- a/client/src/store/actions/integrationActions.js +++ b/client/src/store/actions/integrationActions.js @@ -5,7 +5,10 @@ import { ADD_NEW_MAPPING_PENDING, ADD_NEW_MAPPING_SUCCESS, ADD_NEW_MAPPING_FAILED, -} from "../constants"; + FETCH_INCIDENTS_PENDING, + FETCH_INCIDENTS_SUCCESS, + FETCH_INCIDENTS_FAILED, +} from '../constants'; import API from '../../utilities/api'; @@ -32,3 +35,14 @@ export const addNewMapping = (dispatch, mapping) => { dispatch({type: ADD_NEW_MAPPING_FAILED, payload: error.response}); }); }; + +export const fetchIncidents = (dispatch) => { + dispatch({type: FETCH_INCIDENTS_PENDING}); + API.get('integration/report/allIncidents') + .then(response => { + dispatch({type: FETCH_INCIDENTS_SUCCESS, payload: response.data}); + }) + .catch(error => { + dispatch({type: FETCH_INCIDENTS_FAILED, payload: error.response}); + }); +}; diff --git a/client/src/store/constants.js b/client/src/store/constants.js index aecc675..9b20bbc 100644 --- a/client/src/store/constants.js +++ b/client/src/store/constants.js @@ -9,3 +9,7 @@ export const FETCH_MAPPINGS_FAILED = 'FETCH_MAPPINGS_FAILED'; export const ADD_NEW_MAPPING_PENDING = 'ADD_NEW_MAPPING_PENDING'; export const ADD_NEW_MAPPING_SUCCESS = 'ADD_NEW_MAPPING_SUCCESS'; export const ADD_NEW_MAPPING_FAILED = 'ADD_NEW_MAPPING_FAILED'; + +export const FETCH_INCIDENTS_PENDING = 'FETCH_INCIDENTS_PENDING'; +export const FETCH_INCIDENTS_SUCCESS = 'FETCH_INCIDENTS_SUCCESS'; +export const FETCH_INCIDENTS_FAILED = 'FETCH_INCIDENTS_FAILED'; diff --git a/client/src/store/reducers/incidentsReportReducer.js b/client/src/store/reducers/incidentsReportReducer.js new file mode 100644 index 0000000..85ca58d --- /dev/null +++ b/client/src/store/reducers/incidentsReportReducer.js @@ -0,0 +1,38 @@ +import { + FETCH_INCIDENTS_PENDING, + FETCH_INCIDENTS_SUCCESS, + FETCH_INCIDENTS_FAILED, +} from '../constants'; + +const initialState = { + pending: false, + result: null, + error: null, +}; + +export const incidentsReport = (state, action) => { + state = state || initialState; + action = action || {}; + + switch(action.type){ + case FETCH_INCIDENTS_PENDING: + return Object.assign({}, state, { + pending: true, + error: null, + }); + case FETCH_INCIDENTS_SUCCESS: + return Object.assign({}, state, { + pending: false, + result: action.payload, + error: null, + }); + case FETCH_INCIDENTS_FAILED: + return Object.assign({}, state, { + pending: false, + result: {}, + error: action.payload, + }); + default: + return state; + } +}; diff --git a/client/src/store/reducers/index.js b/client/src/store/reducers/index.js index ed2a547..3c060be 100644 --- a/client/src/store/reducers/index.js +++ b/client/src/store/reducers/index.js @@ -1,12 +1,14 @@ -import { combineReducers } from "redux"; +import { combineReducers } from 'redux'; -import { doorLockData} from "./doorLockReducers"; -import { mappingsData } from "./mappingsReducer"; +import { doorLockData} from './doorLockReducers'; +import { mappingsData } from './mappingsReducer'; import { addMapping } from './addMappingReducer'; +import { incidentsReport } from './incidentsReportReducer'; export const rootReducer = combineReducers({ doorLockData, mappingsData, addMapping, + incidentsReport, });