Multiple bug fixes / Select summary report for month instead of whole date

This commit is contained in:
Senad Uka
2019-08-27 05:53:59 +02:00
parent 1447d800bf
commit 2403b57060
8 changed files with 166 additions and 187 deletions

View File

@@ -1,140 +0,0 @@
import React, { Component } from 'react';
import moment from 'moment';
import { Form, Message, Grid } 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 { inlineButton } = this.props;
const buttonLabel = this.props.buttonLabel || 'Save';
const startDateValue = startDate.format(defaultDateFormat);
const endDateValue = endDate.format(defaultDateFormat);
const buttonRender = (
<Grid.Column width={inlineButton ? 3 : null}>
{ inlineButton && <label>{'\u00A0'}</label> }
<Form.Button onClick={this.onButtonClick.bind(this)}>{buttonLabel}</Form.Button>
</Grid.Column>
);
return (
<Form>
<Grid stackable columns={inlineButton ? null : 'equal'}>
<Grid.Row>
<Grid.Column width={inlineButton ? 7 : null}>
<label>{startDateLabel}</label>
<Form.Input
fluid
required
type="date"
value={startDateValue}
onChange={this.onStartDateChange.bind(this)}
/>
</Grid.Column>
<Grid.Column width={inlineButton ? 6 : null}>
<label>{endDateLabel}</label>
<Form.Input
fluid
required
type="date"
value={endDateValue}
onChange={this.onEndDateChange.bind(this)}
/>
</Grid.Column>
{
inlineButton && buttonRender
}
</Grid.Row>
{ error &&
<Grid.Row>
<Grid.Column>
<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>
</Grid.Column>
</Grid.Row>
}
{
!inlineButton &&
<Grid.Row>
{buttonRender}
</Grid.Row>
}
</Grid>
</Form>
);
}
}
export default DateRangePicker;

View File

@@ -0,0 +1,120 @@
import React, { Component } from 'react';
import moment from 'moment';
import { Form, Grid } from 'semantic-ui-react';
import { defaultDateFormat } from '../../constants/constants';
class MonthSelector extends Component {
constructor(props) {
super(props);
const initialDateTime = moment();
const initialMonth = (initialDateTime.month() === 0) ? 11 : initialDateTime.month() - 1;
const initialYear = (initialDateTime.month() === 0) ? initialDateTime.year() - 1 : initialDateTime.year();
this.state = {
month: initialMonth,
year: initialYear,
monthLabel: props.monthLabel || 'Month',
yearLabel: props.yearLabel || 'Year',
};
}
onMonthSelectionChange = (event, data) => {
const newMonthValue = data.value;
this.setState({month: newMonthValue});
};
onYearChange = (event) => {
const newYearValue = event.target.value ? parseInt(event.target.value) : this.state.year;
this.setState({year: newYearValue});
};
onButtonClick() {
const { onDatesUpdate } = this.props;
const { month, year } = this.state;
const monthYearMoment = moment().month(month).year(year);
if (onDatesUpdate){
onDatesUpdate({
startDate: monthYearMoment.clone().startOf('month').format(defaultDateFormat),
endDate: monthYearMoment.clone().endOf('month').format(defaultDateFormat),
});
}
}
componentDidMount() {
this.onButtonClick();
}
render() {
const { month, year, monthLabel, yearLabel } = this.state;
const { inlineButton } = this.props;
const buttonLabel = this.props.buttonLabel || 'Save';
const buttonRender = (
<Grid.Column width={inlineButton ? 3 : null}>
{ inlineButton && <label>{'\u00A0'}</label> }
<Form.Button onClick={this.onButtonClick.bind(this)}>{buttonLabel}</Form.Button>
</Grid.Column>
);
const monthDropdownOptions = [
{value: 0, text: 'January'},
{value: 1, text: 'February'},
{value: 2, text: 'March'},
{value: 3, text: 'April'},
{value: 4, text: 'May'},
{value: 5, text: 'June'},
{value: 6, text: 'July'},
{value: 7, text: 'August'},
{value: 8, text: 'September'},
{value: 9, text: 'October'},
{value: 10, text: 'November'},
{value: 11, text: 'December'},
];
return (
<Form>
<Grid stackable columns={inlineButton ? null : 'equal'}>
<Grid.Row>
<Grid.Column width={inlineButton ? 7 : null}>
<label>{monthLabel}</label>
<Form.Dropdown
options={monthDropdownOptions}
fluid
selection
defaultValue={month}
onChange={this.onMonthSelectionChange}
/>
</Grid.Column>
<Grid.Column width={inlineButton ? 6 : null}>
<label>{yearLabel}</label>
<Form.Input
fluid
required
type="number"
value={year}
onChange={this.onYearChange}
/>
</Grid.Column>
{
inlineButton && buttonRender
}
</Grid.Row>
{
!inlineButton &&
<Grid.Row>
{buttonRender}
</Grid.Row>
}
</Grid>
</Form>
);
}
}
export default MonthSelector;

