Skip to content

Commit

Permalink
Create reservation rate report components
Browse files Browse the repository at this point in the history
Create component ReservationRateReportModal. This modal lies
in the /reservations page and can be unhidden/shown in
the dropdown of <Lataa Raportti> -> Varausasteraportti.

This modal will take the basic props the modal itself requires
along with units and the action which downloads the report.

Within the modal there are fields where the user can select/
input data: Units, Date range and Time range. Unit seletion field
is a Typeahead component which is also a new package. Lastly
there is the download button which when clicked, will call
the api action to download the report.

Create a container to wrap around the component in question.
  • Loading branch information
Kevin Seestrand committed Mar 1, 2022
1 parent b7d28b2 commit 681199a
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 2 deletions.
2 changes: 2 additions & 0 deletions app/pages/AppContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { fetchAuthState } from 'auth/actions';
import ReservationCancelModal from 'shared/modals/reservation-cancel';
import ReservationInfoModal from 'shared/modals/reservation-info';
import ReservationsRateReportModal from 'shared/modals/reservation-rate-report';
import ReservationSuccessModal from 'shared/modals/reservation-success';
import ResourceImagesModal from 'shared/modals/resource-images';
import ResourceInfoModal from 'shared/modals/resource-info';
Expand Down Expand Up @@ -55,6 +56,7 @@ export class UnconnectedAppContainer extends Component {
</Grid>
</Loader>
<ReservationInfoModal />
<ReservationsRateReportModal />
<ReservationCancelModal />
<ResourceImagesModal />
<ResourceInfoModal />
Expand Down
1 change: 1 addition & 0 deletions app/shared/_shared.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@import './modals/reservation-info/reservation-info';
@import './modals/reservation-success/reservation-success';
@import './modals/resource-selector/resource-selector';
@import './modals/reservation-rate-report/reservation-rate-report';
@import './navbar/navbar';
@import './recurring-reservation-controls/recurring-reservation-controls';
@import './resource-info-button/resource-info-button';
Expand Down
147 changes: 147 additions & 0 deletions app/shared/modals/reservation-rate-report/ReservationsRateReport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import FontAwesome from 'react-fontawesome';
import moment from 'moment';
import React, { Component, PropTypes } from 'react';
import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal';
import Row from 'react-bootstrap/lib/Row';
import FormGroup from 'react-bootstrap/lib/FormGroup';
import ControlLabel from 'react-bootstrap/lib/ControlLabel';
import { Typeahead } from 'react-bootstrap-typeahead';

import DatePicker from 'shared/date-picker';
import DateTimeRange from 'shared/form-fields/DateTimeRange';
import 'react-bootstrap-typeahead/css/Typeahead.css';
import 'react-bootstrap-typeahead/css/Typeahead-bs4.css';


const initialState = {
unitSelections: [],
dateStart: moment().subtract(30, 'days').format('YYYY-MM-DD'),
dateEnd: moment().format('YYYY-MM-DD'),
times: {
begin: { time: '08:00' },
end: { time: '16:00' },
},
loading: false,
};

export default class ReservationsRateReportModal extends Component {
static propTypes = {
onHide: PropTypes.func.isRequired,
show: PropTypes.bool.isRequired,
units: PropTypes.object.isRequired,
fetchReservationsRateReport: PropTypes.func.isRequired,
};

constructor(props) {
super(props);
this.state = initialState;
this.handleChange = this.handleDateChange.bind(this);
this.handleTimeChange = this.handleTimeChange.bind(this);
this.downloadReport = this.downloadReport.bind(this);
}

handleDateChange(date) {
this.setState({ ...date });
}

handleTimeChange(time) {
this.setState({ times: time });
}

downloadReport() {
this.setState({ loading: true });
this.props.fetchReservationsRateReport({
start_date: this.state.dateStart,
end_date: this.state.dateEnd,
start_time: this.state.times.begin.time,
end_time: this.state.times.end.time,
units: this.state.unitSelections.map(selection => selection.value),
}).then(() => {
this.setState({ loading: false });
}).catch(() => {
this.setState({ loading: false });
});
}

render() {
const unitOptions = Object.keys(this.props.units).map((id) => {
const unit = this.props.units[id];
return { value: unit.id, label: unit.name.fi };
});
return (
<Modal
onHide={this.props.onHide}
show={this.props.show}
>
<div className="reservations-rate-report-modal">
<Modal.Header closeButton>
<h2 className="modal-title">Varausaste raportti</h2>
</Modal.Header>
<Modal.Body>
<div className="modal-body">
<Row>
<FormGroup controlId="unit-select-control-group">
<Typeahead
multiple
options={unitOptions}
placeholder="Valitse kiinteistö"
id="unit-multi-select"
onChange={(selected) => {
this.setState({ unitSelections: selected });
}}
className="unit-multi-select"
/>
</FormGroup>
</Row>
<Row>
<FormGroup controlId="dates-control-group">
<div className="date-pickers-container">
<ControlLabel>Varaukset aikavälillä</ControlLabel>
<DatePicker
onChange={dateStart => this.handleDateChange({ dateStart })}
value={this.state.dateStart}
className="date-picker-field"
/>
<div className="delimiter">
<FontAwesome name="caret-right" />
</div>
<DatePicker
onChange={dateEnd => this.handleDateChange({ dateEnd })}
value={this.state.dateEnd}
className="date-picker-field"
/>
</div>
</FormGroup>
</Row>
<Row>
<FormGroup controlId="time-picker-control-group">
<div className="time-picker-container">
<DateTimeRange
id="reservation-time-range"
controlProps={{
renderDatePicker: false,
onChange: time => this.handleTimeChange(time),
value: this.state.times,
}}
/>
</div>
</FormGroup>
</Row>
</div>
</Modal.Body>
<Modal.Footer>
<Button
className="download-button"
onClick={this.downloadReport}
bsStyle="primary"
disabled={this.state.loading}
>
Lataa
</Button>
</Modal.Footer>
</div>
</Modal>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';

import uiActions from 'actions/uiActions';
import { fetchReservationsRateReport } from 'api/actions';
import ReservationsRateReportModal from './ReservationsRateReport';
import Selector from './ReservationsRateReportSelector';

UnconnectedReservationsRateReportModalContainer.propTypes = {
onHide: PropTypes.func.isRequired,
show: PropTypes.bool.isRequired,
units: PropTypes.object.isRequired,
fetchReservationsRateReport: PropTypes.func.isRequired,
};

export function UnconnectedReservationsRateReportModalContainer(props) {
return (
<ReservationsRateReportModal
onHide={props.onHide}
show={props.show}
units={props.units}
fetchReservationsRateReport={props.fetchReservationsRateReport}
/>
);
}

const actions = {
onHide: uiActions.hideReservationsRateReportModal,
fetchReservationsRateReport,
};

export default connect(Selector, actions)(
UnconnectedReservationsRateReportModalContainer
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.reservations-rate-report-modal {
.modal-title {
color: $black;
}
.modal-body {
box-sizing: border-box;
padding: 15px;
width: 100%;

.date-pickers-container {
display: flex;
width: 100%;

.delimiter {
display: flex;
align-items: center;
padding: 0 8px;
font-size: 32px;
}
}

.unit-multi-select {
.rbt-input-wrapper {
padding: 0 5px 0 5px;
}
}

.time-picker-container {
display: flex;
width: 100%;
}

@include input-size(
'.date-picker',
$input-height-base,
$padding-base-vertical,
$padding-base-horizontal,
$font-size-base,
$line-height-base,
$input-border-radius
);

.date-picker {
border: 2px solid $input-border;
background-color: transparent;

input {
padding: 0;
background-color: transparent;
}
}
}

.download-button {
float: left;
}
}

3 changes: 3 additions & 0 deletions app/shared/modals/reservation-rate-report/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ReservationsRateReportModalContainer from './ReservationsRateReportContainer';

export default ReservationsRateReportModalContainer;
14 changes: 12 additions & 2 deletions app/shared/reservations-report-button/ReservationsReportButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import DropdownButton from 'react-bootstrap/lib/DropdownButton';
import MenuItem from 'react-bootstrap/lib/MenuItem';

import { fetchReservationsReport } from 'api/actions';
import uiActions from 'actions/uiActions';

ReservationsReportButton.propTypes = {
onClick: PropTypes.func.isRequired,
searchFilters: PropTypes.object.isRequired,
showReservationsRateReportModal: PropTypes.func.isRequired,
};

export function ReservationsReportButton({ onClick, searchFilters }) {
export function ReservationsReportButton({
onClick, showReservationsRateReportModal, searchFilters,
}) {
return (
<div className="reservations-report-button">
<DropdownButton
Expand All @@ -21,11 +25,17 @@ export function ReservationsReportButton({ onClick, searchFilters }) {
<MenuItem onClick={() => onClick(searchFilters)} >
Varausraportti
</MenuItem>
<MenuItem onClick={showReservationsRateReportModal} >
Varausasteraportti
</MenuItem>
</DropdownButton>
</div>
);
}

const actions = { onClick: fetchReservationsReport };
const actions = {
onClick: fetchReservationsReport,
showReservationsRateReportModal: uiActions.showReservationsRateReportModal,
};

export default connect(null, actions)(ReservationsReportButton);
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"react": "15.3.2",
"react-addons-css-transition-group": "15.3.2",
"react-bootstrap": "0.30.6",
"react-bootstrap-typeahead": "3.4.7",
"react-date-picker": "git://github.com/YoYuUm/react-date-picker.git#build-readonly",
"react-document-title": "2.0.2",
"react-dom": "15.3.2",
Expand Down

0 comments on commit 681199a

Please sign in to comment.