occasion-sdk
Version:
An SDK library that enables access to Occasion's application, providing a rich DSL for creating and managing bookings.
155 lines (127 loc) • 4.1 kB
JavaScript
// @todo Remove includes({ product: 'merchant' }) when AR supports owner assignment to has_many children
// in non-load queries
Occasion.__constructCalendar = function __constructCalendar(month, {
calendar,
monthlyTimeSlotDaysBatchSize,
monthlyTimeSlotPreloadSize,
preload,
prevPagePromise,
relation,
status,
timeZone
} = {}) {
var today = moment.tz(timeZone);
status = status || 'bookable';
var lowerRange;
if(month) {
lowerRange = month.tz(timeZone);
} else {
lowerRange = today;
}
lowerRange = lowerRange.startOf('month');
var upperRange = lowerRange.clone().endOf('month');
var numRequests = Math.ceil(upperRange.diff(lowerRange, 'days') / monthlyTimeSlotDaysBatchSize);
if(numRequests < 1) numRequests = 1;
var i = 0;
var requests = [];
var lower = lowerRange.clone();
var upper = lowerRange.clone().add(monthlyTimeSlotDaysBatchSize, 'days');
while(i < numRequests) {
if(i + 1 == numRequests) upper = upperRange.clone();
requests.push(
relation
.includes({
product: 'merchant'
})
.where({
startsAt: {
ge: lower.toDate(),
le: upper.toDate()
},
status
}).all()
);
lower.add(monthlyTimeSlotDaysBatchSize, 'days');
upper.add(monthlyTimeSlotDaysBatchSize, 'days');
i++;
}
calendar = calendar || {};
if(_.isUndefined(calendar.__currentPage)) calendar.__currentPage = 0;
if(_.isUndefined(calendar.__preloadedPages)) calendar.__preloadedPages = 0;
calendar.__preloading = true;
var currentPromise = Promise.all(requests)
.then(function(timeSlotsArray) {
var allTimeSlots = ActiveResource.Collection
.build(timeSlotsArray)
.map(function(ts) { return ts.toArray() })
.flatten();
let startDate = moment(lowerRange).startOf('month');
let endDate = moment(lowerRange).endOf('month');
var response = ActiveResource.CollectionResponse.build();
let day = startDate;
while(day.isSameOrBefore(endDate)) {
response.push({
day,
timeSlots: allTimeSlots.select((timeSlot) => { return timeSlot.startsAt.isSame(day, 'day'); })
});
day = day.clone().add(1, 'days');
}
response.hasNextPage = function() { return true; };
let commonPaginationOptions = {
calendar,
monthlyTimeSlotDaysBatchSize,
monthlyTimeSlotPreloadSize,
relation,
status,
timeZone
};
response.nextPage = function(preloadCount) {
if(!this.nextPromise) {
this.nextPromise = Occasion.__constructCalendar(
moment(upperRange).add(1, 'days').startOf('month'),
{
...commonPaginationOptions,
preload: preloadCount,
prevPagePromise: currentPromise,
},
);
}
if(_.isUndefined(preloadCount)) {
calendar.__currentPage += 1;
if(!calendar.__preloading &&
calendar.__preloadedPages <= calendar.__currentPage + monthlyTimeSlotPreloadSize / 2) {
calendar.__lastPreloadedPage.nextPage(monthlyTimeSlotPreloadSize);
}
}
return this.nextPromise;
};
if(status !== 'bookable' || (month && !month.isSame(today, 'month'))) {
response.hasPrevPage = function() { return true; };
response.prevPage = function() {
this.prevPromise = this.prevPromise || prevPagePromise ||
Occasion.__constructCalendar(
moment(lowerRange).subtract(1, 'months'),
{
...commonPaginationOptions,
preload: 0,
}
);
calendar.__currentPage -= 1;
return this.prevPromise;
};
}
if(monthlyTimeSlotPreloadSize > 0) {
if(_.isUndefined(preload)) {
response.nextPage(monthlyTimeSlotPreloadSize - 1);
} else if(preload > 0) {
response.nextPage(--preload);
} else {
calendar.__preloading = false;
}
}
calendar.__preloadedPages += 1;
calendar.__lastPreloadedPage = response;
return response;
});
return currentPromise;
};