View File

@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { Container } from 'semantic-ui-react';
import MainMenu from '../../components/MainMenu';
import DateRangePicker from '../../components/DateRangePicker';
import MonthSelector from '../../components/MonthSelector';
import MemberIncidentsTables from '../../components/MemberIncidentsTables';
import GenerateFeesInORDButton from '../../components/GenerateFeesInORDButton';
@@ -38,7 +38,7 @@ class IncidentsReport extends Component {
<MainMenu/>
<h3>Incidents Report</h3>
<hr/>
<DateRangePicker buttonLabel="Show report" onDatesUpdate={this.onDatesUpdate} inlineButton />
<MonthSelector buttonLabel="Show report" onDatesUpdate={this.onDatesUpdate} inlineButton />
<br/>
<GenerateFeesInORDButton
memberIds={memberIds}

View File

@@ -33,7 +33,7 @@ class MemberSelector extends Component {
return (
<Form>
<label>{'\u00A0'}</label>
<label>{'Member name'}</label>
<Dropdown
options={dropdownOptions}
placeholder="Select Member"

View File

@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { Container, Grid } from 'semantic-ui-react';
import MainMenu from '../../components/MainMenu';
import DateRangePicker from '../../components/DateRangePicker';
import MonthSelector from '../../components/MonthSelector';
import MemberSelector from './components/MemberSelector';
import MemberSummary from './components/MemberSummary';
import MemberIncidentsTables from '../../components/MemberIncidentsTables';
@@ -58,7 +58,7 @@ class SpecificMemberIncidentsReport extends Component {
<MemberSelector onMemberSelect={this.onMemberSelectionUpdate.bind(this)} defaultMemberId={memberId} />
</Grid.Column>
<Grid.Column>
<DateRangePicker inlineButton onDatesUpdate={this.onDateRangeUpdate.bind(this)}/>
<MonthSelector inlineButton onDatesUpdate={this.onDateRangeUpdate.bind(this)}/>
</Grid.Column>
</Grid.Row>
<Grid.Row>

View File

@@ -91,8 +91,8 @@ incidentTypeExplanations[incidentType.UNSCHEDULED_INCIDENT_BEFORE_RESERVATION]
incidentTypeExplanations[incidentType.UNSCHEDULED_INCIDENT_AFTER_RESERVATION] = 'Room used after reservation ended';
incidentTypeExplanations[incidentType.UNSCHEDULED_INCIDENT_STANDALONE] = 'Room used without reservation';
incidentTypeExplanations[incidentType.BOOKING_MOVED_TO_ANOTHER_DAY] = 'Reservation moved to another day';
incidentTypeExplanations[incidentType.BOOKING_SHORTENED] = 'Reservation shortened';
incidentTypeExplanations[incidentType.BOOKING_CANCELED_LATE] = 'A reservation canceled after the grace period';
incidentTypeExplanations[incidentType.BOOKING_SHORTENED] = 'Reservation shortened after grace period';
incidentTypeExplanations[incidentType.BOOKING_CANCELED_LATE] = 'Reservation cancelled after grace period';
const UI_TIMEZONE = process.env.UI_TIMEZONE || 'America/Los_Angeles';

View File

@@ -36,7 +36,7 @@ const createFeeFromIncident = (incident) => {
} = incident;
const incidentTypeNumber = incident.incidentType;
const incidentExplanation = incidentTypeExplanations[incidentTypeNumber];
let incidentExplanation = incidentTypeExplanations[incidentTypeNumber];
let date = '';
let price = 0;
@@ -65,10 +65,10 @@ const createFeeFromIncident = (incident) => {
switch (incidentTypeNumber){
case incidentType.UNLOCKED_INCIDENT_RELATED_WITH_RESERVATION:
roomExplanation = resourceName;
dateExplanation = bookingStartMoment.clone().startOf('day').format('ddd, MMM DD');
bookingTimeExplanation = `${bookingStartMoment.clone().format('HH:mm a')} - ${bookingEndMoment.clone().format('HH:mm a')}`;
dateExplanation = bookingStartMoment.clone().startOf('day').format('MMM DD');
bookingTimeExplanation = `[${bookingStartMoment.clone().format('HH:mm')} to ${bookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ''; // `UNLOCK : ${unlockMoment.clone().format('HH:mm a')}`;
additionalIncidentExplanation = ` ${unlockedIncidentLevelsPrices[incidentLevel].description},`;
incidentExplanation += ` ${unlockedIncidentLevelsPrices[incidentLevel].description},`;
incidentTypeExplanation = '';
date = bookingStartMoment.clone().startOf('day').format();
@@ -79,8 +79,8 @@ const createFeeFromIncident = (incident) => {
break;
case incidentType.UNSCHEDULED_INCIDENT_BEFORE_RESERVATION:
roomExplanation = resourceName;
dateExplanation = bookingStartMoment.clone().startOf('day').format('ddd, MMM DD');
bookingTimeExplanation = `${bookingStartMoment.clone().format('HH:mm a')} - ${bookingEndMoment.clone().format('HH:mm a')}`;
dateExplanation = bookingStartMoment.clone().startOf('day').format('MMM DD');
bookingTimeExplanation = `[${bookingStartMoment.clone().format('HH:mm')} to ${bookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Unlock : ${unlockMoment.clone().format('HH:mm a')},`;
incidentTypeExplanation = '';
@@ -92,8 +92,8 @@ const createFeeFromIncident = (incident) => {
break;
case incidentType.UNSCHEDULED_INCIDENT_AFTER_RESERVATION:
roomExplanation = resourceName;
dateExplanation = bookingStartMoment.clone().startOf('day').format('ddd, MMM DD');
bookingTimeExplanation = `${bookingStartMoment.clone().format('HH:mm a')} - ${bookingEndMoment.clone().format('HH:mm a')}`;
dateExplanation = bookingStartMoment.clone().startOf('day').format('MMM DD');
bookingTimeExplanation = `[${bookingStartMoment.clone().format('HH:mm')} to ${bookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Lock : ${lockMoment.clone().format('HH:mm a')},`;
incidentTypeExplanation = '';
@@ -105,10 +105,10 @@ const createFeeFromIncident = (incident) => {
break;
case incidentType.UNLOCKED_INCIDENT_STANDALONE:
roomExplanation = resourceName;
dateExplanation = unlockMoment.clone().startOf('day').format('ddd, MMM DD');
bookingTimeExplanation = `No reservation`;
dateExplanation = unlockMoment.clone().startOf('day').format('MMM DD');
bookingTimeExplanation = `[${unlockMoment.clone().format('HH:mm')} to ${lockMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ''; // `UNLOCK : ${unlockMoment.clone().format('HH:mm a')}`;
additionalIncidentExplanation = ` ${unlockedIncidentLevelsPrices[incidentLevel].description},`;
incidentExplanation += ` ${unlockedIncidentLevelsPrices[incidentLevel].description},`;
incidentTypeExplanation = '';
date = unlockMoment.clone().startOf('day').format();
@@ -119,8 +119,8 @@ const createFeeFromIncident = (incident) => {
break;
case incidentType.UNSCHEDULED_INCIDENT_STANDALONE:
roomExplanation = resourceName;
dateExplanation = unlockMoment.clone().startOf('day').format('ddd, MMM DD');
bookingTimeExplanation = `No reservation`;
dateExplanation = unlockMoment.clone().startOf('day').format('MMM DD');
bookingTimeExplanation = `[${unlockMoment.clone().format('HH:mm')} to ${lockMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Unlock : ${unlockMoment.clone().format('HH:mm a')} Lock : ${lockMoment.clone().format('HH:mm a')},`;
incidentTypeExplanation = '';
@@ -131,14 +131,16 @@ const createFeeFromIncident = (incident) => {
// priceExplanation = `$${totalChargeFee.toFixed(2)}, ${quantity} x $${price.toFixed(2)}`;
break;
case incidentType.BOOKING_MOVED_TO_ANOTHER_DAY:
if (oldResourceName !== newResourceName){
roomExplanation = `${oldResourceName} -> ${newResourceName}`;
}else{
roomExplanation = oldResourceName;
}
// if (oldResourceName !== newResourceName){
// roomExplanation = `${oldResourceName} -> ${newResourceName}`;
// }else{
// roomExplanation = oldResourceName;
// }
roomExplanation = newResourceName;
dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')} -> ${newBookingStartMoment.clone().format('ddd, MMM DD')}`;
bookingTimeExplanation = `(${oldBookingStartMoment.clone().format('HH:mm a')} - ${oldBookingEndMoment.clone().format('HH:mm a')}) -> (${newBookingStartMoment.clone().format('HH:mm a')} - ${newBookingEndMoment.clone().format('HH:mm a')})`;
// dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')} -> ${newBookingStartMoment.clone().format('ddd, MMM DD')}`;
dateExplanation = `${incidentTimestampMoment.clone().format('MMM DD')}`;
bookingTimeExplanation = `[${newBookingStartMoment.clone().format('HH:mm')} to ${newBookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Moved on : ${incidentTimestampMoment.clone().format('MMM DD, HH:mm a')},`;
incidentTypeExplanation = '[Cancellation]';
@@ -149,14 +151,16 @@ const createFeeFromIncident = (incident) => {
// priceExplanation = `$${totalChargeFee.toFixed(2)}, 1 x $${price.toFixed(2)}`;
break;
case incidentType.BOOKING_SHORTENED:
if (oldResourceName !== newResourceName){
roomExplanation = `${oldResourceName} -> ${newResourceName}`;
}else{
roomExplanation = oldResourceName;
}
// if (oldResourceName !== newResourceName){
// roomExplanation = `${oldResourceName} -> ${newResourceName}`;
// }else{
// roomExplanation = oldResourceName;
// }
roomExplanation = newResourceName;
dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')}`;
bookingTimeExplanation = `(${oldBookingStartMoment.clone().format('HH:mm a')} - ${oldBookingEndMoment.clone().format('HH:mm a')}) -> (${newBookingStartMoment.clone().format('HH:mm a')} - ${newBookingEndMoment.clone().format('HH:mm a')})`;
// dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')}`;
dateExplanation = `${incidentTimestampMoment.clone().format('MMM DD')}`;
bookingTimeExplanation = `[${newBookingStartMoment.clone().format('HH:mm')} to ${newBookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Shortened on : ${incidentTimestampMoment.clone().format('MMM DD, HH:mm a')},`;
incidentTypeExplanation = '[Cancellation]';
@@ -168,8 +172,9 @@ const createFeeFromIncident = (incident) => {
break;
case incidentType.BOOKING_CANCELED_LATE:
roomExplanation = oldResourceName;
dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')}`;
bookingTimeExplanation = `${oldBookingStartMoment.clone().format('HH:mm a')} - ${oldBookingEndMoment.clone().format('HH:mm a')}`;
// dateExplanation = `${oldBookingStartMoment.clone().format('ddd, MMM DD')}`;
dateExplanation = `${incidentTimestampMoment.clone().format('MMM DD')}`;
bookingTimeExplanation = `[${oldBookingStartMoment.clone().format('HH:mm')} to ${oldBookingEndMoment.clone().format('HH:mm')}]`;
incidentTimeExplanation = ` Canceled on : ${incidentTimestampMoment.clone().format('MMM DD, HH:mm a')},`;
incidentTypeExplanation = '[Cancellation]';
@@ -181,7 +186,7 @@ const createFeeFromIncident = (incident) => {
break;
}
const formattedName = `${dateExplanation}, ${bookingTimeExplanation}, ${roomExplanation}, ${incidentExplanation}, ${officeName}`;
const formattedName = `${dateExplanation} ${bookingTimeExplanation} ${roomExplanation}, ${officeName}, ${incidentExplanation}`;
return {
name: formattedName,

View File

@@ -19,14 +19,7 @@ const deleteFeesFromORD = (dateRange, memberIds) => {
memberIdsMap[memberId] = true;
});
const deleteRequests = [];
const sendDeleteRequestPromise = (feeId) => {
return new Promise((resolve, reject) => {
API.delete(`fees/${feeId}`)
.then(() => resolve(true))
.catch(() => resolve(false));
});
};
const feeIdsToRemove = [];
fetchedFees.forEach((fee) => {
const { member, date, invoice } = fee;
@@ -35,15 +28,16 @@ const deleteFeesFromORD = (dateRange, memberIds) => {
const isDateInDateRange = startDate.isSameOrBefore(date) && endDate.isSameOrAfter(date);
if (memberIdsMap[member] && isDateInDateRange && (status === UNPAID_FEE_STATUS)) {
deleteRequests.push(sendDeleteRequestPromise(feeId));
feeIdsToRemove.push(feeId);
}
});
Promise.all(deleteRequests)
API.delete('fees', { data: feeIdsToRemove })
.then(() => {
resolve(true);
})
.catch((error) => {
console.log('error : ', error);
reject(error);
});
})