@recras/online-booking-js
Version:
JS library for easy integration of Recras online booking and voucher sales
1,177 lines (1,170 loc) • 147 kB
JavaScript
"use strict";
function _objectValues(obj) {
var values = [];
var keys = Object.keys(obj);
for (var k = 0; k < keys.length; k++) values.push(obj[keys[k]]);
return values;
}
function _objectEntries(obj) {
var entries = [];
var keys = Object.keys(obj);
for (var k = 0; k < keys.length; k++) entries.push([keys[k], obj[keys[k]]]);
return entries;
}
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/*******************************
* Recras integration library *
* v 2.1.0 *
*******************************/
var RecrasBooking = /*#__PURE__*/function () {
function RecrasBooking() {
var _this = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, RecrasBooking);
this.datePicker = null;
this.PAYMENT_DIRECT = 'mollie';
this.PAYMENT_AFTERWARDS = 'factuur';
this.RECRAS_INFINITY = 99999; // This is used instead of "true infinity" because JSON doesn't have infinity
this.languageHelper = new RecrasLanguageHelper();
if (!(options instanceof RecrasOptions)) {
throw new Error(this.languageHelper.translate('ERR_OPTIONS_INVALID'));
}
this.options = options;
this.eventHelper = new RecrasEventHelper();
this.eventHelper.setAnalytics(this.options.getAnalytics());
this.eventHelper.setEvents(this.options.getAnalyticsEvents());
var optionsPromise = this.languageHelper.setOptions(options);
this.element = this.options.getElement();
this.element.classList.add('recras-onlinebooking');
this.fetchJson = function (url) {
return RecrasHttpHelper.fetchJson(url, _this.error);
};
this.postJson = function (url, data) {
return RecrasHttpHelper.postJson(_this.options.getApiBase() + url, data, _this.error.bind(_this));
};
if (this.options.getLocale()) {
if (!RecrasLanguageHelper.isValid(this.options.getLocale())) {
console.warn(this.languageHelper.translate('ERR_INVALID_LOCALE', {
LOCALES: RecrasLanguageHelper.validLocales.join(', ')
}));
} else {
this.languageHelper.setLocale(this.options.getLocale());
}
}
if (this.options.getPreFilledAmounts()) {
if (!this.options.isSinglePackage()) {
console.warn(this.languageHelper.translate('ERR_AMOUNTS_NO_PACKAGE'));
}
}
if (this.options.getPreFilledDate()) {
this.prefillDateIfPossible();
}
if (this.options.getPreFilledTime()) {
this.prefillTimeIfPossible();
}
RecrasCSSHelper.loadCSS('global');
RecrasCSSHelper.loadCSS('booking');
RecrasCSSHelper.loadCSS('pikaday');
this.clearAll();
this.loadingIndicatorShow(this.element);
this.promise = optionsPromise.then(function () {
return RecrasCalendarHelper.loadScript();
}).then(function () {
return _this.getTexts();
}).then(function (texts) {
_this.texts = texts;
return _this.getPackages();
}).then(function (packages) {
_this.loadingIndicatorHide();
var pck = _this.options.getPackageId();
if (_this.options.isSinglePackage()) {
if (Array.isArray(pck)) {
pck = pck[0];
}
return _this.changePackage(pck);
} else if (Array.isArray(pck) && pck.length > 1) {
packages = packages.filter(function (p) {
return pck.includes(p.id);
});
}
return _this.showPackages(packages);
});
}
return _createClass(RecrasBooking, [{
key: "prefillDateIfPossible",
value: function prefillDateIfPossible() {
var date = new Date(this.options.getPreFilledDate());
if (isNaN(date.getTime())) {
console.warn(this.languageHelper.translate('ERR_INVALID_DATE'));
return false;
}
if (date < new Date()) {
console.warn(this.languageHelper.translate('ERR_DATE_PAST'));
return false;
}
if (!this.options.isSinglePackage()) {
console.warn(this.languageHelper.translate('ERR_DATE_NO_SINGLE_PACKAGE'));
return false;
}
this.prefilledDate = date;
return true;
}
}, {
key: "prefillTimeIfPossible",
value: function prefillTimeIfPossible() {
var time = this.options.getPreFilledTime();
if (!time.match(/^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/)) {
console.warn(this.languageHelper.translate('ERR_INVALID_TIME'));
return false;
}
this.prefilledTime = time;
return true;
}
}, {
key: "hasAtLeastOneProduct",
value: function hasAtLeastOneProduct(pack) {
if (this.shouldShowBookingSize(pack) && this.bookingSize() > 0) {
return true;
}
var hasAtLeastOneProduct = false;
for (var _i2 = 0, _this$getLinesNoBooki2 = this.getLinesNoBookingSize(pack); _i2 < _this$getLinesNoBooki2.length; _i2++) {
var line = _this$getLinesNoBooki2[_i2];
var lineEl = this.findElement("[data-package-id=\"".concat(line.id, "\"]"));
if (lineEl && lineEl.value > 0) {
hasAtLeastOneProduct = true;
}
}
return hasAtLeastOneProduct;
}
}, {
key: "amountsValid",
value: function amountsValid(pack) {
for (var _i4 = 0, _this$getLinesNoBooki4 = this.getLinesNoBookingSize(pack); _i4 < _this$getLinesNoBooki4.length; _i4++) {
var line = _this$getLinesNoBooki4[_i4];
var lineEl = this.findElement("[data-package-id=\"".concat(line.id, "\"]"));
if (!lineEl) {
console.warn("Element for line ".concat(line.id, " not found"));
return false;
}
var aantal = lineEl.value;
if (aantal > 0 && aantal < line.aantal_personen) {
return false;
}
if (aantal > 0 && line.min && aantal < line.min) {
return false;
}
if (line.max && aantal > line.max) {
return false;
}
}
if (this.shouldShowBookingSize(pack) && this.bookingSize() > 0) {
if (this.bookingSize() < this.bookingSizeMinimum(pack) || this.bookingSize() > this.bookingSizeMaximum(pack)) {
return false;
}
}
return this.hasAtLeastOneProduct(pack);
}
}, {
key: "appendHtml",
value: function appendHtml(msg) {
this.element.insertAdjacentHTML('beforeend', msg);
}
}, {
key: "applyVoucher",
value: function applyVoucher(packageID, voucherCode) {
var _this2 = this;
if (!voucherCode) {
this.setDiscountStatus(this.languageHelper.translate('VOUCHER_EMPTY'));
return Promise.resolve(false);
}
if (this.appliedVouchers[voucherCode]) {
this.setDiscountStatus(this.languageHelper.translate('VOUCHER_ALREADY_APPLIED'));
return Promise.resolve(false);
}
if (!this.selectedDate) {
this.setDiscountStatus(this.languageHelper.translate('DATE_INVALID'));
return Promise.resolve(false);
}
return this.postJson('onlineboeking/controleervoucher', {
arrangement_id: packageID,
datum: RecrasDateHelper.datePartOnly(this.selectedDate),
producten: this.productCounts(),
vouchers: [voucherCode]
}).then(function (json) {
var result = json[voucherCode];
if (!result.valid) {
return Promise.resolve(false);
}
_this2.appliedVouchers[voucherCode] = result.processed;
_this2.showTotalPrice();
return true;
});
}
}, {
key: "recheckDiscountCode",
value: function recheckDiscountCode() {
var _this3 = this;
this.checkDiscountcode(this.selectedPackage.id, RecrasDateHelper.datePartOnly(this.selectedDate), this.discount.code).then(function (status) {
if (status) {
_this3.setDiscountStatus(_this3.languageHelper.translate('DISCOUNT_APPLIED'), false);
} else {
_this3.discount = null;
_this3.showTotalPrice();
var statusEl = _this3.findElement('.discount-status');
if (statusEl) {
statusEl.parentNode.removeChild(statusEl);
}
}
});
}
}, {
key: "recheckVouchers",
value: function recheckVouchers() {
var voucherCodes = Object.keys(this.appliedVouchers);
this.appliedVouchers = [];
var promises = [];
for (var _i6 = 0; _i6 < voucherCodes.length; _i6++) {
var voucherCode = voucherCodes[_i6];
promises.push(this.applyVoucher(this.selectedPackage.id, voucherCode));
}
return Promise.all(promises);
}
}, {
key: "bookingSize",
value: function bookingSize() {
var bookingSizeEl = this.findElement('.bookingsize');
if (!bookingSizeEl) {
return 0;
}
var bookingSizeValue = parseInt(bookingSizeEl.value, 10);
if (isNaN(bookingSizeValue)) {
return 0;
}
return bookingSizeValue;
}
}, {
key: "bookingSizeLines",
value: function bookingSizeLines(pack) {
return pack.regels.filter(function (line) {
return line.onlineboeking_aantalbepalingsmethode === 'boekingsgrootte';
});
}
}, {
key: "bookingSizeMaximum",
value: function bookingSizeMaximum(pack) {
var lines = this.bookingSizeLines(pack).filter(function (line) {
return line.max;
});
if (lines.length === 0) {
return this.RECRAS_INFINITY;
}
var maxes = lines.map(function (line) {
return line.max;
});
return Math.min.apply(Math, _toConsumableArray(maxes));
}
}, {
key: "bookingSizeLineMinimum",
value: function bookingSizeLineMinimum(line) {
if (line.min) {
return line.min;
}
if (line.onlineboeking_aantalbepalingsmethode === 'vast') {
return 0;
}
return line.product.minimum_aantal;
}
}, {
key: "bookingSizeMinimum",
value: function bookingSizeMinimum(pack) {
var _this4 = this;
var minSize = 0;
this.bookingSizeLines(pack).forEach(function (line) {
minSize = Math.max(minSize, _this4.bookingSizeLineMinimum(line));
});
return minSize;
}
}, {
key: "amountFromPersons",
value: function amountFromPersons(product, persons) {
return persons;
//TODO: this doesn't work yet because public product API does not send:
// aantalbepaling, aantal, per_x_personen_afronding, per_x_personen
if (product.aantalbepaling === 'vast') {
return product.aantal;
}
var fn = product.per_x_personen_afronding === 'beneden' ? Math.floor : Math.ceil;
return product.aantal * fn(persons / product.per_x_personen);
}
}, {
key: "bookingSizePrice",
value: function bookingSizePrice(pack) {
var _this5 = this;
var nrOfPersons = Math.max(pack.aantal_personen, 1);
var price = 0;
var lines = this.bookingSizeLines(pack);
lines.forEach(function (line) {
price += Math.max(_this5.amountFromPersons(line.product, nrOfPersons), line.product.minimum_aantal) * parseFloat(line.product.verkoop);
});
return price / nrOfPersons;
}
}, {
key: "filterPackagesFromoptions",
value: function filterPackagesFromoptions(packages) {
var pck = this.options.getPackageId();
if (!Array.isArray(pck)) {
return packages;
}
return packages.filter(function (p) {
return pck.includes(p.id);
});
}
}, {
key: "changePackage",
value: function changePackage(packageID) {
var _this6 = this;
var selectedPackage = this.packages.filter(function (p) {
return p.id === packageID;
});
this.appliedVouchers = {};
this.discount = null;
if (selectedPackage.length === 0) {
// Reset form
this.selectedPackage = null;
this.clearAll();
var packages = this.filterPackagesFromoptions(this.packages);
this.showPackages(packages);
this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_RESET);
return Promise.resolve(false);
} else {
this.clearAllExceptPackageSelection();
this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_PACKAGE_CHANGED, selectedPackage[0].arrangement, selectedPackage[0].id, {
content_type: 'package',
item_id: selectedPackage[0].id
});
}
this.selectedPackage = selectedPackage[0];
return this.showProducts(this.selectedPackage).then(function () {
_this6.nextSectionActive('.recras-package-select', '.recras-amountsform');
_this6.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_PRODUCTS_SHOWN);
if (_this6.options.getAutoScroll() === true) {
var scrollOptions = {
behavior: 'smooth'
};
if (!('scrollBehavior' in document.documentElement.style)) {
scrollOptions = true;
}
_this6.findElement('.recras-amountsform').scrollIntoView(scrollOptions);
}
_this6.checkDependencies();
_this6.loadingIndicatorShow(_this6.findElement('.recras-amountsform'));
return _this6.showDateTimeSelection(_this6.selectedPackage);
}).then(function () {
_this6.loadingIndicatorHide();
_this6.showContactForm(_this6.selectedPackage);
});
}
}, {
key: "checkBookingSize",
value: function checkBookingSize(pack) {
if (!this.shouldShowBookingSize(pack)) {
return;
}
var bookingSize = this.bookingSize();
var bsMaximum = this.bookingSizeMaximum(pack);
var bsMinimum = this.bookingSizeMinimum(pack);
if (bookingSize < bsMinimum) {
this.setMinMaxAmountWarning('bookingsize', bsMinimum, 'minimum');
} else if (bookingSize > bsMaximum) {
this.setMinMaxAmountWarning('bookingsize', bsMaximum, 'maximum');
}
this.maybeDisableBookButton();
}
}, {
key: "checkDependencies",
value: function checkDependencies() {
var _this7 = this;
_toConsumableArray(this.findElements('.recras-product-dependency')).forEach(function (el) {
el.parentNode.removeChild(el);
});
_toConsumableArray(this.findElements('[data-package-id]')).forEach(function (el) {
el.classList.remove('recras-input-invalid');
});
this.requiresProduct = false;
this.productCounts().forEach(function (line) {
if (line.aantal > 0) {
var packageLineID = line.arrangementsregel_id;
var product = _this7.findProduct(packageLineID).product;
var thisProductRequiresProduct = false;
if (!product.vereist_product) {
console.warn('You are logged in to this particular Recras. Because of API differences between logged-in and logged-out state, required products do not work as expected.');
} else {
product.vereist_product.forEach(function (vp) {
if (!_this7.dependencySatisfied(line.aantal, vp)) {
thisProductRequiresProduct = true;
_this7.requiresProduct = true;
var requiredAmount = _this7.requiredAmount(line.aantal, vp);
var requiredProductName = _this7.getProductByID(vp.vereist_product_id).weergavenaam;
var message = _this7.languageHelper.translate('PRODUCT_REQUIRED', {
NUM: line.aantal,
PRODUCT: product.weergavenaam,
REQUIRED_AMOUNT: requiredAmount,
REQUIRED_PRODUCT: requiredProductName
});
_this7.findElement('.recras-amountsform').insertAdjacentHTML('beforeend', "<span class=\"recras-product-dependency\">".concat(message, "</span>"));
}
});
}
if (thisProductRequiresProduct) {
var productInput = _this7.findElement("[data-package-id=\"".concat(packageLineID, "\"]"));
productInput.classList.add('recras-input-invalid');
}
}
});
this.maybeDisableBookButton();
}
}, {
key: "checkDiscountAndVoucher",
value: function checkDiscountAndVoucher() {
var _this8 = this;
var discountPromise = this.checkDiscountcode(this.selectedPackage.id, RecrasDateHelper.datePartOnly(this.selectedDate), this.findElement('#discountcode').value.trim());
var voucherPromise = this.applyVoucher(this.selectedPackage.id, this.findElement('#discountcode').value.trim());
Promise.all([discountPromise, voucherPromise]).then(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
discountStatus = _ref2[0],
voucherStatus = _ref2[1];
if (discountStatus || voucherStatus) {
var status;
if (discountStatus) {
status = 'DISCOUNT_APPLIED';
} else {
status = 'VOUCHER_APPLIED';
}
_this8.setDiscountStatus(_this8.languageHelper.translate(status), false);
_this8.findElement('#discountcode').value = '';
_this8.nextSectionActive('.recras-discounts', '.recras-contactform');
} else {
_this8.setDiscountStatus(_this8.languageHelper.translate('DISCOUNT_INVALID'));
}
});
}
}, {
key: "checkDiscountcode",
value: function checkDiscountcode(packageID, date, code) {
var _this9 = this;
return this.fetchJson(this.options.getApiBase() + 'onlineboeking/controleerkortingscode' + '?datum=' + date + '&arrangement=' + packageID + '&kortingscode=' + encodeURIComponent(code)).then(function (discount) {
if (discount === false) {
return false;
}
discount.code = code;
_this9.discount = discount;
_this9.showTotalPrice();
return true;
});
}
}, {
key: "checkMaximumForPackage",
value: function checkMaximumForPackage() {
var _this0 = this;
var maxPerLine = this.selectedPackage.maximum_aantal_personen_online;
if (maxPerLine === null) {
return Promise.resolve(null);
}
var showWarning = false;
var selectedProducts = this.productCounts();
return this.languageHelper.filterTags(this.texts.maximum_aantal_online_boeking_overschreden, this.selectedPackage ? this.selectedPackage.id : null).then(function (msg) {
selectedProducts.forEach(function (p) {
if (p.aantal > maxPerLine && !showWarning) {
var input = _this0.findElement("[data-package-id=\"".concat(p.arrangementsregel_id, "\"]"));
if (!input) {
input = _this0.findElement('#bookingsize');
}
if (input) {
var warningEl = document.createElement('div');
warningEl.classList.add('maximum-amount');
warningEl.classList.add('recras-full-width');
warningEl.innerHTML = msg;
input.parentNode.parentNode.insertBefore(warningEl, input.parentNode.nextSibling);
input.classList.add('recras-input-invalid');
} else {
_this0.findElement('.recras-amountsform').insertAdjacentHTML('beforeend', "<span class=\"maximum-amount\">".concat(msg, "</span>"));
}
showWarning = true;
}
});
});
}
}, {
key: "contactFormValid",
value: function contactFormValid() {
var contactFormIsValid = this.findElement('.recras-contactform').checkValidity();
var contactFormRequiredCheckboxes = this.contactForm.checkRequiredCheckboxes();
return contactFormIsValid && contactFormRequiredCheckboxes;
}
}, {
key: "setMinMaxAmountWarning",
value: function setMinMaxAmountWarning(lineID, minAmount) {
var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'minimum';
var warnEl = document.createElement('span');
warnEl.classList.add(type + '-amount');
var lineEl = this.findElement("#".concat(lineID));
if (!lineEl) {
console.warn("Element for line ".concat(lineID, " not found"));
return false;
}
lineEl.classList.add('recras-input-invalid');
var text;
if (type === 'minimum') {
text = this.languageHelper.translate('PRODUCT_MINIMUM', {
MINIMUM: minAmount
});
} else {
text = this.languageHelper.translate('PRODUCT_MAXIMUM', {
MAXIMUM: minAmount
});
}
warnEl.innerHTML = text;
var label = this.findElement("label[for=\"".concat(lineID, "\"]"));
label.parentNode.appendChild(warnEl);
}
}, {
key: "checkMinMaxAmounts",
value: function checkMinMaxAmounts() {
for (var _i8 = 0, _this$productCounts2 = this.productCounts(); _i8 < _this$productCounts2.length; _i8++) {
var product = _this$productCounts2[_i8];
if (product.aantal < 1) {
continue;
}
var packageLineID = product.arrangementsregel_id;
var packageLine = this.findProduct(packageLineID);
var input = this.findElement("[data-package-id=\"".concat(packageLineID, "\"]"));
if (!input) {
// This is a "booking size" line - this is handled in checkBookingSize
continue;
}
if (product.aantal < packageLine.product.minimum_aantal) {
this.setMinMaxAmountWarning(input.id, packageLine.product.minimum_aantal, 'minimum');
} else if (packageLine.min !== undefined && product.aantal < packageLine.min) {
this.setMinMaxAmountWarning(input.id, packageLine.min, 'minimum');
} else if (packageLine.max !== null && product.aantal > packageLine.max) {
this.setMinMaxAmountWarning(input.id, packageLine.max, 'maximum');
}
}
}
}, {
key: "clearAll",
value: function clearAll() {
this.clearElements(this.element.children);
}
}, {
key: "clearAllExceptPackageSelection",
value: function clearAllExceptPackageSelection() {
var packageSelect = this.findElement('.recras-package-select');
if (packageSelect) {
packageSelect.classList.remove('recras-completed');
packageSelect.classList.add('recras-active');
}
var elements = document.querySelectorAll('#' + this.element.id + ' > *:not(.recras-package-select)');
this.clearElements(elements);
}
}, {
key: "clearElements",
value: function clearElements(elements) {
if (this.datePicker) {
this.datePicker.destroy();
}
this.availableDays = [];
_toConsumableArray(elements).forEach(function (el) {
el.parentNode.removeChild(el);
});
this.maybeAddLatestErrorElement();
}
}, {
key: "dependencySatisfied",
value: function dependencySatisfied(hasNow, requiredProduct) {
for (var _i0 = 0, _this$productCounts4 = this.productCounts(); _i0 < _this$productCounts4.length; _i0++) {
var line = _this$productCounts4[_i0];
if (line.aantal === 0) {
continue;
}
var product = this.findProduct(line.arrangementsregel_id).product;
if (product.id !== parseInt(requiredProduct.vereist_product_id, 10)) {
continue;
}
var requiredAmount = this.requiredAmount(hasNow, requiredProduct);
return line.aantal >= requiredAmount;
}
return false;
}
}, {
key: "error",
value: function error(msg) {
this.loadingIndicatorHide();
var bookingErrorsEl = this.findElement('#bookingErrors');
if (bookingErrorsEl) {
bookingErrorsEl.parentNode.appendChild(this.findElement('.latestError'));
}
this.maybeAddLatestErrorElement();
this.findElement('.latestError').innerHTML = "<strong>".concat(this.languageHelper.translate('ERR_GENERAL'), "</strong><p>").concat(msg, "</p>");
}
}, {
key: "findElement",
value: function findElement(querystring) {
return this.element.querySelector(querystring);
}
}, {
key: "findElements",
value: function findElements(querystring) {
return this.element.querySelectorAll(querystring);
}
}, {
key: "findProduct",
value: function findProduct(packageLineID) {
return this.selectedPackage.regels.filter(function (line) {
return line.id === packageLineID;
})[0];
}
}, {
key: "formatPrice",
value: function formatPrice(price) {
return this.languageHelper.formatPrice(price);
}
}, {
key: "getAvailableDays",
value: function getAvailableDays(packageID, begin, end) {
var _this1 = this;
var postData = {
arrangement_id: packageID,
begin: RecrasDateHelper.datePartOnly(begin),
eind: RecrasDateHelper.datePartOnly(end),
producten: this.productCountsNoBookingSize()
};
if (this.shouldShowBookingSize(this.selectedPackage)) {
postData.boekingsgrootte = this.bookingSize();
}
return this.postJson('onlineboeking/beschikbaredagen', postData).then(function (json) {
_this1.availableDays = _this1.availableDays.concat(json);
return _this1.availableDays;
});
}
}, {
key: "getAvailableTimes",
value: function getAvailableTimes(packageID, date) {
var _this10 = this;
return this.postJson('onlineboeking/beschikbaretijden', {
arrangement_id: packageID,
datum: RecrasDateHelper.datePartOnly(date),
producten: this.productCounts()
}).then(function (json) {
_this10.availableTimes = json;
return _this10.availableTimes;
});
}
}, {
key: "getContactForm",
value: function getContactForm(pack) {
var _this11 = this;
this.options.setOption('form_id', pack.onlineboeking_contactformulier_id);
var contactForm = new RecrasContactForm(this.options);
return contactForm.getContactFormFields().then(function () {
_this11.contactForm = contactForm;
return contactForm;
});
}
}, {
key: "getDiscountPrice",
value: function getDiscountPrice(discount) {
if (!discount) {
return 0;
}
return discount.percentage / 100 * this.getSubTotal() * -1;
}
}, {
key: "getLinesBookingSize",
value: function getLinesBookingSize(pack) {
return pack.regels.filter(function (line) {
return line.onlineboeking_aantalbepalingsmethode === 'boekingsgrootte';
});
}
}, {
key: "getLinesNoBookingSize",
value: function getLinesNoBookingSize(pack) {
return pack.regels.filter(function (line) {
return line.onlineboeking_aantalbepalingsmethode !== 'boekingsgrootte';
});
}
}, {
key: "getPackages",
value: function getPackages() {
var _this12 = this;
return this.fetchJson(this.options.getApiBase() + 'arrangementen').then(function (json) {
_this12.packages = json;
return _this12.packages;
});
}
}, {
key: "getProductByID",
value: function getProductByID(id) {
var products = this.selectedPackage.regels.map(function (r) {
return r.product;
});
return products.filter(function (p) {
return p.id === id;
})[0];
}
}, {
key: "getSubTotal",
value: function getSubTotal() {
var _this13 = this;
var total = 0;
this.productCounts().forEach(function (line) {
var product = _this13.findProduct(line.arrangementsregel_id).product;
var aantal = line.aantal;
if (isNaN(aantal)) {
aantal = 0;
}
total += aantal * parseFloat(product.verkoop);
});
return total;
}
}, {
key: "getSetting",
value: function getSetting(settingName) {
return this.fetchJson(this.options.getApiBase() + 'instellingen/' + settingName);
}
}, {
key: "getTexts",
value: function getTexts() {
var settings = ['maximum_aantal_online_boeking_overschreden', 'online_boeking_betaalkeuze', 'online_boeking_betaalkeuze_achteraf_titel', 'online_boeking_betaalkeuze_ideal_titel', 'online_boeking_step0_text_pre', 'online_boeking_step0_text_post', 'online_boeking_step1_text_pre', 'online_boeking_step1_text_post', 'online_boeking_step3_text_post'];
var promises = [];
for (var _i10 = 0; _i10 < settings.length; _i10++) {
var setting = settings[_i10];
promises.push(this.getSetting(setting));
}
return Promise.all(promises).then(function (settings) {
var texts = {};
settings.forEach(function (setting) {
texts[setting.slug] = setting.waarde;
});
return texts;
});
}
}, {
key: "getTotalPrice",
value: function getTotalPrice() {
var total = this.getSubTotal();
total += this.getDiscountPrice(this.discount);
total += this.getVouchersPrice();
return total;
}
}, {
key: "getVouchersPrice",
value: function getVouchersPrice() {
var voucherPrice = 0;
_objectValues(this.appliedVouchers).forEach(function (voucher) {
_objectValues(voucher).forEach(function (line) {
voucherPrice -= line.aantal * line.prijs_per_stuk;
});
});
return voucherPrice;
}
}, {
key: "loadingIndicatorHide",
value: function loadingIndicatorHide() {
_toConsumableArray(document.querySelectorAll('.recrasLoadingIndicator')).forEach(function (el) {
el.parentNode.removeChild(el);
});
}
}, {
key: "loadingIndicatorShow",
value: function loadingIndicatorShow(afterEl) {
if (!afterEl) {
return;
}
afterEl.insertAdjacentHTML('beforeend', "<span class=\"recrasLoadingIndicator\">".concat(this.languageHelper.translate('LOADING'), "</span>"));
}
}, {
key: "maybeAddLatestErrorElement",
value: function maybeAddLatestErrorElement() {
var errorEl = this.findElement('.latestError');
if (!errorEl) {
this.appendHtml("<div class=\"latestError\"></div>");
}
}
}, {
key: "maybeDisableBookButton",
value: function maybeDisableBookButton() {
var _this14 = this;
var button = this.findElement('.bookPackage');
if (!button) {
return false;
}
var bookingDisabledReasons = [];
if (this.requiresProduct) {
bookingDisabledReasons.push('BOOKING_DISABLED_REQUIRED_PRODUCT');
}
if (!this.amountsValid(this.selectedPackage)) {
bookingDisabledReasons.push('BOOKING_DISABLED_AMOUNTS_INVALID');
}
if (!this.selectedDate) {
bookingDisabledReasons.push('BOOKING_DISABLED_INVALID_DATE');
}
if (!this.selectedTime) {
bookingDisabledReasons.push('BOOKING_DISABLED_INVALID_TIME');
}
if (!this.contactFormValid()) {
bookingDisabledReasons.push('BOOKING_DISABLED_CONTACT_FORM_INVALID');
}
var agreeEl = this.findElement('#recrasAgreeToAttachments');
if (agreeEl && !agreeEl.checked) {
bookingDisabledReasons.push('BOOKING_DISABLED_AGREEMENT');
}
if (bookingDisabledReasons.length > 0) {
var reasonsList = bookingDisabledReasons.map(function (reason) {
return _this14.languageHelper.translate(reason);
}).join('<li>');
this.findElement('#bookingErrors').innerHTML = "<ul><li>".concat(reasonsList, "</ul>");
button.setAttribute('disabled', 'disabled');
} else {
this.findElement('#bookingErrors').innerHTML = '';
button.removeAttribute('disabled');
}
}
}, {
key: "nextSectionActive",
value: function nextSectionActive(completedQuery, activeQuery) {
if (completedQuery && this.findElement(completedQuery)) {
this.findElement(completedQuery).classList.add('recras-completed');
this.findElement(completedQuery).classList.remove('recras-active');
}
//TODO: remove active from all sections? Test with invalid amount
if (activeQuery && this.findElement(activeQuery)) {
this.findElement(activeQuery).classList.add('recras-active');
}
}
}, {
key: "normaliseDate",
value: function normaliseDate(date, packageStart, bookingStart) {
var diffSeconds = (date - packageStart) / 1000;
var tempDate = new Date(bookingStart.getTime());
return new Date(tempDate.setSeconds(tempDate.getSeconds() + diffSeconds));
}
}, {
key: "paymentMethods",
value: function paymentMethods(pack) {
var methods = [];
if (pack.mag_online_geboekt_worden_direct_betalen) {
methods.push(this.PAYMENT_DIRECT);
}
if (pack.mag_online_geboekt_worden_achteraf_betalen) {
methods.push(this.PAYMENT_AFTERWARDS);
}
return methods;
}
}, {
key: "preFillAmounts",
value: function preFillAmounts(amounts) {
var _this15 = this;
_objectEntries(amounts).forEach(function (idAmount) {
var el;
if (idAmount[0] === 'bookingsize') {
el = _this15.findElement('#bookingsize');
} else {
el = _this15.findElement("[data-package-id=\"".concat(idAmount[0], "\"]"));
}
if (el) {
el.value = idAmount[1];
_this15.updateProductPrice(el);
}
});
this.updateProductAmounts();
}
}, {
key: "previewTimes",
value: function previewTimes() {
var _this16 = this;
_toConsumableArray(this.findElements('.time-preview')).forEach(function (el) {
el.parentNode.removeChild(el);
});
if (this.selectedTime) {
var linesWithTime = this.selectedPackage.regels.filter(function (line) {
return !!line.begin;
});
var linesBegin = linesWithTime.map(function (line) {
return new Date(line.begin);
});
var packageStart = new Date(Math.min.apply(Math, _toConsumableArray(linesBegin))); // Math.min transforms dates to timestamps
var linesNoBookingSize = this.getLinesNoBookingSize(this.selectedPackage);
linesNoBookingSize.forEach(function (line, idx) {
if (line.begin !== null || line.eind !== null) {
var normalisedStart = _this16.normaliseDate(new Date(line.begin), packageStart, _this16.selectedDate);
var normalisedEnd = _this16.normaliseDate(new Date(line.eind), packageStart, _this16.selectedDate);
_this16.findElement("label[for=\"packageline".concat(idx, "\"]")).insertAdjacentHTML('afterbegin', "<span class=\"time-preview\">".concat(RecrasDateHelper.timePartOnly(normalisedStart), " \u2013 ").concat(RecrasDateHelper.timePartOnly(normalisedEnd), "</span>"));
}
});
}
}
}, {
key: "productCountsBookingSize",
value: function productCountsBookingSize() {
var _this17 = this;
return this.getLinesBookingSize(this.selectedPackage).map(function (line) {
return {
aantal: _this17.bookingSize(),
arrangementsregel_id: line.id
};
});
}
}, {
key: "productCountsNoBookingSize",
value: function productCountsNoBookingSize() {
return _toConsumableArray(this.findElements('[id^="packageline"]')).map(function (line) {
return {
aantal: isNaN(parseInt(line.value)) ? 0 : parseInt(line.value),
arrangementsregel_id: parseInt(line.dataset.packageId, 10)
};
});
}
}, {
key: "productCounts",
value: function productCounts() {
var counts = [];
counts = counts.concat(this.productCountsNoBookingSize());
counts = counts.concat(this.productCountsBookingSize());
return counts;
}
}, {
key: "removeWarnings",
value: function removeWarnings() {
_toConsumableArray(this.findElements('.booking-error:not(#bookingErrors)')).forEach(function (el) {
el.parentNode.removeChild(el);
});
_toConsumableArray(this.findElements('.minimum-amount')).forEach(function (el) {
el.parentNode.removeChild(el);
});
_toConsumableArray(this.findElements('.maximum-amount')).forEach(function (el) {
el.parentNode.removeChild(el);
});
_toConsumableArray(this.findElements('.recras-input-invalid')).forEach(function (el) {
el.classList.remove('recras-input-invalid');
});
_toConsumableArray(this.findElements('.recras-success')).forEach(function (el) {
el.parentNode.removeChild(el);
});
}
/**
* requiredAmount calculates the amount N needed of Y in the sentence 'product X requires N times product Y'
*
* @param {number} hasNow The amount of product X selected
* @param {object} requiredProduct
* @param {number} requiredProduct.aantal The base amount of Y required
* @param {number} requiredProduct.per_x_aantal The quantum of X that will require product Y
* @param {"boven"|"beneden"} requiredProduct.afronding Indication of how hasNow / per_x_aantal should be rounded ("boven" will round up, "beneden" will round down)
* @return {number} The amount of product Y needed
*/
}, {
key: "requiredAmount",
value: function requiredAmount(hasNow, requiredProduct) {
var requiredFraction = hasNow / requiredProduct.per_x_aantal;
if (requiredProduct.afronding === 'boven') {
requiredFraction = Math.ceil(requiredFraction);
} else {
requiredFraction = Math.floor(requiredFraction);
}
return requiredProduct.aantal * requiredFraction;
}
}, {
key: "resetForm",
value: function resetForm() {
this.changePackage(null);
}
}, {
key: "selectSingleTime",
value: function selectSingleTime() {
if (this.findElements('#recras-onlinebooking-time option[value]').length !== 1) {
return;
}
this.findElement('#recras-onlinebooking-time option[value]').selected = true;
this.findElement('#recras-onlinebooking-time').dispatchEvent(new Event('change'));
}
}, {
key: "setDiscountStatus",
value: function setDiscountStatus(statusText) {
var isError = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var statusEl = this.findElement('.discount-status');
if (!statusEl) {
this.element.querySelector('.recras-discounts').insertAdjacentHTML('beforeend', "<span class=\"discount-status\"></span>");
statusEl = this.findElement('.discount-status');
}
if (isError) {
statusEl.classList.add('booking-error');
} else {
statusEl.classList.remove('booking-error');
}
statusEl.innerHTML = statusText;
}
}, {
key: "setHtml",
value: function setHtml(msg) {
this.element.innerHTML = msg;
}
}, {
key: "showStandardAttachments",
value: function showStandardAttachments() {
if (!this.selectedPackage || !this.findElement('.standard-attachments')) {
return true;
}
var attachments = this.standardAttachments(this.selectedPackage);
var attachmentHtml = "";
if (Object.keys(attachments).length) {
attachmentHtml += "<p><label><input type=\"checkbox\" id=\"recrasAgreeToAttachments\" required>".concat(this.languageHelper.translate('AGREE_ATTACHMENTS'), "</label></p>");
attachmentHtml += "<ul>";
_objectValues(attachments).forEach(function (attachment) {
attachmentHtml += "<li><a href=\"".concat(attachment.filename, "\" download target=\"_blank\">").concat(attachment.naam, "</a></li>");
});
attachmentHtml += "</ul>";
}
this.findElement('.standard-attachments').innerHTML = attachmentHtml;
var agreeEl = this.findElement('#recrasAgreeToAttachments');
if (agreeEl) {
agreeEl.addEventListener('change', this.maybeDisableBookButton.bind(this));
}
}
}, {
key: "showTotalPrice",
value: function showTotalPrice() {
_toConsumableArray(this.findElements('.discountLine, .voucherLine, .priceWithDiscount')).forEach(function (el) {
el.parentNode.removeChild(el);
});
var html = "";
if (this.discount) {
html += "<div class=\"discountLine\"><div>".concat(this.discount.naam, "</div><div>").concat(this.formatPrice(this.getDiscountPrice(this.discount)), "</div></div>");
}
if (Object.keys(this.appliedVouchers).length) {
html += "<div class=\"voucherLine\"><div>".concat(this.languageHelper.translate('VOUCHERS_DISCOUNT'), "</div><div>").concat(this.formatPrice(this.getVouchersPrice()), "</div></div>");
}
if (this.discount || Object.keys(this.appliedVouchers).length) {
html += "<div class=\"priceWithDiscount\"><div>".concat(this.languageHelper.translate('PRICE_TOTAL_WITH_DISCOUNT'), "</div><div>").concat(this.formatPrice(this.getTotalPrice()), "</div></div>");
}
var elementToInsertBefore = this.findElement('.recras-amountsform p:last-of-type');
if (elementToInsertBefore) {
elementToInsertBefore.insertAdjacentHTML('beforebegin', html);
}
var subtotalEl = this.findElement('.priceSubtotal');
if (subtotalEl) {
subtotalEl.innerHTML = this.formatPrice(this.getSubTotal());
}
}
}, {
key: "sortPackages",
value: function sortPackages(packages) {
// Packages from the API are sorted by internal name, not by display name
// However, display name is not required so fallback to internal name
return packages.sort(function (a, b) {
var aName = a.weergavenaam || a.arrangement;
var bName = b.weergavenaam || b.arrangement;
if (aName < bName) {
return -1;
}
if (aName > bName) {
return 1;
}
return 0;
});
}
}, {
key: "shouldShowBookingSize",
value: function shouldShowBookingSize(pack) {
return this.bookingSizeLines(pack).length > 0;
}
}, {
key: "showBookButton",
value: function showBookButton() {
var _this18 = this;
var promises = [];
var paymentMethods = this.paymentMethods(this.selectedPackage);
var paymentText = '';
var textPostBooking = '';
if (paymentMethods.indexOf(this.PAYMENT_DIRECT) > -1 && paymentMethods.indexOf(this.PAYMENT_AFTERWARDS) > -1) {
// Let user decide how to pay
promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze, this.selectedPackage ? this.selectedPackage.id : null));
promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze_ideal_titel, this.selectedPackage ? this.selectedPackage.id : null));
promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze_achteraf_titel, this.selectedPackage ? this.selectedPackage.id : null));
Promise.all(promises).then(function (msgs) {
paymentText = "<p>".concat(msgs[0], "</p>");
paymentText += "<ul>\n <li><label><input type=\"radio\" name=\"paymentMethod\" checked value=\"".concat(_this18.PAYMENT_DIRECT, "\"> ").concat(msgs[1], "</label>\n <li><label><input type=\"radio\" name=\"paymentMethod\" value=\"").concat(_this18.PAYMENT_AFTERWARDS, "\"> ").concat(msgs[2], "</label>\n </ul>");
});
} else {
// One fixed choice
promises.push(Promise.resolve(''));
}
promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step3_text_post, this.selectedPackage ? this.selectedPackage.id : null).then(function (msg) {
textPostBooking = msg;
}));
Promise.all(promises).then(function () {
var html = "<div class=\"recras-finalise\">\n <p>".concat(textPostBooking, "</p>\n <div class=\"standard-attachments\"></div>\n ").concat(paymentText, "\n <button type=\"submit\" class=\"bookPackage\" disabled>").concat(_this18.languageHelper.translate('BUTTON_BOOK_NOW'), "</button>\n <div class=\"booking-error\" id=\"bookingErrors\"></div>\n </div>");
_this18.appendHtml(html);
_this18.findElement('.bookPackage').addEventListener('click', _this18.submitBooking.bind(_this18));
_this18.maybeDisableBookButton();
_this18.updateProductAmounts();
});
}
}, {
key: "showDiscountFields",
value: function showDiscountFields() {
var _this19 = this;
var existingEl = this.findElement('.recras-discounts');
if (existingEl) {
existingEl.parentNode.removeChild(existingEl);
}
var html = "\n <form class=\"recras-discounts\">\n <div>\n <label for=\"discountcode\">".concat(this.languageHelper.translate('DISCOUNT_TITLE'), "</label>\n <input type=\"text\" id=\"discountcode\" class=\"discountcode\" maxlength=\"50\" disabled>\n </div>\n <button type=\"submit\" class=\"button-secondary\">").concat(this.languageHelper.translate('DISCOUNT_CHECK'), "</button>\n </form>\n ");
this.findElement('.recras-datetime').insertAdjacentHTML('afterend', html);
this.findElement('.recras-discounts').addEventListener('submit', function (e) {
e.preventDefault();
_this19.checkDiscountAndVoucher();
return false;
});
}
}, {
key: "showContactForm",
value: function showContactForm(pack) {
var _this20 = this;
this.loadingIndicatorShow(this.findElement('.recras-datetime'));
this.getContactForm(pack).then(function (form) {
return form.generateForm();
}).then(function (html) {
_this20.appendHtml(html);
_this20.loadingIndicatorHide();
_this20.showBookButton();
_this20.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_CONTACT_FORM_SHOWN);
_toConsumableArray(_this20.findElements('[name^="contactformulier"]')).forEach(function (el) {
el.addEventListener('input', _this20.maybeDisableBookButton.bind(_this20));
el.addEventListener('input', function () {
if (_this20.contactFormValid()) {
_this20.nextSectionActive('.recras-contactform', '.recras-finalise');
}
});
});
});
}
}, {
key: "maybeFillTime",
value: function maybeFillTime(times) {
times = times.map(func