UNPKG

@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
"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