@voyantjs/bookings-ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +201 -109
  2. package/README.md +11 -0
  3. package/dist/components/booking-activity-timeline.d.ts.map +1 -1
  4. package/dist/components/booking-activity-timeline.js +34 -14
  5. package/dist/components/booking-cancellation-dialog.d.ts.map +1 -1
  6. package/dist/components/booking-cancellation-dialog.js +15 -16
  7. package/dist/components/booking-create-dialog.d.ts.map +1 -1
  8. package/dist/components/booking-create-dialog.js +77 -13
  9. package/dist/components/booking-dialog.d.ts.map +1 -1
  10. package/dist/components/booking-dialog.js +27 -21
  11. package/dist/components/booking-document-dialog.d.ts.map +1 -1
  12. package/dist/components/booking-document-dialog.js +27 -13
  13. package/dist/components/booking-document-list.d.ts.map +1 -1
  14. package/dist/components/booking-document-list.js +9 -4
  15. package/dist/components/booking-group-link-dialog.d.ts.map +1 -1
  16. package/dist/components/booking-group-link-dialog.js +17 -6
  17. package/dist/components/booking-group-section.d.ts.map +1 -1
  18. package/dist/components/booking-group-section.js +8 -2
  19. package/dist/components/booking-guarantee-dialog.d.ts.map +1 -1
  20. package/dist/components/booking-guarantee-dialog.js +30 -14
  21. package/dist/components/booking-guarantee-list.d.ts.map +1 -1
  22. package/dist/components/booking-guarantee-list.js +11 -8
  23. package/dist/components/booking-item-dialog.d.ts.map +1 -1
  24. package/dist/components/booking-item-dialog.js +34 -20
  25. package/dist/components/booking-item-list.d.ts.map +1 -1
  26. package/dist/components/booking-item-list.js +10 -9
  27. package/dist/components/booking-item-travelers.d.ts.map +1 -1
  28. package/dist/components/booking-item-travelers.js +9 -4
  29. package/dist/components/booking-list.d.ts.map +1 -1
  30. package/dist/components/booking-list.js +17 -8
  31. package/dist/components/booking-notes.d.ts.map +1 -1
  32. package/dist/components/booking-notes.js +5 -2
  33. package/dist/components/booking-payment-schedule-dialog.d.ts.map +1 -1
  34. package/dist/components/booking-payment-schedule-dialog.js +31 -12
  35. package/dist/components/booking-payment-schedule-list.d.ts.map +1 -1
  36. package/dist/components/booking-payment-schedule-list.js +7 -6
  37. package/dist/components/booking-payments-summary.d.ts.map +1 -1
  38. package/dist/components/booking-payments-summary.js +7 -4
  39. package/dist/components/file-dropzone.d.ts.map +1 -1
  40. package/dist/components/file-dropzone.js +25 -15
  41. package/dist/components/passengers-section.d.ts.map +1 -1
  42. package/dist/components/passengers-section.js +3 -17
  43. package/dist/components/payment-schedule-section.d.ts.map +1 -1
  44. package/dist/components/payment-schedule-section.js +3 -14
  45. package/dist/components/person-picker-section.d.ts.map +1 -1
  46. package/dist/components/person-picker-section.js +3 -19
  47. package/dist/components/price-breakdown-section.d.ts.map +1 -1
  48. package/dist/components/price-breakdown-section.js +15 -18
  49. package/dist/components/product-picker-section.d.ts.map +1 -1
  50. package/dist/components/product-picker-section.js +3 -8
  51. package/dist/components/rooms-stepper-section.d.ts.map +1 -1
  52. package/dist/components/rooms-stepper-section.js +4 -9
  53. package/dist/components/shared-room-section.d.ts.map +1 -1
  54. package/dist/components/shared-room-section.js +3 -9
  55. package/dist/components/status-change-dialog.d.ts.map +1 -1
  56. package/dist/components/status-change-dialog.js +6 -1
  57. package/dist/components/supplier-status-dialog.d.ts.map +1 -1
  58. package/dist/components/supplier-status-dialog.js +31 -15
  59. package/dist/components/supplier-status-list.d.ts.map +1 -1
  60. package/dist/components/supplier-status-list.js +10 -2
  61. package/dist/components/traveler-dialog.d.ts.map +1 -1
  62. package/dist/components/traveler-dialog.js +17 -8
  63. package/dist/components/traveler-list.d.ts.map +1 -1
  64. package/dist/components/traveler-list.js +5 -3
  65. package/dist/components/voucher-picker-section.d.ts.map +1 -1
  66. package/dist/components/voucher-picker-section.js +11 -26
  67. package/dist/i18n/en.d.ts +797 -0
  68. package/dist/i18n/en.d.ts.map +1 -0
  69. package/dist/i18n/en.js +796 -0
  70. package/dist/i18n/index.d.ts +5 -0
  71. package/dist/i18n/index.d.ts.map +1 -0
  72. package/dist/i18n/index.js +3 -0
  73. package/dist/i18n/messages.d.ts +684 -0
  74. package/dist/i18n/messages.d.ts.map +1 -0
  75. package/dist/i18n/messages.js +1 -0
  76. package/dist/i18n/provider.d.ts +1617 -0
  77. package/dist/i18n/provider.d.ts.map +1 -0
  78. package/dist/i18n/provider.js +45 -0
  79. package/dist/i18n/ro.d.ts +797 -0
  80. package/dist/i18n/ro.d.ts.map +1 -0
  81. package/dist/i18n/ro.js +796 -0
  82. package/dist/index.d.ts +1 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +1 -0
  85. package/package.json +40 -20
