| @@ -12,20 +12,43 @@ | ||
| 12 | 12 | |
| 13 | 13 | // Translation helpers — idempotent shim matching booking.js / trip.js so |
| 14 | 14 | // `__()` resolves through wp.i18n when wp-i18n is enqueued, otherwise it |
| 15 | 15 | // falls back to the source string. |
| 16 | +// Parse a numeric min/max attribute while preserving a legitimate 0. | |
| 17 | +// `parseInt(el.getAttribute('max')) || 99` treated max="0" — what a sold-out | |
| 18 | +// departure renders — as "unset" and fell back to the placeholder ceiling, so | |
| 19 | +// the guest selector stayed usable and ignored the departure's real capacity. | |
| 20 | +// Only an absent or non-numeric value may fall back. Installed once and shared | |
| 21 | +// by every frontend script, so load order does not matter. | |
| 22 | +if (typeof window.yatraNumOr !== 'function') { | |
| 23 | + window.yatraNumOr = function (raw, fallback) { | |
| 24 | + var parsed = parseInt(raw, 10); | |
| 25 | + return isNaN(parsed) ? fallback : parsed; | |
| 26 | + }; | |
| 27 | +} | |
| 28 | + | |
| 16 | 29 | (function () { |
| 17 | - if (typeof window.__ === 'function') return; | |
| 18 | - if (window.wp && window.wp.i18n && typeof window.wp.i18n.__ === 'function') { | |
| 19 | - window.__ = function (text, domain) { return window.wp.i18n.__(text, domain || 'yatra'); }; | |
| 20 | - window._n = function (s, p, n, domain) { return window.wp.i18n._n(s, p, n, domain || 'yatra'); }; | |
| 21 | - window._x = function (text, ctx, domain) { return window.wp.i18n._x(text, ctx, domain || 'yatra'); }; | |
| 22 | - window.sprintf = window.sprintf || (window.wp.i18n.sprintf || function (fmt) { return fmt; }); | |
| 30 | + var i18n = (window.wp && window.wp.i18n) ? window.wp.i18n : null; | |
| 31 | + if (i18n && typeof i18n.__ === 'function') { | |
| 32 | + window.__ = function (text, domain) { return i18n.__(text, domain || 'yatra'); }; | |
| 33 | + window._n = function (s, p, n, domain) { return i18n._n(s, p, n, domain || 'yatra'); }; | |
| 34 | + window._x = function (text, ctx, domain) { return i18n._x(text, ctx, domain || 'yatra'); }; | |
| 35 | + // Always bind WordPress's own sprintf (it substitutes %d/%s/%1$s). | |
| 36 | + // Do NOT defer to a pre-existing window.sprintf: a theme or other | |
| 37 | + // plugin can define an incompatible global that leaves placeholders | |
| 38 | + // unsubstituted (the cause of literal "%d"/"%s" in the UI). | |
| 39 | + if (typeof i18n.sprintf === 'function') { | |
| 40 | + window.sprintf = function () { return i18n.sprintf.apply(i18n, arguments); }; | |
| 41 | + } else if (typeof window.sprintf !== 'function') { | |
| 42 | + window.sprintf = function (fmt) { return fmt; }; | |
| 43 | + } | |
| 23 | 44 | } else { |
| 24 | - window.__ = function (text) { return text; }; | |
| 25 | - window._n = function (s, p, n) { return n === 1 ? s : p; }; | |
| 26 | - window._x = function (text) { return text; }; | |
| 27 | - window.sprintf = window.sprintf || function (fmt) { return fmt; }; | |
| 45 | + // wp.i18n not present — install passthroughs only if nothing usable | |
| 46 | + // exists yet (don't clobber a real binding installed earlier). | |
| 47 | + if (typeof window.__ !== 'function') window.__ = function (text) { return text; }; | |
| 48 | + if (typeof window._n !== 'function') window._n = function (s, p, n) { return n === 1 ? s : p; }; | |
| 49 | + if (typeof window._x !== 'function') window._x = function (text) { return text; }; | |
| 50 | + if (typeof window.sprintf !== 'function') window.sprintf = function (fmt) { return fmt; }; | |
| 28 | 51 | } |
| 29 | 52 | })(); |
| 30 | 53 | |
| 31 | 54 | document.addEventListener('DOMContentLoaded', function() { |
| @@ -351,10 +374,16 @@ | ||
| 351 | 374 | |
| 352 | 375 | updatePricing(); |
| 353 | 376 | }); |
| 354 | 377 | |
| 355 | - // Set today's date by default if available, otherwise use trip fallback pricing | |
| 356 | - const today = new Date().toISOString().split('T')[0]; | |
| 378 | + // Set today's date by default if available, otherwise use trip fallback pricing. | |
| 379 | + // Build LOCAL YYYY-MM-DD, not toISOString() (which is UTC and can land on | |
| 380 | + // the wrong calendar day — mis-matching the availability's departure_date | |
| 381 | + // and pre-selecting the wrong date near midnight). | |
| 382 | + const _now = new Date(); | |
| 383 | + const today = _now.getFullYear() + '-' | |
| 384 | + + String(_now.getMonth() + 1).padStart(2, '0') + '-' | |
| 385 | + + String(_now.getDate()).padStart(2, '0'); | |
| 357 | 386 | if (!dateInput.value) { |
| 358 | 387 | const availabilities = getSidebarAvailabilities(); |
| 359 | 388 | if (availabilities.length > 0) { |
| 360 | 389 | const todayAvailability = availabilities.find(a => a.departure_date === today); |
| @@ -441,9 +470,9 @@ | ||
| 441 | 470 | <div class="yatra-group-discount-badge"> |
| 442 | 471 | <svg width="14" height="14" fill="currentColor" viewBox="0 0 20 20"> |
| 443 | 472 | <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/> |
| 444 | 473 | </svg> |
| 445 | - Group discount applied: -${window.yatraTripData?.currencySymbol || '$'}${discountAmount.toFixed(2)} | |
| 474 | + Group discount applied: -${typeof window.yatra_format_price_js === 'function' ? window.yatra_format_price_js(discountAmount) : (window.yatraTripData?.currencySymbol || '$') + discountAmount.toFixed(2)} | |
| 446 | 475 | </div> |
| 447 | 476 | `; |
| 448 | 477 | } else if (indicator) { |
| 449 | 478 | indicator.remove(); |
| @@ -543,10 +572,10 @@ | ||
| 543 | 572 | } |
| 544 | 573 | |
| 545 | 574 | if (!input) return; |
| 546 | 575 | |
| 547 | - const min = parseInt(input.getAttribute('min')) || 0; | |
| 548 | - const max = parseInt(input.getAttribute('max')) || 99; | |
| 576 | + const min = window.yatraNumOr(input.getAttribute('min'), 0); | |
| 577 | + const max = window.yatraNumOr(input.getAttribute('max'), 99); | |
| 549 | 578 | let value = parseInt(input.value) || 0; |
| 550 | 579 | |
| 551 | 580 | // Update value based on button type |
| 552 | 581 | if (btn.classList.contains('yatra-quantity-plus')) { |
| @@ -602,9 +631,9 @@ | ||
| 602 | 631 | // Regular pricing - sync all num_travelers and enquiry_adults inputs |
| 603 | 632 | const regularInputs = document.querySelectorAll('#num_travelers, #enquiry_adults'); |
| 604 | 633 | regularInputs.forEach(input => { |
| 605 | 634 | if (input !== sourceInput) { |
| 606 | - const max = parseInt(input.getAttribute('max')) || 99; | |
| 635 | + const max = window.yatraNumOr(input.getAttribute('max'), 99); | |
| 607 | 636 | input.value = Math.min(sourceValue, max); |
| 608 | 637 | } |
| 609 | 638 | }); |
| 610 | 639 | |
| @@ -611,9 +640,9 @@ | ||
| 611 | 640 | // Also sync to availability section inputs |
| 612 | 641 | const availabilityInputs = document.querySelectorAll('input[id^="num-travelers-"]'); |
| 613 | 642 | availabilityInputs.forEach(input => { |
| 614 | 643 | if (input !== sourceInput) { |
| 615 | - const max = parseInt(input.getAttribute('max')) || 99; | |
| 644 | + const max = window.yatraNumOr(input.getAttribute('max'), 99); | |
| 616 | 645 | input.value = Math.min(sourceValue, max); |
| 617 | 646 | } |
| 618 | 647 | }); |
| 619 | 648 | |
| @@ -638,15 +667,15 @@ | ||
| 638 | 667 | ); |
| 639 | 668 | |
| 640 | 669 | categoryInputs.forEach(input => { |
| 641 | 670 | if (input !== sourceInput) { |
| 642 | - const max = parseInt(input.getAttribute('max')) || 99; | |
| 671 | + const max = window.yatraNumOr(input.getAttribute('max'), 99); | |
| 643 | 672 | input.value = Math.min(sourceValue, max); |
| 644 | 673 | |
| 645 | 674 | // Update button states for this input |
| 646 | 675 | const row = input.closest('.yatra-quantity-row'); |
| 647 | 676 | if (row) { |
| 648 | - const min = parseInt(input.getAttribute('min')) || 0; | |
| 677 | + const min = window.yatraNumOr(input.getAttribute('min'), 0); | |
| 649 | 678 | const minusBtn = row.querySelector('.yatra-quantity-minus'); |
| 650 | 679 | const plusBtn = row.querySelector('.yatra-quantity-plus'); |
| 651 | 680 | if (minusBtn) minusBtn.disabled = input.value <= min; |
| 652 | 681 | if (plusBtn) plusBtn.disabled = input.value >= max; |