diff --git a/client/src/components/DateRangePicker/index.js b/client/src/components/DateRangePicker/index.js deleted file mode 100644 index 304ed83..0000000 --- a/client/src/components/DateRangePicker/index.js +++ /dev/null @@ -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 = ( - - { inlineButton && } - {buttonLabel} - - ); - - return ( -
- - - - - - - - - - - { - inlineButton && buttonRender - } - - { error && - - - - Wrong date -

{startDateLabel} has to be before {endDateLabel}

-
-
-
- } - { - !inlineButton && - - {buttonRender} - - } -
-
- ); - } -} - -export default DateRangePicker; diff --git a/client/src/components/MonthSelector/index.js b/client/src/components/MonthSelector/index.js new file mode 100644 index 0000000..d4f295c --- /dev/null +++ b/client/src/components/MonthSelector/index.js @@ -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 = ( + + { inlineButton && } + {buttonLabel} + + ); + + 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 ( +
+ + + + + + + + + + + { + inlineButton && buttonRender + } + + { + !inlineButton && + + {buttonRender} + + } + +
+ ); + } +} + +export default MonthSelector; diff --git a/client/src/scenes/IncidentsReport/index.js b/client/src/scenes/IncidentsReport/index.js index 40dad4b..2a2ebc6 100644 --- a/client/src/scenes/IncidentsReport/index.js +++ b/client/src/scenes/IncidentsReport/index.js @@ -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 {

Incidents Report


- +
- + - + diff --git a/constants/constants.js b/constants/constants.js index 26c3997..1a4da0c 100644 --- a/constants/constants.js +++ b/constants/constants.js @@ -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'; diff --git a/services/integration/invoiceIntegration.js b/services/integration/invoiceIntegration.js index 2a4731a..034529c 100644 --- a/services/integration/invoiceIntegration.js +++ b/services/integration/invoiceIntegration.js @@ -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, diff --git a/services/officeRnD/fees.js b/services/officeRnD/fees.js index 83ede89..bf08c11 100644 --- a/services/officeRnD/fees.js +++ b/services/officeRnD/fees.js @@ -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); }); })