@@ -6,6 +6,7 @@ import { usePersonMutation } from "@voyantjs/crm-react";
6
6
  import { Button, Checkbox, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyantjs/ui/components";
7
7
  import { Loader2 } from "lucide-react";
8
8
  import * as React from "react";
9
+ import { formatMessage, useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault, } from "../i18n/provider";
9
10
  import { emptyPassengerListValue, PassengersSection, } from "./passengers-section";
10
11
  import { emptyPaymentScheduleValue, PaymentScheduleSection, } from "./payment-schedule-section";
11
12
  import { emptyPersonPickerValue, PersonPickerSection, } from "./person-picker-section";
@@ -132,6 +133,8 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
132
133
  */
133
134
  const [confirmAfterCreate, setConfirmAfterCreate] = React.useState(false);
134
135
  const [error, setError] = React.useState(null);
136
+ const { formatDate } = useBookingsUiI18nOrDefault();
137
+ const messages = useBookingsUiMessagesOrDefault();
135
138
  React.useEffect(() => {
136
139
  if (!open) {
137
140
  setProduct({ productId: defaultProductId ?? "", optionId: null });
@@ -175,14 +178,16 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
175
178
  .sort((a, b) => a.startsAt.localeCompare(b.startsAt));
176
179
  }, [slotsData, product.optionId]);
177
180
  const formatSlotLabel = React.useCallback((slot) => {
178
- const date = new Date(slot.startsAt).toLocaleDateString(undefined, {
181
+ const date = formatDate(slot.startsAt, {
179
182
  year: "numeric",
180
183
  month: "short",
181
184
  day: "numeric",
182
185
  });
183
- const remaining = !slot.unlimited && typeof slot.remainingPax === "number" ? ` · ${slot.remainingPax} left` : "";
186
+ const remaining = !slot.unlimited && typeof slot.remainingPax === "number"
187
+ ? ` · ${slot.remainingPax} ${messages.bookingCreateDialog.labels.remainingCapacity}`
188
+ : "";
184
189
  return `${date}${remaining}`;
185
- }, []);
190
+ }, [formatDate, messages]);
186
191
  const slotUnitAvailability = useSlotUnitAvailability({
187
192
  slotId: slotId ?? undefined,
188
193
  enabled: open && Boolean(slotId),
@@ -208,28 +213,28 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
208
213
  // Currency placeholder — used for voucher + payment schedule display.
209
214
  // Consumers hooking in real product data should override this by wrapping
210
215
  // the component or swapping in their own currency-aware hook.
211
- const currency = "EUR";
216
+ const currency = messages.bookingCreateDialog.labels.currency;
212
217
  const { create: createPerson } = usePersonMutation();
213
218
  const quickCreateMutation = useBookingQuickCreateMutation();
214
219
  const statusMutation = useBookingStatusByIdMutation();
215
220
  const handleSubmit = async () => {
216
221
  setError(null);
217
222
  if (!product.productId) {
218
- setError("Select a product");
223
+ setError(messages.bookingCreateDialog.validation.selectProduct);
219
224
  return;
220
225
  }
221
226
  let resolvedPersonId = null;
222
227
  try {
223
228
  if (person.mode === "existing") {
224
229
  if (!person.personId) {
225
- setError("Select a person or switch to create mode");
230
+ setError(messages.bookingCreateDialog.validation.selectPerson);
226
231
  return;
227
232
  }
228
233
  resolvedPersonId = person.personId;
229
234
  }
230
235
  else {
231
236
  if (!person.newPerson.firstName.trim() || !person.newPerson.lastName.trim()) {
232
- setError("First and last name are required");
237
+ setError(messages.bookingCreateDialog.validation.firstAndLastNameRequired);
233
238
  return;
234
239
  }
235
240
  const created = await createPerson.mutateAsync({
@@ -241,7 +246,7 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
241
246
  resolvedPersonId = created.id;
242
247
  }
243
248
  if (sharedRoom.enabled && sharedRoom.mode === "join" && !sharedRoom.groupId) {
244
- setError("Select a shared-room group to join");
249
+ setError(messages.bookingCreateDialog.validation.selectSharedRoomGroup);
245
250
  return;
246
251
  }
247
252
  const bookingNumber = generateBookingNumber();
@@ -258,7 +263,7 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
258
263
  ? {
259
264
  action: "create",
260
265
  kind: "shared_room",
261
- label: `Shared room ${bookingNumber}`,
266
+ label: `${messages.bookingCreateDialog.labels.sharedRoomGeneratedLabelPrefix} - ${bookingNumber}`,
262
267
  optionUnitId: product.optionId,
263
268
  makeBookingPrimary: true,
264
269
  }
@@ -295,8 +300,10 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
295
300
  }
296
301
  catch (statusErr) {
297
302
  setError(statusErr instanceof Error
298
- ? `Booking created but confirm failed: ${statusErr.message}`
299
- : "Booking created but confirm failed");
303
+ ? formatMessage(messages.bookingCreateDialog.validation.confirmFailedPrefix, {
304
+ message: statusErr.message,
305
+ })
306
+ : messages.bookingCreateDialog.validation.confirmFailed);
300
307
  onCreated?.(booking);
301
308
  return;
302
309
  }
@@ -305,9 +312,66 @@ export function BookingCreateDialog({ open, onOpenChange, onCreated, defaultProd
305
312
  onCreated?.(finalBooking);
306
313
  }
307
314
  catch (err) {
308
- setError(err instanceof Error ? err.message : "Failed to create booking");
315
+ setError(err instanceof Error ? err.message : messages.bookingCreateDialog.validation.createFailed);
309
316
  }
310
317
  };
311
318
  const isSubmitting = quickCreateMutation.isPending || createPerson.isPending || statusMutation.isPending;
312
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Quick Book" }) }), _jsxs(DialogBody, { className: "grid gap-4", children: [_jsx(ProductPickerSection, { value: product, onChange: setProduct, enabled: open, lockProduct: Boolean(defaultProductId) }), product.productId ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: "Departure" }), _jsxs(Select, { value: slotId ?? "__none__", onValueChange: (v) => setSlotId(v === "__none__" ? null : (v ?? null)), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Select a departure..." }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none__", children: "No specific departure" }), slots.length === 0 ? (_jsx(SelectItem, { value: "__empty__", disabled: true, children: "No open departures for this product" })) : (slots.map((slot) => (_jsx(SelectItem, { value: slot.id, children: formatSlotLabel(slot) }, slot.id))))] })] })] })) : null, slotId ? (_jsx(RoomsStepperSection, { value: rooms, onChange: setRooms, slotId: slotId, enabled: open })) : null, _jsx(PersonPickerSection, { value: person, onChange: setPerson, enabled: open }), _jsx(SharedRoomSection, { value: sharedRoom, onChange: setSharedRoom, productId: product.productId || undefined, enabled: open }), product.productId ? (_jsx(PassengersSection, { value: passengers, onChange: setPassengers, roomUnits: roomUnitOptions.length > 0 ? roomUnitOptions : undefined })) : null, product.productId ? (_jsx(PriceBreakdownSection, { productId: product.productId, optionId: product.optionId, unitQuantities: rooms.quantities })) : null, _jsx(VoucherPickerSection, { value: voucher, onChange: setVoucher, currency: currency }), _jsx(PaymentScheduleSection, { value: paymentSchedule, onChange: setPaymentSchedule, currency: currency }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Internal Notes" }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Quick context for this booking..." })] }), _jsxs("div", { className: "flex items-start gap-2 rounded-md border p-3", children: [_jsx(Checkbox, { id: "quickbook-confirm-after-create", checked: confirmAfterCreate, onCheckedChange: (v) => setConfirmAfterCreate(v === true), className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "quickbook-confirm-after-create", className: "cursor-pointer text-sm", children: "Confirm & notify traveler after creating" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Transitions to confirmed after create. When the notifications module's auto-dispatch is on, this fires the doc bundle + traveler email via the booking.confirmed subscriber." })] })] }), error && _jsx("p", { className: "text-xs text-destructive", children: error })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Cancel" }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || !product.productId, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Create Draft Booking"] })] })] }) }));
319
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.bookingCreateDialog.title }) }), _jsxs(DialogBody, { className: "grid gap-4", children: [_jsx(ProductPickerSection, { value: product, onChange: setProduct, enabled: open, lockProduct: Boolean(defaultProductId), labels: {
320
+ optionNone: messages.bookingCreateDialog.labels.noSpecificOption,
321
+ } }), product.productId ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: messages.bookingCreateDialog.fields.departure }), _jsxs(Select, { value: slotId ?? "__none__", onValueChange: (v) => setSlotId(v === "__none__" ? null : (v ?? null)), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: messages.bookingCreateDialog.placeholders.departure }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__none__", children: messages.bookingCreateDialog.placeholders.departureNone }), slots.length === 0 ? (_jsx(SelectItem, { value: "__empty__", disabled: true, children: messages.bookingCreateDialog.placeholders.departureEmpty })) : (slots.map((slot) => (_jsx(SelectItem, { value: slot.id, children: formatSlotLabel(slot) }, slot.id))))] })] })] })) : null, slotId ? (_jsx(RoomsStepperSection, { value: rooms, onChange: setRooms, slotId: slotId, enabled: open, labels: {
322
+ heading: messages.bookingCreateDialog.labels.roomsHeading,
323
+ noSlot: messages.bookingCreateDialog.labels.roomsNoSlot,
324
+ noUnits: messages.bookingCreateDialog.labels.roomsNoUnits,
325
+ remaining: messages.bookingCreateDialog.labels.roomsRemaining,
326
+ unlimited: messages.bookingCreateDialog.labels.roomsUnlimited,
327
+ } })) : null, _jsx(PersonPickerSection, { value: person, onChange: setPerson, enabled: open, labels: {
328
+ createNewPerson: messages.bookingCreateDialog.labels.createNewPerson,
329
+ selectExistingPerson: messages.bookingCreateDialog.labels.selectExistingPerson,
330
+ organizationNone: messages.bookingCreateDialog.labels.organizationNone,
331
+ } }), _jsx(SharedRoomSection, { value: sharedRoom, onChange: setSharedRoom, productId: product.productId || undefined, enabled: open, labels: {
332
+ toggle: messages.bookingCreateDialog.labels.sharedRoomToggle,
333
+ createMode: messages.bookingCreateDialog.labels.sharedRoomCreateMode,
334
+ joinMode: messages.bookingCreateDialog.labels.sharedRoomJoinMode,
335
+ selectPlaceholder: messages.bookingCreateDialog.labels.sharedRoomSelectPlaceholder,
336
+ noGroups: messages.bookingCreateDialog.labels.sharedRoomNoGroups,
337
+ createHint: messages.bookingCreateDialog.labels.sharedRoomCreateHint,
338
+ } }), product.productId ? (_jsx(PassengersSection, { value: passengers, onChange: setPassengers, roomUnits: roomUnitOptions.length > 0 ? roomUnitOptions : undefined, labels: {
339
+ heading: messages.bookingCreateDialog.labels.passengerHeading,
340
+ addPassenger: messages.bookingCreateDialog.labels.addPassenger,
341
+ role: messages.bookingCreateDialog.labels.passengerRole,
342
+ roleLead: messages.bookingCreateDialog.labels.passengerLead,
343
+ roleAdult: messages.bookingCreateDialog.labels.passengerAdult,
344
+ roleChild: messages.bookingCreateDialog.labels.passengerChild,
345
+ roleInfant: messages.bookingCreateDialog.labels.passengerInfant,
346
+ room: messages.bookingCreateDialog.labels.passengerRoom,
347
+ noRoom: messages.bookingCreateDialog.labels.passengerNoRoom,
348
+ remove: messages.bookingCreateDialog.labels.passengerRemove,
349
+ empty: messages.bookingCreateDialog.labels.passengerEmpty,
350
+ } })) : null, product.productId ? (_jsx(PriceBreakdownSection, { productId: product.productId, optionId: product.optionId, unitQuantities: rooms.quantities, labels: {
351
+ heading: messages.bookingCreateDialog.labels.breakdownHeading,
352
+ total: messages.bookingCreateDialog.labels.breakdownTotal,
353
+ onRequest: messages.bookingCreateDialog.labels.breakdownOnRequest,
354
+ groupRate: messages.bookingCreateDialog.labels.breakdownGroupRate,
355
+ empty: messages.bookingCreateDialog.labels.breakdownEmpty,
356
+ noPricing: messages.bookingCreateDialog.labels.breakdownNoPricing,
357
+ } })) : null, _jsx(VoucherPickerSection, { value: voucher, onChange: setVoucher, currency: currency, labels: {
358
+ heading: messages.bookingCreateDialog.labels.voucherHeading,
359
+ codePlaceholder: messages.bookingCreateDialog.labels.voucherCodePlaceholder,
360
+ apply: messages.bookingCreateDialog.labels.voucherApply,
361
+ clear: messages.bookingCreateDialog.labels.voucherClear,
362
+ remainingLabel: messages.bookingCreateDialog.labels.voucherRemainingLabel,
363
+ invalidLabel: messages.bookingCreateDialog.labels.voucherInvalidLabel,
364
+ } }), _jsx(PaymentScheduleSection, { value: paymentSchedule, onChange: setPaymentSchedule, currency: currency, labels: {
365
+ heading: messages.bookingCreateDialog.labels.paymentHeading,
366
+ modeUnpaid: messages.bookingCreateDialog.labels.paymentModeUnpaid,
367
+ modeFull: messages.bookingCreateDialog.labels.paymentModeFull,
368
+ modeAdvance: messages.bookingCreateDialog.labels.paymentModeAdvance,
369
+ modeSplit: messages.bookingCreateDialog.labels.paymentModeSplit,
370
+ dueDate: messages.bookingCreateDialog.labels.paymentDueDate,
371
+ amount: messages.bookingCreateDialog.labels.paymentAmount,
372
+ firstInstallment: messages.bookingCreateDialog.labels.paymentFirstInstallment,
373
+ secondInstallment: messages.bookingCreateDialog.labels.paymentSecondInstallment,
374
+ preset5050: messages.bookingCreateDialog.labels.paymentPreset5050,
375
+ unpaidHint: messages.bookingCreateDialog.labels.paymentUnpaidHint,
376
+ } }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingCreateDialog.fields.internalNotes }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: messages.bookingCreateDialog.placeholders.internalNotes })] }), _jsxs("div", { className: "flex items-start gap-2 rounded-md border p-3", children: [_jsx(Checkbox, { id: "quickbook-confirm-after-create", checked: confirmAfterCreate, onCheckedChange: (v) => setConfirmAfterCreate(v === true), className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "quickbook-confirm-after-create", className: "cursor-pointer text-sm", children: messages.bookingCreateDialog.fields.confirmAfterCreate }), _jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingCreateDialog.fields.confirmAfterCreateHint })] })] }), error && _jsx("p", { className: "text-xs text-destructive", children: error })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), disabled: isSubmitting, children: messages.common.cancel }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || !product.productId, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.bookingCreateDialog.actions.createDraftBooking] })] })] }) }));
313
377
  }
