PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.17
Yatra – Travel Booking & Tour Operator Software v3.0.17
3.0.17 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 All 85 releases
yatra / assets / dist / js / BookingForm-hQVneAfI.js

BookingForm-hQVneAfI.js in Yatra – Travel Booking & Tour Operator Software 3.0.17, at assets/dist/js/BookingForm-hQVneAfI.js

1,865 lines 91.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { v as useQueryClient, r as reactExports, u as useQuery, a6 as React, w as useMutation, j as jsxRuntimeExports, D as ArrowLeft, ay as X, y as ChevronDown, aP as Search, aA as AlertCircle, U as Users, ax as Plus, aO as Trash2, bd as ChevronUp, E as Loader2, aW as Save } from "./react-vendor-CithbthY.js";
2 import { a as apiClient, A as API_ENDPOINTS, f as formatYatraMoney, h as getCurrencySymbol, g as todayYmd, _ as __, I as Input, S as SearchableSelect, l as getCountrySelectOptions, b as apiService, d as formatDateForInput } from "./index-Dec_weLB.js";
3 import { u as usePermissions, X as Skeleton, C as Card, f as CardHeader, d as CardContent, P as PageHeader, B as Button, z as ConditionalRender, g as CardTitle, D as DatePicker, S as Select } from "../../admin/dist/js/app.js";
4 class TaxService {
5 constructor() {
6 this.taxSettings = null;
7 }
8 static getInstance() {
9 if (!TaxService.instance) {
10 TaxService.instance = new TaxService();
11 }
12 return TaxService.instance;
13 }
14 /**
15 * Load tax settings from API
16 */
17 async loadTaxSettings() {
18 try {
19 const settings = await apiClient.get(API_ENDPOINTS.SETTINGS);
20 this.taxSettings = (settings == null ? void 0 : settings.data) ?? settings;
21 } catch (error) {
22 console.error("Failed to load tax settings:", error);
23 }
24 }
25 /**
26 * Get tax settings
27 */
28 getTaxSettings() {
29 return this.taxSettings;
30 }
31 /**
32 * Check if tax is enabled
33 */
34 isTaxEnabled() {
35 var _a;
36 return ((_a = this.taxSettings) == null ? void 0 : _a.enable_tax) === true;
37 }
38 /**
39 * Calculate tax for booking
40 */
41 calculateTax(amount, country) {
42 var _a, _b;
43 if (!this.isTaxEnabled()) {
44 return {
45 tax_amount: 0,
46 tax_rate: 0,
47 tax_inclusive: false,
48 taxes: []
49 };
50 }
51 const taxInclusive = ((_a = this.taxSettings) == null ? void 0 : _a.tax_inclusive) === true;
52 const multipleTaxesEnabled = ((_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes_enabled) === true;
53 if (multipleTaxesEnabled) {
54 return this.calculateMultipleTaxes(amount, country, taxInclusive);
55 } else {
56 return this.calculateSingleTax(amount, country, taxInclusive);
57 }
58 }
59 /**
60 * Calculate single tax (backward compatibility)
61 */
62 calculateSingleTax(amount, country, taxInclusive = false) {
63 var _a, _b, _c, _d, _e, _f;
64 let taxRate = ((_a = this.taxSettings) == null ? void 0 : _a.tax_rate) || 0;
65 const taxName = ((_b = this.taxSettings) == null ? void 0 : _b.tax_name) || ((_c = this.taxSettings) == null ? void 0 : _c.tax_label) || "Tax";
66 if (((_d = this.taxSettings) == null ? void 0 : _d.tax_by_country) === true && country && ((_f = (_e = this.taxSettings) == null ? void 0 : _e.tax_rates) == null ? void 0 : _f[country])) {
67 taxRate = this.taxSettings.tax_rates[country];
68 }
69 let taxAmount;
70 if (taxInclusive) {
71 taxAmount = amount - amount / (1 + taxRate / 100);
72 } else {
73 taxAmount = amount * (taxRate / 100);
74 }
75 return {
76 tax_amount: Math.round(taxAmount * 100) / 100,
77 tax_rate: taxRate,
78 tax_inclusive: taxInclusive,
79 taxes: [
80 {
81 name: taxName,
82 rate: taxRate,
83 amount: Math.round(taxAmount * 100) / 100
84 }
85 ]
86 };
87 }
88 /**
89 * Calculate multiple taxes
90 */
91 calculateMultipleTaxes(amount, country, taxInclusive = false) {
92 var _a, _b, _c;
93 let taxes = ((_a = this.taxSettings) == null ? void 0 : _a.multiple_taxes) || [];
94 if (country && ((_c = (_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes_by_country) == null ? void 0 : _c[country])) {
95 taxes = this.taxSettings.multiple_taxes_by_country[country];
96 }
97 const calculatedTaxes = [];
98 let totalTaxAmount = 0;
99 for (const tax of taxes) {
100 const taxRate = tax.rate || 0;
101 const taxName = tax.name || "Tax";
102 let taxAmount;
103 if (taxInclusive) {
104 const baseAmount = amount - totalTaxAmount;
105 taxAmount = baseAmount * (taxRate / 100);
106 } else {
107 taxAmount = amount * (taxRate / 100);
108 }
109 taxAmount = Math.round(taxAmount * 100) / 100;
110 totalTaxAmount += taxAmount;
111 calculatedTaxes.push({
112 name: taxName,
113 rate: taxRate,
114 amount: taxAmount
115 });
116 }
117 return {
118 tax_amount: Math.round(totalTaxAmount * 100) / 100,
119 tax_rate: taxes.reduce(
120 (sum, tax) => sum + (tax.rate || 0),
121 0
122 ),
123 tax_inclusive: taxInclusive,
124 taxes: calculatedTaxes
125 };
126 }
127 /**
128 * Calculate complete booking tax breakdown
129 */
130 calculateBookingTax(subtotal, country) {
131 const taxDetails = this.calculateTax(subtotal, country);
132 let finalSubtotal;
133 let finalTotal;
134 if (taxDetails.tax_inclusive) {
135 finalSubtotal = subtotal - taxDetails.tax_amount;
136 finalTotal = subtotal;
137 } else {
138 finalSubtotal = subtotal;
139 finalTotal = subtotal + taxDetails.tax_amount;
140 }
141 const formattedTaxes = taxDetails.taxes.map((tax) => ({
142 ...tax,
143 formatted_amount: this.formatPrice(tax.amount),
144 formatted_rate: `${tax.rate.toFixed(2)}%`
145 }));
146 const taxBreakdown = formattedTaxes.map(
147 (tax) => `${tax.name} (${tax.formatted_rate}): ${tax.formatted_amount}`
148 ).join("\n");
149 return {
150 subtotal: Math.round(finalSubtotal * 100) / 100,
151 tax_amount: taxDetails.tax_amount,
152 total_amount: Math.round(finalTotal * 100) / 100,
153 tax_rate: taxDetails.tax_rate,
154 tax_inclusive: taxDetails.tax_inclusive,
155 taxes: formattedTaxes,
156 tax_breakdown: taxBreakdown
157 };
158 }
159 /**
160 * Format price display
161 */
162 formatPrice(amount) {
163 var _a;
164 const currency = ((_a = this.taxSettings) == null ? void 0 : _a.currency) || "USD";
165 return formatYatraMoney(Number(amount) || 0, currency, {
166 zeroAsUnknown: false
167 });
168 }
169 /**
170 * Get currency symbol
171 */
172 getCurrencySymbol(currency) {
173 const symbols = {
174 USD: "$",
175 EUR: "€",
176 GBP: "£",
177 JPY: "¥",
178 AUD: "A$",
179 CAD: "C$",
180 CHF: "CHF",
181 CNY: "¥",
182 INR: "₹"
183 };
184 return symbols[currency] || currency;
185 }
186 /**
187 * Get tax breakdown for display
188 */
189 getTaxBreakdown(taxDetails) {
190 return taxDetails.taxes.map((tax) => ({
191 name: tax.name,
192 rate: tax.rate,
193 amount: tax.amount,
194 formatted_amount: this.formatPrice(tax.amount),
195 formatted_rate: `${tax.rate.toFixed(2)}%`,
196 formatted_line: `${tax.name} (${tax.rate.toFixed(2)}%): ${this.formatPrice(tax.amount)}`
197 }));
198 }
199 /**
200 * Format tax display for booking summary
201 */
202 formatTaxDisplay(taxDetails) {
203 const breakdown = this.getTaxBreakdown(taxDetails);
204 return breakdown.map((tax) => tax.formatted_line).join("\n");
205 }
206 /**
207 * Validate tax configuration
208 */
209 validateTaxConfiguration() {
210 var _a, _b, _c, _d;
211 const errors = [];
212 if (!this.isTaxEnabled()) {
213 return { valid: true, errors: [] };
214 }
215 const multipleTaxesEnabled = ((_a = this.taxSettings) == null ? void 0 : _a.multiple_taxes_enabled) === true;
216 if (multipleTaxesEnabled) {
217 const multipleTaxes = ((_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes) || [];
218 if (multipleTaxes.length === 0) {
219 errors.push("At least one tax must be configured");
220 }
221 let totalRate = 0;
222 for (let i = 0; i < multipleTaxes.length; i++) {
223 const tax = multipleTaxes[i];
224 if (!tax.name || tax.name.trim() === "") {
225 errors.push(`Tax ${i + 1}: Name is required`);
226 }
227 if (typeof tax.rate !== "number" || tax.rate < 0 || tax.rate > 100) {
228 errors.push(`Tax ${i + 1}: Rate must be between 0 and 100`);
229 } else {
230 totalRate += tax.rate;
231 }
232 }
233 if (totalRate > 100) {
234 errors.push("Total tax rate cannot exceed 100%");
235 }
236 } else {
237 const taxRate = ((_c = this.taxSettings) == null ? void 0 : _c.tax_rate) || 0;
238 const taxName = ((_d = this.taxSettings) == null ? void 0 : _d.tax_name) || "";
239 if (typeof taxRate !== "number" || taxRate < 0 || taxRate > 100) {
240 errors.push("Tax rate must be between 0 and 100");
241 }
242 if (!taxName || taxName.trim() === "") {
243 errors.push("Tax name is required");
244 }
245 }
246 return {
247 valid: errors.length === 0,
248 errors
249 };
250 }
251 /**
252 * Get tax summary for reporting
253 */
254 getTaxSummary(bookings) {
255 const summary = {
256 total_tax_collected: 0,
257 total_bookings_with_tax: 0,
258 tax_breakdown: {},
259 average_tax_rate: 0
260 };
261 let totalTaxRate = 0;
262 let taxRateCount = 0;
263 for (const booking of bookings) {
264 const taxAmount = booking.tax_amount || 0;
265 if (taxAmount > 0) {
266 summary.total_tax_collected += taxAmount;
267 summary.total_bookings_with_tax++;
268 const taxRate = booking.tax_rate || 0;
269 if (taxRate > 0) {
270 totalTaxRate += taxRate;
271 taxRateCount++;
272 }
273 const taxBreakdown = booking.tax_breakdown || [];
274 for (const tax of taxBreakdown) {
275 const taxName = tax.name;
276 if (!summary.tax_breakdown[taxName]) {
277 summary.tax_breakdown[taxName] = {
278 name: taxName,
279 total_amount: 0,
280 count: 0,
281 average_rate: 0
282 };
283 }
284 summary.tax_breakdown[taxName].total_amount += tax.amount;
285 summary.tax_breakdown[taxName].count++;
286 summary.tax_breakdown[taxName].average_rate += tax.rate;
287 }
288 }
289 }
290 if (taxRateCount > 0) {
291 summary.average_tax_rate = totalTaxRate / taxRateCount;
292 }
293 for (const taxName in summary.tax_breakdown) {
294 const taxData = summary.tax_breakdown[taxName];
295 if (taxData.count > 0) {
296 taxData.average_rate = taxData.average_rate / taxData.count;
297 }
298 }
299 return summary;
300 }
301 }
302 const taxService = TaxService.getInstance();
303 const countrySelectOptions = getCountrySelectOptions();
304 const CORE_CONTACT_IDS = [
305 "first_name",
306 "last_name",
307 "email",
308 "phone",
309 "country"
310 ];
311 const normalizeDateInput = (value) => {
312 if (!value) return "";
313 return formatDateForInput(value) || value;
314 };
315 const BookingForm = () => {
316 var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
317 const queryClient = useQueryClient();
318 const { can } = usePermissions();
319 const globalCurrency = ((_a = window == null ? void 0 : window.yatraAdmin) == null ? void 0 : _a.currency) || "USD";
320 const currencySymbol = getCurrencySymbol(globalCurrency);
321 const [formData, setFormData] = reactExports.useState({
322 customer_name: "",
323 customer_email: "",
324 customer_phone: "",
325 customer_country: "",
326 trip_id: "",
327 booking_date: todayYmd(),
328 travel_date: "",
329 departure_time: "",
330 travelers: "1",
331 subtotal: "",
332 tax_amount: "",
333 total_amount: "",
334 currency: globalCurrency,
335 payment_status: "pending",
336 booking_status: "pending",
337 payment_method: "",
338 notes: ""
339 });
340 const [travelersData, setTravelersData] = reactExports.useState([{}]);
341 const [expandedTravelers, setExpandedTravelers] = reactExports.useState([0]);
342 const [emergencyContactData, setEmergencyContactData] = reactExports.useState({});
343 const [contactExtraData, setContactExtraData] = reactExports.useState({});
344 const [errors, setErrors] = reactExports.useState({});
345 const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
346 const [tripSearchQuery, setTripSearchQuery] = reactExports.useState("");
347 const [isTripDropdownOpen, setIsTripDropdownOpen] = reactExports.useState(false);
348 const tripDropdownRef = reactExports.useRef(null);
349 reactExports.useEffect(() => {
350 const handleClickOutside = (event) => {
351 if (tripDropdownRef.current && !tripDropdownRef.current.contains(event.target)) {
352 setIsTripDropdownOpen(false);
353 }
354 };
355 document.addEventListener("mousedown", handleClickOutside);
356 return () => document.removeEventListener("mousedown", handleClickOutside);
357 }, []);
358 const selectedTripId = formData.trip_id ? Number(formData.trip_id) : null;
359 const { data: formConfig } = useQuery({
360 queryKey: ["booking-form-config", selectedTripId],
361 queryFn: async () => {
362 var _a2;
363 const response = await apiService.getBookingFormConfig(selectedTripId);
364 return ((_a2 = response == null ? void 0 : response.data) == null ? void 0 : _a2.booking_form_config) || (response == null ? void 0 : response.booking_form_config) || null;
365 }
366 });
367 const travelerFields = reactExports.useMemo(() => {
368 var _a2;
369 if (!((_a2 = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _a2.fields)) return [];
370 return formConfig.traveler_form.fields.filter((field) => field.enabled).sort((a, b) => a.order - b.order);
371 }, [formConfig]);
372 const emergencyContactFields = reactExports.useMemo(() => {
373 var _a2;
374 if (!((_a2 = formConfig == null ? void 0 : formConfig.emergency_contact_form) == null ? void 0 : _a2.fields)) return [];
375 return formConfig.emergency_contact_form.fields.filter((field) => field.enabled).sort((a, b) => a.order - b.order);
376 }, [formConfig]);
377 const contactExtraFields = reactExports.useMemo(() => {
378 var _a2;
379 if (!((_a2 = formConfig == null ? void 0 : formConfig.contact_form) == null ? void 0 : _a2.fields)) return [];
380 if (formConfig.contact_form.enabled === false) return [];
381 return formConfig.contact_form.fields.filter((field) => field.enabled && !CORE_CONTACT_IDS.includes(field.id)).sort((a, b) => a.order - b.order);
382 }, [formConfig]);
383 const createEmptyTraveler = () => {
384 const empty = {};
385 travelerFields.forEach((field) => {
386 empty[field.id] = "";
387 });
388 return empty;
389 };
390 const action = reactExports.useMemo(() => {
391 const params = new URLSearchParams(window.location.search);
392 return params.get("action") || "create";
393 }, []);
394 const bookingId = reactExports.useMemo(() => {
395 const params = new URLSearchParams(window.location.search);
396 return params.get("id") ? parseInt(params.get("id") || "0") : null;
397 }, []);
398 const isEditMode = action === "edit" && bookingId !== null;
399 const { data: gatewaysData } = useQuery({
400 queryKey: ["payment-gateways"],
401 queryFn: async () => {
402 const result = await apiService.getPaymentGateways();
403 if (result == null ? void 0 : result.success) {
404 return {
405 data: result.data.filter((gw) => gw.enabled).map((gw) => ({
406 id: gw.id,
407 title: gw.title || gw.name
408 }))
409 };
410 }
411 return { data: [] };
412 }
413 });
414 const { data: tripsData, isLoading: isLoadingTrips } = useQuery({
415 queryKey: ["trips-list-all"],
416 queryFn: async () => {
417 return await apiService.getTrips({ per_page: 500 });
418 },
419 // Always fetch trips when user can manage bookings
420 enabled: can("yatra_view_bookings") || can("yatra_view_trips"),
421 retry: 1
422 });
423 const { data: availableDatesData } = useQuery({
424 queryKey: ["booking-form-available-dates", formData.trip_id],
425 queryFn: async () => {
426 if (!formData.trip_id) return null;
427 return await apiService.getTripAvailableDates(formData.trip_id);
428 },
429 enabled: !!formData.trip_id,
430 retry: 1
431 });
432 const departureTimesForDate = React.useMemo(() => {
433 const rows = (availableDatesData == null ? void 0 : availableDatesData.data) ?? availableDatesData ?? [];
434 if (!Array.isArray(rows) || !formData.travel_date) return [];
435 const row = rows.find(
436 (r) => ((r == null ? void 0 : r.date) ?? (r == null ? void 0 : r.departure_date)) === formData.travel_date
437 );
438 if (!row) return [];
439 const times = Array.isArray(row.departure_times) ? row.departure_times : [row.time ?? row.departure_time ?? ""];
440 return Array.from(new Set(times.filter((t) => !!t)));
441 }, [availableDatesData, formData.travel_date]);
442 const { data: bookingData, isLoading: isLoadingBooking } = useQuery({
443 queryKey: ["booking", bookingId],
444 queryFn: async () => {
445 if (!bookingId) return null;
446 const result = await apiService.getBooking(bookingId);
447 if (!result) {
448 throw new Error("Failed to fetch booking");
449 }
450 const booking = (result == null ? void 0 : result.data) ?? result;
451 if (booking && booking.id) {
452 const contact = booking.contact || {};
453 const firstName = booking.contact_first_name || contact.first_name || "";
454 const lastName = booking.contact_last_name || contact.last_name || "";
455 const customerName = booking.customer_name || `${firstName} ${lastName}`.trim();
456 let travelers = [];
457 if (booking.travelers && Array.isArray(booking.travelers)) {
458 travelers = booking.travelers.map((t) => {
459 const traveler = {};
460 const fieldsData = t.fields || t;
461 if (fieldsData && typeof fieldsData === "object") {
462 Object.entries(fieldsData).forEach(([key, value]) => {
463 if (![
464 "id",
465 "booking_id",
466 "traveller_index",
467 "is_lead",
468 "created_at",
469 "updated_at"
470 ].includes(key)) {
471 traveler[key] = String(value || "");
472 }
473 });
474 }
475 if (t.is_lead !== void 0) {
476 traveler["is_lead"] = String(t.is_lead);
477 }
478 return traveler;
479 });
480 }
481 if (travelers.length === 0) {
482 travelers = [{}];
483 }
484 let emergencyContact = {};
485 if (booking.emergency_contact && typeof booking.emergency_contact === "object") {
486 Object.entries(booking.emergency_contact).forEach(([key, value]) => {
487 emergencyContact[key] = String(value || "");
488 });
489 } else if (contact.emergency_name || contact.emergency_phone || contact.emergency_relationship) {
490 emergencyContact = {
491 name: String(contact.emergency_name || ""),
492 phone: String(contact.emergency_phone || ""),
493 relationship: String(contact.emergency_relationship || "")
494 };
495 }
496 const mappedData = {
497 id: booking.id,
498 customer_name: customerName,
499 customer_email: booking.customer_email || contact.email || booking.contact_email || "",
500 customer_phone: booking.customer_phone || contact.phone || booking.contact_phone || "",
501 customer_country: booking.contact_country || "",
502 trip_id: String(booking.trip_id || ""),
503 trip_title: booking.trip_title || "",
504 booking_date: normalizeDateInput(
505 booking.booking_date ?? booking.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
506 ),
507 travel_date: normalizeDateInput(booking.travel_date ?? ""),
508 travelers: String(booking.travelers || "1"),
509 travelers_data: travelers,
510 // Add the correctly parsed travelers data
511 subtotal: String(
512 booking.subtotal || booking.total_amount || ""
513 ),
514 tax_amount: String(booking.tax_amount || "0"),
515 total_amount: String(booking.total_amount || ""),
516 currency: booking.currency || "USD",
517 payment_status: booking.payment_status || "pending",
518 booking_status: booking.booking_status || "pending",
519 payment_method: booking.payment_method || "",
520 notes: booking.notes || "",
521 emergency_contact: emergencyContact,
522 contact_data: booking.contact_data || null
523 };
524 return mappedData;
525 }
526 return null;
527 },
528 enabled: isEditMode && can("yatra_view_bookings")
529 });
530 const [isDataLoaded, setIsDataLoaded] = reactExports.useState(false);
531 reactExports.useEffect(() => {
532 var _a2;
533 if (bookingData && isEditMode) {
534 setFormData({
535 customer_name: bookingData.customer_name || "",
536 customer_email: bookingData.customer_email || "",
537 customer_phone: bookingData.customer_phone || "",
538 customer_country: bookingData.contact_country || bookingData.customer_country || "",
539 trip_id: String(bookingData.trip_id || ""),
540 booking_date: bookingData.booking_date || todayYmd(),
541 travel_date: bookingData.travel_date || "",
542 departure_time: bookingData.departure_time || "",
543 travelers: String(
544 bookingData.travelers_count || ((_a2 = bookingData.travelers_data) == null ? void 0 : _a2.length) || "1"
545 ),
546 subtotal: String(
547 bookingData.subtotal || bookingData.total_amount || ""
548 ),
549 tax_amount: String(bookingData.tax_amount || "0"),
550 total_amount: String(bookingData.total_amount || ""),
551 currency: bookingData.currency || "USD",
552 payment_status: bookingData.payment_status || "pending",
553 booking_status: bookingData.booking_status || "pending",
554 payment_method: bookingData.payment_method || "",
555 notes: bookingData.special_requests || bookingData.notes || ""
556 });
557 if (bookingData.travelers_data && Array.isArray(bookingData.travelers_data) && bookingData.travelers_data.length > 0) {
558 setTravelersData(bookingData.travelers_data);
559 setExpandedTravelers([0]);
560 } else {
561 setTravelersData([{}]);
562 setExpandedTravelers([0]);
563 }
564 if (bookingData.emergency_contact) {
565 setEmergencyContactData(bookingData.emergency_contact);
566 }
567 const cd = bookingData.contact_data;
568 if (cd && typeof cd === "object") {
569 const extras = {};
570 Object.entries(cd).forEach(([k, v]) => {
571 if (!CORE_CONTACT_IDS.includes(k)) {
572 extras[k] = v == null ? "" : String(v);
573 }
574 });
575 setContactExtraData(extras);
576 }
577 setIsDataLoaded(true);
578 }
579 }, [bookingData, isEditMode]);
580 reactExports.useEffect(() => {
581 var _a2;
582 if (isEditMode) return;
583 if (formData.trip_id && formData.travelers) {
584 const selectedTrip = (_a2 = tripsData == null ? void 0 : tripsData.data) == null ? void 0 : _a2.find(
585 (trip) => String(trip.id) === formData.trip_id
586 );
587 if (selectedTrip) {
588 const subtotal = selectedTrip.price * parseInt(formData.travelers);
589 const taxCalculation = taxService.calculateBookingTax(
590 subtotal,
591 formData.customer_country
592 );
593 setFormData((prev) => ({
594 ...prev,
595 subtotal: taxCalculation.subtotal.toString(),
596 tax_amount: taxCalculation.tax_amount.toString(),
597 total_amount: taxCalculation.total_amount.toString()
598 }));
599 }
600 }
601 }, [
602 formData.trip_id,
603 formData.travelers,
604 formData.customer_country,
605 tripsData == null ? void 0 : tripsData.data,
606 isEditMode
607 ]);
608 reactExports.useEffect(() => {
609 taxService.loadTaxSettings();
610 }, []);
611 const handleFieldChange = (field, value) => {
612 setFormData((prev) => ({ ...prev, [field]: value }));
613 if (errors[field]) {
614 setErrors((prev) => ({ ...prev, [field]: "" }));
615 }
616 };
617 const handleEmergencyContactChange = (field, value) => {
618 setEmergencyContactData((prev) => ({ ...prev, [field]: value }));
619 };
620 const handleContactExtraChange = (field, value) => {
621 setContactExtraData((prev) => ({ ...prev, [field]: value }));
622 };
623 const renderDynamicInput = (field, value, onChange, idPrefix) => {
624 var _a2;
625 const id = `${idPrefix}-${field.id}`;
626 if (field.type === "select") {
627 return /* @__PURE__ */ jsxRuntimeExports.jsxs(
628 Select,
629 {
630 id,
631 value,
632 onChange: (e) => onChange(e.target.value),
633 children: [
634 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
635 (_a2 = field.options) == null ? void 0 : _a2.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value))
636 ]
637 }
638 );
639 }
640 if (field.type === "country") {
641 return /* @__PURE__ */ jsxRuntimeExports.jsx(
642 SearchableSelect,
643 {
644 value,
645 onChange,
646 options: countrySelectOptions,
647 placeholder: field.placeholder || __("Select Country", "yatra"),
648 searchPlaceholder: __("Search country", "yatra")
649 }
650 );
651 }
652 if (field.type === "textarea") {
653 return /* @__PURE__ */ jsxRuntimeExports.jsx(
654 "textarea",
655 {
656 id,
657 value,
658 onChange: (e) => onChange(e.target.value),
659 placeholder: field.placeholder,
660 rows: 2,
661 className: "flex w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:placeholder:text-gray-400 resize-none"
662 }
663 );
664 }
665 if (field.type === "checkbox") {
666 return /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 cursor-pointer", children: [
667 /* @__PURE__ */ jsxRuntimeExports.jsx(
668 "input",
669 {
670 type: "checkbox",
671 className: "rounded border-gray-300",
672 checked: value === "1" || value === "true",
673 onChange: (e) => onChange(e.target.checked ? "1" : "")
674 }
675 ),
676 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field.placeholder || field.label })
677 ] });
678 }
679 return /* @__PURE__ */ jsxRuntimeExports.jsx(
680 Input,
681 {
682 id,
683 type: field.type === "email" ? "email" : field.type === "tel" ? "tel" : field.type === "date" ? "date" : field.type === "number" ? "number" : "text",
684 value,
685 onChange: (e) => onChange(e.target.value),
686 placeholder: field.placeholder
687 }
688 );
689 };
690 const handleTravelerChange = (index, field, value) => {
691 setTravelersData((prev) => {
692 const updated = [...prev];
693 updated[index] = { ...updated[index], [field]: value };
694 return updated;
695 });
696 };
697 const handleTravelersCountChange = (value) => {
698 setFormData((prev) => ({ ...prev, travelers: value }));
699 if (errors.travelers) {
700 setErrors((prev) => ({ ...prev, travelers: "" }));
701 }
702 if (value.trim() === "") {
703 return;
704 }
705 const parsed = parseInt(value, 10);
706 if (isNaN(parsed) || parsed < 1) {
707 return;
708 }
709 setTravelersData((prev) => {
710 if (parsed === prev.length) {
711 return prev;
712 }
713 if (parsed < prev.length) {
714 return prev.slice(0, parsed);
715 }
716 const grown = [...prev];
717 while (grown.length < parsed) {
718 grown.push(createEmptyTraveler());
719 }
720 return grown;
721 });
722 setExpandedTravelers((prev) => prev.filter((i) => i < parsed));
723 };
724 const addTraveler = () => {
725 const newTraveler = createEmptyTraveler();
726 setTravelersData((prev) => [...prev, newTraveler]);
727 setFormData((prev) => ({
728 ...prev,
729 travelers: String(travelersData.length + 1)
730 }));
731 setExpandedTravelers((prev) => [...prev, travelersData.length]);
732 };
733 const removeTraveler = (index) => {
734 if (travelersData.length <= 1) return;
735 setTravelersData((prev) => prev.filter((_, i) => i !== index));
736 setFormData((prev) => ({
737 ...prev,
738 travelers: String(travelersData.length - 1)
739 }));
740 setExpandedTravelers(
741 (prev) => prev.filter((i) => i !== index).map((i) => i > index ? i - 1 : i)
742 );
743 };
744 const toggleTravelerExpanded = (index) => {
745 setExpandedTravelers(
746 (prev) => prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]
747 );
748 };
749 const validateForm = () => {
750 const newErrors = {};
751 if (!formData.customer_name.trim()) {
752 newErrors.customer_name = __("Customer name is required", "yatra");
753 }
754 if (!formData.customer_email.trim()) {
755 newErrors.customer_email = __("Customer email is required", "yatra");
756 } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.customer_email)) {
757 newErrors.customer_email = __("Invalid email address", "yatra");
758 }
759 if (!formData.trip_id) {
760 newErrors.trip_id = __("Trip is required", "yatra");
761 }
762 if (!formData.booking_date) {
763 newErrors.booking_date = __("Booking date is required", "yatra");
764 }
765 if (departureTimesForDate.length > 1 && !formData.departure_time) {
766 newErrors.departure_time = __("Departure time is required", "yatra");
767 }
768 if (!formData.travel_date) {
769 newErrors.travel_date = __("Travel date is required", "yatra");
770 }
771 if (!formData.travelers || parseInt(formData.travelers) < 1) {
772 newErrors.travelers = __(
773 "Number of travelers must be at least 1",
774 "yatra"
775 );
776 }
777 if (!formData.total_amount || parseFloat(formData.total_amount) <= 0) {
778 newErrors.total_amount = __(
779 "Total amount must be greater than 0",
780 "yatra"
781 );
782 }
783 setErrors(newErrors);
784 return Object.keys(newErrors).length === 0;
785 };
786 const saveMutation = useMutation({
787 mutationFn: async (data) => {
788 const nameParts = data.customer_name.trim().split(" ");
789 const firstName = nameParts[0] || "";
790 const lastName = nameParts.slice(1).join(" ") || "";
791 const payload = {
792 contact_first_name: firstName,
793 contact_last_name: lastName,
794 contact_email: data.customer_email.trim(),
795 contact_phone: data.customer_phone.trim(),
796 // contact_country column (previously not submitted, so edits were lost).
797 contact_country: data.customer_country || "",
798 trip_id: parseInt(data.trip_id),
799 travel_date: data.travel_date,
800 // Which departure the booking occupies. A trip running several
801 // departures a day counts capacity per (date, time), so a booking saved
802 // without this matches no slot and never reduces frontend availability.
803 departure_time: data.departure_time || "",
804 travelers_count: travelersData.length,
805 total_amount: parseFloat(data.total_amount),
806 payment_status: data.payment_status,
807 status: data.booking_status,
808 payment_gateway: data.payment_method.trim(),
809 special_requests: data.notes.trim(),
810 // Include travelers data - use 'travelers' key as expected by BookingService.updateBooking
811 travelers: travelersData,
812 // Include emergency contact data
813 emergency_contact: emergencyContactData,
814 // Full contact_data JSON: core fields + every extra/custom contact field,
815 // so admin edits round-trip and feed the {{contact_*}} email variables.
816 contact_data: {
817 first_name: firstName,
818 last_name: lastName,
819 email: data.customer_email.trim(),
820 phone: data.customer_phone.trim(),
821 country: data.customer_country || "",
822 ...contactExtraData
823 }
824 };
825 return isEditMode ? await apiService.updateBooking(bookingId, payload) : await apiService.createBooking(payload);
826 },
827 onSuccess: () => {
828 var _a2;
829 queryClient.invalidateQueries({ queryKey: ["bookings"] });
830 window.location.href = `${((_a2 = window.yatraAdmin) == null ? void 0 : _a2.siteUrl) || ""}/wp-admin/admin.php?page=yatra&subpage=bookings`;
831 },
832 onError: (error) => {
833 var _a2, _b2, _c2, _d2, _e2;
834 const validationErrors = ((_c2 = (_b2 = (_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.data) == null ? void 0 : _b2.data) == null ? void 0 : _c2.validation_errors) || ((_e2 = (_d2 = error == null ? void 0 : error.response) == null ? void 0 : _d2.data) == null ? void 0 : _e2.validation_errors);
835 const fieldErrors = {};
836 let detail = "";
837 if (validationErrors && typeof validationErrors === "object") {
838 for (const [field, messages] of Object.entries(validationErrors)) {
839 const msg = Array.isArray(messages) ? String(messages[0]) : String(messages);
840 fieldErrors[field] = msg;
841 detail = detail ? `${detail} ${msg}` : msg;
842 }
843 }
844 const errorMessage = detail || (error == null ? void 0 : error.message) || __("An error occurred while saving the booking", "yatra");
845 setErrors({ ...fieldErrors, submit: errorMessage });
846 setIsSubmitting(false);
847 }
848 });
849 const handleSubmit = async (e) => {
850 e.preventDefault();
851 if (!validateForm()) {
852 return;
853 }
854 setIsSubmitting(true);
855 setErrors({});
856 saveMutation.mutate(formData);
857 };
858 const handleCancel = () => {
859 var _a2;
860 window.location.href = `${((_a2 = window.yatraAdmin) == null ? void 0 : _a2.siteUrl) || ""}/wp-admin/admin.php?page=yatra&subpage=bookings`;
861 };
862 if (isEditMode && isLoadingBooking) {
863 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
864 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
865 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
866 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-8 w-48" }),
867 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-64" })
868 ] }),
869 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-24" })
870 ] }),
871 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-3", children: [
872 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:col-span-2 space-y-3", children: [
873 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
874 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-40" }) }),
875 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
876 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
877 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
878 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-24" }),
879 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
880 ] }),
881 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
882 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-24" }),
883 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
884 ] })
885 ] }),
886 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
887 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-28" }),
888 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
889 ] })
890 ] })
891 ] }),
892 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
893 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-32" }) }),
894 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
895 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
896 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-16" }),
897 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
898 ] }),
899 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
900 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
901 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-24" }),
902 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
903 ] }),
904 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
905 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-20" }),
906 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
907 ] })
908 ] }),
909 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
910 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
911 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-32" }),
912 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
913 ] }),
914 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
915 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-24" }),
916 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
917 ] })
918 ] }),
919 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
920 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-16" }),
921 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-20 w-full" })
922 ] })
923 ] })
924 ] })
925 ] }),
926 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
927 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
928 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-5 w-32" }) }),
929 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
930 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
931 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-24" }),
932 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
933 ] }),
934 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
935 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-28" }),
936 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
937 ] }),
938 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
939 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-28" }),
940 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-full" })
941 ] })
942 ] })
943 ] }),
944 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
945 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 flex-1" }),
946 /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-10 w-20" })
947 ] }) }) })
948 ] })
949 ] })
950 ] });
951 }
952 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
953 /* @__PURE__ */ jsxRuntimeExports.jsx(
954 PageHeader,
955 {
956 title: isEditMode ? __("Edit Booking", "yatra") : __("Create Booking", "yatra"),
957 description: isEditMode ? __("Update booking information", "yatra") : __("Create a new customer booking", "yatra"),
958 actions: /* @__PURE__ */ jsxRuntimeExports.jsxs(
959 Button,
960 {
961 variant: "outline",
962 onClick: handleCancel,
963 className: "flex items-center gap-2",
964 children: [
965 /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { className: "w-4 h-4" }),
966 __("Back", "yatra")
967 ]
968 }
969 )
970 }
971 ),
972 /* @__PURE__ */ jsxRuntimeExports.jsx(ConditionalRender, { capability: "yatra_edit_bookings", children: /* @__PURE__ */ jsxRuntimeExports.jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-3", children: [
973 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:col-span-2 space-y-3", children: [
974 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
975 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardTitle, { className: "text-base", children: __("Customer Information", "yatra") }) }),
976 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
977 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
978 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
979 /* @__PURE__ */ jsxRuntimeExports.jsxs(
980 "label",
981 {
982 htmlFor: "customer_name",
983 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
984 children: [
985 __("Customer Name", "yatra"),
986 " ",
987 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
988 ]
989 }
990 ),
991 /* @__PURE__ */ jsxRuntimeExports.jsx(
992 Input,
993 {
994 id: "customer_name",
995 type: "text",
996 value: formData.customer_name,
997 onChange: (e) => handleFieldChange("customer_name", e.target.value),
998 placeholder: __("Enter customer name", "yatra"),
999 className: errors.customer_name ? "border-red-500" : "",
1000 required: true
1001 }
1002 ),
1003 errors.customer_name && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.customer_name })
1004 ] }),
1005 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1006 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1007 "label",
1008 {
1009 htmlFor: "customer_email",
1010 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1011 children: [
1012 __("Customer Email", "yatra"),
1013 " ",
1014 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1015 ]
1016 }
1017 ),
1018 /* @__PURE__ */ jsxRuntimeExports.jsx(
1019 Input,
1020 {
1021 id: "customer_email",
1022 type: "email",
1023 value: formData.customer_email,
1024 onChange: (e) => handleFieldChange("customer_email", e.target.value),
1025 placeholder: __("[email protected]", "yatra"),
1026 className: errors.customer_email ? "border-red-500" : "",
1027 required: true
1028 }
1029 ),
1030 errors.customer_email && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.customer_email })
1031 ] })
1032 ] }),
1033 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1034 /* @__PURE__ */ jsxRuntimeExports.jsx(
1035 "label",
1036 {
1037 htmlFor: "customer_phone",
1038 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1039 children: __("Customer Phone", "yatra")
1040 }
1041 ),
1042 /* @__PURE__ */ jsxRuntimeExports.jsx(
1043 Input,
1044 {
1045 id: "customer_phone",
1046 type: "tel",
1047 value: formData.customer_phone,
1048 onChange: (e) => handleFieldChange("customer_phone", e.target.value),
1049 placeholder: __("+1234567890", "yatra")
1050 }
1051 )
1052 ] }),
1053 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1054 /* @__PURE__ */ jsxRuntimeExports.jsx(
1055 "label",
1056 {
1057 htmlFor: "customer_country",
1058 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1059 children: __("Country", "yatra")
1060 }
1061 ),
1062 /* @__PURE__ */ jsxRuntimeExports.jsx(
1063 SearchableSelect,
1064 {
1065 value: formData.customer_country,
1066 onChange: (v) => handleFieldChange("customer_country", v),
1067 options: countrySelectOptions,
1068 placeholder: __("Select country", "yatra"),
1069 searchPlaceholder: __("Search country", "yatra")
1070 }
1071 )
1072 ] }),
1073 contactExtraFields.map((field) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1074 "div",
1075 {
1076 className: field.width === "full" ? "md:col-span-2" : "",
1077 children: [
1078 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1079 "label",
1080 {
1081 htmlFor: `contact-${field.id}`,
1082 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1083 children: [
1084 field.label,
1085 field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
1086 ]
1087 }
1088 ),
1089 renderDynamicInput(
1090 field,
1091 contactExtraData[field.id] || "",
1092 (v) => handleContactExtraChange(field.id, v),
1093 "contact"
1094 )
1095 ]
1096 },
1097 field.id
1098 ))
1099 ] })
1100 ] }),
1101 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1102 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardTitle, { className: "text-base", children: __("Booking Details", "yatra") }) }),
1103 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
1104 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: tripDropdownRef, className: "relative", children: [
1105 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1106 "label",
1107 {
1108 htmlFor: "trip_search",
1109 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1110 children: [
1111 __("Trip", "yatra"),
1112 " ",
1113 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1114 ]
1115 }
1116 ),
1117 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
1118 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1119 "div",
1120 {
1121 className: `flex items-center border rounded-md bg-white dark:bg-gray-800 cursor-pointer ${errors.trip_id ? "border-red-500" : "border-gray-300 dark:border-gray-600"} ${isTripDropdownOpen ? "ring-2 ring-blue-500" : ""}`,
1122 onClick: () => setIsTripDropdownOpen(!isTripDropdownOpen),
1123 children: [
1124 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 px-3 py-2 text-sm", children: formData.trip_id ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-900 dark:text-white", children: ((_c = (_b = tripsData == null ? void 0 : tripsData.data) == null ? void 0 : _b.find(
1125 (t) => String(t.id) === formData.trip_id
1126 )) == null ? void 0 : _c.title) || (bookingData == null ? void 0 : bookingData.trip_title) || `Trip ID: ${formData.trip_id}` }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: isLoadingTrips ? __("Loading trips...", "yatra") : __("Select a trip", "yatra") }) }),
1127 formData.trip_id && /* @__PURE__ */ jsxRuntimeExports.jsx(
1128 "button",
1129 {
1130 type: "button",
1131 className: "p-2 text-gray-400 hover:text-gray-600",
1132 onClick: (e) => {
1133 e.stopPropagation();
1134 handleFieldChange("trip_id", "");
1135 setTripSearchQuery("");
1136 },
1137 children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-4 h-4" })
1138 }
1139 ),
1140 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 text-gray-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1141 ChevronDown,
1142 {
1143 className: `w-4 h-4 transition-transform ${isTripDropdownOpen ? "rotate-180" : ""}`
1144 }
1145 ) })
1146 ]
1147 }
1148 ),
1149 isTripDropdownOpen && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md shadow-lg max-h-60 overflow-hidden", children: [
1150 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
1151 /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "absolute left-2 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" }),
1152 /* @__PURE__ */ jsxRuntimeExports.jsx(
1153 "input",
1154 {
1155 type: "text",
1156 className: "w-full pl-8 pr-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500",
1157 placeholder: __("Search trips...", "yatra"),
1158 value: tripSearchQuery,
1159 onChange: (e) => setTripSearchQuery(e.target.value),
1160 onClick: (e) => e.stopPropagation(),
1161 autoFocus: true
1162 }
1163 )
1164 ] }) }),
1165 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-h-48 overflow-y-auto", children: (() => {
1166 let allTrips = [...(tripsData == null ? void 0 : tripsData.data) || []];
1167 if (isEditMode && (bookingData == null ? void 0 : bookingData.trip_id) && (bookingData == null ? void 0 : bookingData.trip_title)) {
1168 const bookedTripExists = allTrips.some(
1169 (t) => String(t.id) === String(bookingData.trip_id)
1170 );
1171 if (!bookedTripExists) {
1172 allTrips.unshift({
1173 id: bookingData.trip_id,
1174 title: bookingData.trip_title,
1175 price: bookingData.total_amount || 0,
1176 currency: globalCurrency,
1177 status: "publish"
1178 });
1179 }
1180 }
1181 const filteredTrips = allTrips.filter(
1182 (trip) => trip.title.toLowerCase().includes(tripSearchQuery.toLowerCase()) || String(trip.id).includes(tripSearchQuery)
1183 );
1184 if (filteredTrips.length === 0) {
1185 return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-4 text-sm text-gray-500 text-center", children: __("No trips found", "yatra") });
1186 }
1187 return filteredTrips.map((trip) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1188 "div",
1189 {
1190 className: `px-3 py-2 text-sm cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 ${formData.trip_id === String(trip.id) ? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-400" : "text-gray-900 dark:text-white"}`,
1191 onClick: () => {
1192 handleFieldChange(
1193 "trip_id",
1194 String(trip.id)
1195 );
1196 setIsTripDropdownOpen(false);
1197 setTripSearchQuery("");
1198 },
1199 children: [
1200 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: trip.title }),
1201 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [
1202 "ID: ",
1203 trip.id
1204 ] })
1205 ]
1206 },
1207 trip.id
1208 ));
1209 })() })
1210 ] })
1211 ] }),
1212 errors.trip_id && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.trip_id })
1213 ] }),
1214 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
1215 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1216 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1217 "label",
1218 {
1219 htmlFor: "booking_date",
1220 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1221 children: [
1222 __("Booking Date", "yatra"),
1223 " ",
1224 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1225 ]
1226 }
1227 ),
1228 /* @__PURE__ */ jsxRuntimeExports.jsx(
1229 DatePicker,
1230 {
1231 value: formData.booking_date,
1232 onChange: (value) => handleFieldChange("booking_date", value),
1233 placeholder: __("Select booking date", "yatra"),
1234 error: !!errors.booking_date
1235 }
1236 ),
1237 errors.booking_date && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.booking_date })
1238 ] }),
1239 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1240 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1241 "label",
1242 {
1243 htmlFor: "travel_date",
1244 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1245 children: [
1246 __("Travel Date", "yatra"),
1247 " ",
1248 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1249 ]
1250 }
1251 ),
1252 /* @__PURE__ */ jsxRuntimeExports.jsx(
1253 DatePicker,
1254 {
1255 value: formData.travel_date,
1256 onChange: (value) => {
1257 handleFieldChange("travel_date", value);
1258 handleFieldChange("departure_time", "");
1259 },
1260 placeholder: __("Select travel date", "yatra"),
1261 error: !!errors.travel_date
1262 }
1263 ),
1264 errors.travel_date && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.travel_date })
1265 ] }),
1266 departureTimesForDate.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1267 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1268 "label",
1269 {
1270 htmlFor: "departure_time",
1271 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1272 children: [
1273 __("Departure Time", "yatra"),
1274 " ",
1275 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1276 ]
1277 }
1278 ),
1279 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1280 "select",
1281 {
1282 id: "departure_time",
1283 name: "departure_time",
1284 value: formData.departure_time,
1285 onChange: (e) => handleFieldChange("departure_time", e.target.value),
1286 className: `w-full rounded-md border px-3 py-2 text-sm bg-white dark:bg-gray-800 dark:text-white ${errors.departure_time ? "border-red-500" : "border-gray-300 dark:border-gray-600"}`,
1287 required: true,
1288 children: [
1289 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: __("Select departure time", "yatra") }),
1290 departureTimesForDate.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: t, children: t }, t))
1291 ]
1292 }
1293 ),
1294 errors.departure_time ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.departure_time }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: __(
1295 "This date has several departures. Pick the one this booking is for so its seats are reserved.",
1296 "yatra"
1297 ) })
1298 ] })
1299 ] }),
1300 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
1301 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1302 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1303 "label",
1304 {
1305 htmlFor: "travelers",
1306 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1307 children: [
1308 __("Number of Travelers", "yatra"),
1309 " ",
1310 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1311 ]
1312 }
1313 ),
1314 /* @__PURE__ */ jsxRuntimeExports.jsx(
1315 Input,
1316 {
1317 id: "travelers",
1318 type: "number",
1319 min: "1",
1320 value: formData.travelers,
1321 onChange: (e) => handleTravelersCountChange(e.target.value),
1322 className: errors.travelers ? "border-red-500" : "",
1323 required: true
1324 }
1325 ),
1326 errors.travelers && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.travelers })
1327 ] }),
1328 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gray-50 dark:bg-gray-700/50 rounded-lg p-3 border border-gray-200 dark:border-gray-600", children: [
1329 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-medium text-gray-900 dark:text-white mb-2 text-sm", children: __("Pricing Breakdown", "yatra") }),
1330 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 text-sm", children: formData.subtotal ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1331 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
1332 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600 dark:text-gray-400", children: __("Subtotal", "yatra") }),
1333 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium text-gray-900 dark:text-white", children: [
1334 currencySymbol,
1335 parseFloat(formData.subtotal).toFixed(2)
1336 ] })
1337 ] }),
1338 (bookingData == null ? void 0 : bookingData.itinerary_costs_total) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
1339 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600 dark:text-gray-400", children: __("Itinerary Costs", "yatra") }),
1340 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium text-gray-900 dark:text-white", children: [
1341 getCurrencySymbol(
1342 formData.currency || globalCurrency
1343 ),
1344 bookingData.itinerary_costs_total.toFixed(2)
1345 ] })
1346 ] }),
1347 parseFloat(formData.tax_amount) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
1348 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600 dark:text-gray-400", children: __("Tax", "yatra") }),
1349 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium text-gray-900 dark:text-white", children: [
1350 currencySymbol,
1351 parseFloat(formData.tax_amount).toFixed(2)
1352 ] })
1353 ] }),
1354 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t pt-2 flex justify-between font-semibold", children: [
1355 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-900 dark:text-white", children: __("Total", "yatra") }),
1356 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-gray-900 dark:text-white", children: [
1357 getCurrencySymbol(
1358 formData.currency || globalCurrency
1359 ),
1360 formData.total_amount
1361 ] })
1362 ] })
1363 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-gray-500 dark:text-gray-400 py-2", children: __(
1364 "Select a trip and number of travelers to see pricing",
1365 "yatra"
1366 ) }) })
1367 ] }),
1368 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1369 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1370 "label",
1371 {
1372 htmlFor: "total_amount",
1373 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1374 children: [
1375 __("Total Amount", "yatra"),
1376 " (",
1377 formData.currency || globalCurrency,
1378 ")",
1379 " ",
1380 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
1381 ]
1382 }
1383 ),
1384 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
1385 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500", children: getCurrencySymbol(
1386 formData.currency || globalCurrency
1387 ) }),
1388 /* @__PURE__ */ jsxRuntimeExports.jsx(
1389 Input,
1390 {
1391 id: "total_amount",
1392 type: "number",
1393 step: "0.01",
1394 min: "0",
1395 value: formData.total_amount,
1396 onChange: (e) => handleFieldChange("total_amount", e.target.value),
1397 placeholder: "0.00",
1398 className: `pl-7 ${errors.total_amount ? "border-red-500" : ""}`,
1399 required: true
1400 }
1401 )
1402 ] }),
1403 errors.total_amount && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-sm text-red-500", children: errors.total_amount })
1404 ] })
1405 ] }),
1406 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1407 /* @__PURE__ */ jsxRuntimeExports.jsx(
1408 "label",
1409 {
1410 htmlFor: "notes",
1411 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1412 children: __("Notes", "yatra")
1413 }
1414 ),
1415 /* @__PURE__ */ jsxRuntimeExports.jsx(
1416 "textarea",
1417 {
1418 id: "notes",
1419 value: formData.notes,
1420 onChange: (e) => handleFieldChange("notes", e.target.value),
1421 placeholder: __(
1422 "Additional notes or special requests",
1423 "yatra"
1424 ),
1425 rows: 3,
1426 className: "flex w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:ring-offset-gray-900 dark:placeholder:text-gray-400 dark:focus-visible:ring-blue-400 resize-none"
1427 }
1428 )
1429 ] })
1430 ] })
1431 ] }),
1432 ((_d = formConfig == null ? void 0 : formConfig.emergency_contact_form) == null ? void 0 : _d.enabled) !== false && emergencyContactFields.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1433 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "pb-2", children: [
1434 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [
1435 /* @__PURE__ */ jsxRuntimeExports.jsx(AlertCircle, { className: "w-4 h-4" }),
1436 ((_e = formConfig == null ? void 0 : formConfig.emergency_contact_form) == null ? void 0 : _e.title) || __("Emergency Contact", "yatra")
1437 ] }),
1438 ((_f = formConfig == null ? void 0 : formConfig.emergency_contact_form) == null ? void 0 : _f.description) && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400 mt-1", children: formConfig.emergency_contact_form.description })
1439 ] }),
1440 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: emergencyContactFields.map((field) => {
1441 var _a2;
1442 return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1443 "div",
1444 {
1445 className: field.width === "full" ? "md:col-span-2" : "",
1446 children: [
1447 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1448 "label",
1449 {
1450 htmlFor: `emergency-${field.id}`,
1451 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",
1452 children: [
1453 field.label,
1454 field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
1455 ]
1456 }
1457 ),
1458 field.type === "select" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1459 Select,
1460 {
1461 id: `emergency-${field.id}`,
1462 value: emergencyContactData[field.id] || "",
1463 onChange: (e) => handleEmergencyContactChange(
1464 field.id,
1465 e.target.value
1466 ),
1467 children: [
1468 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
1469 (_a2 = field.options) == null ? void 0 : _a2.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value))
1470 ]
1471 }
1472 ) : field.type === "country" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1473 SearchableSelect,
1474 {
1475 value: emergencyContactData[field.id] || "",
1476 onChange: (v) => handleEmergencyContactChange(field.id, v),
1477 options: countrySelectOptions,
1478 placeholder: field.placeholder || __("Select Country", "yatra"),
1479 searchPlaceholder: __(
1480 "Search country",
1481 "yatra"
1482 )
1483 }
1484 ) : field.type === "textarea" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1485 "textarea",
1486 {
1487 id: `emergency-${field.id}`,
1488 value: emergencyContactData[field.id] || "",
1489 onChange: (e) => handleEmergencyContactChange(
1490 field.id,
1491 e.target.value
1492 ),
1493 placeholder: field.placeholder,
1494 rows: 2,
1495 className: "flex w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:placeholder:text-gray-400 resize-none"
1496 }
1497 ) : field.type === "checkbox" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 cursor-pointer", children: [
1498 /* @__PURE__ */ jsxRuntimeExports.jsx(
1499 "input",
1500 {
1501 type: "checkbox",
1502 className: "rounded border-gray-300",
1503 checked: emergencyContactData[field.id] === "1" || emergencyContactData[field.id] === "true",
1504 onChange: (e) => handleEmergencyContactChange(
1505 field.id,
1506 e.target.checked ? "1" : ""
1507 )
1508 }
1509 ),
1510 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field.placeholder || field.label })
1511 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1512 Input,
1513 {
1514 id: `emergency-${field.id}`,
1515 type: field.type === "email" ? "email" : field.type === "tel" ? "tel" : field.type === "date" ? "date" : field.type === "number" ? "number" : "text",
1516 value: emergencyContactData[field.id] || "",
1517 onChange: (e) => handleEmergencyContactChange(
1518 field.id,
1519 e.target.value
1520 ),
1521 placeholder: field.placeholder
1522 }
1523 )
1524 ]
1525 },
1526 field.id
1527 );
1528 }) }) })
1529 ] }),
1530 ((_g = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _g.enabled) !== false && travelerFields.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1531 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "pb-2", children: [
1532 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
1533 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [
1534 /* @__PURE__ */ jsxRuntimeExports.jsx(Users, { className: "w-4 h-4" }),
1535 ((_h = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _h.title) || __("Travelers Information", "yatra"),
1536 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-normal text-gray-500 dark:text-gray-400", children: [
1537 "(",
1538 travelersData.length,
1539 " ",
1540 travelersData.length === 1 ? __("traveler", "yatra") : __("travelers", "yatra"),
1541 ")"
1542 ] })
1543 ] }),
1544 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1545 travelersData.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
1546 Button,
1547 {
1548 type: "button",
1549 variant: "ghost",
1550 size: "sm",
1551 onClick: () => setExpandedTravelers(
1552 expandedTravelers.length === travelersData.length ? [] : travelersData.map((_, i) => i)
1553 ),
1554 className: "text-gray-500 text-xs",
1555 children: expandedTravelers.length === travelersData.length ? __("Collapse All", "yatra") : __("Expand All", "yatra")
1556 }
1557 ),
1558 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1559 Button,
1560 {
1561 type: "button",
1562 variant: "outline",
1563 size: "sm",
1564 onClick: addTraveler,
1565 className: "flex items-center gap-1",
1566 children: [
1567 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "w-3 h-3" }),
1568 __("Add Traveler", "yatra")
1569 ]
1570 }
1571 )
1572 ] })
1573 ] }),
1574 ((_i = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _i.description) && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400 mt-1", children: formConfig.traveler_form.description })
1575 ] }),
1576 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "space-y-3", children: travelersData.map((traveler, travelerIndex) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1577 "div",
1578 {
1579 className: `border rounded-lg ${travelerIndex === 0 ? "border-blue-200 dark:border-blue-800 bg-blue-50/50 dark:bg-blue-900/10" : "border-gray-200 dark:border-gray-700"}`,
1580 children: [
1581 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1582 "div",
1583 {
1584 className: "flex items-center justify-between p-3 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800/50 rounded-t-lg",
1585 onClick: () => toggleTravelerExpanded(travelerIndex),
1586 children: [
1587 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
1588 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-sm text-gray-900 dark:text-white whitespace-nowrap", children: travelerIndex === 0 ? __("Lead Traveler", "yatra") : `${__("Traveler", "yatra")} ${travelerIndex + 1}` }),
1589 traveler.first_name || traveler.last_name ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400 truncate", children: [
1590 "-",
1591 " ",
1592 [traveler.first_name, traveler.last_name].filter(Boolean).join(" ")
1593 ] }) : null,
1594 travelerIndex === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300 px-2 py-0.5 rounded whitespace-nowrap", children: __("Primary", "yatra") })
1595 ] }),
1596 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 ml-2", children: [
1597 travelersData.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1598 Button,
1599 {
1600 type: "button",
1601 variant: "ghost",
1602 size: "sm",
1603 onClick: (e) => {
1604 e.stopPropagation();
1605 removeTraveler(travelerIndex);
1606 },
1607 className: "text-red-500 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-900/20 h-8 px-2 flex items-center gap-1",
1608 title: __("Remove Traveler", "yatra"),
1609 children: [
1610 /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "w-4 h-4" }),
1611 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs hidden sm:inline", children: __("Remove", "yatra") })
1612 ]
1613 }
1614 ),
1615 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6 h-6 flex items-center justify-center", children: expandedTravelers.includes(travelerIndex) ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { className: "w-4 h-4 text-gray-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "w-4 h-4 text-gray-500" }) })
1616 ] })
1617 ]
1618 }
1619 ),
1620 expandedTravelers.includes(travelerIndex) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 pt-0 border-t border-gray-100 dark:border-gray-700/50", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 mt-3", children: travelerFields.filter(
1621 (field) => (field.applies_to ?? "all") !== "lead" || travelerIndex === 0
1622 ).map((field) => {
1623 var _a2;
1624 return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1625 "div",
1626 {
1627 className: field.width === "full" ? "md:col-span-2" : "",
1628 children: [
1629 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1630 "label",
1631 {
1632 htmlFor: `traveler-${travelerIndex}-${field.id}`,
1633 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",
1634 children: [
1635 field.label,
1636 field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
1637 ]
1638 }
1639 ),
1640 field.type === "select" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1641 Select,
1642 {
1643 id: `traveler-${travelerIndex}-${field.id}`,
1644 value: traveler[field.id] || "",
1645 onChange: (e) => handleTravelerChange(
1646 travelerIndex,
1647 field.id,
1648 e.target.value
1649 ),
1650 children: [
1651 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
1652 (_a2 = field.options) == null ? void 0 : _a2.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1653 "option",
1654 {
1655 value: opt.value,
1656 children: opt.label
1657 },
1658 opt.value
1659 ))
1660 ]
1661 }
1662 ) : field.type === "country" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1663 SearchableSelect,
1664 {
1665 value: traveler[field.id] || "",
1666 onChange: (v) => handleTravelerChange(
1667 travelerIndex,
1668 field.id,
1669 v
1670 ),
1671 options: countrySelectOptions,
1672 placeholder: field.placeholder || __("Select Country", "yatra"),
1673 searchPlaceholder: __(
1674 "Search country",
1675 "yatra"
1676 )
1677 }
1678 ) : field.type === "textarea" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1679 "textarea",
1680 {
1681 id: `traveler-${travelerIndex}-${field.id}`,
1682 value: traveler[field.id] || "",
1683 onChange: (e) => handleTravelerChange(
1684 travelerIndex,
1685 field.id,
1686 e.target.value
1687 ),
1688 placeholder: field.placeholder,
1689 rows: 2,
1690 className: "flex w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:placeholder:text-gray-400 resize-none"
1691 }
1692 ) : field.type === "checkbox" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 cursor-pointer", children: [
1693 /* @__PURE__ */ jsxRuntimeExports.jsx(
1694 "input",
1695 {
1696 type: "checkbox",
1697 className: "rounded border-gray-300",
1698 checked: traveler[field.id] === "1" || traveler[field.id] === "true",
1699 onChange: (e) => handleTravelerChange(
1700 travelerIndex,
1701 field.id,
1702 e.target.checked ? "1" : ""
1703 )
1704 }
1705 ),
1706 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field.placeholder || field.label })
1707 ] }) : field.type === "date" || field.id.toLowerCase().includes("date") || field.id.toLowerCase().includes("expiry") ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1708 DatePicker,
1709 {
1710 value: traveler[field.id] || "",
1711 onChange: (value) => handleTravelerChange(
1712 travelerIndex,
1713 field.id,
1714 value
1715 ),
1716 placeholder: field.placeholder || __("Select date", "yatra")
1717 }
1718 ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1719 Input,
1720 {
1721 id: `traveler-${travelerIndex}-${field.id}`,
1722 type: field.type === "email" ? "email" : field.type === "tel" ? "tel" : field.type === "number" ? "number" : "text",
1723 value: traveler[field.id] || "",
1724 onChange: (e) => handleTravelerChange(
1725 travelerIndex,
1726 field.id,
1727 e.target.value
1728 ),
1729 placeholder: field.placeholder
1730 }
1731 )
1732 ]
1733 },
1734 field.id
1735 );
1736 }) }) })
1737 ]
1738 },
1739 travelerIndex
1740 )) })
1741 ] })
1742 ] }),
1743 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
1744 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1745 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardTitle, { className: "text-base", children: __("Status & Payment", "yatra") }) }),
1746 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
1747 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1748 /* @__PURE__ */ jsxRuntimeExports.jsx(
1749 "label",
1750 {
1751 htmlFor: "booking_status",
1752 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1753 children: __("Booking Status", "yatra")
1754 }
1755 ),
1756 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1757 Select,
1758 {
1759 id: "booking_status",
1760 value: formData.booking_status,
1761 onChange: (e) => handleFieldChange("booking_status", e.target.value),
1762 children: [
1763 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pending", children: __("Pending", "yatra") }),
1764 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "confirmed", children: __("Confirmed", "yatra") }),
1765 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "cancelled", children: __("Cancelled", "yatra") }),
1766 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "completed", children: __("Completed", "yatra") }),
1767 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "refunded", children: __("Refunded", "yatra") }),
1768 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "failed", children: __("Failed", "yatra") })
1769 ]
1770 }
1771 )
1772 ] }),
1773 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1774 /* @__PURE__ */ jsxRuntimeExports.jsx(
1775 "label",
1776 {
1777 htmlFor: "payment_status",
1778 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1779 children: __("Payment Status", "yatra")
1780 }
1781 ),
1782 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1783 Select,
1784 {
1785 id: "payment_status",
1786 value: formData.payment_status,
1787 onChange: (e) => handleFieldChange("payment_status", e.target.value),
1788 children: [
1789 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pending", children: __("Pending", "yatra") }),
1790 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "partial", children: __("Partial", "yatra") }),
1791 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "paid", children: __("Paid", "yatra") }),
1792 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "refunded", children: __("Refunded", "yatra") })
1793 ]
1794 }
1795 )
1796 ] }),
1797 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1798 /* @__PURE__ */ jsxRuntimeExports.jsx(
1799 "label",
1800 {
1801 htmlFor: "payment_method",
1802 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1803 children: __("Payment Method", "yatra")
1804 }
1805 ),
1806 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1807 Select,
1808 {
1809 id: "payment_method",
1810 value: formData.payment_method,
1811 onChange: (e) => handleFieldChange("payment_method", e.target.value),
1812 children: [
1813 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: __("Select payment method", "yatra") }),
1814 (_j = gatewaysData == null ? void 0 : gatewaysData.data) == null ? void 0 : _j.map((gw) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: gw.id, children: gw.title }, gw.id)),
1815 (!(gatewaysData == null ? void 0 : gatewaysData.data) || gatewaysData.data.length === 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1816 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pay_later", children: __("Pay Later", "yatra") }),
1817 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "bank_transfer", children: __("Bank Transfer", "yatra") }),
1818 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "stripe", children: __("Stripe", "yatra") }),
1819 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "paypal", children: __("PayPal", "yatra") })
1820 ] })
1821 ]
1822 }
1823 )
1824 ] })
1825 ] })
1826 ] }),
1827 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1828 errors.submit && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 text-sm text-red-500 bg-red-50 dark:bg-red-900/20 rounded-md", children: errors.submit }),
1829 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1830 /* @__PURE__ */ jsxRuntimeExports.jsx(
1831 Button,
1832 {
1833 type: "submit",
1834 disabled: isSubmitting,
1835 className: "flex-1 flex items-center justify-center gap-2",
1836 children: isSubmitting ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1837 /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-4 h-4 animate-spin" }),
1838 __("Saving...", "yatra")
1839 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1840 /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { className: "w-4 h-4" }),
1841 isEditMode ? __("Update Booking", "yatra") : __("Create Booking", "yatra")
1842 ] })
1843 }
1844 ),
1845 /* @__PURE__ */ jsxRuntimeExports.jsx(
1846 Button,
1847 {
1848 type: "button",
1849 variant: "outline",
1850 onClick: handleCancel,
1851 disabled: isSubmitting,
1852 children: __("Cancel", "yatra")
1853 }
1854 )
1855 ] })
1856 ] }) }) })
1857 ] })
1858 ] }) }) })
1859 ] });
1860 };
1861 export {
1862 BookingForm as default
1863 };
1864 //# sourceMappingURL=BookingForm-hQVneAfI.js.map
1865