update
This commit is contained in:
@@ -1647,3 +1647,94 @@ button.carei-reservation-trigger:hover {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* ──────────────────────────────────────────────────────────────
|
||||
Flatpickr — compact theme + Carei colors
|
||||
────────────────────────────────────────────────────────────── */
|
||||
.flatpickr-calendar {
|
||||
width: 260px !important;
|
||||
font-size: 13px !important;
|
||||
box-shadow: 0 6px 20px rgba(47, 36, 130, 0.15);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.flatpickr-calendar.open { z-index: 100000; }
|
||||
.flatpickr-months { padding: 4px 0; }
|
||||
.flatpickr-month { height: 28px; }
|
||||
.flatpickr-current-month {
|
||||
font-size: 13px;
|
||||
padding: 4px 0 0 0;
|
||||
height: 24px;
|
||||
}
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months,
|
||||
.flatpickr-current-month input.cur-year {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.flatpickr-prev-month,
|
||||
.flatpickr-next-month {
|
||||
padding: 4px 8px;
|
||||
height: 28px;
|
||||
}
|
||||
.flatpickr-prev-month svg,
|
||||
.flatpickr-next-month svg { width: 12px; height: 12px; }
|
||||
.flatpickr-weekdays { height: 24px; }
|
||||
.flatpickr-weekday {
|
||||
font-size: 11px !important;
|
||||
font-weight: 600;
|
||||
color: #6b6b8a !important;
|
||||
}
|
||||
.dayContainer {
|
||||
padding: 2px;
|
||||
width: 252px;
|
||||
min-width: 252px;
|
||||
max-width: 252px;
|
||||
}
|
||||
.flatpickr-day {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 12px;
|
||||
max-width: 32px;
|
||||
border-radius: 4px;
|
||||
margin: 1px 0;
|
||||
}
|
||||
.flatpickr-day.today { border-color: #2F2482; }
|
||||
.flatpickr-day.selected,
|
||||
.flatpickr-day.startRange,
|
||||
.flatpickr-day.endRange,
|
||||
.flatpickr-day.selected:hover {
|
||||
background: #2F2482 !important;
|
||||
border-color: #2F2482 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
.flatpickr-day:hover,
|
||||
.flatpickr-day.prevMonthDay:hover,
|
||||
.flatpickr-day.nextMonthDay:hover {
|
||||
background: rgba(47, 36, 130, 0.08);
|
||||
}
|
||||
.flatpickr-time {
|
||||
height: 32px;
|
||||
border-top: 1px solid rgba(47, 36, 130, 0.12);
|
||||
}
|
||||
.flatpickr-time input {
|
||||
font-size: 13px;
|
||||
height: 32px;
|
||||
}
|
||||
.flatpickr-time .flatpickr-time-separator,
|
||||
.flatpickr-time .flatpickr-am-pm {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.flatpickr-time input:hover,
|
||||
.flatpickr-time input:focus {
|
||||
background: rgba(47, 36, 130, 0.05);
|
||||
}
|
||||
.flatpickr-time .numInputWrapper span {
|
||||
width: 12px;
|
||||
height: 50%;
|
||||
}
|
||||
@media (max-width: 380px) {
|
||||
.flatpickr-calendar { width: calc(100vw - 24px) !important; }
|
||||
.dayContainer { width: 100%; min-width: 0; max-width: 100%; }
|
||||
.flatpickr-day { max-width: none; }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// ─── i18n Helpers ─────────────────────────────────────────────
|
||||
var I18N = (window.careiI18n || {});
|
||||
function t(key, fallback) {
|
||||
return (key in I18N) ? I18N[key] : (fallback || key);
|
||||
}
|
||||
function tFmt(key, params, fallback) {
|
||||
var str = t(key, fallback);
|
||||
if (params && typeof str === 'string') {
|
||||
Object.keys(params).forEach(function (k) {
|
||||
str = str.replace(new RegExp('%' + k + '%', 'g'), params[k]);
|
||||
});
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function pluralPl(n, one, few, many) {
|
||||
if (n === 1) return one;
|
||||
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) return few;
|
||||
return many;
|
||||
}
|
||||
|
||||
var REST_URL = (window.careiReservation && window.careiReservation.restUrl) || '/wp-json/carei/v1/';
|
||||
var NONCE = (window.careiReservation && window.careiReservation.nonce) || '';
|
||||
|
||||
@@ -48,13 +68,13 @@
|
||||
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 msg = (body && body.message) || (body && body.detail) || tFmt('errorApiHttp', {status: status}, '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);
|
||||
var err = new Error(tFmt('errorApiHttp', {status: status}, 'Błąd API: HTTP %status%'));
|
||||
err.httpStatus = status;
|
||||
throw err;
|
||||
});
|
||||
@@ -64,13 +84,13 @@
|
||||
|
||||
function handleFetchError(err, retryFn, isRetry) {
|
||||
if (err.name === 'AbortError') {
|
||||
throw new Error('Przekroczono czas oczekiwania. Spróbuj ponownie.');
|
||||
throw new Error(t('errorTimeout', '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 new Error(t('errorNetwork', 'Brak połączenia z serwerem. Sprawdź internet i spróbuj ponownie.'));
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -79,7 +99,7 @@
|
||||
|
||||
var overlay, form, segmentSelect, dateFrom, dateTo, daysCount;
|
||||
var pickupSelect, returnSelect, returnWrap, sameReturnCheck;
|
||||
var extrasWrapper, extrasContainer, insuranceContainer, abroadSection, abroadToggle, abroadSearch, abroadInput, abroadResults, abroadSelected, errorSummary;
|
||||
var extrasWrapper, extrasContainer, abroadSection, abroadToggle, abroadSearch, abroadInput, abroadResults, abroadSelected, errorSummary;
|
||||
var summaryOverlay, summaryDetails, summaryTable, summaryTotal, summaryError;
|
||||
var summaryBack, summaryConfirm;
|
||||
var successView, successNumber, successClose;
|
||||
@@ -104,7 +124,6 @@
|
||||
sameReturnCheck = document.getElementById('carei-same-return');
|
||||
extrasWrapper = document.getElementById('carei-extras-wrapper');
|
||||
extrasContainer = document.getElementById('carei-extras-container');
|
||||
insuranceContainer = document.getElementById('carei-insurance-container');
|
||||
protectionContainer = document.getElementById('carei-protection-packages-container');
|
||||
abroadSection = document.getElementById('carei-abroad-section');
|
||||
abroadToggle = document.getElementById('carei-abroad-toggle');
|
||||
@@ -127,6 +146,89 @@
|
||||
successClose = document.getElementById('carei-success-close');
|
||||
}
|
||||
|
||||
// ─── Flatpickr date pickers (cross-browser, locale-aware) ─────
|
||||
// If Flatpickr fails to load (CDN blocked, network, etc.), fall back gracefully
|
||||
// to native <input type="datetime-local"> — never break date picking.
|
||||
function initDatePickers() {
|
||||
if (typeof window.flatpickr !== 'function') {
|
||||
console.warn('[carei] Flatpickr not loaded — keeping native datetime-local picker.');
|
||||
return;
|
||||
}
|
||||
var isEn = (document.documentElement.lang || '').toLowerCase().indexOf('en') === 0;
|
||||
var locale = 'default';
|
||||
if (!isEn && window.flatpickr.l10ns && window.flatpickr.l10ns.pl) {
|
||||
locale = window.flatpickr.l10ns.pl;
|
||||
}
|
||||
var baseOpts = {
|
||||
enableTime: true,
|
||||
time_24hr: true,
|
||||
dateFormat: 'Y-m-d\\TH:i',
|
||||
altInput: true,
|
||||
altFormat: isEn ? 'Y-m-d H:i' : 'd.m.Y H:i',
|
||||
minuteIncrement: 15,
|
||||
minDate: 'today',
|
||||
locale: locale,
|
||||
allowInput: false,
|
||||
// Force Flatpickr on mobile too (otherwise falls back to native iOS/Android picker — inconsistent look, locale = OS)
|
||||
disableMobile: true,
|
||||
// With enableTime, flatpickr doesn't auto-close on date click (time still editable).
|
||||
// Auto-close 1.5s after last change — gives user time to adjust time, then dismisses.
|
||||
onChange: function (selectedDates, dateStr, instance) {
|
||||
if (instance._careiCloseTimer) clearTimeout(instance._careiCloseTimer);
|
||||
instance._careiCloseTimer = setTimeout(function () {
|
||||
instance.close();
|
||||
}, 1500);
|
||||
}
|
||||
};
|
||||
|
||||
// Modal inputs — use static:true so popup renders INSIDE input container
|
||||
// (bypasses focus trap + z-index conflicts with modal overlay).
|
||||
var modalTargets = [dateFrom, dateTo];
|
||||
// Hero search inputs — render popup to body (default behavior is fine, no modal).
|
||||
var heroTargets = [
|
||||
document.getElementById('carei-search-date-from'),
|
||||
document.getElementById('carei-search-date-to')
|
||||
];
|
||||
|
||||
function attach(el, opts) {
|
||||
if (!el) return;
|
||||
// If already initialized, destroy previous instance (idempotent re-init)
|
||||
if (el._flatpickr) {
|
||||
try { el._flatpickr.destroy(); } catch (e) {}
|
||||
}
|
||||
try {
|
||||
el.setAttribute('type', 'text');
|
||||
window.flatpickr(el, opts);
|
||||
// Bind click on the whole field container — any click (icon, label, padding, input)
|
||||
// opens the flatpickr. Simplest UX.
|
||||
var field = el.closest('.carei-form__field--date') || el.closest('.carei-search-form__field');
|
||||
if (field && !field.dataset.careiFpBound) {
|
||||
field.dataset.careiFpBound = '1';
|
||||
field.style.cursor = 'pointer';
|
||||
var lastCloseAt = 0;
|
||||
if (el._flatpickr) {
|
||||
var origOnClose = el._flatpickr.config.onClose || [];
|
||||
el._flatpickr.config.onClose = (Array.isArray(origOnClose) ? origOnClose.slice() : [origOnClose]).concat([function () { lastCloseAt = Date.now(); }]);
|
||||
}
|
||||
field.addEventListener('click', function (e) {
|
||||
// Ignore clicks that originated inside the flatpickr popup itself.
|
||||
if (e.target.closest && e.target.closest('.flatpickr-calendar')) return;
|
||||
// Debounce: if we just closed (within 300ms, e.g. via date selection), don't reopen.
|
||||
if (Date.now() - lastCloseAt < 300) return;
|
||||
if (el._flatpickr) el._flatpickr.open();
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[carei] Flatpickr init failed for', el.id, err);
|
||||
try { el.setAttribute('type', 'datetime-local'); } catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
var modalOpts = Object.assign({}, baseOpts, { static: true });
|
||||
modalTargets.forEach(function (el) { attach(el, modalOpts); });
|
||||
heroTargets.forEach(function (el) { attach(el, baseOpts); });
|
||||
}
|
||||
|
||||
// ─── State ────────────────────────────────────────────────────
|
||||
|
||||
var mapData = null;
|
||||
@@ -247,23 +349,23 @@
|
||||
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);
|
||||
var label = typeof c === 'string' ? tFmt('segmentLabel', {name: c}, 'Segment %name%') : (c.description || c.name || c);
|
||||
return { value: val, label: label };
|
||||
});
|
||||
populateSelect(segmentSelect, allSegments, 'Wybierz segment pojazdu');
|
||||
populateSelect(segmentSelect, allSegments, t('selectSegment', 'Wybierz segment pojazdu'));
|
||||
} else {
|
||||
populateSelect(segmentSelect, [], 'Brak segmentów');
|
||||
populateSelect(segmentSelect, [], t('noSegments', 'Brak segmentów'));
|
||||
}
|
||||
if (segmentSelect) setSelectLoading(segmentSelect, false);
|
||||
|
||||
if (pickupSelect) {
|
||||
populateSelect(pickupSelect, [], 'Najpierw wybierz segment');
|
||||
populateSelect(pickupSelect, [], t('pickupPlaceholder', 'Najpierw wybierz segment'));
|
||||
pickupSelect.disabled = true;
|
||||
}
|
||||
}).catch(function (err) {
|
||||
console.error('Failed to load initial data:', err);
|
||||
if (segmentSelect) {
|
||||
populateSelect(segmentSelect, [], 'Błąd ładowania');
|
||||
populateSelect(segmentSelect, [], t('errorLoading', 'Błąd ładowania'));
|
||||
setSelectLoading(segmentSelect, false);
|
||||
}
|
||||
});
|
||||
@@ -274,7 +376,7 @@
|
||||
function onSegmentChange() {
|
||||
var selectedSegment = segmentSelect ? segmentSelect.value : '';
|
||||
if (!selectedSegment || !mapData || !pickupSelect) {
|
||||
if (pickupSelect) { populateSelect(pickupSelect, [], 'Najpierw wybierz segment'); pickupSelect.disabled = true; }
|
||||
if (pickupSelect) { populateSelect(pickupSelect, [], t('pickupPlaceholder', 'Najpierw wybierz segment')); pickupSelect.disabled = true; }
|
||||
hideExtras();
|
||||
return;
|
||||
}
|
||||
@@ -289,10 +391,10 @@
|
||||
}
|
||||
});
|
||||
if (filteredOptions.length > 0) {
|
||||
populateSelect(pickupSelect, filteredOptions, 'Miejsce odbioru');
|
||||
populateSelect(pickupSelect, filteredOptions, t('pickupLabel', 'Miejsce odbioru'));
|
||||
pickupSelect.disabled = false;
|
||||
} else {
|
||||
populateSelect(pickupSelect, [], 'Brak lokalizacji dla tego segmentu');
|
||||
populateSelect(pickupSelect, [], t('noPickupForSegment', 'Brak lokalizacji dla tego segmentu'));
|
||||
pickupSelect.disabled = true;
|
||||
}
|
||||
if (returnSelect) {
|
||||
@@ -301,7 +403,7 @@
|
||||
if (b.city) label += ' — ' + b.city;
|
||||
return { value: b.name, label: label };
|
||||
});
|
||||
populateSelect(returnSelect, returnOptions, 'Miejsce zwrotu');
|
||||
populateSelect(returnSelect, returnOptions, t('returnLabel', 'Miejsce zwrotu'));
|
||||
}
|
||||
hideExtras();
|
||||
}
|
||||
@@ -353,7 +455,7 @@
|
||||
function checkPastAndWarn(input, label) {
|
||||
if (!input || !input.value) return;
|
||||
if (input.value < getNowLocal()) {
|
||||
warnPastDate(input, label + ' — data lub godzina już minęły');
|
||||
warnPastDate(input, tFmt('warnPastDate', {label: label}, '%label% — data lub godzina już minęły'));
|
||||
} else {
|
||||
clearDateError(input);
|
||||
}
|
||||
@@ -367,13 +469,13 @@
|
||||
if (!dateMinListenersBound) {
|
||||
if (dateFrom) {
|
||||
dateFrom.addEventListener('change', function () {
|
||||
checkPastAndWarn(dateFrom, 'Rozpoczęcie');
|
||||
checkPastAndWarn(dateFrom, t('dateStart', 'Rozpoczęcie'));
|
||||
if (dateTo && dateFrom.value) dateTo.setAttribute('min', dateFrom.value);
|
||||
});
|
||||
}
|
||||
if (dateTo) {
|
||||
dateTo.addEventListener('change', function () {
|
||||
checkPastAndWarn(dateTo, 'Zakończenie');
|
||||
checkPastAndWarn(dateTo, t('dateEnd', 'Zakończenie'));
|
||||
});
|
||||
}
|
||||
dateMinListenersBound = true;
|
||||
@@ -417,16 +519,18 @@
|
||||
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: <strong>0 dni</strong>'; return;
|
||||
daysCount.innerHTML = tFmt('daysCount', {count: 0, unit: t('dayMany', 'dni')}, 'Wybrano: <strong>%count% %unit%</strong>'); return;
|
||||
}
|
||||
var diff = Math.ceil((to - from) / 86400000);
|
||||
daysCount.innerHTML = 'Wybrano: <strong>' + diff + ' ' + (diff === 1 ? 'dzień' : 'dni') + '</strong>';
|
||||
var dayUnit = diff === 1 ? t('dayWord', 'dzień') : t('daysWord', 'dni');
|
||||
daysCount.innerHTML = tFmt('daysCount', {count: diff, unit: dayUnit}, 'Wybrano: <strong>%count% %unit%</strong>');
|
||||
}
|
||||
|
||||
// ─── Protection Packages (WP-managed: SOFT, PREMIUM) ──────────
|
||||
|
||||
function loadProtectionPackages() {
|
||||
return fetch(REST_URL + 'protection-packages', {
|
||||
var lang = (document.documentElement.lang || '').toLowerCase().indexOf('en') === 0 ? 'en' : 'pl';
|
||||
return fetch(REST_URL + 'protection-packages?lang=' + lang, {
|
||||
credentials: 'same-origin'
|
||||
}).then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (data) {
|
||||
@@ -444,7 +548,7 @@
|
||||
var pkg = protectionPackages[key];
|
||||
if (!pkg) return;
|
||||
var price = parseFloat(pkg.pricePerDay || 0);
|
||||
var priceLabel = price > 0 ? price.toFixed(0) + ' zł/doba' : 'Gratis';
|
||||
var priceLabel = price > 0 ? tFmt('pricePerDay', {price: price.toFixed(0)}, '%price% zł/doba') : t('free', 'Gratis');
|
||||
var descHtml = pkg.description ? '<span class="carei-form__protection-package__desc">' + escHtml(pkg.description) + '</span>' : '';
|
||||
var card = document.createElement('label');
|
||||
card.className = 'carei-form__protection-package';
|
||||
@@ -500,7 +604,7 @@
|
||||
var pricelist = pricelists[0];
|
||||
currentPriceListId = pricelist.id;
|
||||
var items = pricelist.additionalItems;
|
||||
var insuranceItems = [], extraItems = [];
|
||||
var extraItems = [];
|
||||
abroadItems = [];
|
||||
selectedCountries = {};
|
||||
if (Array.isArray(items)) {
|
||||
@@ -510,19 +614,20 @@
|
||||
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;
|
||||
// Drop Softra-insurance items — pakiety ochronne są zarządzane w panelu WP (SOFT/PREMIUM).
|
||||
if (name.indexOf('ubezp') !== -1 || name.indexOf('ochrony') !== -1 ||
|
||||
name.indexOf('zniesienie') !== -1 || name.indexOf('insurance') !== -1) {
|
||||
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();
|
||||
@@ -533,8 +638,12 @@
|
||||
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');
|
||||
? tFmt('priceRange', {min: price.toFixed(0), max: maxPrice.toFixed(0)}, 'od %min% do %max% zł')
|
||||
: (price > 0
|
||||
? (item.unit === 'doba'
|
||||
? tFmt('pricePerDay', {price: price.toFixed(0)}, '%price% zł/doba')
|
||||
: tFmt('priceSimple', {price: price.toFixed(0)}, '%price% zł'))
|
||||
: t('free', 'Gratis'));
|
||||
var card = document.createElement('div');
|
||||
card.className = 'carei-form__extra-card';
|
||||
card.innerHTML =
|
||||
@@ -652,7 +761,7 @@
|
||||
function buildCountryCard(item, isSelected) {
|
||||
var id = item.id || item.code;
|
||||
var price = parseFloat(item.price || item.minPrice || 0);
|
||||
var priceHtml = '<span class="carei-abroad__price-val">' + (price > 0 ? price.toFixed(0) + ' zł' : 'Gratis') + '</span>';
|
||||
var priceHtml = '<span class="carei-abroad__price-val">' + (price > 0 ? tFmt('priceSimple', {price: price.toFixed(0)}, '%price% zł') : t('free', 'Gratis')) + '</span>';
|
||||
|
||||
var card = document.createElement('div');
|
||||
card.className = 'carei-abroad__card' + (isSelected ? ' carei-abroad__card--selected' : '');
|
||||
@@ -660,7 +769,7 @@
|
||||
'<span class="carei-abroad__flag">' + escHtml(item._countryFlag) + '</span>' +
|
||||
'<span class="carei-abroad__name">' + escHtml(item._countryName) + '</span>' +
|
||||
'<span class="carei-abroad__price">' + priceHtml + '</span>' +
|
||||
'<span role="button" tabindex="0" class="carei-abroad__action" data-abroad-id="' + escAttr(id) + '" title="' + (isSelected ? 'Usuń' : 'Dodaj') + '">' +
|
||||
'<span role="button" tabindex="0" class="carei-abroad__action" data-abroad-id="' + escAttr(id) + '" title="' + (isSelected ? t('btnRemove', 'Usuń') : t('btnAdd', 'Dodaj')) + '">' +
|
||||
(isSelected
|
||||
? '<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 3l8 8M11 3l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>'
|
||||
: '<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>'
|
||||
@@ -694,7 +803,7 @@
|
||||
if (!select) return;
|
||||
select.innerHTML = '';
|
||||
var ph = document.createElement('option');
|
||||
ph.value = ''; ph.disabled = true; ph.selected = true; ph.textContent = placeholder || 'Wybierz...';
|
||||
ph.value = ''; ph.disabled = true; ph.selected = true; ph.textContent = placeholder || t('selectPlaceholder', 'Wybierz...');
|
||||
select.appendChild(ph);
|
||||
options.forEach(function (opt) {
|
||||
var o = document.createElement('option');
|
||||
@@ -720,15 +829,15 @@
|
||||
// ─── 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-email', type: 'email', msg: 'Podaj poprawny adres e-mail' },
|
||||
{ id: 'carei-phone', type: 'phone', msg: 'Podaj numer telefonu (min. 9 cyfr)' },
|
||||
{ id: 'carei-privacy', type: 'checkbox', msg: 'Wymagana zgoda na Politykę Prywatności' }
|
||||
{ id: 'carei-segment', type: 'select', msgKey: 'selectSegment', msgFallback: 'Wybierz segment pojazdu' },
|
||||
{ id: 'carei-date-from', type: 'input', msgKey: 'enterDateFrom', msgFallback: 'Podaj datę rozpoczęcia' },
|
||||
{ id: 'carei-date-to', type: 'input', msgKey: 'enterDateTo', msgFallback: 'Podaj datę zakończenia' },
|
||||
{ id: 'carei-pickup-branch', type: 'select', msgKey: 'selectPickup', msgFallback: 'Wybierz miejsce odbioru' },
|
||||
{ id: 'carei-firstname', type: 'input', msgKey: 'enterFirstName', msgFallback: 'Podaj imię' },
|
||||
{ id: 'carei-lastname', type: 'input', msgKey: 'enterLastName', msgFallback: 'Podaj nazwisko' },
|
||||
{ id: 'carei-email', type: 'email', msgKey: 'enterEmail', msgFallback: 'Podaj poprawny adres e-mail' },
|
||||
{ id: 'carei-phone', type: 'phone', msgKey: 'enterPhone', msgFallback: 'Podaj numer telefonu (min. 9 cyfr)' },
|
||||
{ id: 'carei-privacy', type: 'checkbox', msgKey: 'privacyRequired', msgFallback: 'Wymagana zgoda na Politykę Prywatności' }
|
||||
];
|
||||
|
||||
function validateForm() {
|
||||
@@ -747,23 +856,23 @@
|
||||
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 (hasError) { valid = false; markFieldError(el, t(f.msgKey, f.msgFallback), f.type); }
|
||||
});
|
||||
|
||||
var now = new Date();
|
||||
if (dateFrom && dateFrom.value && new Date(dateFrom.value) < now) {
|
||||
valid = false; markFieldError(dateFrom, 'Data lub godzina rozpoczęcia już minęły', 'input');
|
||||
valid = false; markFieldError(dateFrom, t('dateStartPast', 'Data lub godzina rozpoczęcia już minęły'), 'input');
|
||||
}
|
||||
if (dateTo && dateTo.value && new Date(dateTo.value) < now) {
|
||||
valid = false; markFieldError(dateTo, 'Data lub godzina zakończenia już minęły', 'input');
|
||||
valid = false; markFieldError(dateTo, t('dateEndPast', 'Data lub godzina zakończenia już minęły'), 'input');
|
||||
}
|
||||
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');
|
||||
valid = false; markFieldError(dateTo, t('dateEndAfterStart', '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');
|
||||
valid = false; markFieldError(returnSelect, t('selectReturn', 'Wybierz miejsce zwrotu'), 'select');
|
||||
}
|
||||
if (errorSummary) errorSummary.style.display = valid ? 'none' : 'block';
|
||||
return valid;
|
||||
@@ -826,11 +935,11 @@
|
||||
if (state === 'loading') {
|
||||
btn.disabled = true;
|
||||
btn.setAttribute('aria-busy', 'true');
|
||||
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> Przetwarzanie...';
|
||||
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> ' + escHtml(t('btnProcessing', 'Przetwarzanie...'));
|
||||
} else {
|
||||
btn.disabled = false;
|
||||
btn.setAttribute('aria-busy', 'false');
|
||||
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> Wyślij';
|
||||
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> ' + escHtml(t('btnSubmit', 'Wyślij'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,7 +968,7 @@
|
||||
function createCustomerAndShowSummary() {
|
||||
var fd = collectFormData();
|
||||
hideSummaryError();
|
||||
announce('Ładowanie podsumowania...');
|
||||
announce(t('loadingSummary', 'Ładowanie podsumowania...'));
|
||||
|
||||
apiPost('customer', {
|
||||
firstName: fd.firstName,
|
||||
@@ -878,11 +987,11 @@
|
||||
currentCustomerId = res.customerId;
|
||||
return loadPricingSummary(fd);
|
||||
}
|
||||
throw new Error(res.rejectReason || 'Nie udało się utworzyć klienta');
|
||||
throw new Error(res.rejectReason || t('errorCustomerCreate', 'Nie udało się utworzyć klienta'));
|
||||
}).catch(function (err) {
|
||||
console.error('Customer creation failed:', err);
|
||||
setSubmitState('ready');
|
||||
showFormError('Błąd tworzenia klienta: ' + err.message);
|
||||
showFormError(tFmt('errorCustomerCreatePrefix', {msg: err.message}, 'Błąd tworzenia klienta: %msg%'));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -905,7 +1014,7 @@
|
||||
}).catch(function (err) {
|
||||
console.error('Pricing summary failed:', err);
|
||||
setSubmitState('ready');
|
||||
showFormError('Błąd pobierania podsumowania: ' + err.message);
|
||||
showFormError(tFmt('errorSummaryPrefix', {msg: err.message}, 'Błąd pobierania podsumowania: %msg%'));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -965,7 +1074,12 @@
|
||||
function buildBookingComments(userMessage) {
|
||||
var pkg = getSelectedProtectionPayload();
|
||||
if (!pkg) return userMessage || '';
|
||||
var pkgLine = 'Pakiet ochronny: ' + pkg.name + ' — ' + pkg.pricePerDay.toFixed(2) + ' zł/doba × ' + pkg.days + ' = ' + pkg.total.toFixed(2) + ' zł (do doliczenia poza systemem)';
|
||||
var pkgLine = tFmt('protectionComment', {
|
||||
name: pkg.name,
|
||||
perDay: pkg.pricePerDay.toFixed(2),
|
||||
days: pkg.days,
|
||||
total: pkg.total.toFixed(2)
|
||||
}, 'Pakiet ochronny: %name% — %perDay% zł/doba × %days% = %total% zł (do doliczenia poza systemem)');
|
||||
return userMessage ? (pkgLine + '\n\n' + userMessage) : pkgLine;
|
||||
}
|
||||
|
||||
@@ -1023,7 +1137,7 @@
|
||||
|
||||
// Animated transition: form → summary
|
||||
transitionStep(form, summaryOverlay, function () {
|
||||
announce('Podsumowanie rezerwacji');
|
||||
announce(t('announceSummary', 'Podsumowanie rezerwacji'));
|
||||
var title = summaryOverlay.querySelector('.carei-summary__title');
|
||||
if (title) title.focus();
|
||||
});
|
||||
@@ -1039,40 +1153,40 @@
|
||||
returnLabel = returnSelect.options[returnSelect.selectedIndex].text;
|
||||
}
|
||||
var html =
|
||||
'<div><strong>Segment:</strong> ' + escHtml(segLabel) + '</div>' +
|
||||
'<div><strong>Od:</strong> ' + escHtml(fd.dateFrom.replace('T', ' ')) + '</div>' +
|
||||
'<div><strong>Do:</strong> ' + escHtml(fd.dateTo.replace('T', ' ')) + '</div>' +
|
||||
'<div><strong>Miejsce odbioru:</strong> ' + escHtml(pickupLabel) + '</div>';
|
||||
'<div><strong>' + escHtml(t('labelSegment', 'Segment')) + ':</strong> ' + escHtml(segLabel) + '</div>' +
|
||||
'<div><strong>' + escHtml(t('labelFrom', 'Od')) + ':</strong> ' + escHtml(fd.dateFrom.replace('T', ' ')) + '</div>' +
|
||||
'<div><strong>' + escHtml(t('labelTo', 'Do')) + ':</strong> ' + escHtml(fd.dateTo.replace('T', ' ')) + '</div>' +
|
||||
'<div><strong>' + escHtml(t('labelPickup', 'Miejsce odbioru')) + ':</strong> ' + escHtml(pickupLabel) + '</div>';
|
||||
if (returnLabel) {
|
||||
html += '<div><strong>Miejsce zwrotu:</strong> ' + escHtml(returnLabel) + '</div>';
|
||||
html += '<div><strong>' + escHtml(t('labelReturn', 'Miejsce zwrotu')) + ':</strong> ' + escHtml(returnLabel) + '</div>';
|
||||
}
|
||||
html += '<div><strong>Najemca:</strong> ' + escHtml(fd.firstName + ' ' + fd.lastName) + '</div>' +
|
||||
'<div><strong>Email:</strong> ' + escHtml(fd.email) + '</div>' +
|
||||
'<div><strong>Telefon:</strong> ' + escHtml(fd.phone) + '</div>';
|
||||
html += '<div><strong>' + escHtml(t('labelRenter', 'Najemca')) + ':</strong> ' + escHtml(fd.firstName + ' ' + fd.lastName) + '</div>' +
|
||||
'<div><strong>' + escHtml(t('labelEmail', 'Email')) + ':</strong> ' + escHtml(fd.email) + '</div>' +
|
||||
'<div><strong>' + escHtml(t('labelPhone', 'Telefon')) + ':</strong> ' + escHtml(fd.phone) + '</div>';
|
||||
|
||||
// Selected extras
|
||||
var selectedExtras = getSelectedExtrasForApi();
|
||||
var pkgForDetails = getSelectedProtectionPayload();
|
||||
if (selectedExtras.length > 0 || pkgForDetails) {
|
||||
html += '<div style="margin-top:8px"><strong>Wybrane opcje:</strong></div><ul style="margin:4px 0 0 16px;padding:0;list-style:disc;">';
|
||||
html += '<div style="margin-top:8px"><strong>' + escHtml(t('labelSelectedOptions', 'Wybrane opcje')) + ':</strong></div><ul style="margin:4px 0 0 16px;padding:0;list-style:disc;">';
|
||||
selectedExtras.forEach(function (ex) {
|
||||
var totalPrice = ex.priceAfterDiscount * (ex.amount || 1);
|
||||
var priceInfo = ex.unit === 'doba' && ex.amount > 1
|
||||
? fmtPrice(ex.priceAfterDiscount) + ' zł/doba × ' + ex.amount + ' = ' + fmtPrice(totalPrice) + ' zł'
|
||||
: fmtPrice(totalPrice) + ' zł';
|
||||
? tFmt('priceLineDaily', {perDay: fmtPrice(ex.priceAfterDiscount), days: ex.amount, total: fmtPrice(totalPrice)}, '%perDay% zł/doba × %days% = %total% zł')
|
||||
: tFmt('priceSimpleFmt', {price: fmtPrice(totalPrice)}, '%price% zł');
|
||||
html += '<li>' + escHtml(toSentenceCase(ex.name)) + ' — ' + priceInfo + '</li>';
|
||||
});
|
||||
if (pkgForDetails) {
|
||||
var pkgInfo = pkgForDetails.days > 1
|
||||
? fmtPrice(pkgForDetails.pricePerDay) + ' zł/doba × ' + pkgForDetails.days + ' = ' + fmtPrice(pkgForDetails.total) + ' zł'
|
||||
: fmtPrice(pkgForDetails.total) + ' zł';
|
||||
? tFmt('priceLineDaily', {perDay: fmtPrice(pkgForDetails.pricePerDay), days: pkgForDetails.days, total: fmtPrice(pkgForDetails.total)}, '%perDay% zł/doba × %days% = %total% zł')
|
||||
: tFmt('priceSimpleFmt', {price: fmtPrice(pkgForDetails.total)}, '%price% zł');
|
||||
html += '<li>' + escHtml(pkgForDetails.name) + ' — ' + pkgInfo + '</li>';
|
||||
}
|
||||
html += '</ul>';
|
||||
}
|
||||
|
||||
if (fd.message) {
|
||||
html += '<div style="margin-top:8px"><strong>Wiadomość:</strong> ' + escHtml(fd.message) + '</div>';
|
||||
html += '<div style="margin-top:8px"><strong>' + escHtml(t('labelMessage', 'Wiadomość')) + ':</strong> ' + escHtml(fd.message) + '</div>';
|
||||
}
|
||||
|
||||
summaryDetails.innerHTML = html;
|
||||
@@ -1082,19 +1196,19 @@
|
||||
|
||||
// Price table
|
||||
if (summaryTable && summary.pricelist) {
|
||||
var html = '<table><thead><tr><th>Nazwa</th><th>Ilość</th><th>Netto</th><th>Brutto</th></tr></thead><tbody>';
|
||||
var html = '<table><thead><tr><th>' + escHtml(t('thName', 'Nazwa')) + '</th><th>' + escHtml(t('thQuantity', 'Ilość')) + '</th><th>' + escHtml(t('thNet', 'Netto')) + '</th><th>' + escHtml(t('thGross', 'Brutto')) + '</th></tr></thead><tbody>';
|
||||
summary.pricelist.forEach(function (item) {
|
||||
var rowClass = item.addedBySystem ? ' class="carei-summary__auto-item"' : '';
|
||||
html += '<tr' + rowClass + '>' +
|
||||
'<td>' + escHtml(toSentenceCase(item.name)) + (item.addedBySystem ? ' <small>(auto)</small>' : '') + '</td>' +
|
||||
'<td>' + escHtml(toSentenceCase(item.name)) + (item.addedBySystem ? ' <small>(' + escHtml(t('labelAuto', 'auto')) + ')</small>' : '') + '</td>' +
|
||||
'<td>' + (item.amount || 1) + ' ' + escHtml(item.unit || '') + '</td>' +
|
||||
'<td>' + fmtPrice(item.netValue) + '</td>' +
|
||||
'<td>' + fmtPrice(item.grossValue) + '</td></tr>';
|
||||
});
|
||||
if (protectionPayload) {
|
||||
html += '<tr class="carei-summary__protection-row">' +
|
||||
'<td>' + escHtml(protectionPayload.name) + ' <small>(do doliczenia)</small></td>' +
|
||||
'<td>' + protectionPayload.days + ' doba</td>' +
|
||||
'<td>' + escHtml(protectionPayload.name) + ' <small>(' + escHtml(t('labelExtraCharge', 'do doliczenia')) + ')</small></td>' +
|
||||
'<td>' + protectionPayload.days + ' ' + escHtml(pluralPl(protectionPayload.days, t('dayOne', 'doba'), t('dayFew', 'doby'), t('dayMany', 'dób'))) + '</td>' +
|
||||
'<td>—</td>' +
|
||||
'<td>' + fmtPrice(protectionPayload.total) + '</td></tr>';
|
||||
}
|
||||
@@ -1108,12 +1222,12 @@
|
||||
var protectionTotal = protectionPayload ? protectionPayload.total : 0;
|
||||
var grandGross = softraGross + protectionTotal;
|
||||
var totalsHtml =
|
||||
'<div class="carei-summary__total-row"><span class="carei-summary__total-label">Netto:</span><span class="carei-summary__total-value">' + fmtPrice(summary.totalNetValue) + '</span></div>' +
|
||||
'<div class="carei-summary__total-row"><span class="carei-summary__total-label">VAT:</span><span class="carei-summary__total-value">' + fmtPrice(summary.totalVatValue) + '</span></div>';
|
||||
'<div class="carei-summary__total-row"><span class="carei-summary__total-label">' + escHtml(t('thNet', 'Netto')) + ':</span><span class="carei-summary__total-value">' + fmtPrice(summary.totalNetValue) + '</span></div>' +
|
||||
'<div class="carei-summary__total-row"><span class="carei-summary__total-label">' + escHtml(t('labelVat', 'VAT')) + ':</span><span class="carei-summary__total-value">' + fmtPrice(summary.totalVatValue) + '</span></div>';
|
||||
if (protectionPayload) {
|
||||
totalsHtml += '<div class="carei-summary__total-row"><span class="carei-summary__total-label">Pakiet ochronny:</span><span class="carei-summary__total-value">' + fmtPrice(protectionPayload.total) + '</span></div>';
|
||||
totalsHtml += '<div class="carei-summary__total-row"><span class="carei-summary__total-label">' + escHtml(t('labelProtectionPackage', 'Pakiet ochronny')) + ':</span><span class="carei-summary__total-value">' + fmtPrice(protectionPayload.total) + '</span></div>';
|
||||
}
|
||||
totalsHtml += '<div class="carei-summary__total-row carei-summary__total-row--gross"><span class="carei-summary__total-label">Do zapłaty:</span><span class="carei-summary__total-value">' + fmtPrice(grandGross) + ' zł</span></div>';
|
||||
totalsHtml += '<div class="carei-summary__total-row carei-summary__total-row--gross"><span class="carei-summary__total-label">' + escHtml(t('labelToPay', 'Do zapłaty')) + ':</span><span class="carei-summary__total-value">' + tFmt('priceSimpleFmt', {price: fmtPrice(grandGross)}, '%price% zł') + '</span></div>';
|
||||
summaryTotal.innerHTML = totalsHtml;
|
||||
}
|
||||
}
|
||||
@@ -1136,7 +1250,7 @@
|
||||
if (summaryConfirm) {
|
||||
summaryConfirm.disabled = true;
|
||||
summaryConfirm.setAttribute('aria-busy', 'true');
|
||||
summaryConfirm.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> Rezerwuję...';
|
||||
summaryConfirm.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> ' + escHtml(t('btnBookingInProgress', 'Rezerwuję...'));
|
||||
}
|
||||
hideSummaryError();
|
||||
|
||||
@@ -1178,7 +1292,7 @@
|
||||
showSuccessView(res.reservationNo || res.reservationId);
|
||||
return;
|
||||
}
|
||||
throw new Error(translateRejectReason(res.rejectReason) || 'Rezerwacja nie powiodła się');
|
||||
throw new Error(translateRejectReason(res.rejectReason) || t('errorBookingFailed', 'Rezerwacja nie powiodła się'));
|
||||
}).catch(function (err) {
|
||||
console.error('Booking failed:', err);
|
||||
showSummaryError(err.message);
|
||||
@@ -1189,12 +1303,12 @@
|
||||
function translateRejectReason(reason) {
|
||||
if (!reason) return null;
|
||||
var map = {
|
||||
'CAR_NOT_FOUND': 'Brak dostępnego pojazdu w wybranym terminie. Zmień daty lub segment.',
|
||||
'INVALID_DATE_RANGE': 'Nieprawidłowy zakres dat',
|
||||
'BRANCH_NOT_FOUND': 'Nie znaleziono oddziału',
|
||||
'CUSTOMER_ALREADY_EXISTS': 'Klient o tych danych już istnieje w systemie',
|
||||
'INVALID_PESEL': 'Nieprawidłowy numer PESEL',
|
||||
'PRICE_LIST_EXPIRED': 'Cennik wygasł. Odśwież formularz i spróbuj ponownie.'
|
||||
'CAR_NOT_FOUND': t('rejectCarNotFound', 'Brak dostępnego pojazdu w wybranym terminie. Zmień daty lub segment.'),
|
||||
'INVALID_DATE_RANGE': t('rejectInvalidDateRange', 'Nieprawidłowy zakres dat'),
|
||||
'BRANCH_NOT_FOUND': t('rejectBranchNotFound', 'Nie znaleziono oddziału'),
|
||||
'CUSTOMER_ALREADY_EXISTS': t('rejectCustomerExists', 'Klient o tych danych już istnieje w systemie'),
|
||||
'INVALID_PESEL': t('rejectInvalidPesel', 'Nieprawidłowy numer PESEL'),
|
||||
'PRICE_LIST_EXPIRED': t('rejectPriceListExpired', 'Cennik wygasł. Odśwież formularz i spróbuj ponownie.')
|
||||
};
|
||||
return map[reason] || reason;
|
||||
}
|
||||
@@ -1203,16 +1317,16 @@
|
||||
if (summaryConfirm) {
|
||||
summaryConfirm.disabled = false;
|
||||
summaryConfirm.setAttribute('aria-busy', 'false');
|
||||
summaryConfirm.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> Potwierdź rezerwację';
|
||||
summaryConfirm.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> ' + escHtml(t('btnConfirmBooking', 'Potwierdź rezerwację'));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Success View ─────────────────────────────────────────────
|
||||
|
||||
function showSuccessView(reservationNo) {
|
||||
if (successNumber) successNumber.textContent = 'Nr zamówienia: ' + reservationNo;
|
||||
if (successNumber) successNumber.textContent = tFmt('orderNumber', {no: reservationNo}, 'Nr zamówienia: %no%');
|
||||
transitionStep(summaryOverlay, successView, function () {
|
||||
announce('Rezerwacja potwierdzona');
|
||||
announce(t('announceBookingConfirmed', 'Rezerwacja potwierdzona'));
|
||||
var title = successView.querySelector('.carei-success__title');
|
||||
if (title) title.focus();
|
||||
});
|
||||
@@ -1226,7 +1340,7 @@
|
||||
currentCustomerId = null;
|
||||
currentReservationId = null;
|
||||
hideExtras();
|
||||
if (pickupSelect) { populateSelect(pickupSelect, [], 'Najpierw wybierz segment'); pickupSelect.disabled = true; }
|
||||
if (pickupSelect) { populateSelect(pickupSelect, [], t('pickupPlaceholder', 'Najpierw wybierz segment')); pickupSelect.disabled = true; }
|
||||
closeModal();
|
||||
}
|
||||
|
||||
@@ -1324,13 +1438,13 @@
|
||||
if (Array.isArray(classes) && classes.length > 0) {
|
||||
var segments = 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);
|
||||
var label = typeof c === 'string' ? tFmt('segmentLabel', {name: c}, 'Segment %name%') : (c.description || c.name || c);
|
||||
return { value: val, label: label };
|
||||
});
|
||||
populateSelect(searchSegment, segments, 'Wybierz segment');
|
||||
populateSelect(searchSegment, segments, t('selectSegmentShort', 'Wybierz segment'));
|
||||
}
|
||||
if (searchPickup) {
|
||||
populateSelect(searchPickup, [], 'Najpierw wybierz segment');
|
||||
populateSelect(searchPickup, [], t('pickupPlaceholder', 'Najpierw wybierz segment'));
|
||||
searchPickup.disabled = true;
|
||||
}
|
||||
}).catch(function (err) {
|
||||
@@ -1354,10 +1468,10 @@
|
||||
}
|
||||
});
|
||||
if (opts.length > 0) {
|
||||
populateSelect(searchPickup, opts, 'Miejsce odbioru');
|
||||
populateSelect(searchPickup, opts, t('pickupLabel', 'Miejsce odbioru'));
|
||||
searchPickup.disabled = false;
|
||||
} else {
|
||||
populateSelect(searchPickup, [], 'Brak lokalizacji');
|
||||
populateSelect(searchPickup, [], t('noLocations', 'Brak lokalizacji'));
|
||||
searchPickup.disabled = true;
|
||||
}
|
||||
});
|
||||
@@ -1449,6 +1563,9 @@
|
||||
// Inicjalizuj search form niezależnie od modala
|
||||
initSearchForm();
|
||||
|
||||
// Flatpickr on both modal + hero inputs — safe to call even if modal absent
|
||||
initDatePickers();
|
||||
|
||||
if (!overlay || !form) return;
|
||||
|
||||
initModal();
|
||||
|
||||
Reference in New Issue
Block a user