Skip to content

Commit

Permalink
Merge pull request #901 from sharetribe/max-time-slots
Browse files Browse the repository at this point in the history
Availability improvements
  • Loading branch information
lyyder authored Aug 17, 2018
2 parents fa28faa + 09991d2 commit 324baa3
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 20 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ way to update this template, but currently, we follow a pattern:

---
## Upcoming version 2018-08-XX
* [fix] Drop date time from time slots request query params
[#901](https://github.com/sharetribe/flex-template-web/pull/901)
* [fix] Make a second time slots request when required
[#901](https://github.com/sharetribe/flex-template-web/pull/901)
* [add] Map component (used in ListingPage) using Mapbox instead of Google Maps
[#896](https://github.com/sharetribe/flex-template-web/pull/896)
* [add] Listing availability
[#868](https://github.com/sharetribe/flex-template-web/pull/868), [#873](https://github.com/sharetribe/flex-template-web/pull/873), [#891](https://github.com/sharetribe/flex-template-web/pull/891) & [#892](https://github.com/sharetribe/flex-template-web/pull/892)


* [add] Add support for user's current location as a default
suggestion in the location autocomplete search.
[#895](https://github.com/sharetribe/flex-template-web/pull/895)
Expand Down
3 changes: 2 additions & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const fetchAvailableTimeSlots = true;

// A maximum number of days forwards during which a booking can be made.
// This is limited due to Stripe holding funds up to 90 days from the
// moment they are charged.
// moment they are charged. Also note that available time slots can only
// be fetched for 180 days in the future.
const dayCountAvailableForBooking = 90;

// To pass environment variables to the client app in the build
Expand Down
68 changes: 51 additions & 17 deletions src/containers/ListingPage/ListingPage.duck.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const initialState = {
reviews: [],
fetchReviewsError: null,
timeSlots: null,
fetchTimesLotsError: null,
fetchTimeSlotsError: null,
sendEnquiryInProgress: false,
sendEnquiryError: null,
enquiryModalOpenForListingId: null,
Expand Down Expand Up @@ -185,13 +185,56 @@ export const fetchReviews = listingId => (dispatch, getState, sdk) => {
});
};

export const fetchTimeSlots = params => (dispatch, getState, sdk) => {
const timeSlotsRequest = params => (dispatch, getState, sdk) => {
return sdk.timeslots.query(params).then(response => {
return denormalisedResponseEntities(response);
});
};

export const fetchTimeSlots = listingId => (dispatch, getState, sdk) => {
dispatch(fetchTimeSlotsRequest);
return sdk.timeslots
.query(params)
.then(response => {
const timeSlots = denormalisedResponseEntities(response);
dispatch(fetchTimeSlotsSuccess(timeSlots));

// Time slots can be fetched for 90 days at a time,
// for at most 180 days from now. If max number of bookable
// day exceeds 90, a second request is made.

const maxTimeSlots = 90;
// booking range: today + bookable days -1
const bookingRange = config.dayCountAvailableForBooking - 1;
const timeSlotsRange = Math.min(bookingRange, maxTimeSlots);

const start = moment
.utc()
.startOf('day')
.toDate();
const end = moment()
.utc()
.startOf('day')
.add(timeSlotsRange, 'days')
.toDate();
const params = { listingId, start, end };

return dispatch(timeSlotsRequest(params))
.then(timeSlots => {
const secondRequest = bookingRange > maxTimeSlots;

if (secondRequest) {
const secondRange = Math.min(maxTimeSlots, bookingRange - maxTimeSlots);
const secondParams = {
listingId,
start: end,
end: moment(end)
.add(secondRange, 'days')
.toDate(),
};

return dispatch(timeSlotsRequest(secondParams)).then(secondBatch => {
const combined = timeSlots.concat(secondBatch);
dispatch(fetchTimeSlotsSuccess(combined));
});
} else {
dispatch(fetchTimeSlotsSuccess(timeSlots));
}
})
.catch(e => {
dispatch(fetchTimeSlotsError(storableError(e)));
Expand Down Expand Up @@ -231,18 +274,9 @@ export const loadData = (params, search) => dispatch => {
}

if (config.fetchAvailableTimeSlots) {
// fetch time slots for 90 days starting today
// as the booking can only be done for 90 days
// in the future due to Stripe limitations
const start = moment().toDate();
const end = moment()
.add(config.dayCountAvailableForBooking, 'days')
.toDate();
const timeSlotsParams = { listingId, start, end };

return Promise.all([
dispatch(showListing(listingId)),
dispatch(fetchTimeSlots(timeSlotsParams)),
dispatch(fetchTimeSlots(listingId)),
dispatch(fetchReviews(listingId)),
]);
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/containers/ListingPage/ListingPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export class ListingPageComponent extends Component {
sendEnquiryInProgress,
sendEnquiryError,
timeSlots,
fetchTimeSlotsError,
categoriesConfig,
amenitiesConfig,
} = this.props;
Expand Down Expand Up @@ -479,6 +480,7 @@ export class ListingPageComponent extends Component {
handleMobileBookModalClose={handleMobileBookModalClose}
onManageDisableScrolling={onManageDisableScrolling}
timeSlots={timeSlots}
fetchTimeSlotsError={fetchTimeSlotsError}
/>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions src/containers/ListingPage/SectionBooking.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ const SectionBooking = props => {
handleMobileBookModalClose,
onManageDisableScrolling,
timeSlots,
fetchTimeSlotsError,
} = props;
const showClosedListingHelpText = listing.id && isClosed;

return (
<div>
<ModalInMobile
Expand Down Expand Up @@ -70,6 +72,7 @@ const SectionBooking = props => {
price={price}
isOwnListing={isOwnListing}
timeSlots={timeSlots}
fetchTimeSlotsError={fetchTimeSlotsError}
/>
) : null}
</ModalInMobile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ exports[`ListingPage matches snapshot 1`] = `
</div>
<SectionBooking
authorDisplayName="user-1 display name"
fetchTimeSlotsError={null}
formattedPrice={55}
handleBookButtonClick={[Function]}
handleBookingSubmit={[Function]}
Expand Down
10 changes: 10 additions & 0 deletions src/forms/BookingDatesForm/BookingDatesForm.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@
display: inline-block;
}

.timeSlotsError {
@apply --marketplaceH4FontStyles;
color: var(--failColor);
margin: 0 24px 12px 24px;

@media (--viewportMedium) {
margin: 0 0 12px 0;
}
}

.smallPrint {
@apply --marketplaceTinyFontStyles;
color: var(--matterColorAnti);
Expand Down
7 changes: 7 additions & 0 deletions src/forms/BookingDatesForm/BookingDatesForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export class BookingDatesFormComponent extends Component {
unitType,
values,
timeSlots,
fetchTimeSlotsError,
} = fieldRenderProps;
const { startDate, endDate } = values && values.bookingDates ? values.bookingDates : {};

Expand All @@ -100,6 +101,11 @@ export class BookingDatesFormComponent extends Component {
const endDateErrorMessage = intl.formatMessage({
id: 'FieldDateRangeInput.invalidEndDate',
});
const timeSlotsError = fetchTimeSlotsError ? (
<p className={css.timeSlotsError}>
<FormattedMessage id="BookingDatesForm.timeSlotsError" />
</p>
) : null;

// This is the place to collect breakdown estimation data. See the
// EstimatedBreakdownMaybe component to change the calculations
Expand Down Expand Up @@ -148,6 +154,7 @@ export class BookingDatesFormComponent extends Component {

return (
<Form onSubmit={handleSubmit} className={classes}>
{timeSlotsError}
<FieldDateRangeInput
className={css.bookingDates}
name="bookingDates"
Expand Down
1 change: 1 addition & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"BookingDatesForm.priceBreakdownTitle": "Booking breakdown",
"BookingDatesForm.requestToBook": "Request to book",
"BookingDatesForm.requiredDate": "Oops, make sure your date is correct!",
"BookingDatesForm.timeSlotsError": "Loading listing availability failed. Please refresh the page.",
"BookingDatesForm.youWontBeChargedInfo": "You won't be charged yet",
"CheckoutPage.bookingTimeNotAvailableMessage": "Unfortunately, the requested time is already booked.",
"CheckoutPage.errorlistingLinkText": "the sauna page",
Expand Down

0 comments on commit 324baa3

Please sign in to comment.