PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.9
Yatra – Travel Booking & Tour Operator Software v3.0.2.9
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / templates / partials / single-trip / sticky-sidebar.php

sticky-sidebar.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.9, at templates/partials/single-trip/sticky-sidebar.php

641 lines 27.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Mobile Sticky Sidebar Template
4 *
5 * Displays booking card in sticky bottom position on mobile devices
6 * SEO-friendly approach - separate template, no content duplication
7 *
8 * @package Yatra
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 // Expected variables: $trip, $has_availability, $has_traveler_pricing, $base_price, $pricing_type
16
17 // Determine if this is a multi-day trip
18 $is_multi_day = ($trip->getDurationDays() ?? 1) > 1;
19
20 // Check for group discounts availability (premium feature)
21 $sidebar_has_group_discounts = false;
22 $sidebar_group_discounts_data = [];
23 try {
24 if (class_exists('\Yatra\Services\DiscountService') &&
25 method_exists('\Yatra\Services\DiscountService', 'getGroupDiscountsForTrip')) {
26 $discountService = new \Yatra\Services\DiscountService();
27 $groupDiscountsResult = $discountService->getGroupDiscountsForTrip((int) $trip->getId());
28 if (!empty($groupDiscountsResult)) {
29 $sidebar_has_group_discounts = true;
30 $sidebar_group_discounts_data = $groupDiscountsResult;
31 }
32 }
33 } catch (\Exception $e) {
34 $sidebar_has_group_discounts = false;
35 }
36
37 // Prepare availability data for JavaScript
38 $availability_json = [];
39 $booking_mode = $trip->getBookingMode();
40 if ($has_availability) {
41 foreach ($trip->getAvailabilityDates() as $avail) {
42 $availability_json[] = [
43 'id' => (int) $avail->id,
44 'date' => $avail->departure_date,
45 'departure_date' => $avail->departure_date,
46 'return_date' => (isset($avail->return_date) && $avail->return_date !== '')
47 ? $avail->return_date
48 : (isset($avail->arrival_date) ? $avail->arrival_date : null),
49 'price' => $avail->effective_price ?? $avail->original_price,
50 'original_price' => $avail->original_price,
51 'discounted_price' => $avail->discounted_price,
52 'seats_available' => $avail->seats_available,
53 'seats_total' => $avail->seats_total,
54 'status' => $avail->status,
55 'is_limited' => $avail->is_limited ?? false,
56 'is_sold_out' => $avail->is_sold_out ?? false,
57 ];
58 }
59 }
60
61 // Calculate pricing - use pre-computed values from SingleTripController
62 $pricing = [
63 'has_price' => false,
64 'current_price' => '',
65 'original_price' => '',
66 'price_prefix' => '',
67 'has_discount' => false,
68 'raw_current_price' => 0,
69 'raw_original_price' => 0,
70 'is_traveler_based' => $has_traveler_pricing
71 ];
72
73 $discount = [
74 'has_discount' => false,
75 'discount_text' => '',
76 'discount_percentage' => 0
77 ];
78
79 // Use effective_price_min computed in SingleTripController
80 $effective_min = (float) ($trip->effective_price_min ?? 0);
81 $original_min = (float) ($trip->min_category_original_price ?? 0);
82 $max_discount_pct = (int) ($trip->max_discount_percentage ?? 0);
83
84 if ($effective_min > 0) {
85 $pricing['has_price'] = true;
86 $pricing['raw_current_price'] = $effective_min;
87 $pricing['current_price'] = yatra_format_price($effective_min);
88
89 if ($has_traveler_pricing || $has_availability) {
90 $pricing['price_prefix'] = __('From ', 'yatra');
91 }
92
93 if ($max_discount_pct > 0 && $original_min > $effective_min) {
94 $pricing['has_discount'] = true;
95 $pricing['raw_original_price'] = $original_min;
96 $pricing['original_price'] = yatra_format_price($original_min);
97
98 $discount['has_discount'] = true;
99 $discount['discount_percentage'] = $max_discount_pct;
100 $discount['discount_text'] = sprintf(__('Up to %d%%', 'yatra'), $max_discount_pct);
101 }
102 } else {
103 $original = (float) ($trip->getOriginalPrice() ?? 0);
104 $discounted = (float) ($trip->discounted_price ?? 0);
105
106 if ($discounted > 0) {
107 $current = $discounted;
108 } elseif ($original > 0) {
109 $current = $original;
110 } elseif (!empty($trip->getSalePrice()) && (float)$trip->getSalePrice() > 0) {
111 $current = (float) $trip->getSalePrice();
112 } else {
113 $current = 0;
114 }
115
116 if ($current > 0) {
117 $pricing['has_price'] = true;
118 $pricing['raw_current_price'] = $current;
119 $pricing['current_price'] = yatra_format_price($current);
120
121 if ($current < $original && $original > 0) {
122 $pct = round((($original - $current) / $original) * 100);
123
124 // Only show discount if percentage is greater than 0
125 if ($pct > 0) {
126 $pricing['has_discount'] = true;
127 $pricing['raw_original_price'] = $original;
128 $pricing['original_price'] = yatra_format_price($original);
129
130 $discount['has_discount'] = true;
131 $discount['discount_percentage'] = $pct;
132 $discount['discount_text'] = sprintf(__('%d%%', 'yatra'), $pct);
133 }
134 }
135 }
136 }
137 // Pro: check whether this trip has booking disabled (enquiry-only mode)
138 $booking_disabled = method_exists($trip, 'isBookingDisabled') && $trip->isBookingDisabled();
139 ?>
140 <?php if ($booking_disabled): ?>
141 <div class="yatra-mobile-sticky-sidebar yatra-enquiry-only-sticky" id="yatra-mobile-sticky-sidebar">
142 <div class="yatra-mobile-sticky-content">
143 <div class="yatra-mobile-row-1" style="justify-content:space-between;align-items:center;">
144 <div style="font-size:0.82rem;color:#1a5fa8;padding:0 4px;">
145 <?php esc_html_e('Enquiry only — no direct booking', 'yatra'); ?>
146 </div>
147 <button type="button"
148 class="yatra-mobile-book-btn"
149 style="background:var(--yatra-primary,#3b82f6);"
150 onclick="window.YatraEnquiry?.open?.(); return false;">
151 <?php esc_html_e('Send Enquiry', 'yatra'); ?>
152 </button>
153 </div>
154 </div>
155 </div>
156 <?php else: ?>
157 <div class="yatra-mobile-sticky-sidebar" id="yatra-mobile-sticky-sidebar"
158 data-has-availability="<?php echo $has_availability ? 'true' : 'false'; ?>"
159 data-booking-mode="<?php echo esc_attr($booking_mode); ?>"
160 data-is-multi-day="<?php echo $is_multi_day ? 'true' : 'false'; ?>"
161 data-pricing-type="<?php echo esc_attr($pricing_type); ?>"
162 data-availability='<?php echo esc_attr(json_encode($availability_json)); ?>'
163 data-group-discounts='<?php echo esc_attr(json_encode($sidebar_group_discounts_data)); ?>'>
164 <!-- Two-Row Layout -->
165 <div class="yatra-mobile-sticky-content">
166
167 <!-- Row 1: Compact fields + close (clean grid layout) -->
168 <div class="yatra-mobile-row-1">
169
170 <div class="yatra-mobile-date-section">
171 <div class="yatra-mobile-field-btn yatra-mobile-date-btn"
172 role="button"
173 tabindex="0"
174 aria-label="<?php echo esc_attr__('Select date', 'yatra'); ?>">
175 <span class="yatra-mobile-field-icon" aria-hidden="true">
176 <?php echo yatra_svg_icon('calendar', 'yatra-mobile-icon'); ?>
177 </span>
178 <input type="text"
179 id="mobile_travel_date"
180 name="travel_date"
181 class="yatra-mobile-datepicker-input yatra-mobile-datepicker"
182 placeholder="<?php esc_attr_e('Date', 'yatra'); ?>"
183 data-min-date="<?php echo esc_attr($trip->getAvailableFrom() ?: date('Y-m-d')); ?>"
184 data-max-date="<?php echo esc_attr($trip->getAvailableTo() ?: ''); ?>"
185 readonly
186 required>
187 <svg class="yatra-mobile-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
188 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
189 </svg>
190 </div>
191 </div>
192
193 <div class="yatra-mobile-travelers-section">
194 <?php if ($has_traveler_pricing): ?>
195 <?php
196 // Reuse the same traveler selector component as desktop, but with mobile-specific IDs
197 $traveler_data = \Yatra\Controllers\SingleTripController::prepareTravelerSelectorData($trip, 'sidebar');
198 $rows = $traveler_data['traveler_rows'] ?? [];
199
200 // Prefix IDs so they don't collide with the desktop sidebar.
201 foreach ($rows as &$row) {
202 if (!empty($row['minus_attrs']['data-target'])) {
203 $row['minus_attrs']['data-target'] = 'mobile_' . $row['minus_attrs']['data-target'];
204 }
205 if (!empty($row['plus_attrs']['data-target'])) {
206 $row['plus_attrs']['data-target'] = 'mobile_' . $row['plus_attrs']['data-target'];
207 }
208 if (!empty($row['input_attrs']['id'])) {
209 $row['input_attrs']['id'] = 'mobile_' . $row['input_attrs']['id'];
210 }
211 if (!empty($row['input_attrs']['name'])) {
212 $row['input_attrs']['name'] = 'mobile_' . $row['input_attrs']['name'];
213 }
214 }
215 unset($row);
216
217 // Setup variables for traveler-selector.php
218 $root_id = 'mobile-participants';
219 $root_class = 'yatra-booking-field-select yatra-participants-select yatra-mobile-participants';
220 $container_attrs = [];
221
222 $display_id = 'mobile-participants-display';
223 $display_class = 'yatra-participants-display yatra-mobile-participants-display';
224 $display_attrs = [];
225
226 $dropdown_id = 'mobile-quantity-selector';
227 $dropdown_class = 'yatra-booking-quantity-selector yatra-mobile-quantity-selector';
228 $dropdown_attrs = [];
229
230 $display_text = $traveler_data['traveler_display_text'] ?? __('Select travelers', 'yatra');
231 $icon_html = yatra_svg_icon('users', 'yatra-mobile-icon');
232
233 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-selector.php';
234 ?>
235 <?php else: ?>
236 <!-- Regular Pricing -->
237 <div class="yatra-mobile-booking-field">
238 <div class="yatra-mobile-field-icon">
239 <?php echo yatra_svg_icon('users', 'yatra-mobile-icon'); ?>
240 </div>
241 <div class="yatra-mobile-quantity-controls">
242 <button type="button" class="yatra-mobile-quantity-btn yatra-mobile-quantity-minus" data-target="mobile_num_travelers">
243 <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
244 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"/>
245 </svg>
246 </button>
247 <input type="number"
248 id="mobile_num_travelers"
249 name="num_travelers"
250 class="yatra-mobile-quantity-input"
251 value="1"
252 min="<?php echo esc_attr($trip->getMinTravelers() ?: 1); ?>"
253 max="<?php echo esc_attr($trip->getMaxTravelers() ?: 20); ?>"
254 readonly
255 data-price="<?php echo esc_attr($base_price); ?>">
256 <button type="button" class="yatra-mobile-quantity-btn yatra-mobile-quantity-plus" data-target="mobile_num_travelers">
257 <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
258 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
259 </svg>
260 </button>
261 </div>
262 </div>
263 <?php endif; ?>
264 </div>
265 </div>
266
267 <!-- Close Button (fixed in top-right of sticky container) -->
268 <div class="yatra-mobile-action-buttons">
269 <button type="button"
270 class="yatra-mobile-close-btn"
271 aria-label="<?php echo esc_attr__('Close', 'yatra'); ?>"
272 onclick="yatraCloseMobileSidebar()">
273 <span class="yatra-mobile-close-fallback" aria-hidden="true">&times;</span>
274 </button>
275 </div>
276
277 <!-- Row 2: Primary Actions -->
278 <div class="yatra-mobile-row-2">
279 <button type="button" class="yatra-mobile-check-btn" id="mobile-check-availability-btn" data-trip-id="<?php echo esc_attr($trip->getId()); ?>">
280 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
281 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
282 </svg>
283 <span><?php echo esc_html__('Check', 'yatra'); ?></span>
284 </button>
285 <button type="button" class="yatra-mobile-enquire-btn" id="mobile-open-enquiry-modal" onclick="if (window.enquiryModal) { window.enquiryModal.open(); } else if (window.YatraEnquiry) { window.YatraEnquiry.open(); } return false;">
286 <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
287 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"/>
288 </svg>
289 <span><?php echo esc_html__('Enquire', 'yatra'); ?></span>
290 </button>
291 </div>
292
293 </div>
294
295 </div>
296 <?php endif; // end else (booking not disabled) ?>
297
298 <!-- JavaScript for mobile sidebar interactions -->
299 <script>
300 function yatraScrollToBooking() {
301 const bookingForm = document.querySelector('.yatra-booking-form');
302 if (bookingForm) {
303 bookingForm.scrollIntoView({ behavior: 'smooth', block: 'center' });
304 } else {
305 // Fallback to main sidebar
306 const sidebar = document.querySelector('.yatra-trip-sidebar');
307 if (sidebar) {
308 sidebar.scrollIntoView({ behavior: 'smooth', block: 'start' });
309 }
310 }
311 }
312
313 function yatraScrollToContact() {
314 const contactSection = document.querySelector('#contact') || document.querySelector('.yatra-contact-form');
315 if (contactSection) {
316 contactSection.scrollIntoView({ behavior: 'smooth', block: 'center' });
317 }
318 }
319
320
321 function yatraCloseMobileSidebar() {
322 const sidebar = document.getElementById('yatra-mobile-sticky-sidebar');
323 if (sidebar) {
324 sidebar.classList.add('user-closed');
325
326 // Save closed state in sessionStorage (persists until page reload)
327 sessionStorage.setItem('yatra-mobile-sidebar-closed', 'true');
328
329 // Hide sidebar with animation
330 setTimeout(() => {
331 sidebar.style.transform = 'translateY(100%)';
332 sidebar.style.opacity = '0';
333 }, 100);
334 }
335 }
336
337 // Auto-show on page load (reset closed state)
338 document.addEventListener('DOMContentLoaded', function() {
339 const sidebar = document.getElementById('yatra-mobile-sticky-sidebar');
340
341 if (sidebar) {
342 // Clear any previous closed state on page load
343 sessionStorage.removeItem('yatra-mobile-sidebar-closed');
344
345 // Ensure sidebar is visible on page load (CSS will handle responsive)
346 sidebar.classList.remove('user-closed');
347 sidebar.classList.remove('hidden');
348 }
349
350 // Initialize mobile booking form functionality
351 initializeMobileBookingForm();
352 });
353
354 function initializeMobileBookingForm() {
355 // Mobile quantity controls
356 const mobileMinusBtns = document.querySelectorAll('.yatra-mobile-quantity-minus');
357 const mobilePlusBtns = document.querySelectorAll('.yatra-mobile-quantity-plus');
358
359 mobileMinusBtns.forEach(btn => {
360 btn.addEventListener('click', function() {
361 const targetId = this.getAttribute('data-target');
362 const input = document.getElementById(targetId);
363 if (input) {
364 const current = parseInt(input.value) || 1;
365 const min = parseInt(input.getAttribute('min')) || 1;
366 if (current > min) {
367 input.value = current - 1;
368 updateMobileTotal();
369 }
370 }
371 });
372 });
373
374 mobilePlusBtns.forEach(btn => {
375 btn.addEventListener('click', function() {
376 const targetId = this.getAttribute('data-target');
377 const input = document.getElementById(targetId);
378 if (input) {
379 const current = parseInt(input.value) || 1;
380 const max = parseInt(input.getAttribute('max')) || 20;
381 if (current < max) {
382 input.value = current + 1;
383 updateMobileTotal();
384 }
385 }
386 });
387 });
388
389 // Mobile date picker - Initialize exactly like main date picker
390 const mobileDateInput = document.getElementById('mobile_travel_date');
391 if (mobileDateInput) {
392 // Default value: today (desktop behavior). If availability mode doesn't allow today,
393 // we will swap to the first enabled date after Flatpickr initializes.
394 const today = new Date();
395 today.setHours(0, 0, 0, 0);
396 const todayStr = today.getFullYear() + '-' +
397 String(today.getMonth() + 1).padStart(2, '0') + '-' +
398 String(today.getDate()).padStart(2, '0');
399 if (!mobileDateInput.value) {
400 mobileDateInput.value = todayStr;
401 }
402
403 // Check if Flatpickr is available
404 if (typeof flatpickr === 'undefined') {
405 // Make it a regular date input as fallback
406 mobileDateInput.type = 'date';
407 mobileDateInput.removeAttribute('readonly');
408 } else {
409 // Get availability dates from global trip data with fallback
410 let availabilityDates = [];
411 try {
412 if (window.yatraTripData && Array.isArray(window.yatraTripData.availabilityDates)) {
413 availabilityDates = window.yatraTripData.availabilityDates;
414 }
415 } catch (e) {
416 }
417
418 var mobileFpCommon = {
419 clickOpens: true,
420 appendTo: document.body,
421 static: false,
422 onReady: function(selectedDates, dateStr, instance) {
423 if (instance.calendarContainer) {
424 instance.calendarContainer.style.zIndex = '100050';
425 }
426
427 // Ensure we have a selected date (desktop behavior).
428 // If current value is empty, use today.
429 if (!instance.selectedDates || instance.selectedDates.length === 0) {
430 instance.setDate(mobileDateInput.value || todayStr, true);
431 }
432 },
433 onChange: function(selectedDates, dateStr, instance) {
434 var mainDateInput = document.getElementById('travel_date');
435 if (mainDateInput && mainDateInput._flatpickr) {
436 mainDateInput._flatpickr.setDate(dateStr);
437 }
438 updateMobileTotal();
439 }
440 };
441 function yatraBindMobileDatepickerTouch(inputEl) {
442 if (!inputEl || !inputEl._flatpickr) {
443 return;
444 }
445 var fp = inputEl._flatpickr;
446 var btn = document.querySelector('.yatra-mobile-date-btn');
447 var fallbackWrap = inputEl.closest('.yatra-mobile-date-section');
448 var target = btn || fallbackWrap;
449 if (!target) return;
450 target.addEventListener('click', function(e) {
451 e.stopPropagation();
452 fp.open();
453 });
454 target.addEventListener('keydown', function(e) {
455 var key = e.key || e.code;
456 if (key === 'Enter' || key === ' ' || key === 'Spacebar') {
457 e.preventDefault();
458 e.stopPropagation();
459 fp.open();
460 }
461 });
462 }
463 // Initialize Flatpickr with same configuration as main date picker
464 var altFormat = (window.yatraTripData && (window.yatraTripData.flatpickrAltFormat || window.yatraTripData.altDateFormat))
465 ? (window.yatraTripData.flatpickrAltFormat || window.yatraTripData.altDateFormat)
466 : null;
467 if (!altFormat && window.yatraTripData && (window.yatraTripData.dateFormat || window.yatraTripData.date_format)) {
468 // Keep in sync with assets/js/trip.js helper (minimal mapping)
469 var php = window.yatraTripData.dateFormat || window.yatraTripData.date_format;
470 var map = { d:'d', j:'j', D:'D', l:'l', m:'m', n:'n', M:'M', F:'F', Y:'Y', y:'y' };
471 altFormat = '';
472 var esc = false;
473 for (var i = 0; i < php.length; i++) {
474 var ch = php[i];
475 if (esc) { altFormat += ch; esc = false; continue; }
476 if (ch === '\\\\') { esc = true; continue; }
477 altFormat += map[ch] || ch;
478 }
479 }
480 if (!altFormat) {
481 altFormat = 'F j, Y';
482 }
483
484 if (availabilityDates.length > 0) {
485 // Availability-based booking - enable only specific dates
486 flatpickr(mobileDateInput, Object.assign({}, mobileFpCommon, {
487 dateFormat: 'Y-m-d',
488 altInput: true,
489 altFormat: altFormat,
490 minDate: 'today',
491 enable: availabilityDates,
492 defaultDate: availabilityDates[0] || todayStr,
493 }));
494 } else {
495 // Regular booking - flexible dates with min/max constraints
496 var config = Object.assign({}, mobileFpCommon, {
497 dateFormat: 'Y-m-d',
498 altInput: true,
499 altFormat: altFormat,
500 minDate: 'today',
501 defaultDate: mobileDateInput.value || todayStr,
502 });
503 var minDate = mobileDateInput.getAttribute('data-min-date');
504 var maxDate = mobileDateInput.getAttribute('data-max-date');
505 if (minDate) {
506 config.minDate = minDate;
507 if (!mobileDateInput.value) {
508 config.defaultDate = minDate;
509 }
510 }
511 if (maxDate) {
512 config.maxDate = maxDate;
513 }
514 flatpickr(mobileDateInput, config);
515 }
516 yatraBindMobileDatepickerTouch(mobileDateInput);
517 }
518 }
519
520 // Travelers selector is rendered in the sticky bar using the same component as desktop.
521
522 // Mobile check availability button
523 const mobileCheckBtn = document.getElementById('mobile-check-availability-btn');
524 if (mobileCheckBtn) {
525 mobileCheckBtn.addEventListener('click', function() {
526 // Sync mobile form data with main form
527 syncMobileToMainForm();
528 // Trigger main check availability
529 const mainCheckBtn = document.getElementById('check-availability-btn');
530 if (mainCheckBtn) {
531 mainCheckBtn.click();
532 }
533 });
534 }
535 }
536
537 function syncMobileToMainForm() {
538 // Sync date
539 const mobileDate = document.getElementById('mobile_travel_date');
540 const mainDate = document.getElementById('travel_date');
541 if (mobileDate && mainDate) {
542 // If main date has Flatpickr instance, use it
543 if (mainDate._flatpickr) {
544 mainDate._flatpickr.setDate(mobileDate.value);
545 } else {
546 mainDate.value = mobileDate.value;
547 }
548 }
549
550 // Sync travelers
551 const mobileTravelers = document.getElementById('mobile_num_travelers');
552 const mainTravelers = document.getElementById('num_travelers');
553 if (mobileTravelers && mainTravelers) {
554 mainTravelers.value = mobileTravelers.value;
555 }
556
557 // Sync traveler-based pricing (mobile selector -> desktop selector)
558 const mobileTravelerInputs = document.querySelectorAll('#mobile-quantity-selector input[id^="mobile_traveler_"]');
559 if (mobileTravelerInputs && mobileTravelerInputs.length > 0) {
560 mobileTravelerInputs.forEach((input) => {
561 const desktopId = input.id.replace(/^mobile_/, '');
562 const desktopInput = document.getElementById(desktopId);
563 if (desktopInput) {
564 desktopInput.value = input.value;
565 }
566 });
567 }
568 }
569
570 function updateMobileTotal() {
571 const sidebar = document.getElementById('yatra-mobile-sticky-sidebar');
572 if (!sidebar) return;
573
574 const pricingType = sidebar.getAttribute('data-pricing-type');
575 const mobileTotal = document.getElementById('mobile-total-amount');
576 if (!mobileTotal) return;
577
578 let total = 0;
579
580 if (pricingType === 'traveler_based') {
581 // Traveler-based pricing: sum all category quantities × prices
582 const travelerInputs = document.querySelectorAll('[id^="mobile_traveler_"]');
583 travelerInputs.forEach(input => {
584 const qty = parseInt(input.value) || 0;
585 const price = parseFloat(input.getAttribute('data-price')) || 0;
586 total += qty * price;
587 });
588 } else {
589 // Regular pricing: simple multiplication
590 const travelersInput = document.getElementById('mobile_num_travelers');
591 if (travelersInput) {
592 const travelers = parseInt(travelersInput.value) || 1;
593 const basePrice = parseFloat(travelersInput.getAttribute('data-price')) || 0;
594 total = travelers * basePrice;
595 }
596 }
597
598 // Format and update display (mobile total element has been removed)
599 // The mobile total price display is no longer shown
600 if (mobileTotal) {
601 if (window.yatraTripData && window.yatraTripData.currencySymbol) {
602 mobileTotal.textContent = window.yatraTripData.currencySymbol + total.toFixed(2);
603 } else {
604 mobileTotal.textContent = formatCurrency(total);
605 }
606 }
607
608 // Also sync with main form total if it exists (main total also removed)
609 const mainTotal = document.getElementById('total-amount');
610 if (mainTotal && window.yatraTripData && window.yatraTripData.currencySymbol) {
611 mainTotal.textContent = window.yatraTripData.currencySymbol + total.toFixed(2);
612 }
613 }
614
615 function formatCurrency(amount) {
616 // Simple currency formatting (can be enhanced)
617 return '$' + amount.toFixed(2);
618 }
619
620 // Auto-hide on scroll down, show on scroll up (also works for enquiry-only sticky)
621 let lastScrollTop = 0;
622 const mobileSidebar = document.getElementById('yatra-mobile-sticky-sidebar');
623 const scrollThreshold = 100;
624
625 window.addEventListener('scroll', function() {
626 if (!mobileSidebar) return;
627
628 const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
629
630 if (scrollTop > lastScrollTop && scrollTop > scrollThreshold) {
631 // Scrolling down - hide sidebar
632 mobileSidebar.classList.add('hidden');
633 } else {
634 // Scrolling up - show sidebar
635 mobileSidebar.classList.remove('hidden');
636 }
637
638 lastScrollTop = scrollTop <= 0 ? 0 : scrollTop;
639 }, false);
640 </script>
641