PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.13
Yatra – Travel Booking & Tour Operator Software v3.0.13
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 / content-sidebar.php

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

528 lines 29.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5 ?>
6 <aside class="yatra-trip-sidebar" id="booking">
7 <?php
8 // Group discounts (Advanced Discount / Pro): same payload as the public REST discoverability endpoint
9 $sidebar_has_group_discounts = false;
10 $sidebar_group_discount_cards = [];
11 if (function_exists('yatra_single_trip_get_group_discounts')) {
12 $gd = yatra_single_trip_get_group_discounts((int) $trip->getId());
13 $sidebar_has_group_discounts = !empty($gd['has_group_discounts']);
14 $sidebar_group_discount_cards = isset($gd['group_discounts_data']) && is_array($gd['group_discounts_data'])
15 ? $gd['group_discounts_data']
16 : [];
17 }
18
19 // Pro: check whether this trip has booking disabled (enquiry-only mode)
20 $booking_disabled = method_exists($trip, 'isBookingDisabled') && $trip->isBookingDisabled();
21
22 // Pricing — resolved via centralized TripPricingService (single source of truth)
23 // SingleTripController pre-computes effective_price_min, min_category_original_price, max_discount_percentage
24 $displayPricing = \Yatra\Services\TripPricingService::resolveDisplayPricing($trip);
25
26 $pricing = [
27 'has_price' => $displayPricing['effective_price_min'] > 0,
28 'current_price' => $displayPricing['effective_price_min'] > 0 ? yatra_format_price($displayPricing['effective_price_min']) : '',
29 'original_price' => $displayPricing['has_discount'] ? yatra_format_price($displayPricing['min_category_original_price']) : '',
30 'price_prefix' => $displayPricing['price_prefix'],
31 'has_discount' => $displayPricing['has_discount'],
32 'raw_current_price' => $displayPricing['effective_price_min'],
33 'raw_original_price' => $displayPricing['min_category_original_price'],
34 'is_traveler_based' => $displayPricing['has_traveler_pricing'],
35 ];
36
37 $discount = [
38 'has_discount' => $displayPricing['has_discount'] && $displayPricing['max_discount_percentage'] > 0,
39 'discount_text' => $displayPricing['max_discount_percentage'] > 0
40 ? sprintf(
41 /* translators: %d: maximum discount percentage. */
42 __('Save up to %d%%', 'yatra'),
43 $displayPricing['max_discount_percentage']
44 ) : '',
45 'discount_percentage' => $displayPricing['max_discount_percentage'],
46 ];
47
48 $dp_display_sidebar = apply_filters('yatra_get_dynamic_pricing_display_settings', [
49 'show_original_price' => true,
50 'show_savings_badge' => true,
51 'show_urgency_messages' => false,
52 ]);
53 $dp_show_savings_sidebar = filter_var($dp_display_sidebar['show_savings_badge'] ?? true, FILTER_VALIDATE_BOOLEAN);
54 $show_strike_original_sidebar = filter_var($dp_display_sidebar['show_original_price'] ?? true, FILTER_VALIDATE_BOOLEAN);
55 $yatra_sidebar_urgency = function_exists('yatra_trip_card_dynamic_pricing_urgency_lines')
56 ? yatra_trip_card_dynamic_pricing_urgency_lines((int) $trip->getId(), [
57 'base_sale_price' => (float) ($displayPricing['effective_price_min'] ?? 0),
58 'base_original_price' => (float) ($displayPricing['min_category_original_price'] ?? 0),
59 'sale_price' => (float) ($displayPricing['effective_price_min'] ?? 0),
60 'original_price' => (float) ($displayPricing['min_category_original_price'] ?? 0),
61 'departure_date' => null,
62 'spots_remaining' => null,
63 'availability_id' => null,
64 'surface' => 'single_sidebar',
65 ])
66 : [];
67 ?>
68 <?php if ($booking_disabled): ?>
69 <div class="yatra-booking-card yatra-enquiry-only-card">
70 <!-- Price Display -->
71 <div class="yatra-booking-price">
72 <?php if ($discount['has_discount'] && $dp_show_savings_sidebar): ?>
73 <div class="yatra-booking-discount-badge">
74 <?php echo esc_html($discount['discount_text']); ?>
75 </div>
76 <?php endif; ?>
77 <div class="yatra-booking-price-main">
78 <?php if ($pricing['has_price']): ?>
79 <span class="yatra-booking-price-label-top"><?php echo esc_html__('From', 'yatra'); ?></span>
80 <?php if ($pricing['has_discount'] && !empty($pricing['original_price']) && $show_strike_original_sidebar): ?>
81 <span class="yatra-booking-price-original"><?php echo esc_html($pricing['original_price']); ?></span>
82 <?php endif; ?>
83 <span class="yatra-booking-price-amount" id="display-price"><?php echo esc_html($pricing['current_price']); ?></span>
84 <span class="yatra-booking-price-label"><?php echo esc_html__('per person', 'yatra'); ?></span>
85 <?php if (!empty($yatra_sidebar_urgency)) : ?>
86 <?php foreach ($yatra_sidebar_urgency as $yatra_sb_urg) : ?>
87 <div class="yatra-booking-dp-urgency" style="background-color:#fef3c7;color:#92400e;padding:6px 8px;border-radius:6px;margin-top:8px;font-size:12px;line-height:1.35;">
88 <?php echo esc_html((string) $yatra_sb_urg); ?>
89 </div>
90 <?php endforeach; ?>
91 <?php endif; ?>
92 <?php else: ?>
93 <span class="yatra-booking-price-amount yatra-contact-pricing" id="display-price"><?php echo esc_html__('Contact for pricing', 'yatra'); ?></span>
94 <?php endif; ?>
95 </div>
96 </div>
97
98 <!-- Enquiry-only notice -->
99 <div class="yatra-enquiry-notice" style="margin:12px 0 4px;padding:10px 12px;background:#f0f7ff;border:1px solid #cce0ff;border-radius:6px;font-size:0.85rem;color:#1a5fa8;display:flex;align-items:flex-start;gap:8px;">
100 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="flex-shrink:0;margin-top:1px">
101 <circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
102 </svg>
103 <span><?php esc_html_e('This trip is available for enquiry only. Please contact us to discuss dates and availability.', 'yatra'); ?></span>
104 </div>
105
106 <!-- Enquiry button -->
107 <button type="button" class="yatra-booking-button" style="margin-top:12px;" id="open-enquiry-modal" onclick="window.YatraEnquiry?.open?.(); return false;">
108 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
109 <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"/>
110 </svg>
111 <?php echo esc_html__('Send Enquiry', 'yatra'); ?>
112 </button>
113 <?php
114 // AI: Chat-with-AI widget. The partial gates itself on the
115 // operator's enable flag + module-active state so it's a no-op
116 // when the feature is off.
117 yatra_get_template('partials/single-trip/ai-chat-widget', ['trip' => $trip]);
118 ?>
119 </div>
120 <?php else: ?>
121 <div class="yatra-booking-card">
122
123 <?php if ($sidebar_has_group_discounts && !empty($sidebar_group_discount_cards)): ?>
124 <?php
125 $group_discount_cards = $sidebar_group_discount_cards;
126 $popover_context = 'booking';
127 $popover_uid = 'sb-' . (int) $trip->getId();
128 yatra_get_template('partials/single-trip/group-discount-booking-popover', compact('group_discount_cards', 'popover_context', 'popover_uid'));
129 ?>
130 <?php endif; ?>
131
132 <!-- Price Display -->
133 <div class="yatra-booking-price">
134 <?php if ($discount['has_discount'] && $dp_show_savings_sidebar): ?>
135 <div class="yatra-booking-discount-badge">
136 <?php echo esc_html($discount['discount_text']); ?>
137 </div>
138 <?php endif; ?>
139 <div class="yatra-booking-price-main">
140 <?php if ($pricing['has_price']): ?>
141 <?php if ($has_availability || $has_traveler_pricing): ?>
142 <span class="yatra-booking-price-label-top"><?php echo esc_html__('From', 'yatra'); ?></span>
143 <?php endif; ?>
144 <?php if ($pricing['has_discount'] && !empty($pricing['original_price']) && $show_strike_original_sidebar): ?>
145 <span class="yatra-booking-price-original"><?php echo esc_html($pricing['original_price']); ?></span>
146 <?php endif; ?>
147 <span class="yatra-booking-price-amount" id="display-price"><?php echo esc_html($pricing['current_price']); ?></span>
148 <span class="yatra-booking-price-label"><?php echo esc_html__('per person', 'yatra'); ?></span>
149 <?php if (!empty($yatra_sidebar_urgency)) : ?>
150 <?php foreach ($yatra_sidebar_urgency as $yatra_sb_urg) : ?>
151 <div class="yatra-booking-dp-urgency" style="background-color:#fef3c7;color:#92400e;padding:6px 8px;border-radius:6px;margin-top:8px;font-size:12px;line-height:1.35;">
152 <?php echo esc_html((string) $yatra_sb_urg); ?>
153 </div>
154 <?php endforeach; ?>
155 <?php endif; ?>
156 <?php else: ?>
157 <span class="yatra-booking-price-amount yatra-contact-pricing" id="display-price"><?php echo esc_html__('Contact for pricing', 'yatra'); ?></span>
158 <?php endif; ?>
159 </div>
160 </div>
161
162 <?php if ($trip->getBookingMode() === 'date_specific' && $has_availability): ?>
163 <!-- ========================================== -->
164 <!-- DATE-SPECIFIC BOOKING (Has Availability Dates/Rules) -->
165 <!-- ========================================== -->
166 <div class="yatra-availability-info">
167 <span class="yatra-availability-count">
168 <?php
169 $allAvailability = $trip->getAvailabilityDates();
170 $today = date('Y-m-d');
171
172 // Sidebar count should reflect the same resolved availability set (priority:
173 // manual > recurring rule > trip default). We keep it lightweight here:
174 // count upcoming departures (date + optional time) from the resolved list.
175 $filtered = array_filter($allAvailability, static function ($a) use ($today) {
176 if (!is_object($a)) {
177 return false;
178 }
179 $date = (string) ($a->departure_date ?? '');
180 if ($date === '' || $date < $today) {
181 return false;
182 }
183 return true;
184 });
185
186 // Priority: manual availability dates > recurring rules > trip default.
187 $bySource = [
188 'availability_date' => [],
189 'recurring_rule' => [],
190 'trip_default' => [],
191 '' => [],
192 ];
193 foreach ($filtered as $a) {
194 $src = strtolower(trim((string) ($a->source ?? '')));
195 if (!isset($bySource[$src])) {
196 $src = '';
197 }
198 $bySource[$src][] = $a;
199 }
200
201 $pick = [];
202 if (!empty($bySource['availability_date'])) {
203 $pick = $bySource['availability_date'];
204 } elseif (!empty($bySource['recurring_rule'])) {
205 $pick = $bySource['recurring_rule'];
206 } elseif (!empty($bySource['trip_default'])) {
207 $pick = $bySource['trip_default'];
208 } else {
209 $pick = $filtered;
210 }
211
212 // Count departures:
213 // - if availability entries include departure_time, count unique (date + time) as departures
214 // - otherwise count unique dates.
215 $hasTimeSlots = false;
216 foreach ($pick as $a) {
217 $t = isset($a->departure_time) ? trim((string) $a->departure_time) : '';
218 if ($t !== '' && $t !== '00:00:00') {
219 $hasTimeSlots = true;
220 break;
221 }
222 }
223
224 $unique = [];
225 foreach ($pick as $a) {
226 $date = (string) ($a->departure_date ?? '');
227 if ($date === '') {
228 continue;
229 }
230 if ($hasTimeSlots) {
231 $t = isset($a->departure_time) ? trim((string) $a->departure_time) : '';
232 if ($t !== '' && $t !== '00:00:00') {
233 $date .= '|' . $t;
234 } else {
235 // When some rows have time and others don't, avoid collapsing into date-only.
236 $date .= '|__no_time__';
237 }
238 }
239 $unique[$date] = true;
240 }
241 $countAvailable = count($unique);
242
243 // Pro feature: a Pro module can hook `yatra_use_date_dropdown`
244 // to replace the flatpickr calendar with a <select> of available
245 // departures, and supplies the option list via
246 // `yatra_single_trip_date_dropdown_options`. Free plugin renders
247 // calendar by default (filter returns false / [] when Pro is
248 // inactive or the setting is off).
249 $dropdown_options = (array) apply_filters('yatra_single_trip_date_dropdown_options', [], $trip, $pick);
250 $yatra_use_date_dropdown = (bool) apply_filters('yatra_use_date_dropdown', false, $trip)
251 && !empty($dropdown_options);
252
253 echo esc_html(sprintf(
254 /* translators: %d: number of departures available. */
255 _n('%d departure available', '%d departures available', $countAvailable, 'yatra'),
256 $countAvailable
257 ));
258 ?>
259 </span>
260 </div>
261
262 <form class="yatra-booking-form" data-booking-mode="date_specific">
263 <!-- Date Selection -->
264 <div class="yatra-booking-field-select<?php echo $yatra_use_date_dropdown ? ' yatra-date-as-dropdown' : ''; ?>">
265 <div class="yatra-booking-field-icon">
266 <?php echo yatra_svg_icon('calendar', 'yatra-icon-sm'); ?>
267 </div>
268 <?php if ($yatra_use_date_dropdown): ?>
269 <select id="travel_date"
270 name="travel_date"
271 class="yatra-booking-select yatra-date-dropdown"
272 required>
273 <option value=""><?php esc_html_e('Select a departure date', 'yatra'); ?></option>
274 <?php foreach ($dropdown_options as $opt): ?>
275 <option value="<?php echo esc_attr($opt['value']); ?>"
276 <?php if (!empty($opt['time'])): ?>data-departure-time="<?php echo esc_attr($opt['time']); ?>"<?php endif; ?>>
277 <?php echo esc_html($opt['label']); ?>
278 </option>
279 <?php endforeach; ?>
280 </select>
281 <?php else: ?>
282 <input type="text"
283 id="travel_date"
284 name="travel_date"
285 class="yatra-booking-select yatra-datepicker"
286 placeholder="<?php esc_attr_e('Select date', 'yatra'); ?>"
287 readonly
288 required>
289 <?php endif; ?>
290 <svg class="yatra-select-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
291 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
292 </svg>
293 </div>
294
295 <!-- Travelers Selection - Respects Trip's Pricing Type -->
296 <?php
297 // Use helper function to prepare traveler data
298 $traveler_data = \Yatra\Controllers\SingleTripController::prepareTravelerSelectorData($trip, 'availability');
299
300 if ($traveler_data['has_traveler_pricing']):
301 // Setup variables for traveler-selector.php
302 $root_id = '';
303 $root_class = 'yatra-booking-field-select yatra-participants-select yatra-availability-participants';
304 $container_attrs = [];
305
306 $display_id = 'participants-display';
307 $display_class = 'yatra-participants-display yatra-availability-participants-display';
308 $display_attrs = [];
309
310 $dropdown_id = 'quantity-selector';
311 $dropdown_class = 'yatra-booking-quantity-selector yatra-availability-quantity-selector';
312 $dropdown_attrs = [];
313
314 $display_text = $traveler_data['traveler_display_text'];
315 $icon_html = yatra_svg_icon('users', 'yatra-icon-sm');
316 $rows = $traveler_data['traveler_rows'];
317
318 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-selector.php';
319 else:
320 // Regular Pricing: Simple number of travelers input
321 ?>
322 <div class="yatra-booking-field-group">
323 <label for="num_travelers" class="yatra-booking-field-label"><?php echo esc_html__('Number of Travelers', 'yatra'); ?></label>
324 <?php
325 // Setup variables for traveler-input-simple.php
326 $input_id = 'num_travelers';
327 $input_name = 'num_travelers';
328 $value = 1;
329 $min = $trip->getMinTravelers() ?: 1;
330 $max = $trip->getMaxTravelers() ?: 20;
331 $data_price = $base_price;
332
333 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-input-simple.php';
334 ?>
335 </div>
336 <?php endif; ?>
337 <?php else: ?>
338 <!-- ========================================== -->
339 <!-- FLEXIBLE BOOKING MODE (No Specific Availability Configured) -->
340 <!-- ========================================== -->
341 <div class="yatra-availability-info yatra-flexible-booking-info">
342 <span class="yatra-availability-count">
343 <?php echo esc_html__('Flexible booking available', 'yatra'); ?>
344 </span>
345 <?php if (!empty($trip->getAvailableFrom()) || !empty($trip->getAvailableTo())): ?>
346 <span class="yatra-availability-note">
347 <?php
348 if (!empty($trip->getAvailableFrom()) && !empty($trip->getAvailableTo())) {
349 echo esc_html(sprintf(
350 /* translators: 1: available-from date, 2: available-to date. */
351 __('Available: %1$s - %2$s', 'yatra'),
352 date_i18n(get_option('date_format'), strtotime($trip->getAvailableFrom())),
353 date_i18n(get_option('date_format'), strtotime($trip->getAvailableTo()))
354 ));
355 } elseif (!empty($trip->getAvailableFrom())) {
356 echo esc_html(sprintf(
357 /* translators: %s: available-from date. */
358 __('Available from: %s', 'yatra'),
359 date_i18n(get_option('date_format'), strtotime($trip->getAvailableFrom()))
360 ));
361 } else {
362 echo esc_html(sprintf(
363 /* translators: %s: available-until date. */
364 __('Available until: %s', 'yatra'),
365 date_i18n(get_option('date_format'), strtotime($trip->getAvailableTo()))
366 ));
367 }
368 ?>
369 </span>
370 <?php endif; ?>
371 </div>
372
373 <form class="yatra-booking-form" data-booking-mode="flexible">
374 <!-- Date Selection (Flexible) -->
375 <?php
376 // Same Pro filter contract as the date_specific branch above.
377 // Flexible trips have no discrete availability set, so $pick is
378 // passed as null — the Pro hook synthesizes a list from the
379 // trip's available_from/to window.
380 $flex_dropdown_options = (array) apply_filters('yatra_single_trip_date_dropdown_options', [], $trip, null);
381 $flex_use_date_dropdown = (bool) apply_filters('yatra_use_date_dropdown', false, $trip)
382 && !empty($flex_dropdown_options);
383 ?>
384 <div class="yatra-booking-field-select<?php echo $flex_use_date_dropdown ? ' yatra-date-as-dropdown' : ''; ?>">
385 <div class="yatra-booking-field-icon">
386 <?php echo yatra_svg_icon('calendar', 'yatra-icon-sm'); ?>
387 </div>
388 <?php if ($flex_use_date_dropdown): ?>
389 <select id="travel_date"
390 name="travel_date"
391 class="yatra-booking-select yatra-date-dropdown"
392 required>
393 <option value=""><?php esc_html_e('Select a departure date', 'yatra'); ?></option>
394 <?php foreach ($flex_dropdown_options as $opt): ?>
395 <option value="<?php echo esc_attr($opt['value']); ?>"
396 <?php if (!empty($opt['time'])): ?>data-departure-time="<?php echo esc_attr($opt['time']); ?>"<?php endif; ?>>
397 <?php echo esc_html($opt['label']); ?>
398 </option>
399 <?php endforeach; ?>
400 </select>
401 <?php else: ?>
402 <input type="text"
403 id="travel_date"
404 name="travel_date"
405 class="yatra-booking-select yatra-datepicker"
406 placeholder="<?php esc_attr_e('Select date', 'yatra'); ?>"
407 data-min-date="<?php echo esc_attr($trip->getAvailableFrom() ?: date('Y-m-d')); ?>"
408 data-max-date="<?php echo esc_attr($trip->getAvailableTo() ?: ''); ?>"
409 readonly
410 required>
411 <?php endif; ?>
412 <svg class="yatra-select-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
413 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
414 </svg>
415 </div>
416
417 <!-- Travelers Selection -->
418 <?php
419 // Use helper function to prepare traveler data
420 $traveler_data = \Yatra\Controllers\SingleTripController::prepareTravelerSelectorData($trip, 'sidebar');
421
422 if ($traveler_data['has_traveler_pricing']):
423 // Setup variables for traveler-selector.php
424 $root_id = '';
425 $root_class = 'yatra-booking-field-select yatra-participants-select';
426 $container_attrs = [];
427
428 $display_id = 'participants-display';
429 $display_class = 'yatra-participants-display';
430 $display_attrs = [];
431
432 $dropdown_id = 'quantity-selector';
433 $dropdown_class = 'yatra-booking-quantity-selector';
434 $dropdown_attrs = [];
435
436 $display_text = $traveler_data['traveler_display_text'];
437 $icon_html = yatra_svg_icon('users', 'yatra-icon-sm');
438 $rows = $traveler_data['traveler_rows'];
439
440 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-selector.php';
441 else:
442 // Regular Pricing: Simple number of travelers input
443 ?>
444 <div class="yatra-booking-field-group">
445 <label for="num_travelers" class="yatra-booking-field-label"><?php echo esc_html__('Number of Travelers', 'yatra'); ?></label>
446 <?php
447 // Setup variables for traveler-input-simple.php
448 $input_id = 'num_travelers';
449 $input_name = 'num_travelers';
450 $value = 1;
451 $min = $trip->getMinTravelers() ?: 1;
452 $max = $trip->getMaxTravelers() ?: 20;
453 $data_price = $base_price;
454
455 include YATRA_PLUGIN_PATH . 'templates/partials/traveler-input-simple.php';
456 ?>
457 </div>
458 <?php endif; ?>
459 <?php endif; ?>
460
461
462 <!-- Action Buttons -->
463 <button type="button" class="yatra-booking-button" id="check-availability-btn" data-trip-id="<?php echo esc_attr($trip->getId()); ?>">
464 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
465 <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"/>
466 </svg>
467 <?php echo esc_html__('Check Availability', 'yatra'); ?>
468 </button>
469
470 <button type="button" class="yatra-booking-enquiry-button" id="open-enquiry-modal" onclick="window.YatraEnquiry?.open?.(); return false;">
471 <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
472 <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"/>
473 </svg>
474 <?php echo esc_html__('Make Enquiry', 'yatra'); ?>
475 </button>
476 <?php
477 // AI: Chat-with-AI widget — bookable-trip branch.
478 yatra_get_template('partials/single-trip/ai-chat-widget', ['trip' => $trip]);
479 ?>
480
481 <!-- Cancellation Policy Trust Signal -->
482 <?php
483 $cancellation_policy = '';
484 if (method_exists($trip, 'getCancellationPolicy')) {
485 $cancellation_policy = $trip->getCancellationPolicy();
486 } elseif (isset($trip->cancellation_policy)) {
487 $cancellation_policy = $trip->cancellation_policy;
488 }
489
490 $cancellation_text = '';
491 if (!empty($cancellation_policy)) {
492 // Extract cancellation info from policy
493 $policy_lower = strtolower($cancellation_policy);
494 if (strpos($policy_lower, 'free') !== false || strpos($policy_lower, 'no charge') !== false) {
495 if (preg_match('/(\d+)\s*(hour|day|week)s?\s*before/i', $cancellation_policy, $matches)) {
496 $time_value = $matches[1];
497 $time_unit = $matches[2];
498 $cancellation_text = sprintf(
499 /* translators: 1: numeric time value, 2: time unit (hour/day/week), 3: plural suffix ("s" or empty). */
500 __('Free cancellation up to %1$d %2$s%3$s before', 'yatra'),
501 $time_value,
502 $time_unit,
503 $time_value > 1 ? 's' : ''
504 );
505 } else {
506 $cancellation_text = __('Free cancellation', 'yatra');
507 }
508 } else {
509 // Non-free cancellation, show brief info
510 $cancellation_text = __('Cancellation policy applies', 'yatra');
511 }
512 } else {
513 // Default fallback when no policy is set
514 $cancellation_text = __('Cancellation policy may apply', 'yatra');
515 }
516 ?>
517 <div class="yatra-booking-trust">
518 <div class="yatra-booking-trust-icon">
519 <?php echo yatra_svg_icon('check', 'yatra-icon-xs'); ?>
520 </div>
521 <div class="yatra-booking-trust-text">
522 <strong><?php echo esc_html($cancellation_text); ?></strong>
523 </div>
524 </div>
525 </form>
526 </div>
527 <?php endif; // end else (booking not disabled) ?>
528 </aside>