PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.14.1
Yatra – Travel Booking & Tour Operator Software v3.0.14.1
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-DkL1nwFO.js

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

1,862 lines 90.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { t as useQueryClient, r as reactExports, u as useQuery, a5 as React, v as useMutation, j as jsxRuntimeExports, z as ArrowLeft, ax as X, x as ChevronDown, aO as Search, az as AlertCircle, U as Users, aw as Plus, aN as Trash2, bc as ChevronUp, D as Loader2, aV as Save } from "./react-vendor-xzSqHjRF.js";
2 import { 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-CbMRo6lO.js";
3 import { u as usePermissions, N as Skeleton, C as Card, f as CardHeader, d as CardContent, P as PageHeader, B as Button, r 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 response = await fetch("/wp-json/yatra/v1/settings");
20 const settings = await response.json();
21 this.taxSettings = settings;
22 } catch (error) {
23 console.error("Failed to load tax settings:", error);
24 }
25 }
26 /**
27 * Get tax settings
28 */
29 getTaxSettings() {
30 return this.taxSettings;
31 }
32 /**
33 * Check if tax is enabled
34 */
35 isTaxEnabled() {
36 var _a;
37 return ((_a = this.taxSettings) == null ? void 0 : _a.enable_tax) === true;
38 }
39 /**
40 * Calculate tax for booking
41 */
42 calculateTax(amount, country) {
43 var _a, _b;
44 if (!this.isTaxEnabled()) {
45 return {
46 tax_amount: 0,
47 tax_rate: 0,
48 tax_inclusive: false,
49 taxes: []
50 };
51 }
52 const taxInclusive = ((_a = this.taxSettings) == null ? void 0 : _a.tax_inclusive) === true;
53 const multipleTaxesEnabled = ((_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes_enabled) === true;
54 if (multipleTaxesEnabled) {
55 return this.calculateMultipleTaxes(amount, country, taxInclusive);
56 } else {
57 return this.calculateSingleTax(amount, country, taxInclusive);
58 }
59 }
60 /**
61 * Calculate single tax (backward compatibility)
62 */
63 calculateSingleTax(amount, country, taxInclusive = false) {
64 var _a, _b, _c, _d, _e, _f;
65 let taxRate = ((_a = this.taxSettings) == null ? void 0 : _a.tax_rate) || 0;
66 const taxName = ((_b = this.taxSettings) == null ? void 0 : _b.tax_name) || ((_c = this.taxSettings) == null ? void 0 : _c.tax_label) || "Tax";
67 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])) {
68 taxRate = this.taxSettings.tax_rates[country];
69 }
70 let taxAmount;
71 if (taxInclusive) {
72 taxAmount = amount - amount / (1 + taxRate / 100);
73 } else {
74 taxAmount = amount * (taxRate / 100);
75 }
76 return {
77 tax_amount: Math.round(taxAmount * 100) / 100,
78 tax_rate: taxRate,
79 tax_inclusive: taxInclusive,
80 taxes: [
81 {
82 name: taxName,
83 rate: taxRate,
84 amount: Math.round(taxAmount * 100) / 100
85 }
86 ]
87 };
88 }
89 /**
90 * Calculate multiple taxes
91 */
92 calculateMultipleTaxes(amount, country, taxInclusive = false) {
93 var _a, _b, _c;
94 let taxes = ((_a = this.taxSettings) == null ? void 0 : _a.multiple_taxes) || [];
95 if (country && ((_c = (_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes_by_country) == null ? void 0 : _c[country])) {
96 taxes = this.taxSettings.multiple_taxes_by_country[country];
97 }
98 const calculatedTaxes = [];
99 let totalTaxAmount = 0;
100 for (const tax of taxes) {
101 const taxRate = tax.rate || 0;
102 const taxName = tax.name || "Tax";
103 let taxAmount;
104 if (taxInclusive) {
105 const baseAmount = amount - totalTaxAmount;
106 taxAmount = baseAmount * (taxRate / 100);
107 } else {
108 taxAmount = amount * (taxRate / 100);
109 }
110 taxAmount = Math.round(taxAmount * 100) / 100;
111 totalTaxAmount += taxAmount;
112 calculatedTaxes.push({
113 name: taxName,
114 rate: taxRate,
115 amount: taxAmount
116 });
117 }
118 return {
119 tax_amount: Math.round(totalTaxAmount * 100) / 100,
120 tax_rate: taxes.reduce(
121 (sum, tax) => sum + (tax.rate || 0),
122 0
123 ),
124 tax_inclusive: taxInclusive,
125 taxes: calculatedTaxes
126 };
127 }
128 /**
129 * Calculate complete booking tax breakdown
130 */
131 calculateBookingTax(subtotal, country) {
132 const taxDetails = this.calculateTax(subtotal, country);
133 let finalSubtotal;
134 let finalTotal;
135 if (taxDetails.tax_inclusive) {
136 finalSubtotal = subtotal - taxDetails.tax_amount;
137 finalTotal = subtotal;
138 } else {
139 finalSubtotal = subtotal;
140 finalTotal = subtotal + taxDetails.tax_amount;
141 }
142 const formattedTaxes = taxDetails.taxes.map((tax) => ({
143 ...tax,
144 formatted_amount: this.formatPrice(tax.amount),
145 formatted_rate: `${tax.rate.toFixed(2)}%`
146 }));
147 const taxBreakdown = formattedTaxes.map(
148 (tax) => `${tax.name} (${tax.formatted_rate}): ${tax.formatted_amount}`
149 ).join("\n");
150 return {
151 subtotal: Math.round(finalSubtotal * 100) / 100,
152 tax_amount: taxDetails.tax_amount,
153 total_amount: Math.round(finalTotal * 100) / 100,
154 tax_rate: taxDetails.tax_rate,
155 tax_inclusive: taxDetails.tax_inclusive,
156 taxes: formattedTaxes,
157 tax_breakdown: taxBreakdown
158 };
159 }
160 /**
161 * Format price display
162 */
163 formatPrice(amount) {
164 var _a;
165 const currency = ((_a = this.taxSettings) == null ? void 0 : _a.currency) || "USD";
166 return formatYatraMoney(Number(amount) || 0, currency, {
167 zeroAsUnknown: false
168 });
169 }
170 /**
171 * Get currency symbol
172 */
173 getCurrencySymbol(currency) {
174 const symbols = {
175 USD: "$",
176 EUR: "€",
177 GBP: "£",
178 JPY: "¥",
179 AUD: "A$",
180 CAD: "C$",
181 CHF: "CHF",
182 CNY: "¥",
183 INR: "₹"
184 };
185 return symbols[currency] || currency;
186 }
187 /**
188 * Get tax breakdown for display
189 */
190 getTaxBreakdown(taxDetails) {
191 return taxDetails.taxes.map((tax) => ({
192 name: tax.name,
193 rate: tax.rate,
194 amount: tax.amount,
195 formatted_amount: this.formatPrice(tax.amount),
196 formatted_rate: `${tax.rate.toFixed(2)}%`,
197 formatted_line: `${tax.name} (${tax.rate.toFixed(2)}%): ${this.formatPrice(tax.amount)}`
198 }));
199 }
200 /**
201 * Format tax display for booking summary
202 */
203 formatTaxDisplay(taxDetails) {
204 const breakdown = this.getTaxBreakdown(taxDetails);
205 return breakdown.map((tax) => tax.formatted_line).join("\n");
206 }
207 /**
208 * Validate tax configuration
209 */
210 validateTaxConfiguration() {
211 var _a, _b, _c, _d;
212 const errors = [];
213 if (!this.isTaxEnabled()) {
214 return { valid: true, errors: [] };
215 }
216 const multipleTaxesEnabled = ((_a = this.taxSettings) == null ? void 0 : _a.multiple_taxes_enabled) === true;
217 if (multipleTaxesEnabled) {
218 const multipleTaxes = ((_b = this.taxSettings) == null ? void 0 : _b.multiple_taxes) || [];
219 if (multipleTaxes.length === 0) {
220 errors.push("At least one tax must be configured");
221 }
222 let totalRate = 0;
223 for (let i = 0; i < multipleTaxes.length; i++) {
224 const tax = multipleTaxes[i];
225 if (!tax.name || tax.name.trim() === "") {
226 errors.push(`Tax ${i + 1}: Name is required`);
227 }
228 if (typeof tax.rate !== "number" || tax.rate < 0 || tax.rate > 100) {
229 errors.push(`Tax ${i + 1}: Rate must be between 0 and 100`);
230 } else {
231 totalRate += tax.rate;
232 }
233 }
234 if (totalRate > 100) {
235 errors.push("Total tax rate cannot exceed 100%");
236 }
237 } else {
238 const taxRate = ((_c = this.taxSettings) == null ? void 0 : _c.tax_rate) || 0;
239 const taxName = ((_d = this.taxSettings) == null ? void 0 : _d.tax_name) || "";
240 if (typeof taxRate !== "number" || taxRate < 0 || taxRate > 100) {
241 errors.push("Tax rate must be between 0 and 100");
242 }
243 if (!taxName || taxName.trim() === "") {
244 errors.push("Tax name is required");
245 }
246 }
247 return {
248 valid: errors.length === 0,
249 errors
250 };
251 }
252 /**
253 * Get tax summary for reporting
254 */
255 getTaxSummary(bookings) {
256 const summary = {
257 total_tax_collected: 0,
258 total_bookings_with_tax: 0,
259 tax_breakdown: {},
260 average_tax_rate: 0
261 };
262 let totalTaxRate = 0;
263 let taxRateCount = 0;
264 for (const booking of bookings) {
265 const taxAmount = booking.tax_amount || 0;
266 if (taxAmount > 0) {
267 summary.total_tax_collected += taxAmount;
268 summary.total_bookings_with_tax++;
269 const taxRate = booking.tax_rate || 0;
270 if (taxRate > 0) {
271 totalTaxRate += taxRate;
272 taxRateCount++;
273 }
274 const taxBreakdown = booking.tax_breakdown || [];
275 for (const tax of taxBreakdown) {
276 const taxName = tax.name;
277 if (!summary.tax_breakdown[taxName]) {
278 summary.tax_breakdown[taxName] = {
279 name: taxName,
280 total_amount: 0,
281 count: 0,
282 average_rate: 0
283 };
284 }
285 summary.tax_breakdown[taxName].total_amount += tax.amount;
286 summary.tax_breakdown[taxName].count++;
287 summary.tax_breakdown[taxName].average_rate += tax.rate;
288 }
289 }
290 }
291 if (taxRateCount > 0) {
292 summary.average_tax_rate = totalTaxRate / taxRateCount;
293 }
294 for (const taxName in summary.tax_breakdown) {
295 const taxData = summary.tax_breakdown[taxName];
296 if (taxData.count > 0) {
297 taxData.average_rate = taxData.average_rate / taxData.count;
298 }
299 }
300 return summary;
301 }
302 }
303 const taxService = TaxService.getInstance();
304 const countrySelectOptions = getCountrySelectOptions();
305 const CORE_CONTACT_IDS = [
306 "first_name",
307 "last_name",
308 "email",
309 "phone",
310 "country"
311 ];
312 const normalizeDateInput = (value) => {
313 if (!value) return "";
314 return formatDateForInput(value) || value;
315 };
316 const BookingForm = () => {
317 var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
318 const queryClient = useQueryClient();
319 const { can } = usePermissions();
320 const globalCurrency = ((_a = window == null ? void 0 : window.yatraAdmin) == null ? void 0 : _a.currency) || "USD";
321 const currencySymbol = getCurrencySymbol(globalCurrency);
322 const [formData, setFormData] = reactExports.useState({
323 customer_name: "",
324 customer_email: "",
325 customer_phone: "",
326 customer_country: "",
327 trip_id: "",
328 booking_date: todayYmd(),
329 travel_date: "",
330 departure_time: "",
331 travelers: "1",
332 subtotal: "",
333 tax_amount: "",
334 total_amount: "",
335 currency: globalCurrency,
336 payment_status: "pending",
337 booking_status: "pending",
338 payment_method: "",
339 notes: ""
340 });
341 const [travelersData, setTravelersData] = reactExports.useState([{}]);
342 const [expandedTravelers, setExpandedTravelers] = reactExports.useState([0]);
343 const [emergencyContactData, setEmergencyContactData] = reactExports.useState({});
344 const [contactExtraData, setContactExtraData] = reactExports.useState({});
345 const [errors, setErrors] = reactExports.useState({});
346 const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
347 const [tripSearchQuery, setTripSearchQuery] = reactExports.useState("");
348 const [isTripDropdownOpen, setIsTripDropdownOpen] = reactExports.useState(false);
349 const tripDropdownRef = reactExports.useRef(null);
350 reactExports.useEffect(() => {
351 const handleClickOutside = (event) => {
352 if (tripDropdownRef.current && !tripDropdownRef.current.contains(event.target)) {
353 setIsTripDropdownOpen(false);
354 }
355 };
356 document.addEventListener("mousedown", handleClickOutside);
357 return () => document.removeEventListener("mousedown", handleClickOutside);
358 }, []);
359 const { data: formConfig } = useQuery({
360 queryKey: ["booking-form-config"],
361 queryFn: async () => {
362 var _a2;
363 const response = await apiService.getSettings();
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: __("Search country", "yatra")
1480 }
1481 ) : field.type === "textarea" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1482 "textarea",
1483 {
1484 id: `emergency-${field.id}`,
1485 value: emergencyContactData[field.id] || "",
1486 onChange: (e) => handleEmergencyContactChange(
1487 field.id,
1488 e.target.value
1489 ),
1490 placeholder: field.placeholder,
1491 rows: 2,
1492 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"
1493 }
1494 ) : 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: [
1495 /* @__PURE__ */ jsxRuntimeExports.jsx(
1496 "input",
1497 {
1498 type: "checkbox",
1499 className: "rounded border-gray-300",
1500 checked: emergencyContactData[field.id] === "1" || emergencyContactData[field.id] === "true",
1501 onChange: (e) => handleEmergencyContactChange(
1502 field.id,
1503 e.target.checked ? "1" : ""
1504 )
1505 }
1506 ),
1507 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field.placeholder || field.label })
1508 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1509 Input,
1510 {
1511 id: `emergency-${field.id}`,
1512 type: field.type === "email" ? "email" : field.type === "tel" ? "tel" : field.type === "date" ? "date" : field.type === "number" ? "number" : "text",
1513 value: emergencyContactData[field.id] || "",
1514 onChange: (e) => handleEmergencyContactChange(
1515 field.id,
1516 e.target.value
1517 ),
1518 placeholder: field.placeholder
1519 }
1520 )
1521 ]
1522 },
1523 field.id
1524 );
1525 }) }) })
1526 ] }),
1527 ((_g = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _g.enabled) !== false && travelerFields.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1528 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "pb-2", children: [
1529 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
1530 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [
1531 /* @__PURE__ */ jsxRuntimeExports.jsx(Users, { className: "w-4 h-4" }),
1532 ((_h = formConfig == null ? void 0 : formConfig.traveler_form) == null ? void 0 : _h.title) || __("Travelers Information", "yatra"),
1533 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-normal text-gray-500 dark:text-gray-400", children: [
1534 "(",
1535 travelersData.length,
1536 " ",
1537 travelersData.length === 1 ? __("traveler", "yatra") : __("travelers", "yatra"),
1538 ")"
1539 ] })
1540 ] }),
1541 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1542 travelersData.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
1543 Button,
1544 {
1545 type: "button",
1546 variant: "ghost",
1547 size: "sm",
1548 onClick: () => setExpandedTravelers(
1549 expandedTravelers.length === travelersData.length ? [] : travelersData.map((_, i) => i)
1550 ),
1551 className: "text-gray-500 text-xs",
1552 children: expandedTravelers.length === travelersData.length ? __("Collapse All", "yatra") : __("Expand All", "yatra")
1553 }
1554 ),
1555 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1556 Button,
1557 {
1558 type: "button",
1559 variant: "outline",
1560 size: "sm",
1561 onClick: addTraveler,
1562 className: "flex items-center gap-1",
1563 children: [
1564 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "w-3 h-3" }),
1565 __("Add Traveler", "yatra")
1566 ]
1567 }
1568 )
1569 ] })
1570 ] }),
1571 ((_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 })
1572 ] }),
1573 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "space-y-3", children: travelersData.map((traveler, travelerIndex) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
1574 "div",
1575 {
1576 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"}`,
1577 children: [
1578 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1579 "div",
1580 {
1581 className: "flex items-center justify-between p-3 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800/50 rounded-t-lg",
1582 onClick: () => toggleTravelerExpanded(travelerIndex),
1583 children: [
1584 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
1585 /* @__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}` }),
1586 traveler.first_name || traveler.last_name ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm text-gray-500 dark:text-gray-400 truncate", children: [
1587 "-",
1588 " ",
1589 [traveler.first_name, traveler.last_name].filter(Boolean).join(" ")
1590 ] }) : null,
1591 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") })
1592 ] }),
1593 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 ml-2", children: [
1594 travelersData.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1595 Button,
1596 {
1597 type: "button",
1598 variant: "ghost",
1599 size: "sm",
1600 onClick: (e) => {
1601 e.stopPropagation();
1602 removeTraveler(travelerIndex);
1603 },
1604 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",
1605 title: __("Remove Traveler", "yatra"),
1606 children: [
1607 /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "w-4 h-4" }),
1608 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs hidden sm:inline", children: __("Remove", "yatra") })
1609 ]
1610 }
1611 ),
1612 /* @__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" }) })
1613 ] })
1614 ]
1615 }
1616 ),
1617 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(
1618 (field) => (field.applies_to ?? "all") !== "lead" || travelerIndex === 0
1619 ).map((field) => {
1620 var _a2;
1621 return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1622 "div",
1623 {
1624 className: field.width === "full" ? "md:col-span-2" : "",
1625 children: [
1626 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1627 "label",
1628 {
1629 htmlFor: `traveler-${travelerIndex}-${field.id}`,
1630 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",
1631 children: [
1632 field.label,
1633 field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500 ml-1", children: "*" })
1634 ]
1635 }
1636 ),
1637 field.type === "select" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
1638 Select,
1639 {
1640 id: `traveler-${travelerIndex}-${field.id}`,
1641 value: traveler[field.id] || "",
1642 onChange: (e) => handleTravelerChange(
1643 travelerIndex,
1644 field.id,
1645 e.target.value
1646 ),
1647 children: [
1648 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
1649 (_a2 = field.options) == null ? void 0 : _a2.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
1650 "option",
1651 {
1652 value: opt.value,
1653 children: opt.label
1654 },
1655 opt.value
1656 ))
1657 ]
1658 }
1659 ) : field.type === "country" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1660 SearchableSelect,
1661 {
1662 value: traveler[field.id] || "",
1663 onChange: (v) => handleTravelerChange(
1664 travelerIndex,
1665 field.id,
1666 v
1667 ),
1668 options: countrySelectOptions,
1669 placeholder: field.placeholder || __("Select Country", "yatra"),
1670 searchPlaceholder: __(
1671 "Search country",
1672 "yatra"
1673 )
1674 }
1675 ) : field.type === "textarea" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1676 "textarea",
1677 {
1678 id: `traveler-${travelerIndex}-${field.id}`,
1679 value: traveler[field.id] || "",
1680 onChange: (e) => handleTravelerChange(
1681 travelerIndex,
1682 field.id,
1683 e.target.value
1684 ),
1685 placeholder: field.placeholder,
1686 rows: 2,
1687 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"
1688 }
1689 ) : 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: [
1690 /* @__PURE__ */ jsxRuntimeExports.jsx(
1691 "input",
1692 {
1693 type: "checkbox",
1694 className: "rounded border-gray-300",
1695 checked: traveler[field.id] === "1" || traveler[field.id] === "true",
1696 onChange: (e) => handleTravelerChange(
1697 travelerIndex,
1698 field.id,
1699 e.target.checked ? "1" : ""
1700 )
1701 }
1702 ),
1703 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: field.placeholder || field.label })
1704 ] }) : field.type === "date" || field.id.toLowerCase().includes("date") || field.id.toLowerCase().includes("expiry") ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1705 DatePicker,
1706 {
1707 value: traveler[field.id] || "",
1708 onChange: (value) => handleTravelerChange(
1709 travelerIndex,
1710 field.id,
1711 value
1712 ),
1713 placeholder: field.placeholder || __("Select date", "yatra")
1714 }
1715 ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
1716 Input,
1717 {
1718 id: `traveler-${travelerIndex}-${field.id}`,
1719 type: field.type === "email" ? "email" : field.type === "tel" ? "tel" : field.type === "number" ? "number" : "text",
1720 value: traveler[field.id] || "",
1721 onChange: (e) => handleTravelerChange(
1722 travelerIndex,
1723 field.id,
1724 e.target.value
1725 ),
1726 placeholder: field.placeholder
1727 }
1728 )
1729 ]
1730 },
1731 field.id
1732 );
1733 }) }) })
1734 ]
1735 },
1736 travelerIndex
1737 )) })
1738 ] })
1739 ] }),
1740 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
1741 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { children: [
1742 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardTitle, { className: "text-base", children: __("Status & Payment", "yatra") }) }),
1743 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-3", children: [
1744 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1745 /* @__PURE__ */ jsxRuntimeExports.jsx(
1746 "label",
1747 {
1748 htmlFor: "booking_status",
1749 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1750 children: __("Booking Status", "yatra")
1751 }
1752 ),
1753 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1754 Select,
1755 {
1756 id: "booking_status",
1757 value: formData.booking_status,
1758 onChange: (e) => handleFieldChange("booking_status", e.target.value),
1759 children: [
1760 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pending", children: __("Pending", "yatra") }),
1761 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "confirmed", children: __("Confirmed", "yatra") }),
1762 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "cancelled", children: __("Cancelled", "yatra") }),
1763 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "completed", children: __("Completed", "yatra") }),
1764 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "refunded", children: __("Refunded", "yatra") }),
1765 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "failed", children: __("Failed", "yatra") })
1766 ]
1767 }
1768 )
1769 ] }),
1770 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1771 /* @__PURE__ */ jsxRuntimeExports.jsx(
1772 "label",
1773 {
1774 htmlFor: "payment_status",
1775 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1776 children: __("Payment Status", "yatra")
1777 }
1778 ),
1779 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1780 Select,
1781 {
1782 id: "payment_status",
1783 value: formData.payment_status,
1784 onChange: (e) => handleFieldChange("payment_status", e.target.value),
1785 children: [
1786 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pending", children: __("Pending", "yatra") }),
1787 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "partial", children: __("Partial", "yatra") }),
1788 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "paid", children: __("Paid", "yatra") }),
1789 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "refunded", children: __("Refunded", "yatra") })
1790 ]
1791 }
1792 )
1793 ] }),
1794 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1795 /* @__PURE__ */ jsxRuntimeExports.jsx(
1796 "label",
1797 {
1798 htmlFor: "payment_method",
1799 className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1.5",
1800 children: __("Payment Method", "yatra")
1801 }
1802 ),
1803 /* @__PURE__ */ jsxRuntimeExports.jsxs(
1804 Select,
1805 {
1806 id: "payment_method",
1807 value: formData.payment_method,
1808 onChange: (e) => handleFieldChange("payment_method", e.target.value),
1809 children: [
1810 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: __("Select payment method", "yatra") }),
1811 (_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)),
1812 (!(gatewaysData == null ? void 0 : gatewaysData.data) || gatewaysData.data.length === 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1813 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "pay_later", children: __("Pay Later", "yatra") }),
1814 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "bank_transfer", children: __("Bank Transfer", "yatra") }),
1815 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "stripe", children: __("Stripe", "yatra") }),
1816 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "paypal", children: __("PayPal", "yatra") })
1817 ] })
1818 ]
1819 }
1820 )
1821 ] })
1822 ] })
1823 ] }),
1824 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1825 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 }),
1826 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1827 /* @__PURE__ */ jsxRuntimeExports.jsx(
1828 Button,
1829 {
1830 type: "submit",
1831 disabled: isSubmitting,
1832 className: "flex-1 flex items-center justify-center gap-2",
1833 children: isSubmitting ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1834 /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-4 h-4 animate-spin" }),
1835 __("Saving...", "yatra")
1836 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1837 /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { className: "w-4 h-4" }),
1838 isEditMode ? __("Update Booking", "yatra") : __("Create Booking", "yatra")
1839 ] })
1840 }
1841 ),
1842 /* @__PURE__ */ jsxRuntimeExports.jsx(
1843 Button,
1844 {
1845 type: "button",
1846 variant: "outline",
1847 onClick: handleCancel,
1848 disabled: isSubmitting,
1849 children: __("Cancel", "yatra")
1850 }
1851 )
1852 ] })
1853 ] }) }) })
1854 ] })
1855 ] }) }) })
1856 ] });
1857 };
1858 export {
1859 BookingForm as default
1860 };
1861 //# sourceMappingURL=BookingForm-DkL1nwFO.js.map
1862