PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
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.16, at templates/partials/single-trip/content-sidebar.php

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