PageSourceSearch

https://waldhochseilgarten-jungfernheide.de/en/wp-content/plugins/recras/js/onlinebooking.min.js?ver=2.0.6

js waldhochseilgarten-jungfernheide.de collected 2026-09-26 06:40:32 UTC 168,628 bytes, 3,905 lines download raw bytes

1"use strict";
2
3function _objectValues(obj) {
4    var values = [];
5    var keys = Object.keys(obj);
6
7    for (var k = 0; k < keys.length; k++) values.push(obj[keys[k]]);
8
9    return values;
10}
11
12function _objectEntries(obj) {
13    var entries = [];
14    var keys = Object.keys(obj);
15
16    for (var k = 0; k < keys.length; k++) entries.push([keys[k], obj[keys[k]]]);
17
18    return entries;
19}
20
21function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
22
23function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
24
25function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
26
27function _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."); }
28
29function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
30
31function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
32
33function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
34
35function _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."); }
36
37function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
38
39function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
40
41function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
42
43function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
44
45function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
46
47function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
48
49function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
50
51/*******************************
52 *  Recras integration library  *
53 *  v 2.0.6                     *
54 *******************************/
55var RecrasBooking = /*#__PURE__*/function () {
56    function RecrasBooking() {
57        var _this = this;
58
59        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
60
61        _classCallCheck(this, RecrasBooking);
62
63        this.datePicker = null;
64        this.PAYMENT_DIRECT = 'mollie';
65        this.PAYMENT_AFTERWARDS = 'factuur';
66        this.RECRAS_INFINITY = 99999; // This is used instead of "true infinity" because JSON doesn't have infinity
67
68        this.languageHelper = new RecrasLanguageHelper();
69
70        if (!(options instanceof RecrasOptions)) {
71            throw new Error(this.languageHelper.translate('ERR_OPTIONS_INVALID'));
72        }
73
74        this.options = options;
75        this.eventHelper = new RecrasEventHelper();
76        this.eventHelper.setAnalytics(this.options.getAnalytics());
77        this.eventHelper.setEvents(this.options.getAnalyticsEvents());
78        var optionsPromise = this.languageHelper.setOptions(options);
79        this.element = this.options.getElement();
80        this.element.classList.add('recras-onlinebooking');
81
82        this.fetchJson = function (url) {
83            return RecrasHttpHelper.fetchJson(url, _this.error);
84        };
85
86        this.postJson = function (url, data) {
87            return RecrasHttpHelper.postJson(_this.options.getApiBase() + url, data, _this.error.bind(_this));
88        };
89
90        if (this.options.getLocale()) {
91            if (!RecrasLanguageHelper.isValid(this.options.getLocale())) {
92                console.warn(this.languageHelper.translate('ERR_INVALID_LOCALE', {
93                    LOCALES: RecrasLanguageHelper.validLocales.join(', ')
94                }));
95            } else {
96                this.languageHelper.setLocale(this.options.getLocale());
97            }
98        }
99
100        if (this.options.getPreFilledAmounts()) {
101            if (!this.options.isSinglePackage()) {
102                console.warn(this.languageHelper.translate('ERR_AMOUNTS_NO_PACKAGE'));
103            }
104        }
105
106        if (this.options.getPreFilledDate()) {
107            this.prefillDateIfPossible();
108        }
109
110        if (this.options.getPreFilledTime()) {
111            this.prefillTimeIfPossible();
112        }
113
114        RecrasCSSHelper.loadCSS('global');
115        RecrasCSSHelper.loadCSS('booking');
116        RecrasCSSHelper.loadCSS('pikaday');
117        this.clearAll();
118        this.loadingIndicatorShow(this.element);
119        this.promise = optionsPromise.then(function () {
120            return RecrasCalendarHelper.loadScript();
121        }).then(function () {
122            return _this.getTexts();
123        }).then(function (texts) {
124            _this.texts = texts;
125            return _this.getPackages();
126        }).then(function (packages) {
127            _this.loadingIndicatorHide();
128
129            var pck = _this.options.getPackageId();
130
131            if (_this.options.isSinglePackage()) {
132                if (Array.isArray(pck)) {
133                    pck = pck[0];
134                }
135
136                return _this.changePackage(pck);
137            } else if (Array.isArray(pck) && pck.length > 1) {
138                packages = packages.filter(function (p) {
139                    return pck.includes(p.id);
140                });
141            }
142
143            return _this.showPackages(packages);
144        });
145    }
146
147    _createClass(RecrasBooking, [{
148        key: "prefillDateIfPossible",
149        value: function prefillDateIfPossible() {
150            var date = new Date(this.options.getPreFilledDate());
151
152            if (isNaN(date.getTime())) {
153                console.warn(this.languageHelper.translate('ERR_INVALID_DATE'));
154                return false;
155            }
156
157            if (date < new Date()) {
158                console.warn(this.languageHelper.translate('ERR_DATE_PAST'));
159                return false;
160            }
161
162            if (!this.options.isSinglePackage()) {
163                console.warn(this.languageHelper.translate('ERR_DATE_NO_SINGLE_PACKAGE'));
164                return false;
165            }
166
167            this.prefilledDate = date;
168            return true;
169        }
170    }, {
171        key: "prefillTimeIfPossible",
172        value: function prefillTimeIfPossible() {
173            var time = this.options.getPreFilledTime();
174
175            if (!time.match(/^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/)) {
176                console.warn(this.languageHelper.translate('ERR_INVALID_TIME'));
177                return false;
178            }
179
180            this.prefilledTime = time;
181            return true;
182        }
183    }, {
184        key: "hasAtLeastOneProduct",
185        value: function hasAtLeastOneProduct(pack) {
186            if (this.shouldShowBookingSize(pack) && this.bookingSize() > 0) {
187                return true;
188            }
189
190            var hasAtLeastOneProduct = false;
191
192            for (var _i2 = 0, _this$getLinesNoBooki2 = this.getLinesNoBookingSize(pack); _i2 < _this$getLinesNoBooki2.length; _i2++) {
193                var line = _this$getLinesNoBooki2[_i2];
194                var lineEl = this.findElement("[data-package-id=\"".concat(line.id, "\"]"));
195
196                if (lineEl && lineEl.value > 0) {
197                    hasAtLeastOneProduct = true;
198                }
199            }
200
201            return hasAtLeastOneProduct;
202        }
203    }, {
204        key: "amountsValid",
205        value: function amountsValid(pack) {
206            for (var _i4 = 0, _this$getLinesNoBooki4 = this.getLinesNoBookingSize(pack); _i4 < _this$getLinesNoBooki4.length; _i4++) {
207                var line = _this$getLinesNoBooki4[_i4];
208                var lineEl = this.findElement("[data-package-id=\"".concat(line.id, "\"]"));
209
210                if (!lineEl) {
211                    console.warn("Element for line ".concat(line.id, " not found"));
212                    return false;
213                }
214
215                var aantal = lineEl.value;
216
217                if (aantal > 0 && aantal < line.aantal_personen) {
218                    return false;
219                }
220
221                if (aantal > 0 && line.min && aantal < line.min) {
222                    return false;
223                }
224
225                if (line.max && aantal > line.max) {
226                    return false;
227                }
228            }
229
230            if (this.shouldShowBookingSize(pack) && this.bookingSize() > 0) {
231                if (this.bookingSize() < this.bookingSizeMinimum(pack) || this.bookingSize() > this.bookingSizeMaximum(pack)) {
232                    return false;
233                }
234            }
235
236            return this.hasAtLeastOneProduct(pack);
237        }
238    }, {
239        key: "appendHtml",
240        value: function appendHtml(msg) {
241            this.element.insertAdjacentHTML('beforeend', msg);
242        }
243    }, {
244        key: "applyVoucher",
245        value: function applyVoucher(packageID, voucherCode) {
246            var _this2 = this;
247
248            if (!voucherCode) {
249                this.setDiscountStatus(this.languageHelper.translate('VOUCHER_EMPTY'));
250                return Promise.resolve(false);
251            }
252
253            if (this.appliedVouchers[voucherCode]) {
254                this.setDiscountStatus(this.languageHelper.translate('VOUCHER_ALREADY_APPLIED'));
255                return Promise.resolve(false);
256            }
257
258            if (!this.selectedDate) {
259                this.setDiscountStatus(this.languageHelper.translate('DATE_INVALID'));
260                return Promise.resolve(false);
261            }
262
263            return this.postJson('onlineboeking/controleervoucher', {
264                arrangement_id: packageID,
265                datum: RecrasDateHelper.datePartOnly(this.selectedDate),
266                producten: this.productCounts(),
267                vouchers: [voucherCode]
268            }).then(function (json) {
269                var result = json[voucherCode];
270
271                if (!result.valid) {
272                    return Promise.resolve(false);
273                }
274
275                _this2.appliedVouchers[voucherCode] = result.processed;
276
277                _this2.showTotalPrice();
278
279                return true;
280            });
281        }
282    }, {
283        key: "recheckDiscountCode",
284        value: function recheckDiscountCode() {
285            var _this3 = this;
286
287            this.checkDiscountcode(this.selectedPackage.id, RecrasDateHelper.datePartOnly(this.selectedDate), this.discount.code).then(function (status) {
288                if (status) {
289                    _this3.setDiscountStatus(_this3.languageHelper.translate('DISCOUNT_APPLIED'), false);
290                } else {
291                    _this3.discount = null;
292
293                    _this3.showTotalPrice();
294
295                    var statusEl = _this3.findElement('.discount-status');
296
297                    if (statusEl) {
298                        statusEl.parentNode.removeChild(statusEl);
299                    }
300                }
301            });
302        }
303    }, {
304        key: "recheckVouchers",
305        value: function recheckVouchers() {
306            var voucherCodes = Object.keys(this.appliedVouchers);
307            this.appliedVouchers = [];
308            var promises = [];
309
310            for (var _i6 = 0; _i6 < voucherCodes.length; _i6++) {
311                var voucherCode = voucherCodes[_i6];
312                promises.push(this.applyVoucher(this.selectedPackage.id, voucherCode));
313            }
314
315            return Promise.all(promises);
316        }
317    }, {
318        key: "bookingSize",
319        value: function bookingSize() {
320            var bookingSizeEl = this.findElement('.bookingsize');
321
322            if (!bookingSizeEl) {
323                return 0;
324            }
325
326            var bookingSizeValue = parseInt(bookingSizeEl.value, 10);
327
328            if (isNaN(bookingSizeValue)) {
329                return 0;
330            }
331
332            return bookingSizeValue;
333        }
334    }, {
335        key: "bookingSizeLines",
336        value: function bookingSizeLines(pack) {
337            return pack.regels.filter(function (line) {
338                return line.onlineboeking_aantalbepalingsmethode === 'boekingsgrootte';
339            });
340        }
341    }, {
342        key: "bookingSizeMaximum",
343        value: function bookingSizeMaximum(pack) {
344            var lines = this.bookingSizeLines(pack).filter(function (line) {
345                return line.max;
346            });
347
348            if (lines.length === 0) {
349                return this.RECRAS_INFINITY;
350            }
351
352            var maxes = lines.map(function (line) {
353                return line.max;
354            });
355            return Math.min.apply(Math, _toConsumableArray(maxes));
356        }
357    }, {
358        key: "bookingSizeLineMinimum",
359        value: function bookingSizeLineMinimum(line) {
360            if (line.min) {
361                return line.min;
362            }
363
364            if (line.onlineboeking_aantalbepalingsmethode === 'vast') {
365                return 0;
366            }
367
368            return line.product.minimum_aantal;
369        }
370    }, {
371        key: "bookingSizeMinimum",
372        value: function bookingSizeMinimum(pack) {
373            var _this4 = this;
374
375            var minSize = 0;
376            this.bookingSizeLines(pack).forEach(function (line) {
377                minSize = Math.max(minSize, _this4.bookingSizeLineMinimum(line));
378            });
379            return minSize;
380        }
381    }, {
382        key: "amountFromPersons",
383        value: function amountFromPersons(product, persons) {
384            return persons; //TODO: this doesn't work yet because public product API does not send:
385            // aantalbepaling, aantal, per_x_personen_afronding, per_x_personen
386
387            if (product.aantalbepaling === 'vast') {
388                return product.aantal;
389            }
390
391            var fn = product.per_x_personen_afronding === 'beneden' ? Math.floor : Math.ceil;
392            return product.aantal * fn(persons / product.per_x_personen);
393        }
394    }, {
395        key: "bookingSizePrice",
396        value: function bookingSizePrice(pack) {
397            var _this5 = this;
398
399            var nrOfPersons = Math.max(pack.aantal_personen, 1);
400            var price = 0;
401            var lines = this.bookingSizeLines(pack);
402            lines.forEach(function (line) {
403                price += Math.max(_this5.amountFromPersons(line.product, nrOfPersons), line.product.minimum_aantal) * parseFloat(line.product.verkoop);
404            });
405            return price / nrOfPersons;
406        }
407    }, {
408        key: "filterPackagesFromoptions",
409        value: function filterPackagesFromoptions(packages) {
410            var pck = this.options.getPackageId();
411
412            if (!Array.isArray(pck)) {
413                return packages;
414            }
415
416            return packages.filter(function (p) {
417                return pck.includes(p.id);
418            });
419        }
420    }, {
421        key: "changePackage",
422        value: function changePackage(packageID) {
423            var _this6 = this;
424
425            var selectedPackage = this.packages.filter(function (p) {
426                return p.id === packageID;
427            });
428            this.appliedVouchers = {};
429            this.discount = null;
430
431            if (selectedPackage.length === 0) {
432                // Reset form
433                this.selectedPackage = null;
434                this.clearAll();
435                var packages = this.filterPackagesFromoptions(this.packages);
436                this.showPackages(packages);
437                this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_RESET);
438                return Promise.resolve(false);
439            } else {
440                this.clearAllExceptPackageSelection();
441                this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_PACKAGE_CHANGED, selectedPackage[0].arrangement, selectedPackage[0].id, {
442                    content_type: 'package',
443                    item_id: selectedPackage[0].id
444                });
445            }
446
447            this.selectedPackage = selectedPackage[0];
448            return this.showProducts(this.selectedPackage).then(function () {
449                _this6.nextSectionActive('.recras-package-select', '.recras-amountsform');
450
451                _this6.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_PRODUCTS_SHOWN);
452
453                if (_this6.options.getAutoScroll() === true) {
454                    var scrollOptions = {
455                        behavior: 'smooth'
456                    };
457
458                    if (!('scrollBehavior' in document.documentElement.style)) {
459                        scrollOptions = true;
460                    }
461
462                    _this6.findElement('.recras-amountsform').scrollIntoView(scrollOptions);
463                }
464
465                _this6.checkDependencies();
466
467                _this6.loadingIndicatorShow(_this6.findElement('.recras-amountsform'));
468
469                return _this6.showDateTimeSelection(_this6.selectedPackage);
470            }).then(function () {
471                _this6.loadingIndicatorHide();
472
473                _this6.showContactForm(_this6.selectedPackage);
474            });
475        }
476    }, {
477        key: "checkBookingSize",
478        value: function checkBookingSize(pack) {
479            if (!this.shouldShowBookingSize(pack)) {
480                return;
481            }
482
483            var bookingSize = this.bookingSize();
484            var bsMaximum = this.bookingSizeMaximum(pack);
485            var bsMinimum = this.bookingSizeMinimum(pack);
486
487            if (bookingSize < bsMinimum) {
488                this.setMinMaxAmountWarning('bookingsize', bsMinimum, 'minimum');
489            } else if (bookingSize > bsMaximum) {
490                this.setMinMaxAmountWarning('bookingsize', bsMaximum, 'maximum');
491            }
492
493            this.maybeDisableBookButton();
494        }
495    }, {
496        key: "checkDependencies",
497        value: function checkDependencies() {
498            var _this7 = this;
499
500            _toConsumableArray(this.findElements('.recras-product-dependency')).forEach(function (el) {
501                el.parentNode.removeChild(el);
502            });
503
504            _toConsumableArray(this.findElements('[data-package-id]')).forEach(function (el) {
505                el.classList.remove('recras-input-invalid');
506            });
507
508            this.requiresProduct = false;
509            this.productCounts().forEach(function (line) {
510                if (line.aantal > 0) {
511                    var packageLineID = line.arrangementsregel_id;
512
513                    var product = _this7.findProduct(packageLineID).product;
514
515                    var thisProductRequiresProduct = false;
516
517                    if (!product.vereist_product) {
518                        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.');
519                    } else {
520                        product.vereist_product.forEach(function (vp) {
521                            if (!_this7.dependencySatisfied(line.aantal, vp)) {
522                                thisProductRequiresProduct = true;
523                                _this7.requiresProduct = true;
524
525                                var requiredAmount = _this7.requiredAmount(line.aantal, vp);
526
527                                var requiredProductName = _this7.getProductByID(vp.vereist_product_id).weergavenaam;
528
529                                var message = _this7.languageHelper.translate('PRODUCT_REQUIRED', {
530                                    NUM: line.aantal,
531                                    PRODUCT: product.weergavenaam,
532                                    REQUIRED_AMOUNT: requiredAmount,
533                                    REQUIRED_PRODUCT: requiredProductName
534                                });
535
536                                _this7.findElement('.recras-amountsform').insertAdjacentHTML('beforeend', "<span class=\"recras-product-dependency\">".concat(message, "</span>"));
537                            }
538                        });
539                    }
540
541                    if (thisProductRequiresProduct) {
542                        var productInput = _this7.findElement("[data-package-id=\"".concat(packageLineID, "\"]"));
543
544                        productInput.classList.add('recras-input-invalid');
545                    }
546                }
547            });
548            this.maybeDisableBookButton();
549        }
550    }, {
551        key: "checkDiscountAndVoucher",
552        value: function checkDiscountAndVoucher() {
553            var _this8 = this;
554
555            var discountPromise = this.checkDiscountcode(this.selectedPackage.id, RecrasDateHelper.datePartOnly(this.selectedDate), this.findElement('#discountcode').value.trim());
556            var voucherPromise = this.applyVoucher(this.selectedPackage.id, this.findElement('#discountcode').value.trim());
557            Promise.all([discountPromise, voucherPromise]).then(function (_ref) {
558                var _ref2 = _slicedToArray(_ref, 2),
559                    discountStatus = _ref2[0],
560                    voucherStatus = _ref2[1];
561
562                if (discountStatus || voucherStatus) {
563                    var status;
564
565                    if (discountStatus) {
566                        status = 'DISCOUNT_APPLIED';
567                    } else {
568                        status = 'VOUCHER_APPLIED';
569                    }
570
571                    _this8.setDiscountStatus(_this8.languageHelper.translate(status), false);
572
573                    _this8.findElement('#discountcode').value = '';
574
575                    _this8.nextSectionActive('.recras-discounts', '.recras-contactform');
576                } else {
577                    _this8.setDiscountStatus(_this8.languageHelper.translate('DISCOUNT_INVALID'));
578                }
579            });
580        }
581    }, {
582        key: "checkDiscountcode",
583        value: function checkDiscountcode(packageID, date, code) {
584            var _this9 = this;
585
586            return this.fetchJson(this.options.getApiBase() + 'onlineboeking/controleerkortingscode' + '?datum=' + date + '&arrangement=' + packageID + '&kortingscode=' + encodeURIComponent(code)).then(function (discount) {
587                if (discount === false) {
588                    return false;
589                }
590
591                discount.code = code;
592                _this9.discount = discount;
593
594                _this9.showTotalPrice();
595
596                return true;
597            });
598        }
599    }, {
600        key: "checkMaximumForPackage",
601        value: function checkMaximumForPackage() {
602            var _this10 = this;
603
604            var maxPerLine = this.selectedPackage.maximum_aantal_personen_online;
605
606            if (maxPerLine === null) {
607                return Promise.resolve(null);
608            }
609
610            var showWarning = false;
611            var selectedProducts = this.productCounts();
612            return this.languageHelper.filterTags(this.texts.maximum_aantal_online_boeking_overschreden, this.selectedPackage ? this.selectedPackage.id : null).then(function (msg) {
613                selectedProducts.forEach(function (p) {
614                    if (p.aantal > maxPerLine && !showWarning) {
615                        var input = _this10.findElement("[data-package-id=\"".concat(p.arrangementsregel_id, "\"]"));
616
617                        if (!input) {
618                            input = _this10.findElement('#bookingsize');
619                        }
620
621                        if (input) {
622                            var warningEl = document.createElement('div');
623                            warningEl.classList.add('maximum-amount');
624                            warningEl.classList.add('recras-full-width');
625                            warningEl.innerHTML = msg;
626                            input.parentNode.parentNode.insertBefore(warningEl, input.parentNode.nextSibling);
627                            input.classList.add('recras-input-invalid');
628                        } else {
629                            _this10.findElement('.recras-amountsform').insertAdjacentHTML('beforeend', "<span class=\"maximum-amount\">".concat(msg, "</span>"));
630                        }
631
632                        showWarning = true;
633                    }
634                });
635            });
636        }
637    }, {
638        key: "contactFormValid",
639        value: function contactFormValid() {
640            var contactFormIsValid = this.findElement('.recras-contactform').checkValidity();
641            var contactFormRequiredCheckboxes = this.contactForm.checkRequiredCheckboxes();
642            return contactFormIsValid && contactFormRequiredCheckboxes;
643        }
644    }, {
645        key: "setMinMaxAmountWarning",
646        value: function setMinMaxAmountWarning(lineID, minAmount) {
647            var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'minimum';
648            var warnEl = document.createElement('span');
649            warnEl.classList.add(type + '-amount');
650            var lineEl = this.findElement("#".concat(lineID));
651
652            if (!lineEl) {
653                console.warn("Element for line ".concat(lineID, " not found"));
654                return false;
655            }
656
657            lineEl.classList.add('recras-input-invalid');
658            var text;
659
660            if (type === 'minimum') {
661                text = this.languageHelper.translate('PRODUCT_MINIMUM', {
662                    MINIMUM: minAmount
663                });
664            } else {
665                text = this.languageHelper.translate('PRODUCT_MAXIMUM', {
666                    MAXIMUM: minAmount
667                });
668            }
669
670            warnEl.innerHTML = text;
671            var label = this.findElement("label[for=\"".concat(lineID, "\"]"));
672            label.parentNode.appendChild(warnEl);
673        }
674    }, {
675        key: "checkMinMaxAmounts",
676        value: function checkMinMaxAmounts() {
677            for (var _i8 = 0, _this$productCounts2 = this.productCounts(); _i8 < _this$productCounts2.length; _i8++) {
678                var product = _this$productCounts2[_i8];
679
680                if (product.aantal < 1) {
681                    continue;
682                }
683
684                var packageLineID = product.arrangementsregel_id;
685                var packageLine = this.findProduct(packageLineID);
686                var input = this.findElement("[data-package-id=\"".concat(packageLineID, "\"]"));
687
688                if (!input) {
689                    // This is a "booking size" line - this is handled in checkBookingSize
690                    continue;
691                }
692
693                if (product.aantal < packageLine.product.minimum_aantal) {
694                    this.setMinMaxAmountWarning(input.id, packageLine.product.minimum_aantal, 'minimum');
695                } else if (packageLine.min !== undefined && product.aantal < packageLine.min) {
696                    this.setMinMaxAmountWarning(input.id, packageLine.min, 'minimum');
697                } else if (packageLine.max !== null && product.aantal > packageLine.max) {
698                    this.setMinMaxAmountWarning(input.id, packageLine.max, 'maximum');
699                }
700            }
701        }
702    }, {
703        key: "clearAll",
704        value: function clearAll() {
705            this.clearElements(this.element.children);
706        }
707    }, {
708        key: "clearAllExceptPackageSelection",
709        value: function clearAllExceptPackageSelection() {
710            var packageSelect = this.findElement('.recras-package-select');
711
712            if (packageSelect) {
713                packageSelect.classList.remove('recras-completed');
714                packageSelect.classList.add('recras-active');
715            }
716
717            var elements = document.querySelectorAll('#' + this.element.id + ' > *:not(.recras-package-select)');
718            this.clearElements(elements);
719        }
720    }, {
721        key: "clearElements",
722        value: function clearElements(elements) {
723            if (this.datePicker) {
724                this.datePicker.destroy();
725            }
726
727            this.availableDays = [];
728
729            _toConsumableArray(elements).forEach(function (el) {
730                el.parentNode.removeChild(el);
731            });
732
733            this.maybeAddLatestErrorElement();
734        }
735    }, {
736        key: "dependencySatisfied",
737        value: function dependencySatisfied(hasNow, requiredProduct) {
738            for (var _i10 = 0, _this$productCounts4 = this.productCounts(); _i10 < _this$productCounts4.length; _i10++) {
739                var line = _this$productCounts4[_i10];
740
741                if (line.aantal === 0) {
742                    continue;
743                }
744
745                var product = this.findProduct(line.arrangementsregel_id).product;
746
747                if (product.id !== parseInt(requiredProduct.vereist_product_id, 10)) {
748                    continue;
749                }
750
751                var requiredAmount = this.requiredAmount(hasNow, requiredProduct);
752                return line.aantal >= requiredAmount;
753            }
754
755            return false;
756        }
757    }, {
758        key: "error",
759        value: function error(msg) {
760            this.loadingIndicatorHide();
761            var bookingErrorsEl = this.findElement('#bookingErrors');
762
763            if (bookingErrorsEl) {
764                bookingErrorsEl.parentNode.appendChild(this.findElement('.latestError'));
765            }
766
767            this.maybeAddLatestErrorElement();
768            this.findElement('.latestError').innerHTML = "<strong>".concat(this.languageHelper.translate('ERR_GENERAL'), "</strong><p>").concat(msg, "</p>");
769        }
770    }, {
771        key: "findElement",
772        value: function findElement(querystring) {
773            return this.element.querySelector(querystring);
774        }
775    }, {
776        key: "findElements",
777        value: function findElements(querystring) {
778            return this.element.querySelectorAll(querystring);
779        }
780    }, {
781        key: "findProduct",
782        value: function findProduct(packageLineID) {
783            return this.selectedPackage.regels.filter(function (line) {
784                return line.id === packageLineID;
785            })[0];
786        }
787    }, {
788        key: "formatPrice",
789        value: function formatPrice(price) {
790            return this.languageHelper.formatPrice(price);
791        }
792    }, {
793        key: "getAvailableDays",
794        value: function getAvailableDays(packageID, begin, end) {
795            var _this11 = this;
796
797            var postData = {
798                arrangement_id: packageID,
799                begin: RecrasDateHelper.datePartOnly(begin),
800                eind: RecrasDateHelper.datePartOnly(end),
801                producten: this.productCountsNoBookingSize()
802            };
803
804            if (this.shouldShowBookingSize(this.selectedPackage)) {
805                postData.boekingsgrootte = this.bookingSize();
806            }
807
808            return this.postJson('onlineboeking/beschikbaredagen', postData).then(function (json) {
809                _this11.availableDays = _this11.availableDays.concat(json);
810                return _this11.availableDays;
811            });
812        }
813    }, {
814        key: "getAvailableTimes",
815        value: function getAvailableTimes(packageID, date) {
816            var _this12 = this;
817
818            return this.postJson('onlineboeking/beschikbaretijden', {
819                arrangement_id: packageID,
820                datum: RecrasDateHelper.datePartOnly(date),
821                producten: this.productCounts()
822            }).then(function (json) {
823                _this12.availableTimes = json;
824                return _this12.availableTimes;
825            });
826        }
827    }, {
828        key: "getContactForm",
829        value: function getContactForm(pack) {
830            var _this13 = this;
831
832            this.options.setOption('form_id', pack.onlineboeking_contactformulier_id);
833            var contactForm = new RecrasContactForm(this.options);
834            return contactForm.getContactFormFields().then(function () {
835                _this13.contactForm = contactForm;
836                return contactForm;
837            });
838        }
839    }, {
840        key: "getDiscountPrice",
841        value: function getDiscountPrice(discount) {
842            if (!discount) {
843                return 0;
844            }
845
846            return discount.percentage / 100 * this.getSubTotal() * -1;
847        }
848    }, {
849        key: "getLinesBookingSize",
850        value: function getLinesBookingSize(pack) {
851            return pack.regels.filter(function (line) {
852                return line.onlineboeking_aantalbepalingsmethode === 'boekingsgrootte';
853            });
854        }
855    }, {
856        key: "getLinesNoBookingSize",
857        value: function getLinesNoBookingSize(pack) {
858            return pack.regels.filter(function (line) {
859                return line.onlineboeking_aantalbepalingsmethode !== 'boekingsgrootte';
860            });
861        }
862    }, {
863        key: "getPackages",
864        value: function getPackages() {
865            var _this14 = this;
866
867            return this.fetchJson(this.options.getApiBase() + 'arrangementen').then(function (json) {
868                _this14.packages = json;
869                return _this14.packages;
870            });
871        }
872    }, {
873        key: "getProductByID",
874        value: function getProductByID(id) {
875            var products = this.selectedPackage.regels.map(function (r) {
876                return r.product;
877            });
878            return products.filter(function (p) {
879                return p.id === id;
880            })[0];
881        }
882    }, {
883        key: "getSubTotal",
884        value: function getSubTotal() {
885            var _this15 = this;
886
887            var total = 0;
888            this.productCounts().forEach(function (line) {
889                var product = _this15.findProduct(line.arrangementsregel_id).product;
890
891                var aantal = line.aantal;
892
893                if (isNaN(aantal)) {
894                    aantal = 0;
895                }
896
897                total += aantal * parseFloat(product.verkoop);
898            });
899            return total;
900        }
901    }, {
902        key: "getSetting",
903        value: function getSetting(settingName) {
904            return this.fetchJson(this.options.getApiBase() + 'instellingen/' + settingName);
905        }
906    }, {
907        key: "getTexts",
908        value: function getTexts() {
909            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'];
910            var promises = [];
911
912            for (var _i12 = 0; _i12 < settings.length; _i12++) {
913                var setting = settings[_i12];
914                promises.push(this.getSetting(setting));
915            }
916
917            return Promise.all(promises).then(function (settings) {
918                var texts = {};
919                settings.forEach(function (setting) {
920                    texts[setting.slug] = setting.waarde;
921                });
922                return texts;
923            });
924        }
925    }, {
926        key: "getTotalPrice",
927        value: function getTotalPrice() {
928            var total = this.getSubTotal();
929            total += this.getDiscountPrice(this.discount);
930            total += this.getVouchersPrice();
931            return total;
932        }
933    }, {
934        key: "getVouchersPrice",
935        value: function getVouchersPrice() {
936            var voucherPrice = 0;
937
938            _objectValues(this.appliedVouchers).forEach(function (voucher) {
939                _objectValues(voucher).forEach(function (line) {
940                    voucherPrice -= line.aantal * line.prijs_per_stuk;
941                });
942            });
943
944            return voucherPrice;
945        }
946    }, {
947        key: "loadingIndicatorHide",
948        value: function loadingIndicatorHide() {
949            _toConsumableArray(document.querySelectorAll('.recrasLoadingIndicator')).forEach(function (el) {
950                el.parentNode.removeChild(el);
951            });
952        }
953    }, {
954        key: "loadingIndicatorShow",
955        value: function loadingIndicatorShow(afterEl) {
956            if (!afterEl) {
957                return;
958            }
959
960            afterEl.insertAdjacentHTML('beforeend', "<span class=\"recrasLoadingIndicator\">".concat(this.languageHelper.translate('LOADING'), "</span>"));
961        }
962    }, {
963        key: "maybeAddLatestErrorElement",
964        value: function maybeAddLatestErrorElement() {
965            var errorEl = this.findElement('.latestError');
966
967            if (!errorEl) {
968                this.appendHtml("<div class=\"latestError\"></div>");
969            }
970        }
971    }, {
972        key: "maybeDisableBookButton",
973        value: function maybeDisableBookButton() {
974            var _this16 = this;
975
976            var button = this.findElement('.bookPackage');
977
978            if (!button) {
979                return false;
980            }
981
982            var bookingDisabledReasons = [];
983
984            if (this.requiresProduct) {
985                bookingDisabledReasons.push('BOOKING_DISABLED_REQUIRED_PRODUCT');
986            }
987
988            if (!this.amountsValid(this.selectedPackage)) {
989                bookingDisabledReasons.push('BOOKING_DISABLED_AMOUNTS_INVALID');
990            }
991
992            if (!this.selectedDate) {
993                bookingDisabledReasons.push('BOOKING_DISABLED_INVALID_DATE');
994            }
995
996            if (!this.selectedTime) {
997                bookingDisabledReasons.push('BOOKING_DISABLED_INVALID_TIME');
998            }
999
1000            if (!this.contactFormValid()) {
1001                bookingDisabledReasons.push('BOOKING_DISABLED_CONTACT_FORM_INVALID');
1002            }
1003
1004            var agreeEl = this.findElement('#recrasAgreeToAttachments');
1005
1006            if (agreeEl && !agreeEl.checked) {
1007                bookingDisabledReasons.push('BOOKING_DISABLED_AGREEMENT');
1008            }
1009
1010            if (bookingDisabledReasons.length > 0) {
1011                var reasonsList = bookingDisabledReasons.map(function (reason) {
1012                    return _this16.languageHelper.translate(reason);
1013                }).join('<li>');
1014                this.findElement('#bookingErrors').innerHTML = "<ul><li>".concat(reasonsList, "</ul>");
1015                button.setAttribute('disabled', 'disabled');
1016            } else {
1017                this.findElement('#bookingErrors').innerHTML = '';
1018                button.removeAttribute('disabled');
1019            }
1020        }
1021    }, {
1022        key: "nextSectionActive",
1023        value: function nextSectionActive(completedQuery, activeQuery) {
1024            if (completedQuery && this.findElement(completedQuery)) {
1025                this.findElement(completedQuery).classList.add('recras-completed');
1026                this.findElement(completedQuery).classList.remove('recras-active');
1027            } //TODO: remove active from all sections? Test with invalid amount
1028
1029
1030            if (activeQuery && this.findElement(activeQuery)) {
1031                this.findElement(activeQuery).classList.add('recras-active');
1032            }
1033        }
1034    }, {
1035        key: "normaliseDate",
1036        value: function normaliseDate(date, packageStart, bookingStart) {
1037            var diffSeconds = (date - packageStart) / 1000;
1038            var tempDate = new Date(bookingStart.getTime());
1039            return new Date(tempDate.setSeconds(tempDate.getSeconds() + diffSeconds));
1040        }
1041    }, {
1042        key: "paymentMethods",
1043        value: function paymentMethods(pack) {
1044            var methods = [];
1045
1046            if (pack.mag_online_geboekt_worden_direct_betalen) {
1047                methods.push(this.PAYMENT_DIRECT);
1048            }
1049
1050            if (pack.mag_online_geboekt_worden_achteraf_betalen) {
1051                methods.push(this.PAYMENT_AFTERWARDS);
1052            }
1053
1054            return methods;
1055        }
1056    }, {
1057        key: "preFillAmounts",
1058        value: function preFillAmounts(amounts) {
1059            var _this17 = this;
1060
1061            _objectEntries(amounts).forEach(function (idAmount) {
1062                var el;
1063
1064                if (idAmount[0] === 'bookingsize') {
1065                    el = _this17.findElement('#bookingsize');
1066                } else {
1067                    el = _this17.findElement("[data-package-id=\"".concat(idAmount[0], "\"]"));
1068                }
1069
1070                if (el) {
1071                    el.value = idAmount[1];
1072
1073                    _this17.updateProductPrice(el);
1074                }
1075            });
1076
1077            this.updateProductAmounts();
1078        }
1079    }, {
1080        key: "previewTimes",
1081        value: function previewTimes() {
1082            var _this18 = this;
1083
1084            _toConsumableArray(this.findElements('.time-preview')).forEach(function (el) {
1085                el.parentNode.removeChild(el);
1086            });
1087
1088            if (this.selectedTime) {
1089                var linesWithTime = this.selectedPackage.regels.filter(function (line) {
1090                    return !!line.begin;
1091                });
1092                var linesBegin = linesWithTime.map(function (line) {
1093                    return new Date(line.begin);
1094                });
1095                var packageStart = new Date(Math.min.apply(Math, _toConsumableArray(linesBegin))); // Math.min transforms dates to timestamps
1096
1097                var linesNoBookingSize = this.getLinesNoBookingSize(this.selectedPackage);
1098                linesNoBookingSize.forEach(function (line, idx) {
1099                    if (line.begin !== null || line.eind !== null) {
1100                        var normalisedStart = _this18.normaliseDate(new Date(line.begin), packageStart, _this18.selectedDate);
1101
1102                        var normalisedEnd = _this18.normaliseDate(new Date(line.eind), packageStart, _this18.selectedDate);
1103
1104                        _this18.findElement("label[for=\"packageline".concat(idx, "\"]")).insertAdjacentHTML('afterbegin', "<span class=\"time-preview\">".concat(RecrasDateHelper.timePartOnly(normalisedStart), " \u2013 ").concat(RecrasDateHelper.timePartOnly(normalisedEnd), "</span>"));
1105                    }
1106                });
1107            }
1108        }
1109    }, {
1110        key: "productCountsBookingSize",
1111        value: function productCountsBookingSize() {
1112            var _this19 = this;
1113
1114            return this.getLinesBookingSize(this.selectedPackage).map(function (line) {
1115                return {
1116                    aantal: _this19.bookingSize(),
1117                    arrangementsregel_id: line.id
1118                };
1119            });
1120        }
1121    }, {
1122        key: "productCountsNoBookingSize",
1123        value: function productCountsNoBookingSize() {
1124            return _toConsumableArray(this.findElements('[id^="packageline"]')).map(function (line) {
1125                return {
1126                    aantal: isNaN(parseInt(line.value)) ? 0 : parseInt(line.value),
1127                    arrangementsregel_id: parseInt(line.dataset.packageId, 10)
1128                };
1129            });
1130        }
1131    }, {
1132        key: "productCounts",
1133        value: function productCounts() {
1134            var counts = [];
1135            counts = counts.concat(this.productCountsNoBookingSize());
1136            counts = counts.concat(this.productCountsBookingSize());
1137            return counts;
1138        }
1139    }, {
1140        key: "removeWarnings",
1141        value: function removeWarnings() {
1142            _toConsumableArray(this.findElements('.booking-error:not(#bookingErrors)')).forEach(function (el) {
1143                el.parentNode.removeChild(el);
1144            });
1145
1146            _toConsumableArray(this.findElements('.minimum-amount')).forEach(function (el) {
1147                el.parentNode.removeChild(el);
1148            });
1149
1150            _toConsumableArray(this.findElements('.maximum-amount')).forEach(function (el) {
1151                el.parentNode.removeChild(el);
1152            });
1153
1154            _toConsumableArray(this.findElements('.recras-input-invalid')).forEach(function (el) {
1155                el.classList.remove('recras-input-invalid');
1156            });
1157
1158            _toConsumableArray(this.findElements('.recras-success')).forEach(function (el) {
1159                el.parentNode.removeChild(el);
1160            });
1161        }
1162        /**
1163         * requiredAmount calculates the amount N needed of Y in the sentence 'product X requires N times product Y'
1164         *
1165         * @param {number} hasNow The amount of product X selected
1166         * @param {object} requiredProduct
1167         * @param {number} requiredProduct.aantal The base amount of Y required
1168         * @param {number} requiredProduct.per_x_aantal The quantum of X that will require product Y
1169         * @param {"boven"|"beneden"} requiredProduct.afronding Indication of how hasNow / per_x_aantal should be rounded ("boven" will round up, "beneden" will round down)
1170         * @return {number} The amount of product Y needed
1171         */
1172
1173    }, {
1174        key: "requiredAmount",
1175        value: function requiredAmount(hasNow, requiredProduct) {
1176            var requiredFraction = hasNow / requiredProduct.per_x_aantal;
1177
1178            if (requiredProduct.afronding === 'boven') {
1179                requiredFraction = Math.ceil(requiredFraction);
1180            } else {
1181                requiredFraction = Math.floor(requiredFraction);
1182            }
1183
1184            return requiredProduct.aantal * requiredFraction;
1185        }
1186    }, {
1187        key: "resetForm",
1188        value: function resetForm() {
1189            this.changePackage(null);
1190        }
1191    }, {
1192        key: "selectSingleTime",
1193        value: function selectSingleTime() {
1194            if (this.findElements('#recras-onlinebooking-time option[value]').length !== 1) {
1195                return;
1196            }
1197
1198            this.findElement('#recras-onlinebooking-time option[value]').selected = true;
1199            this.findElement('#recras-onlinebooking-time').dispatchEvent(new Event('change'));
1200        }
1201    }, {
1202        key: "setDiscountStatus",
1203        value: function setDiscountStatus(statusText) {
1204            var isError = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
1205            var statusEl = this.findElement('.discount-status');
1206
1207            if (!statusEl) {
1208                this.element.querySelector('.recras-discounts').insertAdjacentHTML('beforeend', "<span class=\"discount-status\"></span>");
1209                statusEl = this.findElement('.discount-status');
1210            }
1211
1212            if (isError) {
1213                statusEl.classList.add('booking-error');
1214            } else {
1215                statusEl.classList.remove('booking-error');
1216            }
1217
1218            statusEl.innerHTML = statusText;
1219        }
1220    }, {
1221        key: "setHtml",
1222        value: function setHtml(msg) {
1223            this.element.innerHTML = msg;
1224        }
1225    }, {
1226        key: "showStandardAttachments",
1227        value: function showStandardAttachments() {
1228            if (!this.selectedPackage || !this.findElement('.standard-attachments')) {
1229                return true;
1230            }
1231
1232            var attachments = this.standardAttachments(this.selectedPackage);
1233            var attachmentHtml = "";
1234
1235            if (Object.keys(attachments).length) {
1236                attachmentHtml += "<p><label><input type=\"checkbox\" id=\"recrasAgreeToAttachments\" required>".concat(this.languageHelper.translate('AGREE_ATTACHMENTS'), "</label></p>");
1237                attachmentHtml += "<ul>";
1238
1239                _objectValues(attachments).forEach(function (attachment) {
1240                    attachmentHtml += "<li><a href=\"".concat(attachment.filename, "\" download target=\"_blank\">").concat(attachment.naam, "</a></li>");
1241                });
1242
1243                attachmentHtml += "</ul>";
1244            }
1245
1246            this.findElement('.standard-attachments').innerHTML = attachmentHtml;
1247            var agreeEl = this.findElement('#recrasAgreeToAttachments');
1248
1249            if (agreeEl) {
1250                agreeEl.addEventListener('change', this.maybeDisableBookButton.bind(this));
1251            }
1252        }
1253    }, {
1254        key: "showTotalPrice",
1255        value: function showTotalPrice() {
1256            _toConsumableArray(this.findElements('.discountLine, .voucherLine, .priceWithDiscount')).forEach(function (el) {
1257                el.parentNode.removeChild(el);
1258            });
1259
1260            var html = "";
1261
1262            if (this.discount) {
1263                html += "<div class=\"discountLine\"><div>".concat(this.discount.naam, "</div><div>").concat(this.formatPrice(this.getDiscountPrice(this.discount)), "</div></div>");
1264            }
1265
1266            if (Object.keys(this.appliedVouchers).length) {
1267                html += "<div class=\"voucherLine\"><div>".concat(this.languageHelper.translate('VOUCHERS_DISCOUNT'), "</div><div>").concat(this.formatPrice(this.getVouchersPrice()), "</div></div>");
1268            }
1269
1270            if (this.discount || Object.keys(this.appliedVouchers).length) {
1271                html += "<div class=\"priceWithDiscount\"><div>".concat(this.languageHelper.translate('PRICE_TOTAL_WITH_DISCOUNT'), "</div><div>").concat(this.formatPrice(this.getTotalPrice()), "</div></div>");
1272            }
1273
1274            var elementToInsertBefore = this.findElement('.recras-amountsform p:last-of-type');
1275
1276            if (elementToInsertBefore) {
1277                elementToInsertBefore.insertAdjacentHTML('beforebegin', html);
1278            }
1279
1280            var subtotalEl = this.findElement('.priceSubtotal');
1281
1282            if (subtotalEl) {
1283                subtotalEl.innerHTML = this.formatPrice(this.getSubTotal());
1284            }
1285        }
1286    }, {
1287        key: "sortPackages",
1288        value: function sortPackages(packages) {
1289            // Packages from the API are sorted by internal name, not by display name
1290            // However, display name is not required so fallback to internal name
1291            return packages.sort(function (a, b) {
1292                var aName = a.weergavenaam || a.arrangement;
1293                var bName = b.weergavenaam || b.arrangement;
1294
1295                if (aName < bName) {
1296                    return -1;
1297                }
1298
1299                if (aName > bName) {
1300                    return 1;
1301                }
1302
1303                return 0;
1304            });
1305        }
1306    }, {
1307        key: "shouldShowBookingSize",
1308        value: function shouldShowBookingSize(pack) {
1309            return this.bookingSizeLines(pack).length > 0;
1310        }
1311    }, {
1312        key: "showBookButton",
1313        value: function showBookButton() {
1314            var _this20 = this;
1315
1316            var promises = [];
1317            var paymentMethods = this.paymentMethods(this.selectedPackage);
1318            var paymentText = '';
1319            var textPostBooking = '';
1320
1321            if (paymentMethods.indexOf(this.PAYMENT_DIRECT) > -1 && paymentMethods.indexOf(this.PAYMENT_AFTERWARDS) > -1) {
1322                // Let user decide how to pay
1323                promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze, this.selectedPackage ? this.selectedPackage.id : null));
1324                promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze_ideal_titel, this.selectedPackage ? this.selectedPackage.id : null));
1325                promises.push(this.languageHelper.filterTags(this.texts.online_boeking_betaalkeuze_achteraf_titel, this.selectedPackage ? this.selectedPackage.id : null));
1326                Promise.all(promises).then(function (msgs) {
1327                    paymentText = "<p>".concat(msgs[0], "</p>");
1328                    paymentText += "<ul>\n                <li><label><input type=\"radio\" name=\"paymentMethod\" checked value=\"".concat(_this20.PAYMENT_DIRECT, "\"> ").concat(msgs[1], "</label>\n                <li><label><input type=\"radio\" name=\"paymentMethod\" value=\"").concat(_this20.PAYMENT_AFTERWARDS, "\"> ").concat(msgs[2], "</label>\n            </ul>");
1329                });
1330            } else {
1331                // One fixed choice
1332                promises.push(Promise.resolve(''));
1333            }
1334
1335            promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step3_text_post, this.selectedPackage ? this.selectedPackage.id : null).then(function (msg) {
1336                textPostBooking = msg;
1337            }));
1338            Promise.all(promises).then(function () {
1339                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(_this20.languageHelper.translate('BUTTON_BOOK_NOW'), "</button>\n                <div class=\"booking-error\" id=\"bookingErrors\"></div>\n            </div>");
1340
1341                _this20.appendHtml(html);
1342
1343                _this20.findElement('.bookPackage').addEventListener('click', _this20.submitBooking.bind(_this20));
1344
1345                _this20.maybeDisableBookButton();
1346
1347                _this20.updateProductAmounts();
1348            });
1349        }
1350    }, {
1351        key: "showDiscountFields",
1352        value: function showDiscountFields() {
1353            var _this21 = this;
1354
1355            var existingEl = this.findElement('.recras-discounts');
1356
1357            if (existingEl) {
1358                existingEl.parentNode.removeChild(existingEl);
1359            }
1360
1361            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        ");
1362            this.findElement('.recras-datetime').insertAdjacentHTML('afterend', html);
1363            this.findElement('.recras-discounts').addEventListener('submit', function (e) {
1364                e.preventDefault();
1365
1366                _this21.checkDiscountAndVoucher();
1367
1368                return false;
1369            });
1370        }
1371    }, {
1372        key: "showContactForm",
1373        value: function showContactForm(pack) {
1374            var _this22 = this;
1375
1376            this.loadingIndicatorShow(this.findElement('.recras-datetime'));
1377            this.getContactForm(pack).then(function (form) {
1378                return form.generateForm();
1379            }).then(function (html) {
1380                _this22.appendHtml(html);
1381
1382                _this22.loadingIndicatorHide();
1383
1384                _this22.showBookButton();
1385
1386                _this22.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_CONTACT_FORM_SHOWN);
1387
1388                _toConsumableArray(_this22.findElements('[name^="contactformulier"]')).forEach(function (el) {
1389                    el.addEventListener('input', _this22.maybeDisableBookButton.bind(_this22));
1390                    el.addEventListener('input', function () {
1391                        if (_this22.contactFormValid()) {
1392                            _this22.nextSectionActive('.recras-contactform', '.recras-finalise');
1393                        }
1394                    });
1395                });
1396            });
1397        }
1398    }, {
1399        key: "maybeFillTime",
1400        value: function maybeFillTime(times) {
1401            times = times.map(function (time) {
1402                return RecrasDateHelper.timePartOnly(new Date(time));
1403            });
1404            this.showTimes(times);
1405            this.loadingIndicatorHide();
1406
1407            if (!this.prefilledTime) {
1408                this.selectSingleTime();
1409                return;
1410            }
1411
1412            if (times.includes(this.prefilledTime)) {
1413                this.selectTime(this.prefilledTime);
1414                this.selectedDate = RecrasDateHelper.setTimeForDate(this.selectedDate, this.selectedTime);
1415
1416                if (this.options.getPreviewTimes() === true) {
1417                    this.previewTimes();
1418                }
1419
1420                return;
1421            }
1422
1423            this.toggleTimeField('show');
1424        }
1425    }, {
1426        key: "calendarOnDateSelect",
1427        value: function calendarOnDateSelect(date, packageId) {
1428            var _this23 = this;
1429
1430            this.removeWarnings();
1431            this.loadingIndicatorShow(this.findElement('label[for="recras-onlinebooking-time"]'));
1432            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_DATE_SELECTED, RecrasDateHelper.datePartOnly(date));
1433            this.selectedDate = date;
1434
1435            if (this.hasAtLeastOneProduct(this.selectedPackage)) {
1436                this.getAvailableTimes(packageId, date).then(function (times) {
1437                    return _this23.maybeFillTime(times);
1438                });
1439            }
1440
1441            if (this.discount && this.discount.code) {
1442                this.recheckDiscountCode();
1443            }
1444
1445            this.findElement('#discountcode').removeAttribute('disabled');
1446            this.maybeDisableBookButton();
1447        }
1448    }, {
1449        key: "calendarOnDraw",
1450        value: function calendarOnDraw(pika, packageId) {
1451            var lastMonthYear = pika.calendars[pika.calendars.length - 1];
1452            var lastDay = new Date(lastMonthYear.year, lastMonthYear.month, 31);
1453            var lastAvailableDay = this.availableDays.reduce(function (acc, curVal) {
1454                return curVal > acc ? curVal : acc;
1455            }, '');
1456
1457            if (!lastAvailableDay) {
1458                lastAvailableDay = new Date();
1459            } else {
1460                lastAvailableDay = new Date(lastAvailableDay);
1461            }
1462
1463            if (lastAvailableDay > lastDay) {
1464                return;
1465            }
1466
1467            var newEndDate = RecrasDateHelper.clone(lastAvailableDay);
1468            newEndDate.setFullYear(lastMonthYear.year);
1469            newEndDate.setMonth(lastMonthYear.month + 3);
1470            newEndDate.setDate(0); // Set to 0th day of the month = last day of previous month
1471
1472            this.getAvailableDays(packageId, lastAvailableDay, newEndDate);
1473        }
1474    }, {
1475        key: "addDateTimeSelectionHtml",
1476        value: function addDateTimeSelectionHtml() {
1477            var today = RecrasDateHelper.datePartOnly(new Date());
1478            var html = "<form class=\"recras-datetime\">\n            <label for=\"recras-onlinebooking-date\">\n                ".concat(this.languageHelper.translate('DATE'), "\n            </label>\n            <input type=\"text\" id=\"recras-onlinebooking-date\" class=\"recras-onlinebooking-date\" min=\"").concat(today, "\" disabled autocomplete=\"off\">\n            <label for=\"recras-onlinebooking-time\">\n                ").concat(this.languageHelper.translate('TIME'), "\n            </label>\n            <select id=\"recras-onlinebooking-time\" class=\"recras-onlinebooking-time\" disabled autocomplete=\"off\"></select>\n        </form>");
1479            this.appendHtml(html);
1480        }
1481    }, {
1482        key: "selectTime",
1483        value: function selectTime(time) {
1484            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_TIME_SELECTED);
1485            this.selectedTime = time;
1486            this.maybeDisableBookButton();
1487        }
1488    }, {
1489        key: "showDateTimeSelection",
1490        value: function showDateTimeSelection(pack) {
1491            var _this24 = this;
1492
1493            this.addDateTimeSelectionHtml();
1494            this.showDiscountFields();
1495
1496            if (this.prefilledDate) {
1497                this.toggleDateField('hide');
1498                this.calendarOnDateSelect(this.prefilledDate, pack.id);
1499            }
1500
1501            if (this.prefilledTime) {
1502                this.toggleTimeField('hide');
1503            }
1504
1505            if (this.prefilledDate && this.prefilledTime) {
1506                this.findElement('.recras-datetime').classList.add('recrasHidden');
1507            }
1508
1509            if (this.options.getPreFilledAmounts()) {
1510                this.preFillAmounts(this.options.getPreFilledAmounts());
1511            }
1512
1513            var pikadayOptions = _extends(RecrasCalendarHelper.defaultOptions(), {
1514                disableDayFn: function disableDayFn(day) {
1515                    var dateFmt = RecrasDateHelper.datePartOnly(day);
1516                    return _this24.availableDays.indexOf(dateFmt) === -1;
1517                },
1518                field: this.findElement('.recras-onlinebooking-date'),
1519                i18n: RecrasCalendarHelper.i18n(this.languageHelper),
1520                onDraw: function onDraw(pika) {
1521                    return _this24.calendarOnDraw(pika, pack.id);
1522                },
1523                onSelect: function onSelect(date) {
1524                    return _this24.calendarOnDateSelect(date, pack.id);
1525                },
1526                parse: RecrasDateHelper.parseMDY
1527            });
1528
1529            this.datePicker = new Pikaday(pikadayOptions);
1530            this.findElement('.recras-onlinebooking-time').addEventListener('change', function () {
1531                _this24.selectTime(_this24.findElement('.recras-onlinebooking-time').value);
1532
1533                _this24.nextSectionActive('.recras-datetime', '.recras-discounts');
1534
1535                _this24.nextSectionActive(null, '.recras-contactform');
1536
1537                _this24.selectedDate = RecrasDateHelper.setTimeForDate(_this24.selectedDate, _this24.selectedTime);
1538
1539                if (_this24.options.getPreviewTimes() === true) {
1540                    _this24.previewTimes();
1541                }
1542
1543                _this24.maybeDisableBookButton();
1544            });
1545        }
1546    }, {
1547        key: "showPackages",
1548        value: function showPackages(packages) {
1549            var _this25 = this;
1550
1551            packages = packages.filter(function (p) {
1552                return p.mag_online;
1553            });
1554            var packagesSorted = this.sortPackages(packages);
1555            var packageOptions = packagesSorted.map(function (pack) {
1556                return "<option value=\"".concat(pack.id, "\">").concat(pack.weergavenaam || pack.arrangement);
1557            });
1558            var html = '<select class="recras-package-selection"><option>' + packageOptions.join('') + '</select>';
1559            var promises = [];
1560            promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step0_text_pre, this.selectedPackage ? this.selectedPackage.id : null));
1561            promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step0_text_post, this.selectedPackage ? this.selectedPackage.id : null));
1562            return Promise.all(promises).then(function (msgs) {
1563                _this25.appendHtml("<div class=\"recras-package-select recras-active\"><p>".concat(msgs[0], "</p>").concat(html, "<p>\n").concat(msgs[1], "</p></div>"));
1564
1565                _this25.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_PACKAGES_SHOWN);
1566
1567                var packageSelectEl = _this25.findElement('.recras-package-selection');
1568
1569                packageSelectEl.addEventListener('change', function () {
1570                    var selectedPackageId = parseInt(packageSelectEl.value, 10);
1571
1572                    _this25.changePackage(selectedPackageId);
1573                });
1574            });
1575        }
1576    }, {
1577        key: "showProducts",
1578        value: function showProducts(pack) {
1579            var _this26 = this;
1580
1581            var promises = [];
1582            promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step1_text_pre, this.selectedPackage ? this.selectedPackage.id : null));
1583            promises.push(this.languageHelper.filterTags(this.texts.online_boeking_step1_text_post, this.selectedPackage ? this.selectedPackage.id : null));
1584            return Promise.all(promises).then(function (msgs) {
1585                var html = '<form class="recras-amountsform" onsubmit="return false">';
1586                html += "<p>".concat(msgs[0], "</p>");
1587                html += "<div class=\"recras-heading\">\n                <div>&nbsp;</div>\n                <div>".concat(_this26.languageHelper.translate('HEADING_QUANTITY'), "</div>\n                <div class=\"recras-price\">").concat(_this26.languageHelper.translate('HEADING_PRICE'), "</div>\n            </div>");
1588
1589                if (_this26.shouldShowBookingSize(pack)) {
1590                    html += "<div>";
1591                    html += "<div><label for=\"bookingsize\">".concat(pack.weergavenaam || pack.arrangement, "</label></div>");
1592                    html += "<input type=\"number\" id=\"bookingsize\" class=\"bookingsize\" min=\"".concat(_this26.bookingSizeMinimum(pack), "\" max=\"").concat(_this26.bookingSizeMaximum(pack), "\" placeholder=\"0\" data-price=\"").concat(_this26.bookingSizePrice(pack), "\">");
1593                    html += "<div class=\"recras-price recrasUnitPrice\">".concat(_this26.formatPrice(_this26.bookingSizePrice(pack)), "</div>");
1594                    html += "</div>";
1595                }
1596
1597                var linesNoBookingSize = _this26.getLinesNoBookingSize(pack);
1598
1599                linesNoBookingSize.forEach(function (line, idx) {
1600                    html += '<div><div>';
1601                    html += "<label for=\"packageline".concat(idx, "\">").concat(line.beschrijving_templated, "</label>");
1602                    var maxAttr = line.max ? "max=\"".concat(line.max, "\"") : '';
1603                    html += "</div><input id=\"packageline".concat(idx, "\" type=\"number\" min=\"0\" ").concat(maxAttr, " placeholder=\"0\" data-package-id=\"").concat(line.id, "\" data-price=\"").concat(line.product.verkoop, "\">");
1604                    html += "<div class=\"recras-price recrasUnitPrice\">".concat(_this26.formatPrice(line.product.verkoop), "</div>");
1605                    html += '</div>';
1606                });
1607                html += "<div class=\"priceWithoutDiscount\">\n                <div>".concat(_this26.languageHelper.translate('PRICE_TOTAL'), "</div>\n                <div></div>\n                <div class=\"priceSubtotal\"></div>\n            </div>");
1608                html += "<p>".concat(msgs[1], "</p>");
1609                html += '</form>';
1610
1611                _this26.appendHtml(html);
1612
1613                _toConsumableArray(_this26.findElements('[id^="packageline"], .bookingsize')).forEac
1613h(function (el) {
1614                    el.addEventListener('input', _this26.updateProductAmounts.bind(_this26));
1615                    el.addEventListener('input', _this26.updateProductPrice.bind(_this26, el));
1616                });
1617            });
1618        }
1619    }, {
1620        key: "showTimes",
1621        value: function showTimes(times) {
1622            var html = "<option>";
1623            times.forEach(function (time) {
1624                html += "<option value=\"".concat(time, "\">").concat(time);
1625            });
1626            this.findElement('.recras-onlinebooking-time').innerHTML = html;
1627            this.findElement('.recras-onlinebooking-time').removeAttribute('disabled');
1628
1629            if (times.length === 0) {
1630                this.findElement('.recras-datetime').insertAdjacentHTML('afterend', "<div class=\"booking-error\">".concat(this.languageHelper.translate('ERR_NO_TIMES_FOR_DATE'), "</div>"));
1631            }
1632        }
1633    }, {
1634        key: "clearTimes",
1635        value: function clearTimes() {
1636            this.findElement('.recras-onlinebooking-time').innerHTML = '';
1637            this.findElement('.recras-onlinebooking-time').setAttribute('disabled', 'disabled');
1638        }
1639    }, {
1640        key: "standardAttachments",
1641        value: function standardAttachments() {
1642            var _this27 = this;
1643
1644            var attachments = {};
1645
1646            if (!this.selectedPackage.onlineboeking_standaardbijlagen_meesturen) {
1647                return attachments;
1648            }
1649
1650            this.productCounts().forEach(function (line) {
1651                if (line.aantal > 0) {
1652                    var product = _this27.findProduct(line.arrangementsregel_id).product;
1653
1654                    if (product.standaardbijlagen) {
1655                        product.standaardbijlagen.forEach(function (attachment) {
1656                            attachments[attachment.id] = attachment;
1657                        });
1658                    }
1659                }
1660            });
1661            return attachments;
1662        }
1663    }, {
1664        key: "formatGA4Items",
1665        value: function formatGA4Items() {
1666            var _this28 = this;
1667
1668            var items = [];
1669
1670            if (this.bookingSize() > 0) {
1671                var pck = this.selectedPackage;
1672                items.push({
1673                    item_name: pck.weergavenaam || pck.arrangement,
1674                    price: this.bookingSizePrice(pck),
1675                    quantity: this.bookingSize()
1676                });
1677            }
1678
1679            var linesNoBookingSize = this.getLinesNoBookingSize(this.selectedPackage);
1680            linesNoBookingSize = linesNoBookingSize.filter(function (line) {
1681                var lineEl = _this28.findElement("[data-package-id=\"".concat(line.id, "\"]"));
1682
1683                if (!lineEl) {
1684                    return false;
1685                }
1686
1687                if (isNaN(parseInt(lineEl.value))) {
1688                    return false;
1689                }
1690
1691                return parseInt(lineEl.value) > 0;
1692            });
1693            linesNoBookingSize = linesNoBookingSize.map(function (line) {
1694                var lineEl = _this28.findElement("[data-package-id=\"".concat(line.id, "\"]"));
1695
1696                return {
1697                    item_name: line.beschrijving_templated,
1698                    price: line.product.verkoop,
1699                    quantity: parseInt(lineEl.value)
1700                };
1701            });
1702            items.push.apply(items, _toConsumableArray(linesNoBookingSize));
1703            return items;
1704        }
1705    }, {
1706        key: "submitBooking",
1707        value: function submitBooking() {
1708            var _this29 = this;
1709
1710            var productCounts = this.productCounts().map(function (line) {
1711                return line.aantal;
1712            });
1713            var productSum = productCounts.reduce(function (a, b) {
1714                return a + b;
1715            }, 0);
1716
1717            if (this.bookingSize() === 0 && productSum === 0) {
1718                this.error(this.languageHelper.translate('NO_PRODUCTS'));
1719                return false;
1720            }
1721
1722            var status = this.contactForm.checkRequiredCheckboxes();
1723
1724            if (!status) {
1725                return false;
1726            }
1727
1728            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_BOOKING_SUBMITTED, this.selectedPackage.arrangement, Math.round(this.getTotalPrice()));
1729            var paymentMethod = this.paymentMethods(this.selectedPackage)[0];
1730            var paymentMethodEl = this.findElement('[name="paymentMethod"]:checked');
1731
1732            if (paymentMethodEl && this.validPaymentMethod(this.selectedPackage, paymentMethodEl.value)) {
1733                paymentMethod = paymentMethodEl.value;
1734            }
1735
1736            this.loadingIndicatorHide();
1737            this.loadingIndicatorShow(this.findElement('.bookPackage'));
1738            var elem;
1739
1740            if (null !== (elem = this.findElement('.bookPackage'))) {
1741                elem.setAttribute('disabled', 'disabled');
1742            }
1743
1744            var vouchers = Object.keys(this.appliedVouchers).length > 0 ? Object.keys(this.appliedVouchers) : null;
1745            var bookingParams = {
1746                arrangement_id: this.selectedPackage.id,
1747                begin: this.selectedDate,
1748                betaalmethode: paymentMethod,
1749                contactformulier: this.contactForm.generateJson(),
1750                kortingscode: this.discount && this.discount.code || null,
1751                producten: this.productCounts(),
1752                status: null,
1753                stuur_bevestiging_email: true,
1754                vouchers: vouchers
1755            };
1756
1757            if (this.shouldShowBookingSize(this.selectedPackage)) {
1758                bookingParams.boekingsgrootte = this.bookingSize();
1759            }
1760
1761            if (this.options.getRedirectUrl()) {
1762                bookingParams.redirect_url = this.options.getRedirectUrl();
1763            }
1764
1765            return this.postJson('onlineboeking/reserveer', bookingParams).then(function (json) {
1766                if (json.payment_url) {
1767                    _this29.eventHelper.sendEvent(RecrasEventHelper.PREFIX_BOOKING, RecrasEventHelper.EVENT_BOOKING_REDIRECT_PAYMENT, null, Math.round(_this29.getTotalPrice()), {
1768                        currency: _this29.languageHelper.currency,
1769                        value: _this29.getTotalPrice(),
1770                        items: _this29.formatGA4Items()
1771                    });
1772
1773                    window.top.location.href = json.payment_url;
1774                } else if (json.redirect) {
1775                    window.top.location.href = json.redirect;
1776                } else if (json.message && json.status) {
1777                    _this29.findElement('.recras-amountsform').reset();
1778
1779                    _this29.findElement('.recras-datetime').reset();
1780
1781                    _this29.findElement('.recras-contactform').reset();
1782
1783                    _this29.element.scrollIntoView({
1784                        behavior: 'smooth'
1785                    });
1786
1787                    _this29.element.insertAdjacentHTML('afterbegin', "<p class=\"recras-success\">".concat(json.message, "</p>"));
1788                } else {
1789                    console.log(json);
1790                }
1791
1792                _this29.loadingIndicatorHide();
1793
1794                _this29.findElement('.bookPackage').removeAttribute('disabled');
1795            });
1796        }
1797    }, {
1798        key: "toggleDateField",
1799        value: function toggleDateField(showHide) {
1800            var dateEl = this.findElement('#recras-onlinebooking-date');
1801            var labelEl = this.findElement('[for="recras-onlinebooking-date"]');
1802
1803            if (showHide === 'hide') {
1804                dateEl.classList.add('recrasHidden');
1805                labelEl.classList.add('recrasHidden');
1806            } else {
1807                dateEl.classList.remove('recrasHidden');
1808                labelEl.classList.remove('recrasHidden');
1809                this.findElement('.recras-datetime').classList.remove('recrasHidden');
1810            }
1811        }
1812    }, {
1813        key: "toggleTimeField",
1814        value: function toggleTimeField(showHide) {
1815            var timeEl = this.findElement('#recras-onlinebooking-time');
1816            var labelEl = this.findElement('[for="recras-onlinebooking-time"]');
1817
1818            if (showHide === 'hide') {
1819                timeEl.classList.add('recrasHidden');
1820                labelEl.classList.add('recrasHidden');
1821            } else {
1822                timeEl.classList.remove('recrasHidden');
1823                labelEl.classList.remove('recrasHidden');
1824                this.findElement('.recras-datetime').classList.remove('recrasHidden');
1825            }
1826        }
1827    }, {
1828        key: "updateProductAmounts",
1829        value: function updateProductAmounts() {
1830            var _this30 = this;
1831
1832            this.loadingIndicatorHide();
1833            this.availableDays = [];
1834            this.removeWarnings();
1835            this.checkDependencies();
1836            this.checkMinMaxAmounts();
1837            var maxPromise = this.checkMaximumForPackage();
1838            this.checkBookingSize(this.selectedPackage);
1839            this.recheckVouchers().then(function () {
1840                _this30.showTotalPrice();
1841            });
1842            this.showStandardAttachments();
1843            var datePickerEl = this.findElement('.recras-onlinebooking-date');
1844            var thisClass = this;
1845            maxPromise.then(function () {
1846                var amountErrors = thisClass.findElements('.minimum-amount, .maximum-amount, .recras-product-dependency');
1847
1848                if (amountErrors.length > 0) {
1849                    thisClass.nextSectionActive(null, '.recras-amountsform');
1850                    datePickerEl.setAttribute('disabled', 'disabled');
1851                    return;
1852                }
1853
1854                thisClass.nextSectionActive('.recras-amountsform', '.recras-datetime');
1855
1856                if (!thisClass.hasAtLeastOneProduct(thisClass.selectedPackage)) {
1857                    return;
1858                }
1859
1860                thisClass.loadingIndicatorShow(thisClass.findElement('label[for="recras-onlinebooking-date"]'));
1861                var startDate = new Date();
1862                var endDate = new Date();
1863                endDate.setMonth(endDate.getMonth() + 4);
1864                endDate.setDate(0); // Set to 0th day of the month = last day of previous month
1865
1866                if (!thisClass.prefilledDate) {
1867                    thisClass.getAvailableDaysInPeriod(thisClass.selectedPackage.id, startDate, endDate);
1868                    return;
1869                }
1870
1871                var date = thisClass.prefilledDate;
1872                startDate = new Date(date);
1873                endDate = new Date(date);
1874                endDate.setDate(endDate.getDate() + 1);
1875                thisClass.getAvailableDays(thisClass.selectedPackage.id, startDate, endDate).then(function (availableDays) {
1876                    if (availableDays.includes(RecrasDateHelper.datePartOnly(date))) {
1877                        thisClass.toggleDateField('hide');
1878                        thisClass.calendarOnDateSelect(date, thisClass.selectedPackage.id);
1879                    } else {
1880                        thisClass.toggleDateField('show');
1881                        thisClass.getAvailableDaysInPeriod(thisClass.selectedPackage.id, startDate, endDate);
1882                    }
1883                });
1884            });
1885        }
1886    }, {
1887        key: "getAvailableDaysInPeriod",
1888        value: function getAvailableDaysInPeriod(packageId, startDate, endDate) {
1889            var _this31 = this;
1890
1891            var datePickerEl = this.findElement('.recras-onlinebooking-date');
1892            this.getAvailableDays(packageId, startDate, endDate).then(function (availableDays) {
1893                _this31.loadingIndicatorHide();
1894
1895                if (datePickerEl.value && availableDays.indexOf(datePickerEl.value) === -1) {
1896                    datePickerEl.value = '';
1897
1898                    _this31.clearTimes();
1899                } else {
1900                    datePickerEl.removeAttribute('disabled');
1901                }
1902            });
1903        }
1904    }, {
1905        key: "updateProductPrice",
1906        value: function updateProductPrice(el) {
1907            var priceEl = el.parentNode.querySelector('.recras-price');
1908            var amount = parseInt(el.value, 10);
1909
1910            if (isNaN(amount)) {
1911                amount = 0;
1912            }
1913
1914            if (amount > 0) {
1915                priceEl.classList.remove('recrasUnitPrice');
1916            } else {
1917                priceEl.classList.add('recrasUnitPrice');
1918            }
1919
1920            amount = Math.max(amount, 1);
1921            priceEl.innerHTML = this.formatPrice(amount * el.dataset.price);
1922        }
1923    }, {
1924        key: "validPaymentMethod",
1925        value: function validPaymentMethod(pack, method) {
1926            return this.paymentMethods(pack).indexOf(method) > -1;
1927        }
1928    }]);
1929
1930    return RecrasBooking;
1931}();
1932
1933var RecrasCalendarHelper = /*#__PURE__*/function () {
1934    function RecrasCalendarHelper() {
1935        _classCallCheck(this, RecrasCalendarHelper);
1936    }
1937
1938    _createClass(RecrasCalendarHelper, null, [{
1939        key: "defaultOptions",
1940        value: function defaultOptions() {
1941            return {
1942                firstDay: 1,
1943                // Monday
1944                minDate: new Date(),
1945                numberOfMonths: 2,
1946                reposition: false,
1947                position: 'bottom right',
1948                toString: function toString(date) {
1949                    return RecrasDateHelper.toString(date);
1950                }
1951            };
1952        }
1953    }, {
1954        key: "i18n",
1955        value: function i18n(languageHelper) {
1956            return {
1957                previousMonth: languageHelper.translate('DATE_PICKER_PREVIOUS_MONTH'),
1958                nextMonth: languageHelper.translate('DATE_PICKER_NEXT_MONTH'),
1959                months: [languageHelper.translate('DATE_PICKER_MONTH_JANUARY'), languageHelper.translate('DATE_PICKER_MONTH_FEBRUARY'), languageHelper.translate('DATE_PICKER_MONTH_MARCH'), languageHelper.translate('DATE_PICKER_MONTH_APRIL'), languageHelper.translate('DATE_PICKER_MONTH_MAY'), languageHelper.translate('DATE_PICKER_MONTH_JUNE'), languageHelper.translate('DATE_PICKER_MONTH_JULY'), languageHelper.translate('DATE_PICKER_MONTH_AUGUST'), languageHelper.translate('DATE_PICKER_MONTH_SEPTEMBER'), languageHelper.translate('DATE_PICKER_MONTH_OCTOBER'), languageHelper.translate('DATE_PICKER_MONTH_NOVEMBER'), languageHelper.translate('DATE_PICKER_MONTH_DECEMBER')],
1960                weekdays: [languageHelper.translate('DATE_PICKER_DAY_SUNDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_MONDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_TUESDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_WEDNESDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_THURSDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_FRIDAY_LONG'), languageHelper.translate('DATE_PICKER_DAY_SATURDAY_LONG')],
1961                weekdaysShort: [languageHelper.translate('DATE_PICKER_DAY_SUNDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_MONDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_TUESDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_WEDNESDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_THURSDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_FRIDAY_SHORT'), languageHelper.translate('DATE_PICKER_DAY_SATURDAY_SHORT')]
1962            };
1963        }
1964    }, {
1965        key: "loadScript",
1966        value: function loadScript() {
1967            return new Promise(function (resolve, reject) {
1968                var scriptID = 'recrasPikaday'; // Only load script once
1969
1970                if (document.getElementById(scriptID)) {
1971                    resolve(true);
1972                }
1973
1974                var script = document.createElement('script');
1975                script.id = scriptID;
1976                script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pikaday/1.8.2/pikaday.min.js';
1977                script.addEventListener('load', function () {
1978                    return resolve(script);
1979                }, false);
1980                script.addEventListener('error', function () {
1981                    return reject(script);
1982                }, false);
1983                document.head.appendChild(script);
1984            });
1985        }
1986    }]);
1987
1988    return RecrasCalendarHelper;
1989}();
1990
1991var RecrasContactForm = /*#__PURE__*/function () {
1992    function RecrasContactForm() {
1993        var _this32 = this;
1994
1995        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1996
1997        _classCallCheck(this, RecrasContactForm);
1998
1999        this.languageHelper = new RecrasLanguageHelper();
2000
2001        if (!(options instanceof RecrasOptions)) {
2002            throw new Error(this.languageHelper.translate('ERR_OPTIONS_INVALID'));
2003        }
2004
2005        this.options = options;
2006
2007        if (!this.options.getFormId()) {
2008            throw new Error(this.languageHelper.translate('ERR_NO_FORM'));
2009        }
2010
2011        this.checkboxEventListeners = [];
2012        this.eventHelper = new RecrasEventHelper();
2013        this.eventHelper.setEvents(this.options.getAnalyticsEvents());
2014        this.element = this.options.getElement();
2015        this.element.classList.add('recras-contactform-wrapper');
2016        this.languageHelper.setOptions(options);
2017
2018        if (RecrasLanguageHelper.isValid(this.options.getLocale())) {
2019            this.languageHelper.setLocale(this.options.getLocale());
2020        }
2021
2022        this.fetchJson = function (url) {
2023            return RecrasHttpHelper.fetchJson(url, _this32.error.bind(_this32));
2024        };
2025
2026        this.postJson = function (url, data) {
2027            return RecrasHttpHelper.postJson(_this32.options.getApiBase() + url, data, _this32.error.bind(_this32));
2028        };
2029
2030        RecrasCSSHelper.loadCSS('global');
2031        this.GENDERS = {
2032            onbekend: 'GENDER_UNKNOWN',
2033            man: 'GENDER_MALE',
2034            vrouw: 'GENDER_FEMALE'
2035        }; // https://html.spec.whatwg.org/multipage/form-control-infrastru
2035cture.html#inappropriate-for-the-control
2036
2037        this.AUTOCOMPLETE_OPTIONS = {
2038            'contact.naam': 'organization',
2039            'contact.website': 'url',
2040            'contactpersoon.achternaam': 'family-name',
2041            'contactpersoon.adres': 'address-line1',
2042            'contactpersoon.plaats': 'address-level2',
2043            'contactpersoon.postcode': 'postal-code',
2044            'contactpersoon.voornaam': 'given-name'
2045        };
2046    }
2047
2048    _createClass(RecrasContactForm, [{
2049        key: "checkRequiredCheckboxes",
2050        value: function checkRequiredCheckboxes() {
2051            var _this33 = this;
2052
2053            this.removeWarnings();
2054            var isOkay = true;
2055
2056            _toConsumableArray(this.findElements('.checkboxGroupRequired')).forEach(function (group) {
2057                var checked = group.querySelectorAll('input:checked');
2058
2059                if (checked.length === 0) {
2060                    group.parentNode.querySelector('label').insertAdjacentHTML('beforeend', "<div class=\"recrasError\">".concat(_this33.languageHelper.translate('CONTACT_FORM_CHECKBOX_REQUIRED'), "</div>"));
2061                    isOkay = false;
2062                }
2063            });
2064
2065            return isOkay;
2066        }
2067    }, {
2068        key: "appendHtml",
2069        value: function appendHtml(msg) {
2070            this.element.insertAdjacentHTML('beforeend', msg);
2071        }
2072    }, {
2073        key: "error",
2074        value: function error(msg) {
2075            this.removeErrors('.recras-contactform');
2076            this.showInlineError(this.findElement('.submitForm'), msg);
2077        }
2078    }, {
2079        key: "findElement",
2080        value: function findElement(querystring) {
2081            return this.element.querySelector(querystring);
2082        }
2083    }, {
2084        key: "findElements",
2085        value: function findElements(querystring) {
2086            return this.element.querySelectorAll(querystring);
2087        }
2088    }, {
2089        key: "isStandalone",
2090        value: function isStandalone(options) {
2091            return !!options.standalone;
2092        }
2093    }, {
2094        key: "generateForm",
2095        value: function generateForm() {
2096            var _this34 = this;
2097
2098            var extraOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2099            var waitFor = [];
2100
2101            if (this.hasCountryField()) {
2102                waitFor.push(this.getCountryList());
2103            }
2104
2105            if (this.hasBookingDateField() || this.hasRelationDateField()) {
2106                waitFor.push(RecrasCalendarHelper.loadScript());
2107                RecrasCSSHelper.loadCSS('pikaday');
2108            }
2109
2110            return Promise.all(waitFor).then(function () {
2111                var standalone = _this34.isStandalone(extraOptions);
2112
2113                var validateText = standalone ? 'novalidate' : '';
2114                var html = "<form class=\"recras-contactform\" ".concat(validateText, ">");
2115
2116                if (extraOptions.voucherQuantitySelector) {
2117                    html += _this34.quantitySelector(extraOptions.quantityTerm);
2118                }
2119
2120                _this34.contactFormFields.forEach(function (field, idx) {
2121                    html += '<div>' + _this34.showField(field, idx) + '</div>';
2122                });
2123
2124                if (standalone) {
2125                    html += _this34.submitButtonHtml();
2126                }
2127
2128                html += '</form>';
2129                return html;
2130            });
2131        }
2132    }, {
2133        key: "generateJson",
2134        value: function generateJson() {
2135            var formEl = this.options.getElement().querySelector('.recras-contactform');
2136            var elements = formEl.querySelectorAll('[id^="contactformulier-"], input[type="radio"]:checked');
2137            var contactForm = {};
2138
2139            _toConsumableArray(elements).forEach(function (field) {
2140                contactForm[field.dataset.identifier] = field.value;
2141            });
2142
2143            _toConsumableArray(formEl.querySelectorAll('input[type="checkbox"]:checked')).forEach(function (field) {
2144                if (contactForm[field.dataset.identifier] === undefined) {
2145                    contactForm[field.dataset.identifier] = [];
2146                }
2147
2148                contactForm[field.dataset.identifier].push(field.value);
2149            });
2150
2151            if (contactForm['boeking.datum']) {
2152                contactForm['boeking.datum'] = RecrasDateHelper.formatStringForAPI(contactForm['boeking.datum']);
2153            }
2154
2155            return contactForm;
2156        }
2157    }, {
2158        key: "getContactFormFields",
2159        value: function getContactFormFields() {
2160            var _this35 = this;
2161
2162            return this.fetchJson(this.options.getApiBase() + 'contactformulieren/' + this.options.getFormId() + '?embed=Velden').then(function (form) {
2163                _this35.contactFormFields = form.Velden;
2164                _this35.packages = _this35.sortPackages(form.Arrangementen);
2165                return _this35.contactFormFields;
2166            });
2167        }
2168    }, {
2169        key: "getCountryList",
2170        value: function getCountryList() {
2171            var _this36 = this;
2172
2173            return this.fetchJson('https://cdn.rawgit.com/umpirsky/country-list/ddabf3a8/data/' + this.languageHelper.locale + '/country.json').then(function (json) {
2174                _this36.countries = json;
2175                return _this36.countries;
2176            });
2177        }
2178    }, {
2179        key: "sortPackages",
2180        value: function sortPackages(packs) {
2181            return packs.sort(function (a, b) {
2182                // Prioritise package name
2183                if (a.arrangement < b.arrangement) {
2184                    return -1;
2185                }
2186
2187                if (a.arrangement > b.arrangement) {
2188                    return 1;
2189                } // Sort by ID in the off chance that two packages are named the same
2190
2191
2192                if (a.id < b.id) {
2193                    return -1;
2194                }
2195
2196                if (a.id > b.id) {
2197                    return 1;
2198                } // This cannot happen
2199
2200
2201                return 0;
2202            });
2203        }
2204    }, {
2205        key: "getInvalidFields",
2206        value: function getInvalidFields() {
2207            var invalid = [];
2208            var required = this.getEmptyRequiredFields();
2209            var els = this.findElements('.recras-contactform :invalid');
2210
2211            for (var _i14 = 0; _i14 < els.length; _i14++) {
2212                var el = els[_i14];
2213
2214                if (!required.includes(el)) {
2215                    invalid.push(el);
2216                }
2217            }
2218
2219            return invalid;
2220        }
2221    }, {
2222        key: "getEmptyRequiredFields",
2223        value: function getEmptyRequiredFields() {
2224            var isEmpty = [];
2225            var els = this.findElements('.recras-contactform :required');
2226
2227            for (var _i16 = 0; _i16 < els.length; _i16++) {
2228                var el = els[_i16];
2229
2230                if (el.value === undefined || el.value === '') {
2231                    isEmpty.push(el);
2232                }
2233            }
2234
2235            return isEmpty;
2236        }
2237    }, {
2238        key: "getRelationExtraDateFields",
2239        value: function getRelationExtraDateFields() {
2240            return this.contactFormFields.filter(function (field) {
2241                return field.soort_invoer === 'contact.extra' && field.input_type === 'date';
2242            });
2243        }
2244    }, {
2245        key: "hasFieldOfType",
2246        value: function hasFieldOfType(identifier) {
2247            return this.contactFormFields.filter(function (field) {
2248                return field.field_identifier === identifier;
2249            }).length > 0;
2250        }
2251    }, {
2252        key: "hasBookingDateField",
2253        value: function hasBookingDateField() {
2254            return this.hasFieldOfType('boeking.datum');
2255        }
2256    }, {
2257        key: "hasCountryField",
2258        value: function hasCountryField() {
2259            return this.hasFieldOfType('contact.landcode');
2260        }
2261    }, {
2262        key: "hasPackageField",
2263        value: function hasPackageField() {
2264            return this.hasFieldOfType('boeking.arrangement');
2265        }
2266    }, {
2267        key: "hasRelationDateField",
2268        value: function hasRelationDateField() {
2269            return this.getRelationExtraDateFields().length > 0;
2270        }
2271    }, {
2272        key: "isEmpty",
2273        value: function isEmpty() {
2274            var els = this.findElements('.recras-contactform input, .recras-contactform select, .recras-contactform textarea');
2275
2276            var formValues = _toConsumableArray(els).map(function (el) {
2277                return el.value;
2278            });
2279
2280            return !formValues.some(function (v) {
2281                return v !== '';
2282            });
2283        }
2284    }, {
2285        key: "isValid",
2286        value: function isValid() {
2287            return this.findElement('.recras-contactform').checkValidity();
2288        }
2289    }, {
2290        key: "loadingIndicatorHide",
2291        value: function loadingIndicatorHide() {
2292            _toConsumableArray(document.querySelectorAll('.recrasLoadingIndicator')).forEach(function (el) {
2293                el.parentNode.removeChild(el);
2294            });
2295        }
2296    }, {
2297        key: "loadingIndicatorShow",
2298        value: function loadingIndicatorShow(afterEl) {
2299            if (!afterEl) {
2300                return;
2301            }
2302
2303            afterEl.insertAdjacentHTML('beforeend', "<span class=\"recrasLoadingIndicator\">".concat(this.languageHelper.translate('LOADING'), "</span>"));
2304        }
2305    }, {
2306        key: "quantitySelector",
2307        value: function quantitySelector(quantityTerm) {
2308            if (!quantityTerm) {
2309                quantityTerm = this.languageHelper.translate('VOUCHER_QUANTITY');
2310            }
2311
2312            return "<div>\n            <label for=\"number-of-vouchers\">".concat(quantityTerm, "</label>\n            <input type=\"number\" id=\"number-of-vouchers\" class=\"number-of-vouchers\" min=\"1\" max=\"100\" value=\"1\" required>\n        </div>");
2313        }
2314    }, {
2315        key: "removeErrors",
2316        value: function removeErrors() {
2317            var parentQuery = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
2318
2319            _toConsumableArray(this.findElements(parentQuery + ' .booking-error')).forEach(function (el) {
2320                el.parentNode.removeChild(el);
2321            });
2322        }
2323    }, {
2324        key: "removeWarnings",
2325        value: function removeWarnings() {
2326            _toConsumableArray(this.findElements('.recrasError')).forEach(function (el) {
2327                el.parentNode.removeChild(el);
2328            });
2329
2330            _toConsumableArray(this.findElements('.recras-success')).forEach(function (el) {
2331                el.parentNode.removeChild(el);
2332            });
2333        }
2334    }, {
2335        key: "hasEmptyRequiredFields",
2336        value: function hasEmptyRequiredFields() {
2337            return this.getEmptyRequiredFields().length > 0;
2338        }
2339    }, {
2340        key: "showField",
2341        value: function showField(field, idx) {
2342            var _this37 = this;
2343
2344            if (field.soort_invoer === 'header') {
2345                return "<h3>".concat(field.naam, "</h3>");
2346            }
2347
2348            var today = RecrasDateHelper.toString(new Date());
2349            var timePattern = '(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9])';
2350            var label = this.showLabel(field, idx);
2351            var attrRequired = field.verplicht ? 'required' : '';
2352            var classes;
2353            var html;
2354            var placeholder;
2355            var fixedAttributes = "id=\"contactformulier-".concat(idx, "\" name=\"contactformulier").concat(idx, "\" ").concat(attrRequired, " data-identifier=\"").concat(field.field_identifier, "\"");
2356
2357            switch (field.soort_invoer) {
2358                case 'contactpersoon.geslacht':
2359                    html = "<select ".concat(fixedAttributes, " autocomplete=\"sex\">");
2360                    Object.keys(this.GENDERS).forEach(function (key) {
2361                        html += "<option value=\"".concat(key, "\">").concat(_this37.languageHelper.translate(_this37.GENDERS[key]));
2362                    });
2363                    html += '</select>';
2364                    return label + html;
2365
2366                case 'keuze':
2367                    classes = ['checkboxGroup'];
2368
2369                    if (field.verplicht) {
2370                        classes.push('checkboxGroupRequired');
2371                    }
2372
2373                    html = "<div class=\"".concat(classes.join(' '), "\">");
2374                    field.mogelijke_keuzes.forEach(function (choice) {
2375                        html += "<label><input type=\"checkbox\" name=\"contactformulier".concat(idx, "\" value=\"").concat(choice, "\" data-identifier=\"").concat(field.field_identifier, "\">").concat(choice, "</label>");
2376                    });
2377                    html += '</div>';
2378                    return label + html;
2379
2380                case 'keuze_enkel':
2381                case 'contact.soort_klant':
2382                    html = "<div class=\"radioGroup\">";
2383                    field.mogelijke_keuzes.forEach(function (choice) {
2384                        html += "<label><input type=\"radio\" name=\"contactformulier".concat(idx, "\" value=\"").concat(choice, "\" ").concat(attrRequired, " data-identifier=\"").concat(field.field_identifier, "\">").concat(choice, "</label>");
2385                    });
2386                    html += "</div>";
2387                    return label + html;
2388
2389                case 'veel_tekst':
2390                    return label + "<textarea ".concat(fixedAttributes, "></textarea>");
2391
2392                case 'contactpersoon.telefoon1':
2393                case 'contactpersoon.telefoon2':
2394                    return label + "<input type=\"tel\" ".concat(fixedAttributes, " autocomplete=\"tel\">");
2395
2396                case 'contactpersoon.email1':
2397                case 'contactpersoon.email2':
2398                    return label + "<input type=\"email\" ".concat(fixedAttributes, " autocomplete=\"email\">");
2399
2400                case 'contactpersoon.nieuwsbrieven':
2401                    classes = ['checkboxGroup'];
2402
2403                    if (field.verplicht) {
2404                        classes.push('checkboxGroupRequired');
2405                    }
2406
2407                    html = "<div class=\"".concat(classes.join(' '), "\">");
2408                    Object.keys(field.newsletter_options).forEach(function (key) {
2409                        html += "<label><input type=\"checkbox\" name=\"contactformulier".concat(idx, "\" value=\"").concat(key, "\" data-identifier=\"").concat(field.field_identifier, "\">").concat(field.newsletter_options[key], "</label>");
2410                    });
2411                    html += '</div>';
2412                    return label + html;
2413
2414                case 'contact.landcode':
2415                    html = "<select ".concat(fixedAttributes, " autocomplete=\"country\">");
2416                    Object.keys(this.countries).forEach(function (code) {
2417                        var selectedText = code.toUpperCase() === _this37.options.getDefaultCountry() ? 'selected' : '';
2418                        html += "<option value=\"".concat(code, "\" ").concat(selectedText, ">").concat(_this37.countries[code]);
2419                    });
2420                    html += '</select>';
2421                    return label + html;
2422
2423                case 'boeking.datum':
2424                    placeholder = this.languageHelper.translate('DATE_FORMAT');
2425                    return label + "<input type=\"text\" ".concat(fixedAttributes, " min=\"").concat(today, "\" placeholder=\"").concat(placeholder, "\" autocomplete=\"off\">");
2426
2427                case 'boeking.groepsgrootte':
2428                    return label + "<input type=\"number\" ".concat(fixedAttributes, " min=\"1\">");
2429
2430                case 'boeking.starttijd':
2431                    placeholder = this.languageHelper.translate('TIME_FORMAT');
2432                    return label + "<input type=\"time\" ".concat(fixedAttributes, " placeholder=\"").concat(placeholder, "\" pattern=\"").concat(timePattern, "\">");
2433
2434                case 'boeking.arrangement':
2435                    var preFilledPackage = this.options.getPackageId();
2436
2437                    if (field.verplicht && this.packages.length === 1) {
2438                        var pack = this.packages[0];
2439                        html = "<select ".concat(fixedAttributes, ">\n                        <option value=\"").concat(pack.id, "\" selected>").concat(pack.arrangement, "\n                    </select>");
2440                        return label + html;
2441                    }
2442
2443                    html = "<select ".concat(fixedAttributes, ">");
2444                    html += "<option value=\"\">";
2445                    this.packages.forEach(function (pack) {
2446                        var selText = preFilledPackage && preFilledPackage === pack.id ? 'selected' : '';
2447                        html += "<option value=\"".concat(pack.id, "\" ").concat(selText, ">").concat(pack.arrangement);
2448                    });
2449                    html += '</select>';
2450                    return label + html;
2451
2452                case 'contact.extra':
2453                    switch (field.input_type) {
2454                        case 'number':
2455                            return label + "<input type=\"number\" ".concat(fixedAttributes, " autocomplete=\"off\">");
2456
2457                        case 'date':
2458                        case 'text':
2459                            return label + "<input type=\"text\" ".concat(fixedAttributes, " maxlength=\"200\">");
2460
2461                        case 'multiplechoice':
2462                            classes = ['checkboxGroup'];
2463
2464                            if (field.verplicht) {
2465                                classes.push('checkboxGroupRequired');
2466                            }
2467
2468                            html = "<div class=\"".concat(classes.join(' '), "\">");
2469                            field.mogelijke_keuzes.forEach(function (choice) {
2470                                html += "<label><input type=\"checkbox\" name=\"contactformulier".concat(idx, "\" value=\"").concat(choice, "\" data-identifier=\"").concat(field.field_identifier, "\">").concat(choice, "</label>");
2471                            });
2472                            html += '</div>';
2473                            return label + html;
2474
2475                        case 'singlechoice':
2476                            html = "<div class=\"radioGroup\">";
2477                            field.mogelijke_keuzes.forEach(function (choice) {
2478                                html += "<label><input type=\"radio\" name=\"contactformulier".concat(idx, "\" value=\"").concat(choice, "\" ").concat(attrRequired, " data-identifier=\"").concat(field.field_identifier, "\">").concat(choice, "</label>");
2479                            });
2480                            html += "</div>";
2481                            return label + html;
2482
2483                        default:
2484                            console.debug('Unknown type', field.input_type, field);
2485                            return label + "<input type=\"text\" ".concat(fixedAttributes, ">");
2486                    }
2487
2488                case 'contact.website': //TODO: type=url ?
2489
2490                default:
2491                    var autocomplete = this.AUTOCOMPLETE_OPTIONS[field.soort_invoer] ? this.AUTOCOMPLETE_OPTIONS[field.soort_invoer] : '';
2492                    return label + "<input type=\"text\" ".concat(fixedAttributes, " autocomplete=\"").concat(autocomplete, "\">");
2493            }
2494        }
2495    }, {
2496        key: "showForm",
2497        value: function showForm() {
2498            var _this38 = this;
2499
2500            this.loadingIndicatorShow(this.element);
2501            return this.getContactFormFields().then(function () {
2502                return _this38.generateForm({
2503                    standalone: true
2504                });
2505            }).then(function (html) {
2506                _this38.appendHtml(html);
2507
2508                _toConsumableArray(_this38.findElements('.checkboxGroupRequired')).forEach(function (group) {
2509                    _toConsumableArray(group.querySelectorAll('input')).forEach(function (el) {
2510                        el.addEventListener('change', _this38.checkRequiredCheckboxes.bind(_this38));
2511                    });
2512                });
2513
2514                _this38.findElement('.recras-contactform').addEventListener('submit', _this38.submitForm.bind(_this38));
2515
2516                if (_this38.hasBookingDateField()) {
2517                    var pikadayOptions = _extends(RecrasCalendarHelper.defaultOptions(), {
2518                        field: _this38.findElement('[data-identifier="boeking.datum"]'),
2519                        i18n: RecrasCalendarHelper.i18n(_this38.languageHelper),
2520                        numberOfMonths: 1,
2521                        parse: RecrasDateHelper.parseMDY
2522                    });
2523
2524                    new Pikaday(pikadayOptions);
2525                }
2526
2527                if (_this38.hasRelationDateField()) {
2528                    var fields = _this38.getRelationExtraDateFields();
2529
2530                    var thisYear = new Date().getFullYear();
2531
2532                    var _pikadayOptions = _extends(RecrasCalendarHelper.defaultOptions(), {
2533                        i18n: RecrasCalendarHelper.i18n(_this38.languageHelper),
2534                        numberOfMonths: 1,
2535                        yearRange: [thisYear - 90, thisYear + 10]
2536                    });
2537
2538                    delete _pikadayOptions.minDate;
2539
2540                    for (var _i18 = 0; _i18 < fields.length; _i18++) {
2541                        var field = fields[_i18];
2542                        _pikadayOptions.field = _this38.findElement("[data-identifier=\"".concat(field.field_identifier, "\"]"));
2543                        new Pikaday(_pikadayOptions);
2544                    }
2545                }
2546
2547                _this38.loadingIndicatorHide();
2548            });
2549        }
2550    }, {
2551        key: "showInlineError",
2552        value: function showInlineError(element, errorMsg) {
2553            element.parentNode.insertAdjacentHTML('afterend', "<div class=\"booking-error\">".concat(errorMsg, "</div>"));
2554        }
2555    }, {
2556        key: "showErrors",
2557        value: function showErrors() {
2558            var errors = [];
2559
2560            for (var _i20 = 0, _this$getEmptyRequire2 = this.getEmptyRequiredFields(); _i20 < _this$getEmptyRequire2.length; _i20++) {
2561                var el = _this$getEmptyRequire2[_i20];
2562                var labelEl = el.parentNode.querySelector('label');
2563                var requiredText = this.languageHelper.translate('CONTACT_FORM_FIELD_REQUIRED', {
2564                    FIELD_NAME: labelEl.innerText
2565                });
2566                errors.push(requiredText);
2567            }
2568
2569            for (var _i22 = 0, _this$getInvalidField2 = this.getInvalidFields(); _i22 < _this$getInvalidField2.length; _i22++) {
2570                var _el = _this$getInvalidField2[_i22];
2571
2572                var parentEl = _el.closest('div');
2573
2574                if (parentEl.classList.contains('radioGroup')) {
2575                    parentEl = parentEl.parentNode.closest('div');
2576                }
2577
2578                var _labelEl = parentEl.querySelector('label');
2579
2580                console.log(_labelEl, parentEl.querySelectorAll('label'));
2581                var invalidText = this.languageHelper.translate('CONTACT_FORM_FIELD_INVALID', {
2582                    FIELD_NAME: _labelEl.innerText
2583                });
2584                errors.push(invalidText);
2585            }
2586
2587            errors = _toConsumableArray(new Set(errors)); // Only unique text
2588
2589            this.findElement('button[type="submit"]').insertAdjacentHTML('afterend', "<div class=\"booking-error\"><ul><li>".concat(errors.join('<li>'), "</ul></div>"));
2590        }
2591    }, {
2592        key: "showLabel",
2593        value: function showLabel(field, idx) {
2594            var labelText = field.naam;
2595
2596            if (field.verplicht) {
2597                labelText += "<span class=\"recras-contactform-required\" title=\"".concat(this.languageHelper.translate('ATTR_REQUIRED'), "\"></span>");
2598            }
2599
2600            return "<label for=\"contactformulier-".concat(idx, "\">").concat(labelText, "</label>");
2601        }
2602    }, {
2603        key: "submitButtonHtml",
2604        value: function submitButtonHtml() {
2605            return "<button type=\"submit\" class=\"submitForm\">".concat(this.languageHelper.translate('BUTTON_SUBMIT_CONTACT_FORM'), "</button>");
2606        }
2607    }, {
2608        key: "submitForm",
2609        value: function submitForm(e) {
2610            var _this39 = this;
2611
2612            e.preventDefault();
2613            var submitButton = this.findElement('.submitForm');
2614            this.removeErrors('.recras-contactform');
2615
2616            if (this.isEmpty()) {
2617                submitButton.parentNode.insertAdjacentHTML('beforeend', "<div class=\"booking-error\">".concat(this.languageHelper.translate('ERR_CONTACT_FORM_EMPTY'), "</div>"));
2618                return false;
2619            } else if (this.hasEmptyRequiredFields() || !this.isValid()) {
2620                this.showErrors();
2621                return false;
2622            }
2623
2624            if (!this.checkRequiredCheckboxes()) {
2625                return false;
2626            }
2627
2628            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_CONTACT_FORM, RecrasEventHelper.EVENT_CONTACT_FORM_SUBMIT, null, this.options.getFormId());
2629            this.loadingIndicatorHide();
2630            this.loadingIndicatorShow(submitButton);
2631            submitButton.setAttribute('disabled', 'disabled');
2632            this.postJson('contactformulieren/' + this.options.getFormId() + '/opslaan', this.generateJson()).then(function (json) {
2633                if (json.success) {
2634                    if (_this39.options.getRedirectUrl()) {
2635                        window.top.location.href = _this39.options.getRedirectUrl();
2636                    } else {
2637                        _this39.element.scrollIntoView({
2638                            behavior: 'smooth'
2639                        });
2640
2641                        _this39.element.insertAdjacentHTML('afterbegin', "<p class=\"recras-success\">".concat(_this39.languageHelper.translate('CONTACT_FORM_SUBMIT_SUCCESS'), "</p>"));
2642
2643                        submitButton.parentNode.reset();
2644                    }
2645                } else {
2646                    _this39.error(_this39.languageHelper.translate('CONTACT_FORM_SUBMIT_FAILED'));
2647                }
2648
2649                submitButton.removeAttribute('disabled');
2650
2651                _this39.loadingIndicatorHide();
2652            });
2653            return false;
2654        }
2655    }]);
2656
2657    return RecrasContactForm;
2658}();
2659
2660var RecrasCSSHelper = /*#__PURE__*/function () {
2661    function RecrasCSSHelper() {
2662        _classCallCheck(this, RecrasCSSHelper);
2663    }
2664
2665    _createClass(RecrasCSSHelper, null, [{
2666        key: "cssBooking",
2667        value: function cssBooking() {
2668            return "\n.recras-onlinebooking {\n    max-width: 800px;\n}\n.recras-onlinebooking > form + form, .recras-finalise {\n    border-top: 2px solid #dedede; /* Any love for Kirby out there? */\n}\n.recras-amountsform > div {\n    display: grid;\n    grid-template-columns: 1fr 5em 7em;\n}\n.recras-amountsform input {\n    width: auto; /* Firefox fix */\n}\n.recras-input-invalid {\n    border: 1px solid hsl(0, 50%, 50%);\n}\n.booking-error, .minimum-amount {\n    color: hsl(0, 50%, 50%);\n}\n.recras-success {\n    color: hsl(120, 40%, 40%);\n}\n.minimum-amount {\n    padding-left: 0.5em;\n}\n.recras-datetime {\n    display: grid;\n    grid-template-columns: 30% 70%;\n}\n.recras-datetime > * {\n    margin: 0.25em 0;\n}\n.recras-datetime label {\n    display: block;\n}\n.recras-datetime input, .recras-datetime select {\n    max-width: 12em;\n}\n.time-preview {\n    padding-right: 0.5em;\n}\n.recrasUnitPrice {\n    opacity: 0.5;\n}\n.recras-onlinebooking .recrasHidden {\n    display: none;\n}\n";
2669        }
2670    }, {
2671        key: "cssGlobal",
2672        value: function cssGlobal() {
2673            return "\n.latestError, .recrasError {\n    color: hsl(0, 50%, 50%);\n}\n.recras-onlinebooking > *:not(.latestError):not(.recrasLoadingIndicator) {\n    padding: 1em 0;\n}\n.recras-datetime, .recras-discounts > div, .recras-contactform > div {\n    display: grid;\n    grid-template-columns: 1fr 12em;\n}\n.recras-contactform > div {\n    padding-bottom: 0.25em;\n    padding-top: 0.25em;\n}\n.recras-contactform label {\n    display: block;\n}\n.recras-amountsform .recras-full-width {\n    display: block;\n}\n\n.recrasLoadingIndicator {\n    animation: recrasSpinner 1.1s infinite linear;\n    border: 0.2em solid rgba(0, 0, 0, 0.2);\n    border-left-color: rgba(0, 0, 0, 0.5);\n    border-radius: 50%;\n    display: inline-block;\n    height: 2em;\n    overflow: hidden;\n    text-indent: -100vw;\n    width: 2em;\n}\n@keyframes recrasSpinner {\n    0% {\n        transform: rotate(0deg);\n    }\n    100% {\n        transform: rotate(360deg);\n    }\n}\nbutton .recrasLoadingIndicator, label .recrasLoadingIndicator {\n    height: 1em;\n    vertical-align: middle;\n    width: 1em;\n}\nbutton .recrasLoadingIndicator {\n    margin-left: 0.5em;\n}\n.bookPackage, .submitForm, .buyTemplate {\n    font: inherit;\n    font-weight: bold;\n    padding: 0.5em 2em;\n}\n@media (max-width: 520px) {\n    .pika-single {\n        max-width: 256px; /* Single month is 240px + 2x8px margin */\n    }\n}\n";
2674        }
2675    }, {
2676        key: "insertIntoHead",
2677        value: function insertIntoHead(el) {
2678            document.head.insertAdjacentElement('afterbegin', el);
2679        }
2680    }, {
2681        key: "loadInlineCss",
2682        value: function loadInlineCss(cssName, inlineCss) {
2683            var styleEl = document.createElement('style');
2684            styleEl.id = 'recras-css-' + cssName;
2685            styleEl.innerHTML = inlineCss;
2686            RecrasCSSHelper.insertIntoHead(styleEl);
2687        }
2688    }, {
2689        key: "loadExternalCss",
2690        value: function loadExternalCss(cssName, url) {
2691            var linkEl = document.createElement('link');
2692            linkEl.id = 'recras-css-' + cssName;
2693            linkEl.setAttribute('rel', 'stylesheet');
2694            linkEl.setAttribute('type', 'text/css');
2695            linkEl.setAttribute('href', url);
2696            RecrasCSSHelper.insertIntoHead(linkEl);
2697        }
2698    }, {
2699        key: "loadCSS",
2700        value: function loadCSS(cssName) {
2701            var inlineCss;
2702            var url;
2703
2704            switch (cssName) {
2705                case 'booking':
2706                    inlineCss = this.cssBooking();
2707                    break;
2708
2709                case 'global':
2710                    inlineCss = this.cssGlobal();
2711                    break;
2712
2713                case 'pikaday':
2714                    url = 'https://cdnjs.cloudflare.com/ajax/libs/pikaday/1.8.2/css/pikaday.min.css';
2715                    break;
2716
2717                default:
2718                    console.warn('Unknown CSS');
2719                    break;
2720            }
2721
2722            if (document.getElementById('recras-css-' + cssName)) {
2723                return;
2724            }
2725
2726            if (inlineCss) {
2727                RecrasCSSHelper.loadInlineCss(cssName, inlineCss);
2728            }
2729
2730            if (url) {
2731                RecrasCSSHelper.loadExternalCss(cssName, url);
2732            }
2733        }
2734    }]);
2735
2736    return RecrasCSSHelper;
2737}();
2738
2739var RecrasDateHelper = /*#__PURE__*/function () {
2740    function RecrasDateHelper() {
2741        _classCallCheck(this, RecrasDateHelper);
2742    }
2743
2744    _createClass(RecrasDateHelper, null, [{
2745        key: "clone",
2746        value: function clone(date) {
2747            return new Date(date.getTime());
2748        }
2749    }, {
2750        key: "datePartOnly",
2751        value: function datePartOnly(date) {
2752            var x = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000); // Fix off-by-1 errors
2753
2754            return x.toISOString().substr(0, 10); // Format as 2018-03-13
2755        }
2756    }, {
2757        key: "formatStringForAPI",
2758        value: function formatStringForAPI(date) {
2759            // Handle DD-MM-YYYY pattern in code
2760            var datePatternDMY = '(0[1-9]|1[0-9]|2[0-9]|3[01])-(0[1-9]|1[012])-([0-9]{4})';
2761            var dmyMatches = date.match(datePatternDMY);
2762
2763            if (dmyMatches) {
2764                return dmyMatches[3] + '-' + dmyMatches[2] + '-' + dmyMatches[1];
2765            } // Let API handle the rest. That way, the user will get an error if the input is invalid
2766
2767
2768            return date;
2769        }
2770    }, {
2771        key: "parseMDY",
2772        value: function parseMDY(dateStr) {
2773            var parts = dateStr.split('-');
2774            var day = parseInt(parts[0], 10);
2775            var month = parseInt(parts[1], 10) - 1;
2776            var year = parseInt(parts[2], 10);
2777            return new Date(year, month, day);
2778        }
2779    }, {
2780        key: "setTimeForDate",
2781        value: function setTimeForDate(date, timeStr) {
2782            date.setHours(timeStr.substr(0, 2), timeStr.substr(3, 2));
2783            return date;
2784        }
2785    }, {
2786        key: "timePartOnly",
2787        value: function timePartOnly(date) {
2788            return date.toTimeString().substr(0, 5); // Format at 09:00
2789        }
2790    }, {
2791        key: "toString",
2792        value: function toString(date) {
2793            var x = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000); // Fix off-by-1 errors
2794
2795            x = x.toISOString();
2796            return x.substr(8, 2) + '-' + x.substr(5, 2) + '-' + x.substr(0, 4);
2797        }
2798    }]);
2799
2800    return RecrasDateHelper;
2801}();
2802
2803var RecrasEventHelper = /*#__PURE__*/function () {
2804    function RecrasEventHelper() {
2805        _classCallCheck(this, RecrasEventHelper);
2806
2807        this.analyticsEnabled = false;
2808        this.eventsEnabled = RecrasEventHelper.allEvents();
2809    }
2810
2811    _createClass(RecrasEventHelper, [{
2812        key: "eventEnabled",
2813        value: function eventEnabled(name) {
2814            return this.eventsEnabled.includes(name);
2815        }
2816    }, {
2817        key: "ga4EventMap",
2818        value: function ga4EventMap(action) {
2819            var _map;
2820
2821            var map = (_map = {}, _defineProperty(_map, RecrasEventHelper.EVENT_BOOKING_PACKAGE_CHANGED, 'select_content'), _defineProperty(_map, RecrasEventHelper.EVENT_BOOKING_REDIRECT_PAYMENT, 'begin_checkout'), _defineProperty(_map, RecrasEventHelper.EVENT_VOUCHER_TEMPLATE_CHANGED, 'select_content'), _defineProperty(_map, RecrasEventHelper.EVENT_VOUCHER_REDIRECT_PAYMENT, 'begin_checkout'), _map);
2822
2823            if (map[action] === undefined) {
2824                return false;
2825            }
2826
2827            return map[action];
2828        }
2829    }, {
2830        key: "sendAnalyticsEvent",
2831        value: function sendAnalyticsEvent(cat, action) {
2832            var label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
2833            var value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
2834            var ga4Value = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined;
2835
2836            if (typeof window.gtag !== 'function') {
2837                return;
2838            }
2839
2840            if (this.ga4EventMap(action) && ga4Value) {
2841                // v4
2842                window.gtag('event', this.ga4EventMap(action), ga4Value);
2843                return;
2844            } // Global Site Tag (v3)
2845
2846
2847            var eventData = {
2848                event_category: RecrasEventHelper.PREFIX_GLOBAL + ':' + cat
2849            };
2850
2851            if (label) {
2852                eventData.event_label = label;
2853            }
2854
2855            if (value) {
2856                eventData.value = value;
2857            }
2858
2859            window.gtag('event', action, eventData);
2860        }
2861    }, {
2862        key: "sendEvent",
2863        value: function sendEvent(cat, action) {
2864            var label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
2865            var value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
2866            var ga4Value = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined;
2867
2868            if (this.analyticsEnabled && this.eventEnabled(action)) {
2869                this.sendAnalyticsEvent(cat, action, label, value, ga4Value);
2870            }
2871
2872            var event = new Event(RecrasEventHelper.PREFIX_GLOBAL + ':' + cat + ':' + action);
2873            return document.dispatchEvent(event);
2874        }
2875    }, {
2876        key: "setAnalytics",
2877        value: function setAnalytics(bool) {
2878            this.analyticsEnabled = bool;
2879        }
2880    }, {
2881        key: "setEvents",
2882        value: function setEvents(events) {
2883            this.eventsEnabled = events;
2884        }
2885    }], [{
2886        key: "allEvents",
2887        value: function allEvents() {
2888            return [RecrasEventHelper.EVENT_BOOKING_BOOKING_SUBMITTED, RecrasEventHelper.EVENT_BOOKING_CONTACT_FORM_SHOWN, RecrasEventHelper.EVENT_BOOKING_DATE_SELECTED, RecrasEventHelper.EVENT_BOOKING_PACKAGE_CHANGED, RecrasEventHelper.EVENT_BOOKING_PACKAGES_SHOWN, RecrasEventHelper.EVENT_BOOKING_PRODUCTS_SHOWN, RecrasEventHelper.EVENT_BOOKING_REDIRECT_PAYMENT, RecrasEventHelper.EVENT_BOOKING_RESET, RecrasEventHelper.EVENT_BOOKING_TIME_SELECTED, RecrasEventHelper.EVENT_CONTACT_FORM_SUBMIT, RecrasEventHelper.EVENT_VOUCHER_REDIRECT_PAYMENT, RecrasEventHelper.EVENT_VOUCHER_TEMPLATE_CHANGED, RecrasEventHelper.EVENT_VOUCHER_VOUCHER_SUBMITTED];
2889        }
2890    }]);
2891
2892    return RecrasEventHelper;
2893}();
2894
2895_defineProperty(RecrasEventHelper, "PREFIX_GLOBAL", 'Recras');
2896
2897_defineProperty(RecrasEventHelper, "PREFIX_BOOKING", 'Booking');
2898
2899_defineProperty(RecrasEventHelper, "PREFIX_CONTACT_FORM", 'ContactForm');
2900
2901_defineProperty(RecrasEventHelper, "PREFIX_VOUCHER", 'Voucher');
2902
2903_defineProperty(RecrasEventHelper, "EVENT_BOOKING_BOOKING_SUBMITTED", 'BuyInProgress');
2904
2905_defineProperty(RecrasEventHelper, "EVENT_BOOKING_CONTACT_FORM_SHOWN", 'ContactFormShown');
2906
2907_defineProperty(RecrasEventHelper, "EVENT_BOOKING_DATE_SELECTED", 'DateSelected');
2908
2909_defineProperty(RecrasEventHelper, "EVENT_BOOKING_PACKAGE_CHANGED", 'PackageChanged');
2910
2911_defineProperty(RecrasEventHelper, "EVENT_BOOKING_PACKAGES_SHOWN", 'PackagesShown');
2912
2913_defineProperty(RecrasEventHelper, "EVENT_BOOKING_PRODUCTS_SHOWN", 'ProductsShown');
2914
2915_defineProperty(RecrasEventHelper, "EVENT_BOOKING_REDIRECT_PAYMENT", 'RedirectToPayment');
2916
2917_defineProperty(RecrasEventHelper, "EVENT_BOOKING_RESET", 'Reset');
2918
2919_defineProperty(RecrasEventHelper, "EVENT_BOOKING_TIME_SELECTED", 'TimeSelected');
2920
2921_defineProperty(RecrasEventHelper, "EVENT_CONTACT_FORM_SUBMIT", 'Submit');
2922
2923_defineProperty(RecrasEventHelper, "EVENT_VOUCHER_REDIRECT_PAYMENT", 'RedirectToPayment');
2924
2925_defineProperty(RecrasEventHelper, "EVENT_VOUCHER_TEMPLATE_CHANGED", 'TemplateChanged');
2926
2927_defineProperty(RecrasEventHelper, "EVENT_VOUCHER_VOUCHER_SUBMITTED", 'BuyInProgress');
2928
2929var RecrasHttpHelper = /*#__PURE__*/function () {
2930    function RecrasHttpHelper() {
2931        _classCallCheck(this, RecrasHttpHelper);
2932    }
2933
2934    _createClass(RecrasHttpHelper, null, [{
2935        key: "call",
2936        value: function call(url, data, errorHandler) {
2937            if (!url) {
2938                throw new Error('ERR_FETCH_WITHOUT_URL'); //TODO: translate
2939            }
2940
2941            var lastResponse;
2942            return fetch(url, data).then(function (response) {
2943                lastResponse = response;
2944                return response.json();
2945            }).then(function (json) {
2946                if (!lastResponse.ok) {
2947                    var errorMsg = json.error && json.error.message ? json.error.message : lastResponse.status + ' ' + lastResponse.statusText;
2948                    errorHandler(errorMsg);
2949                    return false;
2950                }
2951
2952                return json;
2953            })["catch"](function (err) {
2954                errorHandler(err);
2955            });
2956        }
2957    }, {
2958        key: "fetchJson",
2959        value: function fetchJson(url, errorHandler) {
2960            return this.call(url, {
2961                credentials: 'omit',
2962                method: 'get'
2963            }, errorHandler);
2964        }
2965    }, {
2966        key: "postJson",
2967        value: function postJson(url, data, errorHandler) {
2968            return this.call(url, {
2969                body: JSON.stringify(data),
2970                credentials: 'omit',
2971                method: 'post'
2972            }, errorHandler);
2973        }
2974    }]);
2975
2976    return RecrasHttpHelper;
2977}();
2978
2979var RecrasLanguageHelper = /*#__PURE__*/function () {
2980    function RecrasLanguageHelper() {
2981        _classCallCheck(this, RecrasLanguageHelper);
2982
2983        this.defaultLocale = 'nl_NL';
2984        this.locale = this.defaultLocale;
2985        this.options = null; //TODO: what is the best way to handle multiple locales?
2986
2987        this.i18n = {
2988            de_DE: {
2989                AGREE_ATTACHMENTS: 'Ich stimme den folgenden Unterlagen zu:',
2990                ATTR_REQUIRED: 'Erforderlich',
2991                BOOKING_DISABLED_AGREEMENT: 'Sie haben den Bedingungen noch nicht zugestimmt',
2992                BOOKING_DISABLED_AMOUNTS_INVALID: 'Programmbeträge sind ungültig',
2993                BOOKING_DISABLED_CONTACT_FORM_INVALID: 'Das Kontaktformular ist nicht korrekt ausgefüllt',
2994                BOOKING_DISABLED_INVALID_DATE: 'Kein Datum ausgewählt',
2995                BOOKING_DISABLED_INVALID_TIME: 'Keine Zeit ausgewählt',
2996                BOOKING_DISABLED_REQUIRED_PRODUCT: 'Erforderliches Produkt noch nicht ausgewählt',
2997                BUTTON_BOOK_NOW: 'Jetzt buchen',
2998                BUTTON_BUY_NOW: 'Jetzt kaufen',
2999                BUTTON_SUBMIT_CONTACT_FORM: 'Senden',
3000                CONTACT_FORM_CHECKBOX_REQUIRED: 'Es muss mindestens eine Option aktiviert sein',
3001                CONTACT_FORM_FIELD_INVALID: '"{FIELD_NAME}" ist ungültig',
3002                CONTACT_FORM_FIELD_REQUIRED: '"{FIELD_NAME}" ist ein erforderliches Feld',
3003                CONTACT_FORM_SUBMIT_FAILED: 'Das Kontaktformular konnte nicht gesendet werden. Bitte versuchen Sie es später noch einmal.',
3004                CONTACT_FORM_SUBMIT_SUCCESS: 'Das Kontaktformular wurde erfolgreich gesendet.',
3005                DATE: 'Datum',
3006                DATE_FORMAT: 'TT-MM-JJJJ',
3007                DATE_INVALID: 'Ungültiges datum',
3008                DATE_PICKER_NEXT_MONTH: 'Nächsten Monat',
3009                DATE_PICKER_PREVIOUS_MONTH: 'Vorheriger Monat',
3010                DATE_PICKER_MONTH_JANUARY: 'Januar',
3011                DATE_PICKER_MONTH_FEBRUARY: 'Februar',
3012                DATE_PICKER_MONTH_MARCH: 'März',
3013                DATE_PICKER_MONTH_APRIL: 'April',
3014                DATE_PICKER_MONTH_MAY: 'Mai',
3015                DATE_PICKER_MONTH_JUNE: 'Juni',
3016                DATE_PICKER_MONTH_JULY: 'Juli',
3017                DATE_PICKER_MONTH_AUGUST: 'August',
3018                DATE_PICKER_MONTH_SEPTEMBER: 'September',
3019                DATE_PICKER_MONTH_OCTOBER: 'Oktober',
3020                DATE_PICKER_MONTH_NOVEMBER: 'November',
3021                DATE_PICKER_MONTH_DECEMBER: 'Dezember',
3022                DATE_PICKER_DAY_MONDAY_LONG: 'Montag',
3023                DATE_PICKER_DAY_MONDAY_SHORT: 'Mo',
3024                DATE_PICKER_DAY_TUESDAY_LONG: 'Dienstag',
3025                DATE_PICKER_DAY_TUESDAY_SHORT: 'Di',
3026                DATE_PICKER_DAY_WEDNESDAY_LONG: 'Mittwoch',
3027                DATE_PICKER_DAY_WEDNESDAY_SHORT: 'Mi',
3028                DATE_PICKER_DAY_THURSDAY_LONG: 'Donnerstag',
3029                DATE_PICKER_DAY_THURSDAY_SHORT: 'Do',
3030                DATE_PICKER_DAY_FRIDAY_LONG: 'Freitag',
3031                DATE_PICKER_DAY_FRIDAY_SHORT: 'Fr',
3032                DATE_PICKER_DAY_SATURDAY_LONG: 'Samstag',
3033                DATE_PICKER_DAY_SATURDAY_SHORT: 'Sa',
3034                DATE_PICKER_DAY_SUNDAY_LONG: 'Sonntag',
3035                DATE_PICKER_DAY_SUNDAY_SHORT: 'So',
3036                DISCOUNT_APPLIED: 'Rabatt eingelöst',
3037                DISCOUNT_CHECK: 'Überprüfen',
3038                DISCOUNT_TITLE: 'Rabattcode oder Gutschein',
3039                DISCOUNT_INVALID: 'Ungültiger Rabattcode oder Gutschein',
3040                ERR_AMOUNTS_NO_PACKAGE: 'Die Option "productAmounts" ist gesetzt, aber "package_id" ist nicht gesetzt',
3041                ERR_CONTACT_FORM_EMPTY: 'Das Kontaktformular ist nicht ausgefüllt',
3042                ERR_DATE_NO_SINGLE_PACKAGE: 'Die Option "date" erfordert ein einzelnes vorgefülltes Arrangement ("package_id")',
3043                ERR_DATE_PAST: 'Option "date" ist ein Datum in der Vergangenheit',
3044                ERR_GENERAL: 'Etwas ist schief gelaufen:',
3045                ERR_INVALID_DATE: 'Die Option "date" ist keine gültige ISO 8601-Datumszeichenfolge (z. B. "2019-06-28")',
3046                ERR_INVALID_ELEMENT: 'Option "Element" ist kein gültiges Element',
3047                ERR_INVALID_HOSTNAME: 'Option "recras_hostname" ist ungültig.',
3048                ERR_INVALID_LOCALE: 'Ungültiges Gebietsschema. Gültige Optionen sind: {LOCALES}',
3049                ERR_INVALID_REDIRECT_URL: 'Ungültige redirect URL. Stellen Sie sicher, dass es mit http:// or https:// beginnt',
3050                ERR_INVALID_TIME: 'Die Option "time" ist keine gültige Zeitzeichenfolge (z. B. "16:15")',
3051                ERR_NO_ELEMENT: 'Option "element" nicht eingestellt.',
3052                ERR_NO_FORM: 'Option "form_id" nicht eingestellt.',
3053                ERR_NO_HOSTNAME: 'Option "recras_hostname" nicht eingestellt.',
3054                ERR_NO_TIMES_FOR_DATE: 'Für diese Mengen sind an diesem Datum keine Zeiten mehr verfügbar. Versuchen Sie es mit einem anderen Datum.',
3055                ERR_OPTIONS_INVALID: 'Options is not a "RecrasOptions" object',
3056                GENDER_UNKNOWN: 'Unbekannte',
3057                GENDER_MALE: 'Mann',
3058                GENDER_FEMALE: 'Frau',
3059                HEADING_PRICE: 'Preis',
3060                HEADING_QUANTITY: 'Anzahl',
3061                LOADING: 'Wird geladen...',
3062                NO_PRODUCTS: 'Kein Produkt ausgewählt',
3063                PRICE_TOTAL: 'Insgesamt',
3064                PRICE_TOTAL_WITH_DISCOUNT: 'Insgesamt inklusive Rabatt',
3065                PRODUCT_MAXIMUM: '(höchstens {MAXIMUM})',
3066                PRODUCT_MINIMUM: '(mindestens {MINIMUM})',
3067                PRODUCT_REQUIRED: '{NUM} {PRODUCT} benötigt {REQUIRED_AMOUNT} {REQUIRED_PRODUCT} um auch gebucht zu werden.',
3068                TIME: 'Zeit',
3069                TIME_FORMAT: 'UU:MM',
3070                VOUCHER_ALREADY_APPLIED: 'Gutschein bereits eingelöst',
3071                VOUCHER_APPLIED: 'Gutschein eingelöst',
3072                VOUCHER_EMPTY: 'Leerer Gutscheincode',
3073                VOUCHER_QUANTITY: 'Anzahl der Gutscheine',
3074                VOUCHERS_DISCOUNT: 'Rabatt von Gutschein(en)'
3075            },
3076            en_GB: {
3077                AGREE_ATTACHMENTS: 'I agree with the following documents:',
3078                ATTR_REQUIRED: 'Required',
3079                BOOKING_DISABLED_AGREEMENT: 'You have not agreed to the terms yet',
3080                BOOKING_DISABLED_AMOUNTS_INVALID: 'Programme amounts are invalid',
3081                BOOKING_DISABLED_CONTACT_FORM_INVALID: 'Contact form is not filled in correctly',
3082                BOOKING_DISABLED_INVALID_DATE: 'No date selected',
3083                BOOKING_DISABLED_INVALID_TIME: 'No time selected',
3084                BOOKING_DISABLED_REQUIRED_PRODUCT: 'Required product not yet selected',
3085                BUTTON_BOOK_NOW: 'Book now',
3086                BUTTON_BUY_NOW: 'Buy now',
3087                BUTTON_SUBMIT_CONTACT_FORM: 'Submit',
3088                CONTACT_FORM_CHECKBOX_REQUIRED: 'At least one option must be checked',
3089                CONTACT_FORM_FIELD_INVALID: '"{FIELD_NAME}" is invalid',
3090                CONTACT_FORM_FIELD_REQUIRED: '"{FIELD_NAME}" is a required field',
3091                CONTACT_FORM_SUBMIT_FAILED: 'The contact form could not be sent. Please try again later.',
3092                CONTACT_FORM_SUBMIT_SUCCESS: 'The contact form was sent successfully.',
3093                DATE: 'Date',
3094                DATE_FORMAT: 'DD-MM-YYYY',
3095                DATE_INVALID: 'Invalid date',
3096                DATE_PICKER_NEXT_MONTH: 'Next month',
3097                DATE_PICKER_PREVIOUS_MONTH: 'Previous month',
3098                DATE_PICKER_MONTH_JANUARY: 'January',
3099                DATE_PICKER_MONTH_FEBRUARY: 'February',
3100                DATE_PICKER_MONTH_MARCH: 'March',
3101                DATE_PICKER_MONTH_APRIL: 'April',
3102                DATE_PICKER_MONTH_MAY: 'May',
3103                DATE_PICKER_MONTH_JUNE: 'June',
3104                DATE_PICKER_MONTH_JULY: 'July',
3105                DATE_PICKER_MONTH_AUGUST: 'August',
3106                DATE_PICKER_MONTH_SEPTEMBER: 'September',
3107                DATE_PICKER_MONTH_OCTOBER: 'October',
3108                DATE_PICKER_MONTH_NOVEMBER: 'November',
3109                DATE_PICKER_MONTH_DECEMBER: 'December',
3110                DATE_PICKER_DAY_MONDAY_LONG: 'Monday',
3111                DATE_PICKER_DAY_MONDAY_SHORT: 'Mon',
3112                DATE_PICKER_DAY_TUESDAY_LONG: 'Tuesday',
3113                DATE_PICKER_DAY_TUESDAY_SHORT: 'Tue',
3114                DATE_PICKER_DAY_WEDNESDAY_LONG: 'Wednesday',
3115                DATE_PICKER_DAY_WEDNESDAY_SHORT: 'Wed',
3116                DATE_PICKER_DAY_THURSDAY_LONG: 'Thursday',
3117                DATE_PICKER_DAY_THURSDAY_SHORT: 'Thu',
3118                DATE_PICKER_DAY_FRIDAY_LONG: 'Friday',
3119                DATE_PICKER_DAY_FRIDAY_SHORT: 'Fri',
3120                DATE_PICKER_DAY_SATURDAY_LONG: 'Saturday',
3121                DATE_PICKER_DAY_SATURDAY_SHORT: 'Sat',
3122                DATE_PICKER_DAY_SUNDAY_LONG: 'Sunday',
3123                DATE_PICKER_DAY_SUNDAY_SHORT: 'Sun',
3124                DISCOUNT_APPLIED: 'Discount applied',
3125                DISCOUNT_CHECK: 'Check',
3126                DISCOUNT_TITLE: 'Discount code or voucher',
3127                DISCOUNT_INVALID: 'Invalid discount code or voucher',
3128                ERR_AMOUNTS_NO_PACKAGE: 'Option "productAmounts" is set, but "package_id" is not set',
3129                ERR_CONTACT_FORM_EMPTY: 'Contact form is not filled in',
3130                ERR_DATE_NO_SINGLE_PACKAGE: 'Option "date" requires a single pre-filled package ("package_id")',
3131                ERR_DATE_PAST: 'Option "date" is a date in the past',
3132                ERR_GENERAL: 'Something went wrong:',
3133                ERR_INVALID_DATE: 'Option "date" is not a valid ISO 8601 date string (e.g. "2019-06-28")',
3134                ERR_INVALID_ELEMENT: 'Option "element" is not a valid Element',
3135                ERR_INVALID_HOSTNAME: 'Option "recras_hostname" is invalid.',
3136                ERR_INVALID_LOCALE: 'Invalid locale. Valid options are: {LOCALES}',
3137                ERR_INVALID_REDIRECT_URL: 'Invalid redirect URL. Make sure you it starts with http:// or https://',
3138                ERR_INVALID_TIME: 'Option "time" is not a valid time string (e.g. "16:15")',
3139                ERR_NO_ELEMENT: 'Option "element" not set.',
3140                ERR_NO_FORM: 'Option "form_id" not set.',
3141                ERR_NO_HOSTNAME: 'Option "recras_hostname" not set.',
3142                ERR_NO_TIMES_FOR_DATE: 'There are no more times available on this date for these quantities. Try a different date.',
3143                ERR_OPTIONS_INVALID: 'Options is not a "RecrasOptions" object',
3144                GENDER_UNKNOWN: 'Unknown',
3145                GENDER_MALE: 'Male',
3146                GENDER_FEMALE: 'Female',
3147                HEADING_PRICE: 'Price',
3148                HEADING_QUANTITY: 'Quantity',
3149                LOADING: 'Loading...',
3150                NO_PRODUCTS: 'No product selected',
3151                PRICE_TOTAL: 'Total',
3152                PRICE_TOTAL_WITH_DISCOUNT: 'Total including discount',
3153                PRODUCT_MAXIMUM: '(at most {MAXIMUM})',
3154                PRODUCT_MINIMUM: '(at least {MINIMUM})',
3155                PRODUCT_REQUIRED: '{NUM} {PRODUCT} requires {REQUIRED_AMOUNT} {REQUIRED_PRODUCT} to also be booked.',
3156                TIME: 'Time',
3157                TIME_FORMAT: 'HH:MM',
3158                VOUCHER_ALREADY_APPLIED: 'Voucher already applied',
3159                VOUCHER_APPLIED: 'Voucher applied',
3160                VOUCHER_EMPTY: 'Empty voucher code',
3161                VOUCHER_QUANTITY: 'Number of vouchers',
3162                VOUCHERS_DISCOUNT: 'Discount from voucher(s)'
3163            },
3164            nl_NL: {
3165                AGREE_ATTACHMENTS: 'Ik ga akkoord met de volgende gegevens:',
3166                ATTR_REQUIRED: 'Vereist',
3167                BOOKING_DISABLED_AGREEMENT: 'Je bent nog niet akkoord met de voorwaarden',
3168                BOOKING_DISABLED_AMOUNTS_INVALID: 'Aantallen in programma zijn ongeldig',
3169                BOOKING_DISABLED_CONTACT_FORM_INVALID: 'Contactformulier is niet correct ingevuld',
3170                BOOKING_DISABLED_INVALID_DATE: 'Geen datum geselecteerd',
3171                BOOKING_DISABLED_INVALID_TIME: 'Geen tijd geselecteerd',
3172                BOOKING_DISABLED_REQUIRED_PRODUCT: 'Vereist product nog niet geselecteerd',
3173                BUTTON_BOOK_NOW: 'Nu boeken',
3174                BUTTON_BUY_NOW: 'Nu kopen',
3175                BUTTON_SUBMIT_CONTACT_FORM: 'Versturen',
3176                CONTACT_FORM_CHECKBOX_REQUIRED: 'Ten minste één optie moet aangevinkt worden',
3177                CONTACT_FORM_FIELD_INVALID: '"{FIELD_NAME}" is ongeldig',
3178                CONTACT_FORM_FIELD_REQUIRED: '"{FIELD_NAME}" is een verplicht veld',
3179                CONTACT_FORM_SUBMIT_FAILED: 'Het contactformulier kon niet worden verstuurd. Probeer het later nog eens.',
3180                CONTACT_FORM_SUBMIT_SUCCESS: 'Het contactformulier is succesvol verstuurd.',
3181                DATE: 'Datum',
3182                DATE_FORMAT: 'DD-MM-JJJJ',
3183                DATE_INVALID: 'Ongeldige datum',
3184                DATE_PICKER_NEXT_MONTH: 'Volgende maand',
3185                DATE_PICKER_PREVIOUS_MONTH: 'Vorige maand',
3186                DATE_PICKER_MONTH_JANUARY: 'Januari',
3187                DATE_PICKER_MONTH_FEBRUARY: 'Februari',
3188                DATE_PICKER_MONTH_MARCH: 'Maart',
3189                DATE_PICKER_MONTH_APRIL: 'April',
3190                DATE_PICKER_MONTH_MAY: 'Mei',
3191                DATE_PICKER_MONTH_JUNE: 'Juni',
3192                DATE_PICKER_MONTH_JULY: 'Juli',
3193                DATE_PICKER_MONTH_AUGUST: 'Augustus',
3194                DATE_PICKER_MONTH_SEPTEMBER: 'September',
3195                DATE_PICKER_MONTH_OCTOBER: 'Oktober',
3196                DATE_PICKER_MONTH_NOVEMBER: 'November',
3197                DATE_PICKER_MONTH_DECEMBER: 'December',
3198                DATE_PICKER_DAY_MONDAY_LONG: 'Maandag',
3199                DATE_PICKER_DAY_MONDAY_SHORT: 'Ma',
3200                DATE_PICKER_DAY_TUESDAY_LONG: 'Dinsdag',
3201                DATE_PICKER_DAY_TUESDAY_SHORT: 'Di',
3202                DATE_PICKER_DAY_WEDNESDAY_LONG: 'Woensdag',
3203                DATE_PICKER_DAY_WEDNESDAY_SHORT: 'Wo',
3204                DATE_PICKER_DAY_THURSDAY_LONG: 'Donderdag',
3205                DATE_PICKER_DAY_THURSDAY_SHORT: 'Do',
3206                DATE_PICKER_DAY_FRIDAY_LONG: 'Vrijdag',
3207                DATE_PICKER_DAY_FRIDAY_SHORT: 'Vr',
3208                DATE_PICKER_DAY_SATURDAY_LONG: 'Zaterdag',
3209                DATE_PICKER_DAY_SATURDAY_SHORT: 'Za',
3210                DATE_PICKER_DAY_SUNDAY_LONG: 'Zondag',
3211                DATE_PICKER_DAY_SUNDAY_SHORT: 'Zo',
3212                DISCOUNT_APPLIED: 'Kortingscode toegepast',
3213                DISCOUNT_CHECK: 'Controleren',
3214                DISCOUNT_TITLE: 'Kortingscode of tegoedbon',
3215                DISCOUNT_INVALID: 'Ongeldige kortingscode of tegoedbon',
3216                ERR_AMOUNTS_NO_PACKAGE: 'Optie "productAmounts" is ingesteld, maar "package_id" is niet ingesteld',
3217                ERR_CONTACT_FORM_EMPTY: 'Contactformulier is niet ingevuld',
3218                ERR_DATE_NO_SINGLE_PACKAGE: 'Optie "date" vereist een enkel vooraf ingevuld arrangement ("package_id")',
3219                ERR_DATE_PAST: 'Optie "date" is een datum in het verleden',
3220                ERR_GENERAL: 'Er ging iets mis:',
3221                ERR_INVALID_DATE: 'Optie "date" is geen geldige ISO 8601-datumstring (bijv. "2019-06-28")',
3222                ERR_INVALID_ELEMENT: 'Optie "element" is geen geldig Element',
3223                ERR_INVALID_HOSTNAME: 'Optie "recras_hostname" is ongeldig.',
3224                ERR_INVALID_LOCALE: 'Ongeldige locale. Geldige opties zijn: {LOCALES}',
3225                ERR_INVALID_REDIRECT_URL: 'Ongeldige redirect-URL. Zorg ervoor dat deze begint met http:// of https://',
3226                ERR_INVALID_TIME: 'Optie "time" is geen geldige tijd-string (bijv. "16:15")',
3227                ERR_NO_ELEMENT: 'Optie "element" niet ingesteld.',
3228                ERR_NO_FORM: 'Optie "form_id" niet ingesteld.',
3229                ERR_NO_HOSTNAME: 'Optie "recras_hostname" niet ingesteld.',
3230                ERR_NO_TIMES_FOR_DATE: 'Er zijn geen tijden meer beschikbaar op deze datum voor deze aantallen. Probeer een andere datum.',
3231                ERR_OPTIONS_INVALID: 'Opties is geen "RecrasOptions"-object',
3232                GENDER_UNKNOWN: 'Onbekend',
3233                GENDER_MALE: 'Man',
3234                GENDER_FEMALE: 'Vrouw',
3235                HEADING_PRICE: 'Prijs',
3236                HEADING_QUANTITY: 'Aantal',
3237                LOADING: 'Laden...',
3238                NO_PRODUCTS: 'Geen product gekozen',
3239                PRICE_TOTAL: 'Totaal',
3240                PRICE_TOTAL_WITH_DISCOUNT: 'Totaal inclusief korting',
3241                PRODUCT_MAXIMUM: '(maximaal {MAXIMUM})',
3242                PRODUCT_MINIMUM: '(minimaal {MINIMUM})',
3243                PRODUCT_REQUIRED: '{NUM} {PRODUCT} vereist dat ook {REQUIRED_AMOUNT} {REQUIRED_PRODUCT} geboekt wordt.',
3244                TIME: 'Tijd',
3245                TIME_FORMAT: 'UU:MM',
3246                VOUCHER_ALREADY_APPLIED: 'Tegoedbon al toegepast',
3247                VOUCHER_APPLIED: 'Tegoedbon toegepast',
3248                VOUCHER_EMPTY: 'Lege tegoedbon',
3249                VOUCHER_QUANTITY: 'Aantal tegoedbonnen',
3250                VOUCHERS_DISCOUNT: 'Korting uit tegoedbon(nen)'
3251            },
3252            sv_SE: {
3253                AGREE_ATTACHMENTS: 'Jag håller med följande information:',
3254                ATTR_REQUIRED: "Obligatoriskt",
3255                BOOKING_DISABLED_AGREEMENT: 'Du håller inte med villkoren ännu',
3256                BOOKING_DISABLED_AMOUNTS_INVALID: 'Siffrorna i programmet är ogiltiga',
3257                BOOKING_DISABLED_CONTACT_FORM_INVALID: 'Kontaktformuläret är inte korrekt ifyllt',
3258                BOOKING_DISABLED_INVALID_DATE: 'Inget datum valt',
3259                BOOKING_DISABLED_INVALID_TIME: 'Ingen tid vald',
3260                BOOKING_DISABLED_REQUIRED_PRODUCT: "Nödvändig produkt har ännu inte valts",
3261                BUTTON_BOOK_NOW: 'Boka nu',
3262                BUTTON_BUY_NOW: 'Köp nu',
3263                BUTTON_SUBMIT_CONTACT_FORM: 'Skicka',
3264                CONTACT_FORM_CHECKBOX_REQUIRED: 'Minst ett alternativ måste markeras',
3265                CONTACT_FORM_FIELD_INVALID: '"{FIELD_NAME}" är ogiltig',
3266                CONTACT_FORM_FIELD_REQUIRED: '"{FIELD_NAME}" är ett obligatoriskt fält',
3267                CONTACT_FORM_SUBMIT_FAILED: 'Kontaktformuläret kunde inte skickas. Vänligen försök igen senare.',
3268                CONTACT_FORM_SUBMIT_SUCCESS: 'Kontaktformuläret har skickats.',
3269                DATUM: 'Datum',
3270                DATE_FORMAT: 'DD-MM-ÅÅÅÅ',
3271                DATE_INVALID: "Ogiltigt datum",
3272                DATE_PICKER_NEXT_MONTH: "Nästa månad",
3273                DATE_PICKER_PREVIOUS_MONTH: "Förra månaden",
3274                DATE_PICKER_MONTH_JANUARI: "januari",
3275                DATE_PICKER_MONTH_FEBRUARY: "februari",
3276                DATE_PICKER_MONTH_MARCH: "mars",
3277                DATE_PICKER_MONTH_APRIL: "april",
3278                DATE_PICKER_MONTH_MAY: "aaj",
3279                DATE_PICKER_MONTH_JUNE: "juni",
3280                DATE_PICKER_MONTH_JULY: "Juli",
3281                DATE_PICKER_MONTH_AUGUST: "augusti",
3282                DATE_PICKER_MONTH_SEPTEMBER: "september",
3283                DATE_PICKER_MONTH_OCTOBER: "oktober",
3284                DATE_PICKER_MONTH_NOVEMBER: "november",
3285                DATE_PICKER_MONTH_DECEMBER: "december",
3286                DATE_PICKER_DAY_MONDAY_LONG: "MÃ¥ndag",
3287                DATE_PICKER_DAY_MONDAY_SHORT: 'MÃ¥n',
3288                DATE_PICKER_DAY_TUESDAY_LONG: "Tisdag",
3289                DATE_PICKER_DAY_TUESDAY_SHORT: 'Tis',
3290                DATE_PICKER_DAY_WEDNESDAY_LONG: "Onsdag",
3291                DATE_PICKER_DAY_WEDNESDAY_SHORT: "Ons",
3292                DATE_PICKER_DAY_THURSDAY_LONG: "Torsdag",
3293                DATE_PICKER_DAY_THURSDAY_SHORT: "Tors",
3294                DATE_PICKER_DAY_FRIDAY_LONG: "Fredag",
3295                DATE_PICKER_DAY_FRIDAY_SHORT: "Fre",
3296                DATE_PICKER_DAY_SATURDAY_LONG: 'Lördag',
3297                DATE_PICKER_DAY_SATURDAY_SHORT: 'Lör',
3298                DATE_PICKER_DAY_SUNDAY_LONG: "Söndag",
3299                DATE_PICKER_DAY_SUNDAY_SHORT: "Sön",
3300                DISCOUNT_APPLIED: 'Rabattkod tillämpas',
3301                DISCOUNT_CHECK: "Kontrollera",
3302                DISCOUNT_TITLE: "Rabattkod eller kupong",
3303                DISCOUNT_INVALID: "Ogiltig rabattkod eller kupong",
3304                ERR_AMOUNTS_NO_PACKAGE: 'Alternativ "productAmounts" är inställt, men "package_id" är inte inställt',
3305                ERR_CONTACT_FORM_EMPTY: 'Kontaktformuläret är inte ifyllt',
3306                ERR_DATE_NO_SINGLE_PACKAGE: 'Alternativ "date" kräver ett enda förfyllt paket ("package_id")',
3307                ERR_DATE_PAST: 'Alternativ "date" är ett datum tidigare',
3308                ERR_GENERAL: 'NÃ¥got gick fel:',
3309                ERR_INVALID_DATE: 'Alternativ "date" är inte en giltig ISO 8601-datumsträng (t.ex. "2019-06-28")',
3310                ERR_INVALID_ELEMENT: 'Alternativet "element" är inte ett giltigt element',
3311                ERR_INVALID_HOSTNAME: 'Alternativet "recras_hostname" är ogiltigt.',
3312                ERR_INVALID_LOCALE: 'Ogiltig land-språkkombination. Giltiga alternativ är: {LOCALES} ',
3313                ERR_INVALID_REDIRECT_URL: 'Ogiltig omdirigerings-URL. Se till att det börjar med http:// eller https:// ',
3314                ERR_INVALID_TIME: 'Alternativ "time" är inte en giltig tidsnotation (t.ex. "16:15")',
3315                ERR_NO_ELEMENT: 'Alternativet "element" är inte inställt.',
3316                ERR_NO_FORM: 'Alternativ "form_id" inte inställt.',
3317                ERR_NO_HOSTNAME: 'Alternativ "recras_hostname" inte inställt.',
3318                ERR_NO_TIMES_FOR_DATE: 'Det finns inga fler tillgängliga tider på detta datum för dessa nummer. Prova ett annat datum. ',
3319                ERR_OPTIONS_INVALID: 'Alternativ är inte ett "RecrasOptions"-objekt',
3320                GENDER_UNKNOWN: "Okänd",
3321                GENDER_MALE: "Man",
3322                GENDER_FEMALE: "Kvinna",
3323                HEADING_PRICE: "Pris",
3324                HEADING_QUANTITY: "Antal",
3325                LOADING: 'Laddar ...',
3326                NO_PRODUCTS: 'Ingen produkt vald',
3327                PRICE_TOTAL: 'Totalt',
3328                PRICE_TOTAL_WITH_DISCOUNT: "Totalt inklusive rabatt",
3329                PRODUCT_MAXIMUM: '(maximalt {MAXIMUM})',
3330                PRODUCT_MINIMUM: '(minimalt {MINIMUM})',
3331                PRODUCT_REQUIRED: '{NUM} {PRODUCT} kräver att {REQUIRED_AMOUNT} {REQUIRED_PRODUCT} också bokas.',
3332                TIME: 'Tid',
3333                TIME_FORMAT: 'TT:MM',
3334                VOUCHER_ALREADY_APPLIED: 'Kupongen är redan inlöst',
3335                VOUCHER_APPLIED: 'Kupong inlöst',
3336                VOUCHER_EMPTY: "Tom kupong",
3337                VOUCHER_QUANTITY: 'Antal kuponger',
3338                VOUCHERS_DISCOUNT: 'Rabatt från kupong(er)'
3339            }
3340        };
3341    }
3342
3343    _createClass(RecrasLanguageHelper, [{
3344        key: "error",
3345        value: function error(msg) {
3346            console.log('Error', msg); //TODO
3347        }
3348    }, {
3349        key: "extractTags",
3350        value: function extractTags(msg) {
3351            var alphanumericWithUnderscore = '[a-zA-Z0-9_]';
3352            var regexPartMulticolumn = '((?:\\((?:\\w+)(?::[^)]*)?\\))*)';
3353            var regex = new RegExp('{' + alphanumericWithUnderscore + '+' + regexPartMulticolumn + '}', 'g');
3354            var tags = msg.match(regex);
3355
3356            if (!Array.isArray(tags)) {
3357                return [];
3358            }
3359
3360            return tags.map(function (tag) {
3361                return tag.substring(1, tag.length - 1);
3362            }); // Strip { and }
3363        }
3364    }, {
3365        key: "filterTags",
3366        value: function filterTags(msg, packageID) {
3367            var tags = this.extractTags(msg);
3368
3369            if (tags.length === 0) {
3370                return Promise.resolve(msg);
3371            }
3372
3373            return RecrasHttpHelper.postJson(this.options.getApiBase() + 'tagfilter', {
3374                tags: tags,
3375                context: {
3376                    packageID: packageID
3377                }
3378            }, this.error).then(function (filtered) {
3379                Object.keys(filtered).forEach(function (tag) {
3380                    msg = msg.split('{' + tag + '}').join(filtered[tag]);
3381                });
3382                return msg;
3383            });
3384        }
3385    }, {
3386        key: "formatLocale",
3387        value: function formatLocale(what) {
3388            switch (what) {
3389                case 'currency':
3390                    return this.locale.replace('_', '-').toUpperCase();
3391
3392                default:
3393                    return this.locale;
3394            }
3395        }
3396    }, {
3397        key: "formatPrice",
3398        value: function formatPrice(price) {
3399            return parseFloat(price).toLocaleString(this.formatLocale('currency'), {
3400                currency: this.currency,
3401                style: 'currency'
3402            });
3403        }
3404    }, {
3405        key: "setCurrency",
3406        value: function setCurrency() {
3407            var _this40 = this;
3408
3409            var errorHandler = function errorHandler(err) {
3410                _this40.currency = 'eur';
3411
3412                _this40.error(err);
3413            };
3414
3415            return RecrasHttpHelper.fetchJson(this.options.getApiBase() + 'instellingen/currency', errorHandler).then(function (setting) {
3416                _this40.currency = setting.waarde;
3417            });
3418        }
3419    }, {
3420        key: "setLocale",
3421        value: function setLocale(locale) {
3422            this.locale = locale;
3423        }
3424    }, {
3425        key: "setOptions",
3426        value: function setOptions(options) {
3427            this.options = options;
3428            return this.setCurrency();
3429        }
3430    }, {
3431        key: "translate",
3432        value: function translate(string) {
3433            var vars = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3434            var translated;
3435
3436            if (this.i18n[this.locale] && this.i18n[this.locale][string]) {
3437                translated = this.i18n[this.locale][string];
3438            } else if (this.i18n.en_GB[string]) {
3439                translated = this.i18n.en_GB[string];
3440            } else {
3441                translated = string;
3442                console.warn('String not translated: ' + string);
3443            }
3444
3445            if (Object.keys(vars).length > 0) {
3446                Object.keys(vars).forEach(function (key) {
3447                    translated = translated.replace('{' + key + '}', vars[key]);
3448                });
3449            }
3450
3451            return translated;
3452        }
3453    }], [{
3454        key: "isValid",
3455        value: function isValid(locale) {
3456            return this.validLocales.indexOf(locale) > -1;
3457        }
3458    }]);
3459
3460    return RecrasLanguageHelper;
3461}();
3462
3463_defineProperty(RecrasLanguageHelper, "validLocales", ['de_DE', 'en_GB', 'nl_NL', 'sv_SE']);
3464
3465var RecrasOptions = /*#__PURE__*/function () {
3466    function RecrasOptions(options) {
3467        _classCallCheck(this, RecrasOptions);
3468
3469        this.languageHelper = new RecrasLanguageHelper();
3470        this.validate(options);
3471        this.options = this.setOptions(options);
3472    }
3473
3474    _createClass(RecrasOptions, [{
3475        key: "getAnalyticsEvents",
3476        value: function getAnalyticsEvents() {
3477            if (!Array.isArray(this.options.analyticsEvents)) {
3478                this.options.analyticsEvents = RecrasEventHelper.allEvents();
3479            }
3480
3481            this.options.analyticsEvents = this.options.analyticsEvents.filter(function (event) {
3482                var eventExists = RecrasEventHelper.allEvents().includes(event);
3483
3484                if (!eventExists) {
3485                    console.warn('Invalid event: ' + event);
3486                }
3487
3488                return eventExists;
3489            });
3490
3491            if (this.options.analyticsEvents.length === 0) {
3492                this.options.analyticsEvents = RecrasEventHelper.allEvents();
3493            }
3494
3495            return this.options.analyticsEvents;
3496        }
3497    }, {
3498        key: "getAnalytics",
3499        value: function getAnalytics() {
3500            return this.options.analytics;
3501        }
3502    }, {
3503        key: "getApiBase",
3504        value: function getApiBase() {
3505            return this.getHostname() + '/api2/';
3506        }
3507    }, {
3508        key: "getAutoScroll",
3509        value: function getAutoScroll() {
3510            return this.options.autoScroll !== undefined ? this.options.autoScroll : true;
3511        }
3512    }, {
3513        key: "getDefaultCountry",
3514        value: function getDefaultCountry() {
3515            if (this.options.defaultCountry !== undefined) {
3516                return this.options.defaultCountry;
3517            }
3518
3519            return this.getLocale().substr(3, 2); // en_IE -> IE
3520        }
3521    }, {
3522        key: "getElement",
3523        value: function getElement() {
3524            return this.options.element;
3525        }
3526    }, {
3527        key: "getFormId",
3528        value: function getFormId() {
3529            return this.options.form_id;
3530        }
3531    }, {
3532        key: "getHostname",
3533        value: function getHostname() {
3534            return this.options.hostname;
3535        }
3536    }, {
3537        key: "getLocale",
3538        value: function getLocale() {
3539            return this.options.locale;
3540        }
3541    }, {
3542        key: "getPackageId",
3543        value: function getPackageId() {
3544            return this.options.package_id;
3545        }
3546    }, {
3547        key: "getPreFilledAmounts",
3548        value: function getPreFilledAmounts() {
3549            return this.options.productAmounts;
3550        }
3551    }, {
3552        key: "getPreFilledDate",
3553        value: function getPreFilledDate() {
3554            return this.options.date;
3555        }
3556    }, {
3557        key: "getPreFilledTime",
3558        value: function getPreFilledTime() {
3559            return this.options.time;
3560        }
3561    }, {
3562        key: "getPreviewTimes",
3563        value: function getPreviewTimes() {
3564            return this.options.previewTimes !== undefined ? this.options.previewTimes : true;
3565        }
3566    }, {
3567        key: "getRedirectUrl",
3568        value: function getRedirectUrl() {
3569            return this.options.redirect_url;
3570        }
3571    }, {
3572        key: "getVoucherTemplateId",
3573        value: function getVoucherTemplateId() {
3574            return this.options.voucher_template_id;
3575        }
3576    }, {
3577        key: "isSinglePackage",
3578        value: function isSinglePackage() {
3579            if (Array.isArray(this.options.package_id)) {
3580                return this.options.package_id.length === 1;
3581            }
3582
3583            return !isNaN(parseInt(this.options.package_id, 10));
3584        }
3585    }, {
3586        key: "setOption",
3587        value: function setOption(option, value) {
3588            this.options[option] = value;
3589        }
3590    }, {
3591        key: "setOptions",
3592        value: function setOptions(options) {
3593            var protocol = 'https';
3594
3595            if (RecrasOptions.hostnamesDebug.includes(options.recras_hostname)) {
3596                protocol = 'http';
3597            }
3598
3599            options.hostname = protocol + '://' + options.recras_hostname;
3600            return options;
3601        }
3602    }, {
3603        key: "validate",
3604        value: function validate(options) {
3605            var hostnameRegex = new RegExp(/^[a-z0-9\-]+\.recras\.nl$/i);
3606
3607            if (!options.element) {
3608                throw new Error(this.languageHelper.translate('ERR_NO_ELEMENT'));
3609            }
3610
3611            if (options.element instanceof Element === false) {
3612                throw new Error(this.languageHelper.translate('ERR_INVALID_ELEMENT'));
3613            }
3614
3615            if (!options.recras_hostname) {
3616                throw new Error(this.languageHelper.translate('ERR_NO_HOSTNAME'));
3617            }
3618
3619            if (!hostnameRegex.test(options.recras_hostname) && !RecrasOptions.hostnamesDebug.includes(options.recras_hostname)) {
3620                throw new Error(this.languageHelper.translate('ERR_INVALID_HOSTNAME'));
3621            }
3622
3623            if (options.redirect_url) {
3624                if (options.redirect_url.indexOf('http://') === -1 && options.redirect_url.indexOf('https://') === -1) {
3625                    throw new Error(this.languageHelper.translate('ERR_INVALID_REDIRECT_URL'));
3626                }
3627            }
3628        }
3629    }]);
3630
3631    return RecrasOptions;
3632}();
3633
3634_defineProperty(RecrasOptions, "hostnamesDebug", ['nginx:8886', // Local development
3635    'nginx' // Docker Selenium tests
3636]);
3637
3638var RecrasVoucher = /*#__PURE__*/function () {
3639    function RecrasVoucher() {
3640        var _this41 = this;
3641
3642        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3643
3644        _classCallCheck(this, RecrasVoucher);
3645
3646        this.languageHelper = new RecrasLanguageHelper();
3647
3648        if (options instanceof RecrasOptions === false) {
3649            throw new Error(this.languageHelper.translate('ERR_OPTIONS_INVALID'));
3650        }
3651
3652        this.options = options;
3653        this.eventHelper = new RecrasEventHelper();
3654        this.eventHelper.setEvents(this.options.getAnalyticsEvents());
3655        this.element = this.options.getElement();
3656        this.element.classList.add('recras-buy-voucher');
3657
3658        this.fetchJson = function (url) {
3659            return RecrasHttpHelper.fetchJson(url, _this41.error);
3660        };
3661
3662        this.postJson = function (url, data) {
3663            return RecrasHttpHelper.postJson(_this41.options.getApiBase() + url, data, _this41.error);
3664        };
3665
3666        RecrasCSSHelper.loadCSS('global');
3667
3668        if (this.options.getLocale()) {
3669            if (!RecrasLanguageHelper.isValid(this.options.getLocale())) {
3670                console.warn(this.languageHelper.translate('ERR_INVALID_LOCALE', {
3671                    LOCALES: RecrasLanguageHelper.validLocales.join(', ')
3672                }));
3673            } else {
3674                this.languageHelper.setLocale(this.options.getLocale());
3675            }
3676        }
3677
3678        this.languageHelper.setOptions(options).then(function () {
3679            return _this41.getVoucherTemplates();
3680        }).then(function (templates) {
3681            if (_this41.options.getVoucherTemplateId()) {
3682                _this41.changeTemplate(_this41.options.getVoucherTemplateId());
3683            } else {
3684                _this41.showTemplates(templates);
3685            }
3686        });
3687    }
3688
3689    _createClass(RecrasVoucher, [{
3690        key: "appendHtml",
3691        value: function appendHtml(msg) {
3692            this.element.insertAdjacentHTML('beforeend', msg);
3693        }
3694    }, {
3695        key: "formatGA4Item",
3696        value: function formatGA4Item() {
3697            return [{
3698                item_name: this.selectedTemplate.name,
3699                price: this.selectedTemplate.price,
3700                quantity: parseInt(this.findElement('#number-of-vouchers').value)
3701            }];
3702        }
3703    }, {
3704        key: "buyTemplate",
3705        value: function buyTemplate() {
3706            var _this42 = this;
3707
3708            var status = this.contactForm.checkRequiredCheckboxes();
3709
3710            if (!status) {
3711                return false;
3712            }
3713
3714            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_VOUCHER, RecrasEventHelper.EVENT_VOUCHER_VOUCHER_SUBMITTED, this.selectedTemplate.name, Math.round(this.totalPrice()));
3715            this.findElement('.buyTemplate').setAttribute('disabled', 'disabled');
3716            var payload = {
3717                voucher_template_id: this.selectedTemplate.id,
3718                number_of_vouchers: parseInt(this.findElement('.number-of-vouchers').value, 10),
3719                contact_form: this.contactForm.generateJson()
3720            };
3721
3722            if (this.options.getRedirectUrl()) {
3723                payload.redirect_url = this.options.getRedirectUrl();
3724            }
3725
3726            this.postJson('vouchers/buy', payload).then(function (json) {
3727                if (json.payment_url) {
3728                    _this42.eventHelper.sendEvent(RecrasEventHelper.PREFIX_VOUCHER, RecrasEventHelper.EVENT_VOUCHER_REDIRECT_PAYMENT, null, Math.round(_this42.totalPrice()), {
3729                        currency: _this42.languageHelper.currency,
3730                        value: _this42.totalPrice(),
3731                        items: _this42.formatGA4Item()
3732                    });
3733
3734                    window.top.location.href = json.payment_url;
3735                } else {
3736                    console.log(json);
3737                }
3738
3739                _this42.findElement('.buyTemplate').removeAttribute('disabled');
3740            });
3741        }
3742    }, {
3743        key: "changeTemplate",
3744        value: function changeTemplate(templateID) {
3745            this.selectedTemplate = this.templates.filter(function (t) {
3746                return t.id === templateID;
3747            })[0];
3748            this.clearAllExceptTemplateSelection();
3749            this.showContactForm(this.selectedTemplate);
3750            this.eventHelper.sendEvent(RecrasEventHelper.PREFIX_VOUCHER, RecrasEventHelper.EVENT_VOUCHER_TEMPLATE_CHANGED, null, templateID, {
3751                content_type: 'voucher',
3752                item_id: templateID
3753            });
3754        }
3755    }, {
3756        key: "clearAll",
3757        value: function clearAll() {
3758            this.clearElements(this.element.children);
3759        }
3760    }, {
3761        key: "clearAllExceptTemplateSelection",
3762        value: function clearAllExceptTemplateSelection() {
3763            var elements = document.querySelectorAll('#' + this.element.id + ' > *:not(.recras-voucher-templates)');
3764            this.clearElements(elements);
3765        }
3766    }, {
3767        key: "clearElements",
3768        value: function clearElements(elements) {
3769            _toConsumableArray(elements).forEach(function (el) {
3770                el.parentNode.removeChild(el);
3771            });
3772
3773            this.maybeAddLatestErrorElement();
3774        }
3775    }, {
3776        key: "error",
3777        value: function error(msg) {
3778            this.maybeAddLatestErrorElement();
3779            this.findElement('.latestError').innerHTML = "<strong>".concat(this.languageHelper.translate('ERR_GENERAL'), "</strong><p>").concat(msg, "</p>");
3780        }
3781    }, {
3782        key: "findElement",
3783        value: function findElement(querystring) {
3784            return this.element.querySelector(querystring);
3785        }
3786    }, {
3787        key: "findElements",
3788        value: function findElements(querystring) {
3789            return this.element.querySelectorAll(querystring);
3790        }
3791    }, {
3792        key: "formatPrice",
3793        value: function formatPrice(price) {
3794            return this.languageHelper.formatPrice(price);
3795        }
3796    }, {
3797        key: "getContactForm",
3798        value: function getContactForm(template) {
3799            var _this43 = this;
3800
3801            this.options.setOption('form_id', template.contactform_id);
3802            var contactForm = new RecrasContactForm(this.options);
3803            return contactForm.getContactFormFields().then(function () {
3804                _this43.contactForm = contactForm;
3805                return contactForm;
3806            });
3807        }
3808    }, {
3809        key: "getVoucherTemplates",
3810        value: function getVoucherTemplates() {
3811            var _this44 = this;
3812
3813            return this.fetchJson(this.options.getApiBase() + 'voucher_templates').then(function (templates) {
3814                templates = templates.filter(function (template) {
3815                    return !!template.contactform_id;
3816                });
3817                _this44.templates = templates;
3818                return templates;
3819            });
3820        }
3821    }, {
3822        key: "maybeAddLatestErrorElement",
3823        value: function maybeAddLatestErrorElement() {
3824            var errorEl = this.findElement('.latestError');
3825
3826            if (!errorEl) {
3827                this.appendHtml("<div class=\"latestError\"></div>");
3828            }
3829        }
3830    }, {
3831        key: "maybeDisableBuyButton",
3832        value: function maybeDisableBuyButton() {
3833            var button = this.findElement('.buyTemplate');
3834
3835            if (!button) {
3836                return false;
3837            }
3838
3839            var shouldDisable = false;
3840            this.contactForm.removeErrors();
3841
3842            if (this.contactForm.hasEmptyRequiredFields() || !this.contactForm.isValid() || !this.contactForm.checkRequiredCheckboxes()) {
3843                this.contactForm.showErrors();
3844                shouldDisable = true;
3845            }
3846
3847            if (shouldDisable) {
3848                button.setAttribute('disabled', 'disabled');
3849            } else {
3850                button.removeAttribute('disabled');
3851            }
3852        }
3853    }, {
3854        key: "showBuyButton",
3855        value: function showBuyButton() {
3856            var html = "<div><button type=\"submit\" class=\"buyTemplate\" disabled>".concat(this.languageHelper.translate('BUTTON_BUY_NOW'), "</button></div>");
3857            this.appendHtml(html);
3858            this.findElement('.buyTemplate').addEventListener('click', this.buyTemplate.bind(this));
3859        }
3860    }, {
3861        key: "showContactForm",
3862        value: function showContactForm(template) {
3863            var _this45 = this;
3864
3865            return this.getContactForm(template).then(function (form) {
3866                return form.generateForm({
3867                    voucherQuantitySelector: true,
3868                    quantityTerm: _this45.selectedTemplate.quantity_term
3869                });
3870            }).then(function (html) {
3871                _this45.appendHtml(html);
3872
3873                _this45.showBuyButton();
3874
3875                _toConsumableArray(_this45.findElements('#number-of-vouchers, [name^="contactformulier"]')).forEach(function (el) {
3876                    el.addEventListener('change', _this45.maybeDisableBuyButton.bind(_this45));
3877                });
3878            });
3879        }
3880    }, {
3881        key: "showTemplates",
3882        value: function showTemplates(templates) {
3883            var _this46 = this;
3884
3885            var templateOptions = templates.map(function (template) {
3886                return "<option value=\"".concat(template.id, "\">").concat(template.name, " (").concat(_this46.formatPrice(template.price), ")");
3887            });
3888            var html = "<select class=\"recrasVoucherTemplates\"><option>".concat(templateOptions.join(''), "</select>");
3889            this.appendHtml("<div class=\"recras-voucher-templates\">".concat(html, "</div>"));
3890            var voucherSelectEl = this.findElement('.recrasVoucherTemplates');
3891            voucherSelectEl.addEventListener('change', function () {
3892                var selectedTemplateId = parseInt(voucherSelectEl.value, 10);
3893
3894                _this46.changeTemplate(selectedTemplateId);
3895            });
3896        }
3897    }, {
3898        key: "totalPrice",
3899        value: function totalPrice() {
3900            return this.selectedTemplate.price * this.findElement('#number-of-vouchers').value;
3901        }
3902    }]);
3903
3904    return RecrasVoucher;
3905}();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.