(function () { 'use strict'; var REST_URL = (window.careiReservation && window.careiReservation.restUrl) || '/wp-json/carei/v1/'; var NONCE = (window.careiReservation && window.careiReservation.nonce) || ''; // ─── API Helpers ────────────────────────────────────────────── var API_TIMEOUT_MS = 15000; function apiGet(endpoint, isRetry) { var controller = new AbortController(); var timer = setTimeout(function () { controller.abort(); }, API_TIMEOUT_MS); return fetch(REST_URL + endpoint, { method: 'GET', headers: { 'X-WP-Nonce': NONCE, 'Content-Type': 'application/json' }, signal: controller.signal }).then(function (r) { clearTimeout(timer); return handleResponse(r); }).catch(function (err) { clearTimeout(timer); return handleFetchError(err, function () { return apiGet(endpoint, true); }, isRetry); }); } function apiPost(endpoint, data, isRetry) { var controller = new AbortController(); var timer = setTimeout(function () { controller.abort(); }, API_TIMEOUT_MS); return fetch(REST_URL + endpoint, { method: 'POST', headers: { 'X-WP-Nonce': NONCE, 'Content-Type': 'application/json' }, body: JSON.stringify(data), signal: controller.signal }).then(function (r) { clearTimeout(timer); if ((r.status === 401 || r.status === 403) && !isRetry) { return apiPost(endpoint, data, true); } return handleResponse(r); }).catch(function (err) { clearTimeout(timer); return handleFetchError(err, function () { return apiPost(endpoint, data, true); }, isRetry); }); } function handleResponse(r) { if (!r.ok) { var status = r.status; return r.json().then(function (body) { var msg = (body && body.message) || (body && body.detail) || ('Błąd API: HTTP ' + status); var err = new Error(msg); err.httpStatus = status; throw err; }).catch(function (parseErr) { if (parseErr.httpStatus) throw parseErr; var err = new Error('Błąd API: HTTP ' + status); err.httpStatus = status; throw err; }); } return r.json(); } function handleFetchError(err, retryFn, isRetry) { if (err.name === 'AbortError') { throw new Error('Przekroczono czas oczekiwania. Spróbuj ponownie.'); } if (err instanceof TypeError && !isRetry) { return retryFn(); } if (err instanceof TypeError) { throw new Error('Brak połączenia z serwerem. Sprawdź internet i spróbuj ponownie.'); } throw err; } // ─── DOM Refs ───────────────────────────────────────────────── var overlay, form, segmentSelect, dateFrom, dateTo, daysCount; var pickupSelect, returnSelect, returnWrap, sameReturnCheck; var extrasWrapper, extrasContainer, insuranceContainer, abroadSection, abroadToggle, abroadSearch, abroadInput, abroadResults, abroadSelected, errorSummary; var summaryOverlay, summaryDetails, summaryTable, summaryTotal, summaryError; var summaryBack, summaryConfirm; var successView, successNumber, successClose; function initRefs() { overlay = document.querySelector('[data-carei-modal]'); form = document.getElementById('carei-reservation-form'); segmentSelect = document.getElementById('carei-segment'); dateFrom = document.getElementById('carei-date-from'); dateTo = document.getElementById('carei-date-to'); daysCount = document.getElementById('carei-days-count'); pickupSelect = document.getElementById('carei-pickup-branch'); returnSelect = document.getElementById('carei-return-branch'); returnWrap = document.getElementById('carei-return-wrap'); sameReturnCheck = document.getElementById('carei-same-return'); extrasWrapper = document.getElementById('carei-extras-wrapper'); extrasContainer = document.getElementById('carei-extras-container'); insuranceContainer = document.getElementById('carei-insurance-container'); abroadSection = document.getElementById('carei-abroad-section'); abroadToggle = document.getElementById('carei-abroad-toggle'); abroadSearch = document.getElementById('carei-abroad-search'); abroadInput = document.getElementById('carei-abroad-input'); abroadResults = document.getElementById('carei-abroad-results'); abroadSelected = document.getElementById('carei-abroad-selected'); errorSummary = document.getElementById('carei-error-summary'); // Summary overlay summaryOverlay = document.getElementById('carei-summary-overlay'); summaryDetails = document.getElementById('carei-summary-details'); summaryTable = document.getElementById('carei-summary-table'); summaryTotal = document.getElementById('carei-summary-total'); summaryError = document.getElementById('carei-summary-error'); summaryBack = document.getElementById('carei-summary-back'); summaryConfirm = document.getElementById('carei-summary-confirm'); // Success view successView = document.getElementById('carei-success-view'); successNumber = document.getElementById('carei-success-number'); successClose = document.getElementById('carei-success-close'); } // ─── State ──────────────────────────────────────────────────── var mapData = null; var allSegments = []; var currentPriceListId = null; var currentCustomerId = null; var currentReservationId = null; var agreementDefs = []; var lastFocusedElement = null; var abroadItems = []; var selectedCountries = {}; // ─── Modal Open/Close ───────────────────────────────────────── function initModal() { document.querySelectorAll('[data-carei-open-modal]').forEach(function (btn) { btn.addEventListener('click', function (e) { e.preventDefault(); openModal(btn); }); }); document.querySelectorAll('[data-carei-close-modal]').forEach(function (btn) { btn.addEventListener('click', closeModal); }); if (overlay) { overlay.addEventListener('click', function (e) { if (e.target === overlay) closeModal(); }); overlay.addEventListener('keydown', handleFocusTrap); } document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && overlay && overlay.classList.contains('is-open')) closeModal(); }); } var dataLoaded = false; function openModal(triggerBtn) { if (!overlay) return; lastFocusedElement = triggerBtn || document.activeElement; overlay.classList.add('is-open'); document.body.style.overflow = 'hidden'; if (!dataLoaded) { loadInitialData(); initDateLabels(); dataLoaded = true; } // Pre-select segment from trigger attribute var presetSegment = triggerBtn && triggerBtn.getAttribute('segment'); if (presetSegment && segmentSelect) { var trySet = function () { if (segmentSelect.querySelector('option[value="' + presetSegment + '"]')) { segmentSelect.value = presetSegment; segmentSelect.dispatchEvent(new Event('change')); return true; } return false; }; if (!trySet()) { var attempts = 0; var iv = setInterval(function () { if (trySet() || ++attempts > 20) clearInterval(iv); }, 100); } } setTimeout(function () { if (segmentSelect) segmentSelect.focus(); }, 350); } function closeModal() { if (!overlay) return; overlay.classList.remove('is-open'); document.body.style.overflow = ''; if (lastFocusedElement && lastFocusedElement.focus) { setTimeout(function () { lastFocusedElement.focus(); }, 300); } } // ─── Focus Trap ───────────────────────────────────────────── var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; function handleFocusTrap(e) { if (e.key !== 'Tab') return; var modal = overlay.querySelector('.carei-modal'); if (!modal) return; var focusable = Array.prototype.slice.call(modal.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) { return el.offsetParent !== null; }); if (focusable.length === 0) return; var first = focusable[0]; var last = focusable[focusable.length - 1]; if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault(); last.focus(); } } else { if (document.activeElement === last) { e.preventDefault(); first.focus(); } } } // ─── Initial Data Loading ───────────────────────────────────── function loadInitialData() { if (segmentSelect) setSelectLoading(segmentSelect, true); Promise.all([ apiGet('car-classes-all'), apiGet('segments-branches-map'), apiGet('agreements') ]).then(function (results) { var classes = results[0]; mapData = results[1]; agreementDefs = Array.isArray(results[2]) ? results[2] : []; if (Array.isArray(classes) && classes.length > 0) { allSegments = classes.map(function (c) { var val = typeof c === 'string' ? c : (c.name || c); var label = typeof c === 'string' ? ('Segment ' + c) : (c.description || c.name || c); return { value: val, label: label }; }); populateSelect(segmentSelect, allSegments, 'Wybierz segment pojazdu'); } else { populateSelect(segmentSelect, [], 'Brak segmentów'); } if (segmentSelect) setSelectLoading(segmentSelect, false); if (pickupSelect) { populateSelect(pickupSelect, [], 'Najpierw wybierz segment'); pickupSelect.disabled = true; } }).catch(function (err) { console.error('Failed to load initial data:', err); if (segmentSelect) { populateSelect(segmentSelect, [], 'Błąd ładowania'); setSelectLoading(segmentSelect, false); } }); } // ─── Segment Change → Filter Pickup Locations ───────────────── function onSegmentChange() { var selectedSegment = segmentSelect ? segmentSelect.value : ''; if (!selectedSegment || !mapData || !pickupSelect) { if (pickupSelect) { populateSelect(pickupSelect, [], 'Najpierw wybierz segment'); pickupSelect.disabled = true; } hideExtras(); return; } var segBranches = mapData.segmentToBranches[selectedSegment] || []; var allBranches = mapData.branches || []; var filteredOptions = []; allBranches.forEach(function (b) { if (segBranches.indexOf(b.name || '') !== -1) { var label = b.description || b.name; if (b.city) label += ' — ' + b.city; filteredOptions.push({ value: b.name, label: label }); } }); if (filteredOptions.length > 0) { populateSelect(pickupSelect, filteredOptions, 'Miejsce odbioru'); pickupSelect.disabled = false; } else { populateSelect(pickupSelect, [], 'Brak lokalizacji dla tego segmentu'); pickupSelect.disabled = true; } if (returnSelect) { var returnOptions = allBranches.map(function (b) { var label = b.description || b.name; if (b.city) label += ' — ' + b.city; return { value: b.name, label: label }; }); populateSelect(returnSelect, returnOptions, 'Miejsce zwrotu'); } hideExtras(); } function onPickupChange() { maybeShowExtras(); } function maybeShowExtras() { var segment = segmentSelect ? segmentSelect.value : ''; var pickup = pickupSelect ? pickupSelect.value : ''; var from = dateFrom ? dateFrom.value : ''; var to = dateTo ? dateTo.value : ''; if (segment && pickup && from && to) { showExtras(); loadExtras(); } else { hideExtras(); } } function showExtras() { if (extrasWrapper) extrasWrapper.style.display = ''; } function hideExtras() { if (extrasWrapper) extrasWrapper.style.display = 'none'; } // ─── Date Labels ────────────────────────────────────────────── function initDateLabels() { [dateFrom, dateTo].forEach(function (input) { if (!input) return; updateDateEmpty(input); input.addEventListener('change', function () { updateDateEmpty(input); updateDaysCount(); }); input.addEventListener('input', function () { updateDateEmpty(input); }); }); } function updateDateEmpty(input) { var wrap = input.closest('.carei-form__date-wrap'); if (input.value) { input.classList.remove('is-empty'); if (wrap) wrap.classList.add('has-value'); } else { input.classList.add('is-empty'); if (wrap) wrap.classList.remove('has-value'); } } function pad(n) { return String(n).padStart(2, '0'); } // ─── Days Count ─────────────────────────────────────────────── function getRentalDays() { if (!dateFrom || !dateTo) return 1; var from = new Date(dateFrom.value), to = new Date(dateTo.value); if (isNaN(from.getTime()) || isNaN(to.getTime()) || to <= from) return 1; return Math.ceil((to - from) / 86400000); } function updateDaysCount() { if (!dateFrom || !dateTo || !daysCount) return; var from = new Date(dateFrom.value), to = new Date(dateTo.value); if (isNaN(from.getTime()) || isNaN(to.getTime()) || to <= from) { daysCount.innerHTML = 'Wybrano: 0 dni'; return; } var diff = Math.ceil((to - from) / 86400000); daysCount.innerHTML = 'Wybrano: ' + diff + ' ' + (diff === 1 ? 'dzień' : 'dni') + ''; } // ─── Load Extras from Pricelist ─────────────────────────────── function loadExtras() { if (!segmentSelect || !dateFrom || !dateTo || !pickupSelect) return; var category = segmentSelect.value, fromVal = dateFrom.value, toVal = dateTo.value, branch = pickupSelect.value; if (!category || !fromVal || !toVal || !branch) return; apiPost('pricelist', { category: category, dateFrom: fromVal + ':00', dateTo: toVal + ':00', pickUpLocation: branch }).then(function (pricelists) { if (!Array.isArray(pricelists) || pricelists.length === 0) return; var pricelist = pricelists[0]; currentPriceListId = pricelist.id; var items = pricelist.additionalItems; var insuranceItems = [], extraItems = []; abroadItems = []; selectedCountries = {}; if (Array.isArray(items)) { items.forEach(function (item) { var name = (item.name || '').toLowerCase(); // Skip penalty/return items var code = (item.code || '').toUpperCase(); if (code.indexOf('BRAK') === 0 || code.indexOf('BRUD') === 0 || code.indexOf('KARA') === 0 || code.indexOf('MYCIE USŁU') === 0 || code === 'MYJ WEW') return; if (name.indexOf('wyjazd za granic') !== -1) { item._countryName = parseCountryName(item.name); item._countryFlag = getCountryFlag(item._countryName); abroadItems.push(item); } else if (name.indexOf('ubezp') !== -1 || name.indexOf('ochrony') !== -1 || name.indexOf('zniesienie') !== -1 || name.indexOf('insurance') !== -1) { insuranceItems.push(item); } else { extraItems.push(item); } }); } if (insuranceContainer) { insuranceContainer.innerHTML = ''; insuranceItems.forEach(function (item) { insuranceContainer.appendChild(buildExtraCard(item)); }); } if (extrasContainer) { extrasContainer.innerHTML = ''; extraItems.forEach(function (item) { extrasContainer.appendChild(buildExtraCard(item)); }); } if (abroadSection) { abroadSection.style.display = abroadItems.length > 0 ? '' : 'none'; } renderAbroadSelected(); }).catch(function (err) { console.error('Failed to load pricelist:', err); }); } function buildExtraCard(item) { var price = parseFloat(item.price || item.minPrice || 0); var maxPrice = parseFloat(item.maxPrice || 0); var priceLabel = (maxPrice > 0 && maxPrice !== price) ? 'od ' + price.toFixed(0) + ' do ' + maxPrice.toFixed(0) + ' zł' : (price > 0 ? price.toFixed(0) + ' zł' + (item.unit === 'doba' ? '/doba' : '') : 'Gratis'); var card = document.createElement('div'); card.className = 'carei-form__extra-card'; card.innerHTML = ''; return card; } // ─── Abroad Country Search ───────────────────────────────────── var COUNTRY_FLAGS = { 'niemcy': '\u{1F1E9}\u{1F1EA}', 'czechy': '\u{1F1E8}\u{1F1FF}', 'słowacja': '\u{1F1F8}\u{1F1F0}', 'austria': '\u{1F1E6}\u{1F1F9}', 'francja': '\u{1F1EB}\u{1F1F7}', 'włochy': '\u{1F1EE}\u{1F1F9}', 'hiszpania': '\u{1F1EA}\u{1F1F8}', 'holandia': '\u{1F1F3}\u{1F1F1}', 'belgia': '\u{1F1E7}\u{1F1EA}', 'dania': '\u{1F1E9}\u{1F1F0}', 'szwecja': '\u{1F1F8}\u{1F1EA}', 'norwegia': '\u{1F1F3}\u{1F1F4}', 'finlandia': '\u{1F1EB}\u{1F1EE}', 'szwajcaria': '\u{1F1E8}\u{1F1ED}', 'węgry': '\u{1F1ED}\u{1F1FA}', 'chorwacja': '\u{1F1ED}\u{1F1F7}', 'słowenia': '\u{1F1F8}\u{1F1EE}', 'litwa': '\u{1F1F1}\u{1F1F9}', 'łotwa': '\u{1F1F1}\u{1F1FB}', 'estonia': '\u{1F1EA}\u{1F1EA}', 'rumunia': '\u{1F1F7}\u{1F1F4}', 'bułgaria': '\u{1F1E7}\u{1F1EC}', 'portugalia': '\u{1F1F5}\u{1F1F9}', 'grecja': '\u{1F1EC}\u{1F1F7}', 'wielka brytania': '\u{1F1EC}\u{1F1E7}', 'irlandia': '\u{1F1EE}\u{1F1EA}', 'luksemburg': '\u{1F1F1}\u{1F1FA}', 'serbia': '\u{1F1F7}\u{1F1F8}', 'czarnogóra': '\u{1F1F2}\u{1F1EA}', 'albania': '\u{1F1E6}\u{1F1F1}', 'turcja': '\u{1F1F9}\u{1F1F7}', 'ukraina': '\u{1F1FA}\u{1F1E6}', 'mołdawia': '\u{1F1F2}\u{1F1E9}' }; function parseCountryName(name) { var raw = (name || '').replace(/wyjazd za granic[eę]\s*[-–—]?\s*/i, '').trim(); if (!raw) return name || ''; return raw.split(/\s+/).map(function (w) { return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase(); }).join(' '); } function getCountryFlag(countryName) { var key = (countryName || '').toLowerCase(); return COUNTRY_FLAGS[key] || '\u{1F3F3}\u{FE0F}'; } function initAbroad() { if (!abroadToggle || !abroadSearch) return; abroadToggle.addEventListener('change', function () { if (abroadToggle.checked) { abroadSearch.style.display = ''; } else { abroadSearch.style.display = 'none'; selectedCountries = {}; if (abroadInput) abroadInput.value = ''; renderAbroadResults([]); renderAbroadSelected(); } }); var abroadClear = document.getElementById('carei-abroad-clear'); if (abroadInput) { abroadInput.addEventListener('input', function () { updateAbroadClear(); var query = abroadInput.value.trim().toLowerCase(); if (!query) { renderAbroadResults([]); return; } var filtered = abroadItems.filter(function (item) { return item._countryName.toLowerCase().indexOf(query) !== -1; }); renderAbroadResults(filtered); }); abroadInput.addEventListener('focus', function () { var query = abroadInput.value.trim().toLowerCase(); if (query) { var filtered = abroadItems.filter(function (item) { return item._countryName.toLowerCase().indexOf(query) !== -1; }); renderAbroadResults(filtered); } }); } if (abroadClear) { abroadClear.addEventListener('click', function () { if (abroadInput) { abroadInput.value = ''; abroadInput.focus(); } renderAbroadResults([]); updateAbroadClear(); }); } function updateAbroadClear() { var wrap = abroadInput ? abroadInput.closest('.carei-abroad__input-wrap') : null; if (wrap) { if (abroadInput.value.trim()) { wrap.classList.add('has-text'); } else { wrap.classList.remove('has-text'); } } } } function renderAbroadResults(items) { if (!abroadResults) return; abroadResults.innerHTML = ''; if (!items || items.length === 0) return; items.forEach(function (item) { var id = item.id || item.code; var isSelected = !!selectedCountries[id]; abroadResults.appendChild(buildCountryCard(item, isSelected)); }); } function renderAbroadSelected() { if (!abroadSelected) return; abroadSelected.innerHTML = ''; var keys = Object.keys(selectedCountries); if (keys.length === 0) return; keys.forEach(function (id) { var item = selectedCountries[id]; abroadSelected.appendChild(buildCountryCard(item, true)); }); } function buildCountryCard(item, isSelected) { var id = item.id || item.code; var price = parseFloat(item.price || item.minPrice || 0); var priceHtml = '' + (price > 0 ? price.toFixed(0) + ' zł' : 'Gratis') + ''; var card = document.createElement('div'); card.className = 'carei-abroad__card' + (isSelected ? ' carei-abroad__card--selected' : ''); card.innerHTML = '' + escHtml(item._countryFlag) + '' + '' + escHtml(item._countryName) + '' + '' + priceHtml + '' + '' + (isSelected ? '' : '' ) + ''; card.querySelector('.carei-abroad__action').addEventListener('click', function (e) { e.preventDefault(); if (selectedCountries[id]) { delete selectedCountries[id]; } else { selectedCountries[id] = item; } var query = abroadInput ? abroadInput.value.trim().toLowerCase() : ''; if (query) { var filtered = abroadItems.filter(function (it) { return it._countryName.toLowerCase().indexOf(query) !== -1; }); renderAbroadResults(filtered); } else { renderAbroadResults([]); } renderAbroadSelected(); }); return card; } // ─── Select Helpers ─────────────────────────────────────────── function populateSelect(select, options, placeholder) { if (!select) return; select.innerHTML = ''; var ph = document.createElement('option'); ph.value = ''; ph.disabled = true; ph.selected = true; ph.textContent = placeholder || 'Wybierz...'; select.appendChild(ph); options.forEach(function (opt) { var o = document.createElement('option'); o.value = opt.value; o.textContent = opt.label; select.appendChild(o); }); } function setSelectLoading(select, loading) { if (!select) return; var wrap = select.closest('.carei-form__select-wrap'); if (wrap) wrap.classList.toggle('carei-form__select-wrap--loading', loading); } // ─── Same Return Location ───────────────────────────────────── function initSameReturn() { if (!sameReturnCheck || !returnWrap) return; sameReturnCheck.addEventListener('change', function () { returnWrap.classList.toggle('is-visible', !sameReturnCheck.checked); }); } // ─── Validation ─────────────────────────────────────────────── var requiredFields = [ { id: 'carei-segment', type: 'select', msg: 'Wybierz segment pojazdu' }, { id: 'carei-date-from', type: 'input', msg: 'Podaj datę rozpoczęcia' }, { id: 'carei-date-to', type: 'input', msg: 'Podaj datę zakończenia' }, { id: 'carei-pickup-branch', type: 'select', msg: 'Wybierz miejsce odbioru' }, { id: 'carei-firstname', type: 'input', msg: 'Podaj imię' }, { id: 'carei-lastname', type: 'input', msg: 'Podaj nazwisko' }, { id: 'carei-city', type: 'input', msg: 'Podaj miejscowość' }, { id: 'carei-zipcode', type: 'input', msg: 'Podaj kod pocztowy' }, { id: 'carei-street', type: 'input', msg: 'Podaj ulicę' }, { id: 'carei-email', type: 'email', msg: 'Podaj poprawny adres e-mail' }, { id: 'carei-phone', type: 'phone', msg: 'Podaj numer telefonu (min. 9 cyfr)' }, { id: 'carei-pesel', type: 'pesel', msg: 'Podaj poprawny PESEL (11 cyfr)' }, { id: 'carei-privacy', type: 'checkbox', msg: 'Wymagana zgoda na Politykę Prywatności' } ]; function validateForm() { var valid = true; form.querySelectorAll('.carei-form__field--error').forEach(function (el) { el.classList.remove('carei-form__field--error'); }); form.querySelectorAll('.carei-form__checkbox-label--error').forEach(function (el) { el.classList.remove('carei-form__checkbox-label--error'); }); form.querySelectorAll('.carei-form__error-msg').forEach(function (el) { el.remove(); }); requiredFields.forEach(function (f) { var el = document.getElementById(f.id); if (!el) return; var hasError = false; if (f.type === 'checkbox') { if (!el.checked) hasError = true; } else if (f.type === 'email') { if (!el.value.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(el.value.trim())) hasError = true; } else if (f.type === 'phone') { if (el.value.replace(/\D/g, '').length < 9) hasError = true; } else if (f.type === 'pesel') { if (!/^\d{11}$/.test(el.value.trim())) hasError = true; } else if (f.type === 'select') { if (!el.value) hasError = true; } else { if (!el.value.trim()) hasError = true; } if (hasError) { valid = false; markFieldError(el, f.msg, f.type); } }); if (dateFrom && dateTo && dateFrom.value && dateTo.value) { if (new Date(dateTo.value) <= new Date(dateFrom.value)) { valid = false; markFieldError(dateTo, 'Data zakończenia musi być po dacie rozpoczęcia', 'input'); } } if (sameReturnCheck && !sameReturnCheck.checked && returnSelect && !returnSelect.value) { valid = false; markFieldError(returnSelect, 'Wybierz miejsce zwrotu', 'select'); } if (errorSummary) errorSummary.style.display = valid ? 'none' : 'block'; return valid; } function markFieldError(el, msg, type) { if (type === 'checkbox') { var label = el.closest('.carei-form__checkbox-label'); if (label) label.classList.add('carei-form__checkbox-label--error'); } else { var field = el.closest('.carei-form__field'); if (!field) { field = el.closest('.carei-form__phone-wrap'); if (field) field = field.closest('.carei-form__field'); } if (field) { field.classList.add('carei-form__field--error'); var errEl = document.createElement('span'); errEl.className = 'carei-form__error-msg'; errEl.textContent = msg; field.appendChild(errEl); } } } function initClearErrors() { if (!form) return; form.addEventListener('focusin', function (e) { var field = e.target.closest('.carei-form__field'); if (field && field.classList.contains('carei-form__field--error')) { field.classList.remove('carei-form__field--error'); var errMsg = field.querySelector('.carei-form__error-msg'); if (errMsg) errMsg.remove(); } var label = e.target.closest('.carei-form__checkbox-label'); if (label) label.classList.remove('carei-form__checkbox-label--error'); }); form.addEventListener('change', function (e) { if (e.target.type === 'checkbox') { var label = e.target.closest('.carei-form__checkbox-label'); if (label) label.classList.remove('carei-form__checkbox-label--error'); } }); } // ─── Form Submit → Booking Flow ─────────────────────────────── function initSubmit() { if (!form) return; form.addEventListener('submit', function (e) { e.preventDefault(); if (!validateForm()) return; setSubmitState('loading'); createCustomerAndShowSummary(); }); if (summaryBack) summaryBack.addEventListener('click', handleSummaryBack); if (summaryConfirm) summaryConfirm.addEventListener('click', handleSummaryConfirm); if (successClose) successClose.addEventListener('click', handleSuccessClose); } function setSubmitState(state) { var btn = form ? form.querySelector('.carei-form__submit') : null; if (!btn) return; if (state === 'loading') { btn.disabled = true; btn.setAttribute('aria-busy', 'true'); btn.innerHTML = ' Przetwarzanie...'; } else { btn.disabled = false; btn.setAttribute('aria-busy', 'false'); btn.innerHTML = ' Wyślij'; } } function collectFormData() { var phoneRaw = document.getElementById('carei-phone') ? document.getElementById('carei-phone').value.replace(/\D/g, '') : ''; return { segment: segmentSelect ? segmentSelect.value : '', dateFrom: dateFrom ? dateFrom.value : '', dateTo: dateTo ? dateTo.value : '', pickupBranch: pickupSelect ? pickupSelect.value : '', sameReturn: sameReturnCheck ? sameReturnCheck.checked : true, returnBranch: (sameReturnCheck && !sameReturnCheck.checked && returnSelect) ? returnSelect.value : '', firstName: val('carei-firstname'), lastName: val('carei-lastname'), city: val('carei-city'), zipCode: val('carei-zipcode'), street: val('carei-street'), email: val('carei-email'), phone: '+48' + phoneRaw, pesel: val('carei-pesel'), message: val('carei-message'), privacy: document.getElementById('carei-privacy') ? document.getElementById('carei-privacy').checked : false }; } function val(id) { var el = document.getElementById(id); return el ? el.value.trim() : ''; } // ─── Step 1: Create Customer ────────────────────────────────── function createCustomerAndShowSummary() { var fd = collectFormData(); hideSummaryError(); announce('Ładowanie podsumowania...'); apiPost('customer', { firstName: fd.firstName, lastName: fd.lastName, name: fd.firstName + ' ' + fd.lastName, isCompany: false, address: { city: fd.city, zipCode: fd.zipCode, street: fd.street, homeNo: '-' }, pesel: fd.pesel, email: fd.email, phoneMobile: fd.phone, paymentMethod: 'GOTÓWKA', skipAccountCreate: true, emailVerified: true }).then(function (res) { if (res && res.customerId) { currentCustomerId = res.customerId; return loadPricingSummary(fd); } throw new Error(res.rejectReason || 'Nie udało się utworzyć klienta'); }).catch(function (err) { console.error('Customer creation failed:', err); setSubmitState('ready'); showFormError('Błąd tworzenia klienta: ' + err.message); }); } // ─── Step 2: Pricing Summary ────────────────────────────────── function loadPricingSummary(fd) { var returnBranch = fd.sameReturn ? fd.pickupBranch : fd.returnBranch; return apiPost('pricing-summary', { dateFrom: fd.dateFrom + ':00', dateTo: fd.dateTo + ':00', customerId: currentCustomerId, pickUpLocation: { branchName: fd.pickupBranch, outOfBranch: 'N' }, returnLocation: { branchName: returnBranch, outOfBranch: 'N' }, carParameters: { categoryName: fd.segment }, priceListId: currentPriceListId, priceItems: getSelectedExtrasForApi() }).then(function (summary) { showSummaryOverlay(summary, fd); }).catch(function (err) { console.error('Pricing summary failed:', err); setSubmitState('ready'); showFormError('Błąd pobierania podsumowania: ' + err.message); }); } function getSelectedExtrasForApi() { var items = []; if (!form) return items; var days = getRentalDays(); form.querySelectorAll('input[name="extras[]"]:checked').forEach(function (cb) { var price = parseFloat(cb.getAttribute('data-price') || 0); var unit = cb.getAttribute('data-unit') || 'szt.'; var amount = unit === 'doba' ? days : 1; items.push({ id: cb.value, name: cb.getAttribute('data-name') || '', unit: unit, amount: amount, priceBeforeDiscount: price, discount: 0, priceAfterDiscount: price }); }); Object.keys(selectedCountries).forEach(function (id) { var item = selectedCountries[id]; var price = parseFloat(item.price || item.minPrice || 0); var unit = item.unit || 'szt.'; var amount = unit === 'doba' ? days : 1; items.push({ id: item.id || item.code, name: item.name, unit: unit, amount: amount, priceBeforeDiscount: price, discount: 0, priceAfterDiscount: price }); }); return items; } // ─── Step Transitions ────────────────────────────────────────── function hideStep(el) { if (!el) return; el.style.display = 'none'; el.classList.remove('carei-step--entering', 'carei-step--exiting'); } function showStep(el) { if (!el) return; el.style.display = ''; el.classList.remove('carei-step--hidden'); } function transitionStep(outEl, inEl, callback) { if (outEl) { outEl.classList.add('carei-step--exiting'); setTimeout(function () { hideStep(outEl); if (inEl) { inEl.classList.add('carei-step--entering'); showStep(inEl); requestAnimationFrame(function () { requestAnimationFrame(function () { inEl.classList.remove('carei-step--entering'); if (callback) callback(); }); }); } else if (callback) { callback(); } }, 250); } else if (inEl) { inEl.classList.add('carei-step--entering'); showStep(inEl); requestAnimationFrame(function () { requestAnimationFrame(function () { inEl.classList.remove('carei-step--entering'); if (callback) callback(); }); }); } } // ─── Step 3: Show Summary Overlay ───────────────────────────── function showSummaryOverlay(summary, fd) { if (!summaryOverlay) return; hideSummaryError(); // Populate content before transition populateSummaryContent(summary, fd); // Animated transition: form → summary transitionStep(form, summaryOverlay, function () { announce('Podsumowanie rezerwacji'); var title = summaryOverlay.querySelector('.carei-summary__title'); if (title) title.focus(); }); } function populateSummaryContent(summary, fd) { // Details if (summaryDetails) { var segLabel = segmentSelect ? segmentSelect.options[segmentSelect.selectedIndex].text : fd.segment; var pickupLabel = pickupSelect ? pickupSelect.options[pickupSelect.selectedIndex].text : fd.pickupBranch; var returnLabel = ''; if (!fd.sameReturn && returnSelect) { returnLabel = returnSelect.options[returnSelect.selectedIndex].text; } var html = '
| Nazwa | Ilość | Netto | Brutto |
|---|---|---|---|
| ' + escHtml(toSentenceCase(item.name)) + (item.addedBySystem ? ' (auto)' : '') + ' | ' + '' + (item.amount || 1) + ' ' + escHtml(item.unit || '') + ' | ' + '' + fmtPrice(item.netValue) + ' | ' + '' + fmtPrice(item.grossValue) + ' |