@@ -1 +1 @@
1
- {"version":3,"file":"booking-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,0BAA0B,CAAA;AA2CjF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAUD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,SAAS,EACT,gBAAgB,GACjB,EAAE,kBAAkB,2CAoBpB"}
1
+ {"version":3,"file":"booking-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,0BAA0B,CAAA;AA8CjF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAWD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,SAAS,EACT,gBAAgB,GACjB,EAAE,kBAAkB,2CAoBpB"}
@@ -9,25 +9,29 @@ import { Loader2 } from "lucide-react";
9
9
  import { useEffect } from "react";
10
10
  import { useForm } from "react-hook-form";
11
11
  import { z } from "zod/v4";
12
+ import { useBookingsUiMessagesOrDefault } from "../i18n/provider";
12
13
  import { BookingCreateDialog } from "./booking-create-dialog";
13
- const bookingFormSchema = z.object({
14
- bookingNumber: z.string().min(1, "Booking number is required"),
15
- status: z.enum(["draft", "confirmed", "in_progress", "completed", "cancelled"]),
16
- sellCurrency: z.string().min(3).max(3, "Use 3-letter ISO code"),
17
- sellAmountCents: z.coerce.number().int().min(0).optional().or(z.literal("")).nullable(),
18
- costAmountCents: z.coerce.number().int().min(0).optional().or(z.literal("")).nullable(),
19
- startDate: z.string().optional().nullable(),
20
- endDate: z.string().optional().nullable(),
21
- pax: z.coerce.number().int().positive().optional().or(z.literal("")).nullable(),
22
- internalNotes: z.string().optional().nullable(),
23
- });
24
- const BOOKING_STATUSES = [
25
- { value: "draft", label: "Draft" },
26
- { value: "confirmed", label: "Confirmed" },
27
- { value: "in_progress", label: "In Progress" },
28
- { value: "completed", label: "Completed" },
29
- { value: "cancelled", label: "Cancelled" },
14
+ function createBookingFormSchema(messages) {
15
+ return z.object({
16
+ bookingNumber: z.string().min(1, messages.bookingDialog.validation.bookingNumberRequired),
17
+ status: z.enum(["draft", "confirmed", "in_progress", "completed", "cancelled"]),
18
+ sellCurrency: z.string().min(3).max(3, messages.bookingDialog.validation.sellCurrencyInvalid),
19
+ sellAmountCents: z.coerce.number().int().min(0).optional().or(z.literal("")).nullable(),
20
+ costAmountCents: z.coerce.number().int().min(0).optional().or(z.literal("")).nullable(),
21
+ startDate: z.string().optional().nullable(),
22
+ endDate: z.string().optional().nullable(),
23
+ pax: z.coerce.number().int().positive().optional().or(z.literal("")).nullable(),
24
+ internalNotes: z.string().optional().nullable(),
25
+ });
26
+ }
27
+ const BOOKING_STATUS_VALUES = [
28
+ "draft",
29
+ "confirmed",
30
+ "in_progress",
31
+ "completed",
32
+ "cancelled",
30
33
  ];
34
+ const DEFAULT_CURRENCY = "EUR"; // i18n-literal-ok ISO default currency
31
35
  /**
32
36
  * Single booking dialog that handles both create and edit:
33
37
  * - Create (no `booking` prop): renders the rich product → option → person
@@ -45,12 +49,14 @@ export function BookingDialog({ open, onOpenChange, booking, onSuccess, defaultP
45
49
  }
46
50
  function BookingEditDialog({ open, onOpenChange, booking, onSuccess }) {
47
51
  const { update } = useBookingMutation();
52
+ const messages = useBookingsUiMessagesOrDefault();
53
+ const bookingFormSchema = createBookingFormSchema(messages);
48
54
  const form = useForm({
49
55
  resolver: zodResolver(bookingFormSchema),
50
56
  defaultValues: {
51
57
  bookingNumber: "",
52
58
  status: "draft",
53
- sellCurrency: "EUR",
59
+ sellCurrency: DEFAULT_CURRENCY,
54
60
  sellAmountCents: "",
55
61
  costAmountCents: "",
56
62
  startDate: "",
@@ -95,14 +101,14 @@ function BookingEditDialog({ open, onOpenChange, booking, onSuccess }) {
95
101
  onSuccess?.(saved);
96
102
  };
97
103
  const isSubmitting = update.isPending;
98
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Edit Booking" }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Booking Number" }), _jsx(Input, { ...form.register("bookingNumber"), placeholder: "BK-2501-1234" }), form.formState.errors.bookingNumber && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.bookingNumber.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Status" }), _jsxs(Select, { value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: BOOKING_STATUSES.map((status) => (_jsx(SelectItem, { value: status.value, children: status.label }, status.value))) })] })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Sell Currency" }), _jsx(CurrencyCombobox, { value: form.watch("sellCurrency") || null, onChange: (next) => form.setValue("sellCurrency", next ?? "EUR", {
104
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.bookingDialog.editTitle }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.bookingNumber }), _jsx(Input, { ...form.register("bookingNumber"), placeholder: messages.bookingDialog.placeholders.bookingNumber }), form.formState.errors.bookingNumber && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.bookingNumber.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.status }), _jsxs(Select, { value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: BOOKING_STATUS_VALUES.map((status) => (_jsx(SelectItem, { value: status, children: messages.common.bookingStatusLabels[status] }, status))) })] })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.sellCurrency }), _jsx(CurrencyCombobox, { value: form.watch("sellCurrency") || null, onChange: (next) => form.setValue("sellCurrency", next ?? DEFAULT_CURRENCY, {
99
105
  shouldValidate: true,
100
106
  shouldDirty: true,
101
- }) })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Travel Dates" }), _jsx(DateRangePicker, { value: {
107
+ }) })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.travelDates }), _jsx(DateRangePicker, { value: {
102
108
  from: form.watch("startDate") || null,
103
109
  to: form.watch("endDate") || null,
104
110
  }, onChange: (nextValue) => {
105
111
  form.setValue("startDate", nextValue?.from ?? "", { shouldDirty: true });
106
112
  form.setValue("endDate", nextValue?.to ?? "", { shouldDirty: true });
107
- }, placeholder: "Pick travel dates", className: "w-full" })] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Sell Amount (cents)" }), _jsx(Input, { ...form.register("sellAmountCents"), type: "number", min: "0" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Cost Amount (cents)" }), _jsx(Input, { ...form.register("costAmountCents"), type: "number", min: "0" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Travelers (Pax)" }), _jsx(Input, { ...form.register("pax"), type: "number", min: "1", placeholder: "2" })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Internal Notes" }), _jsx(Textarea, { ...form.register("internalNotes"), placeholder: "Private operations notes..." })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), children: "Cancel" }), _jsxs(Button, { type: "submit", size: "sm", disabled: isSubmitting, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save Changes"] })] })] })] }) }));
113
+ }, placeholder: messages.bookingDialog.placeholders.travelDates, className: "w-full" })] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.sellAmountCents }), _jsx(Input, { ...form.register("sellAmountCents"), type: "number", min: "0" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.costAmountCents }), _jsx(Input, { ...form.register("costAmountCents"), type: "number", min: "0" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.pax }), _jsx(Input, { ...form.register("pax"), type: "number", min: "1", placeholder: messages.bookingDialog.placeholders.pax })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDialog.fields.internalNotes }), _jsx(Textarea, { ...form.register("internalNotes"), placeholder: messages.bookingDialog.placeholders.internalNotes })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), children: messages.common.cancel }), _jsxs(Button, { type: "submit", size: "sm", disabled: isSubmitting, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.common.saveChanges] })] })] })] }) }));
108
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"booking-document-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-document-dialog.tsx"],"names":[],"mappings":"AA4CA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,GACV,EAAE,0BAA0B,2CAmJ5B"}
1
+ {"version":3,"file":"booking-document-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-document-dialog.tsx"],"names":[],"mappings":"AAkDA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,GACV,EAAE,0BAA0B,2CAgK5B"}
@@ -8,21 +8,29 @@ import { Loader2 } from "lucide-react";
8
8
  import { useEffect } from "react";
9
9
  import { useForm } from "react-hook-form";
10
10
  import { z } from "zod/v4";
11
+ import { useBookingsUiMessagesOrDefault } from "../i18n/provider";
11
12
  import { FileDropzone } from "./file-dropzone";
12
13
  const documentTypes = ["visa", "insurance", "health", "passport_copy", "other"];
13
14
  const UNASSIGNED = "__unassigned__";
14
- const documentFormSchema = z.object({
15
- type: z.enum(documentTypes).default("other"),
16
- fileName: z.string().min(1, "File name is required").max(500),
17
- fileUrl: z.string().url("Must be a valid URL"),
18
- travelerId: z.string().optional().nullable(),
19
- expiresAt: z.string().optional().nullable(),
20
- notes: z.string().optional().nullable(),
21
- });
15
+ function createDocumentFormSchema(messages) {
16
+ return z.object({
17
+ type: z.enum(documentTypes).default("other"),
18
+ fileName: z
19
+ .string()
20
+ .min(1, messages.bookingDocumentDialog.validation.fileNameRequired)
21
+ .max(500),
22
+ fileUrl: z.string().url(messages.bookingDocumentDialog.validation.fileUrlInvalid),
23
+ travelerId: z.string().optional().nullable(),
24
+ expiresAt: z.string().optional().nullable(),
25
+ notes: z.string().optional().nullable(),
26
+ });
27
+ }
22
28
  export function BookingDocumentDialog({ open, onOpenChange, bookingId, onSuccess, }) {
23
29
  const { create } = useBookingTravelerDocumentMutation(bookingId);
24
30
  const { data: travelersData } = useTravelers(bookingId);
25
31
  const travelers = travelersData?.data ?? [];
32
+ const messages = useBookingsUiMessagesOrDefault();
33
+ const documentFormSchema = createDocumentFormSchema(messages);
26
34
  const form = useForm({
27
35
  resolver: zodResolver(documentFormSchema),
28
36
  defaultValues: {
@@ -51,17 +59,23 @@ export function BookingDocumentDialog({ open, onOpenChange, bookingId, onSuccess
51
59
  onOpenChange(false);
52
60
  onSuccess?.();
53
61
  };
54
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Add Document" }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Type" }), _jsxs(Select, { items: documentTypes.map((t) => ({ label: t.replace(/_/g, " "), value: t })), value: form.watch("type"), onValueChange: (v) => form.setValue("type", (v ?? "other")), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: documentTypes.map((t) => (_jsx(SelectItem, { value: t, children: t.replace(/_/g, " ") }, t))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Traveler (optional)" }), _jsxs(Select, { items: [
55
- { label: "Booking-wide", value: UNASSIGNED },
62
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.bookingDocumentDialog.title }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDocumentDialog.fields.type }), _jsxs(Select, { items: documentTypes.map((t) => ({
63
+ label: messages.bookingDocumentDialog.documentTypeLabels[t],
64
+ value: t,
65
+ })), value: form.watch("type"), onValueChange: (v) => form.setValue("type", (v ?? "other")), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: documentTypes.map((t) => (_jsx(SelectItem, { value: t, children: messages.bookingDocumentDialog.documentTypeLabels[t] }, t))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDocumentDialog.fields.traveler }), _jsxs(Select, { items: [
66
+ {
67
+ label: messages.bookingDocumentDialog.placeholders.travelerUnassigned,
68
+ value: UNASSIGNED,
69
+ },
56
70
  ...travelers.map((traveler) => ({
57
71
  label: `${traveler.firstName} ${traveler.lastName}`,
58
72
  value: traveler.id,
59
73
  })),
60
- ], value: form.watch("travelerId") ?? UNASSIGNED, onValueChange: (v) => form.setValue("travelerId", v ?? UNASSIGNED), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNASSIGNED, children: "Booking-wide" }), travelers.map((traveler) => (_jsxs(SelectItem, { value: traveler.id, children: [traveler.firstName, " ", traveler.lastName] }, traveler.id)))] })] })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "File" }), _jsx(FileDropzone, { accept: "application/pdf,image/*", maxSize: 10 * 1024 * 1024, onUploaded: (upload) => {
74
+ ], value: form.watch("travelerId") ?? UNASSIGNED, onValueChange: (v) => form.setValue("travelerId", v ?? UNASSIGNED), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNASSIGNED, children: messages.bookingDocumentDialog.placeholders.travelerUnassigned }), travelers.map((traveler) => (_jsxs(SelectItem, { value: traveler.id, children: [traveler.firstName, " ", traveler.lastName] }, traveler.id)))] })] })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDocumentDialog.fields.file }), _jsx(FileDropzone, { accept: "application/pdf,image/*", maxSize: 10 * 1024 * 1024, onUploaded: (upload) => {
61
75
  form.setValue("fileUrl", upload.url, { shouldValidate: true });
62
76
  form.setValue("fileName", upload.name, { shouldValidate: true });
63
- }, helperText: "Drop passport, visa, or insurance document (PDF or image)" }), form.formState.errors.fileUrl && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.fileUrl.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Expires At (optional)" }), _jsx(DatePicker, { value: form.watch("expiresAt") || null, onChange: (next) => form.setValue("expiresAt", next ?? "", {
77
+ }, helperText: messages.bookingDocumentDialog.placeholders.helperText }), form.formState.errors.fileUrl && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.fileUrl.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDocumentDialog.fields.expiresAt }), _jsx(DatePicker, { value: form.watch("expiresAt") || null, onChange: (next) => form.setValue("expiresAt", next ?? "", {
64
78
  shouldValidate: true,
65
79
  shouldDirty: true,
66
- }), placeholder: "Select expiry date", className: "w-full" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Notes" }), _jsx(Textarea, { ...form.register("notes"), placeholder: "Additional notes..." })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), children: "Cancel" }), _jsxs(Button, { type: "submit", size: "sm", disabled: create.isPending, children: [create.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Add Document"] })] })] })] }) }));
80
+ }), placeholder: messages.bookingDocumentDialog.placeholders.expiresAt, className: "w-full" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingDocumentDialog.fields.notes }), _jsx(Textarea, { ...form.register("notes"), placeholder: messages.bookingDocumentDialog.placeholders.notes })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), children: messages.common.cancel }), _jsxs(Button, { type: "submit", size: "sm", disabled: create.isPending, children: [create.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.bookingDocumentDialog.actions.addDocument] })] })] })] }) }));
67
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"booking-document-list.d.ts","sourceRoot":"","sources":["../../src/components/booking-document-list.tsx"],"names":[],"mappings":"AAsBA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE,wBAAwB,2CAqG1E"}
1
+ {"version":3,"file":"booking-document-list.d.ts","sourceRoot":"","sources":["../../src/components/booking-document-list.tsx"],"names":[],"mappings":"AAuBA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE,wBAAwB,2CAqH1E"}
@@ -4,6 +4,7 @@ import { useBookingTravelerDocumentMutation, useBookingTravelerDocuments, useTra
4
4
  import { Badge, Button, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
5
5
  import { ExternalLink, FileText, Plus, Trash2 } from "lucide-react";
6
6
  import * as React from "react";
7
+ import { useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault } from "../i18n/provider";
7
8
  import { BookingDocumentDialog } from "./booking-document-dialog";
8
9
  const typeVariant = {
9
10
  visa: "default",
@@ -17,20 +18,24 @@ export function BookingDocumentList({ bookingId }) {
17
18
  const { data } = useBookingTravelerDocuments(bookingId);
18
19
  const { data: travelersData } = useTravelers(bookingId);
19
20
  const { remove } = useBookingTravelerDocumentMutation(bookingId);
21
+ const { formatDate } = useBookingsUiI18nOrDefault();
22
+ const messages = useBookingsUiMessagesOrDefault();
20
23
  const documents = data?.data ?? [];
21
24
  const travelers = travelersData?.data ?? [];
22
25
  const travelerMap = new Map();
23
26
  for (const traveler of travelers) {
24
27
  travelerMap.set(traveler.id, traveler);
25
28
  }
26
- return (_jsxs(Card, { "data-slot": "booking-document-list", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(FileText, { className: "h-4 w-4" }), "Documents"] }), _jsxs(Button, { size: "sm", onClick: () => setDialogOpen(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Add Document"] })] }), _jsx(CardContent, { children: documents.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: "No documents yet." })) : (_jsx("div", { className: "rounded border bg-background", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b text-muted-foreground", children: [_jsx("th", { className: "p-2 text-left font-medium", children: "Type" }), _jsx("th", { className: "p-2 text-left font-medium", children: "File" }), _jsx("th", { className: "p-2 text-left font-medium", children: "Traveler" }), _jsx("th", { className: "p-2 text-left font-medium", children: "Expires" }), _jsx("th", { className: "p-2 text-left font-medium", children: "Notes" }), _jsx("th", { className: "w-20 p-2" })] }) }), _jsx("tbody", { children: documents.map((doc) => {
29
+ return (_jsxs(Card, { "data-slot": "booking-document-list", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(FileText, { className: "h-4 w-4" }), messages.bookingDocumentList.title] }), _jsxs(Button, { size: "sm", onClick: () => setDialogOpen(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), messages.bookingDocumentList.addDocument] })] }), _jsx(CardContent, { children: documents.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: messages.bookingDocumentList.empty })) : (_jsx("div", { className: "rounded border bg-background", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b text-muted-foreground", children: [_jsx("th", { className: "p-2 text-left font-medium", children: messages.bookingDocumentList.columns.type }), _jsx("th", { className: "p-2 text-left font-medium", children: messages.bookingDocumentList.columns.file }), _jsx("th", { className: "p-2 text-left font-medium", children: messages.bookingDocumentList.columns.traveler }), _jsx("th", { className: "p-2 text-left font-medium", children: messages.bookingDocumentList.columns.expires }), _jsx("th", { className: "p-2 text-left font-medium", children: messages.bookingDocumentList.columns.notes }), _jsx("th", { className: "w-20 p-2" })] }) }), _jsx("tbody", { children: documents.map((doc) => {
27
30
  const traveler = doc.travelerId ? travelerMap.get(doc.travelerId) : undefined;
28
- return (_jsxs("tr", { className: "border-b last:border-b-0", children: [_jsx("td", { className: "p-2", children: _jsx(Badge, { variant: typeVariant[doc.type] ?? "outline", className: "capitalize", children: doc.type.replace(/_/g, " ") }) }), _jsx("td", { className: "p-2", children: _jsxs("a", { href: doc.fileUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 hover:underline", children: [doc.fileName, _jsx(ExternalLink, { className: "h-3 w-3 text-muted-foreground" })] }) }), _jsx("td", { className: "p-2", children: traveler
31
+ return (_jsxs("tr", { className: "border-b last:border-b-0", children: [_jsx("td", { className: "p-2", children: _jsx(Badge, { variant: typeVariant[doc.type] ?? "outline", children: messages.bookingDocumentDialog.documentTypeLabels[doc.type] }) }), _jsx("td", { className: "p-2", children: _jsxs("a", { href: doc.fileUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 hover:underline", children: [doc.fileName, _jsx(ExternalLink, { className: "h-3 w-3 text-muted-foreground" })] }) }), _jsx("td", { className: "p-2", children: traveler
29
32
  ? `${traveler.firstName} ${traveler.lastName}`
30
33
  : doc.travelerId
31
34
  ? doc.travelerId
32
- : "—" }), _jsx("td", { className: "p-2", children: doc.expiresAt ? new Date(doc.expiresAt).toLocaleDateString() : "-" }), _jsx("td", { className: "max-w-[200px] truncate p-2 text-muted-foreground", children: doc.notes ?? "-" }), _jsx("td", { className: "p-2", children: _jsx("button", { type: "button", onClick: () => {
33
- if (confirm("Delete this document?")) {
35
+ : messages.bookingDocumentList.values.travelerUnavailable }), _jsx("td", { className: "p-2", children: doc.expiresAt
36
+ ? formatDate(doc.expiresAt)
37
+ : messages.bookingDocumentList.values.expiresUnavailable }), _jsx("td", { className: "max-w-[200px] truncate p-2 text-muted-foreground", children: doc.notes ?? messages.bookingDocumentList.values.notesUnavailable }), _jsx("td", { className: "p-2", children: _jsx("button", { type: "button", onClick: () => {
38
+ if (confirm(messages.bookingDocumentList.actions.deleteConfirm)) {
34
39
  remove.mutate(doc.id);
35
40
  }
36
41
  }, className: "text-muted-foreground hover:text-destructive", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) })] }, doc.id));
@@ -1 +1 @@
1
- {"version":3,"file":"booking-group-link-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-group-link-dialog.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC;AAMD,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,QAAQ,GACT,EAAE,2BAA2B,2CAuK7B"}
1
+ {"version":3,"file":"booking-group-link-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-group-link-dialog.tsx"],"names":[],"mappings":"AA2BA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC;AAMD,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,QAAQ,GACT,EAAE,2BAA2B,2CAqL7B"}
@@ -4,12 +4,15 @@ import { useBookingGroupMemberMutation, useBookingGroupMutation, useBookingGroup
4
4
  import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/ui/components";
5
5
  import { Loader2 } from "lucide-react";
6
6
  import * as React from "react";
7
+ import { useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault } from "../i18n/provider";
7
8
  const JOIN_PLACEHOLDER = "__none__";
8
9
  export function BookingGroupLinkDialog({ open, onOpenChange, bookingId, productId, optionUnitId, onLinked, }) {
9
10
  const [mode, setMode] = React.useState("join");
10
11
  const [selectedGroupId, setSelectedGroupId] = React.useState("");
11
12
  const [newGroupLabel, setNewGroupLabel] = React.useState("");
12
13
  const [error, setError] = React.useState(null);
14
+ const { formatDate } = useBookingsUiI18nOrDefault();
15
+ const messages = useBookingsUiMessagesOrDefault();
13
16
  React.useEffect(() => {
14
17
  if (!open) {
15
18
  setMode("join");
@@ -33,7 +36,8 @@ export function BookingGroupLinkDialog({ open, onOpenChange, bookingId, productI
33
36
  let targetGroupId = selectedGroupId;
34
37
  let role = "shared";
35
38
  if (mode === "create") {
36
- const label = newGroupLabel.trim() || `Shared room — ${new Date().toLocaleDateString()}`;
39
+ const label = newGroupLabel.trim() ||
40
+ `${messages.bookingGroupLinkDialog.labels.generatedLabelPrefix} - ${formatDate(new Date())}`;
37
41
  const group = await createGroup.mutateAsync({
38
42
  kind: "shared_room",
39
43
  label,
@@ -45,7 +49,7 @@ export function BookingGroupLinkDialog({ open, onOpenChange, bookingId, productI
45
49
  role = "primary";
46
50
  }
47
51
  if (!targetGroupId || targetGroupId === JOIN_PLACEHOLDER) {
48
- setError("Select a group to join");
52
+ setError(messages.bookingGroupLinkDialog.validation.selectGroup);
49
53
  return;
50
54
  }
51
55
  await addMember.mutateAsync({
@@ -57,12 +61,19 @@ export function BookingGroupLinkDialog({ open, onOpenChange, bookingId, productI
57
61
  onLinked?.(targetGroupId);
58
62
  }
59
63
  catch (err) {
60
- const message = err instanceof Error ? err.message : "Failed to link booking";
64
+ const message = err instanceof Error ? err.message : messages.bookingGroupLinkDialog.validation.linkFailed;
61
65
  setError(message);
62
66
  }
63
67
  };
64
68
  const isSubmitting = createGroup.isPending || addMember.isPending;
65
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Link Booking to Shared Room" }) }), _jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", size: "sm", variant: mode === "join" ? "default" : "ghost", onClick: () => setMode("join"), children: "Join existing" }), _jsx(Button, { type: "button", size: "sm", variant: mode === "create" ? "default" : "ghost", onClick: () => setMode("create"), children: "Create new" })] }), mode === "join" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Existing groups" }), _jsxs(Select, { items: groups.length === 0
66
- ? [{ label: "No existing groups", value: JOIN_PLACEHOLDER }]
67
- : groups.map((g) => ({ label: g.label, value: g.id })), value: selectedGroupId || JOIN_PLACEHOLDER, onValueChange: (v) => setSelectedGroupId(v === JOIN_PLACEHOLDER ? "" : (v ?? "")), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select a group..." }) }), _jsx(SelectContent, { children: groups.length === 0 ? (_jsx(SelectItem, { value: JOIN_PLACEHOLDER, disabled: true, children: "No existing groups" })) : (groups.map((g) => (_jsx(SelectItem, { value: g.id, children: g.label }, g.id)))) })] }), productId && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Filtered to groups for the booking's product." }))] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Group label" }), _jsx(Input, { value: newGroupLabel, onChange: (e) => setNewGroupLabel(e.target.value), placeholder: "e.g. Smith + Jones, Room 204" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "This booking will be marked as the primary member." })] })), error && _jsx("p", { className: "text-xs text-destructive", children: error })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Cancel" }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || (mode === "join" && !selectedGroupId), children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), mode === "create" ? "Create & Link" : "Link to Group"] })] })] }) }));
69
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.bookingGroupLinkDialog.title }) }), _jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", size: "sm", variant: mode === "join" ? "default" : "ghost", onClick: () => setMode("join"), children: messages.bookingGroupLinkDialog.modes.join }), _jsx(Button, { type: "button", size: "sm", variant: mode === "create" ? "default" : "ghost", onClick: () => setMode("create"), children: messages.bookingGroupLinkDialog.modes.create })] }), mode === "join" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingGroupLinkDialog.fields.existingGroups }), _jsxs(Select, { items: groups.length === 0
70
+ ? [
71
+ {
72
+ label: messages.bookingGroupLinkDialog.placeholders.noExistingGroups,
73
+ value: JOIN_PLACEHOLDER,
74
+ },
75
+ ]
76
+ : groups.map((g) => ({ label: g.label, value: g.id })), value: selectedGroupId || JOIN_PLACEHOLDER, onValueChange: (v) => setSelectedGroupId(v === JOIN_PLACEHOLDER ? "" : (v ?? "")), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: messages.bookingGroupLinkDialog.placeholders.selectGroup }) }), _jsx(SelectContent, { children: groups.length === 0 ? (_jsx(SelectItem, { value: JOIN_PLACEHOLDER, disabled: true, children: messages.bookingGroupLinkDialog.placeholders.noExistingGroups })) : (groups.map((g) => (_jsx(SelectItem, { value: g.id, children: g.label }, g.id)))) })] }), productId && (_jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingGroupLinkDialog.hints.productFiltered }))] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingGroupLinkDialog.fields.groupLabel }), _jsx(Input, { value: newGroupLabel, onChange: (e) => setNewGroupLabel(e.target.value), placeholder: messages.bookingGroupLinkDialog.placeholders.groupLabel }), _jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingGroupLinkDialog.hints.primaryMember })] })), error && _jsx("p", { className: "text-xs text-destructive", children: error })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), disabled: isSubmitting, children: messages.common.cancel }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || (mode === "join" && !selectedGroupId), children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), mode === "create"
77
+ ? messages.bookingGroupLinkDialog.actions.createAndLink
78
+ : messages.bookingGroupLinkDialog.actions.linkToGroup] })] })] }) }));
68
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"booking-group-section.d.ts","sourceRoot":"","sources":["../../src/components/booking-group-section.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE,wBAAwB,2CAsH1B"}
1
+ {"version":3,"file":"booking-group-section.d.ts","sourceRoot":"","sources":["../../src/components/booking-group-section.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE,wBAAwB,2CA4H1B"}
@@ -4,9 +4,11 @@ import { useBookingGroup, useBookingGroupForBooking, useBookingGroupMemberMutati
4
4
  import { Badge, Button, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
5
5
  import { Link2, Unlink, Users } from "lucide-react";
6
6
  import * as React from "react";
7
+ import { formatMessage, useBookingsUiMessagesOrDefault } from "../i18n/provider";
7
8
  import { BookingGroupLinkDialog } from "./booking-group-link-dialog";
8
9
  export function BookingGroupSection({ bookingId, productId, optionUnitId, }) {
9
10
  const [linkDialogOpen, setLinkDialogOpen] = React.useState(false);
11
+ const messages = useBookingsUiMessagesOrDefault();
10
12
  // Auto-resolve product/option-unit from items when the caller hasn't
11
13
  // supplied them. Explicit `null` is respected as an override.
12
14
  const shouldAutoResolve = productId === undefined || optionUnitId === undefined;
@@ -22,10 +24,14 @@ export function BookingGroupSection({ bookingId, productId, optionUnitId, }) {
22
24
  const handleRemove = async () => {
23
25
  if (!groupId)
24
26
  return;
25
- if (!confirm("Remove this booking from the shared-room group?"))
27
+ if (!confirm(messages.bookingGroupSection.actions.removeConfirm))
26
28
  return;
27
29
  await removeMember.mutateAsync({ groupId, bookingId });
28
30
  };
29
31
  const siblings = members.filter((m) => m.bookingId !== bookingId);
30
- return (_jsxs(Card, { "data-slot": "booking-group-section", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-4 w-4" }), "Shared Room"] }), group ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: handleRemove, disabled: removeMember.isPending, children: [_jsx(Unlink, { className: "mr-2 h-4 w-4" }), "Remove from group"] })) : (_jsxs(Button, { size: "sm", onClick: () => setLinkDialogOpen(true), children: [_jsx(Link2, { className: "mr-2 h-4 w-4" }), "Link to shared room"] }))] }), _jsx(CardContent, { children: !group ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: "This booking is not linked to a shared-room group." })) : (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-md border bg-muted/30 p-3 text-sm", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Group" }), _jsx("div", { className: "font-medium", children: group.label })] }), _jsx(Badge, { variant: "outline", className: "capitalize", children: group.kind.replace(/_/g, " ") })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: ["Sibling bookings (", siblings.length, ")"] }), siblings.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "No other bookings linked yet. Share the group id with another booking to link them." })) : (_jsx("ul", { className: "space-y-1", children: siblings.map((m) => (_jsxs("li", { className: "flex items-center justify-between rounded px-2 py-1 text-sm", children: [_jsx("span", { className: "font-mono text-xs", children: m.booking?.bookingNumber ?? m.bookingId }), _jsxs("div", { className: "flex items-center gap-2", children: [m.role === "primary" && (_jsx(Badge, { variant: "default", className: "text-xs", children: "Primary" })), m.booking?.status && (_jsx("span", { className: "text-xs text-muted-foreground capitalize", children: m.booking.status.replace(/_/g, " ") }))] })] }, m.id))) }))] })] })) }), _jsx(BookingGroupLinkDialog, { open: linkDialogOpen, onOpenChange: setLinkDialogOpen, bookingId: bookingId, productId: effectiveProductId, optionUnitId: effectiveOptionUnitId })] }));
32
+ return (_jsxs(Card, { "data-slot": "booking-group-section", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-4 w-4" }), messages.bookingGroupSection.title] }), group ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: handleRemove, disabled: removeMember.isPending, children: [_jsx(Unlink, { className: "mr-2 h-4 w-4" }), messages.bookingGroupSection.actions.removeFromGroup] })) : (_jsxs(Button, { size: "sm", onClick: () => setLinkDialogOpen(true), children: [_jsx(Link2, { className: "mr-2 h-4 w-4" }), messages.bookingGroupSection.actions.linkToSharedRoom] }))] }), _jsx(CardContent, { children: !group ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: messages.bookingGroupSection.empty })) : (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-md border bg-muted/30 p-3 text-sm", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: messages.bookingGroupSection.group }), _jsx("div", { className: "font-medium", children: group.label })] }), _jsx(Badge, { variant: "outline", children: group.kind === "shared_room"
33
+ ? messages.bookingGroupSection.sharedRoomKind
34
+ : group.kind.replace(/_/g, " ") })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: formatMessage(messages.bookingGroupSection.siblingBookings, {
35
+ count: siblings.length,
36
+ }) }), siblings.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingGroupSection.noSiblingBookings })) : (_jsx("ul", { className: "space-y-1", children: siblings.map((m) => (_jsxs("li", { className: "flex items-center justify-between rounded px-2 py-1 text-sm", children: [_jsx("span", { className: "font-mono text-xs", children: m.booking?.bookingNumber ?? m.bookingId }), _jsxs("div", { className: "flex items-center gap-2", children: [m.role === "primary" && (_jsx(Badge, { variant: "default", className: "text-xs", children: messages.bookingGroupSection.primaryBadge })), m.booking?.status && (_jsx("span", { className: "text-xs text-muted-foreground", children: messages.common.bookingStatusLabels[m.booking.status] }))] })] }, m.id))) }))] })] })) }), _jsx(BookingGroupLinkDialog, { open: linkDialogOpen, onOpenChange: setLinkDialogOpen, bookingId: bookingId, productId: effectiveProductId, optionUnitId: effectiveOptionUnitId })] }));
31
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"booking-guarantee-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-guarantee-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,sBAAsB,EAA+B,MAAM,yBAAyB,CAAA;AA4DlG,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,sBAAsB,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,2BAA2B,2CAqL7B"}
1
+ {"version":3,"file":"booking-guarantee-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-guarantee-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,sBAAsB,EAA+B,MAAM,yBAAyB,CAAA;AAgElG,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,sBAAsB,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,2BAA2B,2CA4M7B"}