@voyantjs/bookings-ui 0.50.4 → 0.50.6

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 (40) hide show
  1. package/dist/components/booking-create-dialog.d.ts +1 -1
  2. package/dist/components/booking-create-dialog.d.ts.map +1 -1
  3. package/dist/components/booking-create-dialog.js +64 -24
  4. package/dist/components/booking-create-page.d.ts +2 -1
  5. package/dist/components/booking-create-page.d.ts.map +1 -1
  6. package/dist/components/booking-create-page.js +2 -2
  7. package/dist/components/booking-create-utils.d.ts +33 -0
  8. package/dist/components/booking-create-utils.d.ts.map +1 -0
  9. package/dist/components/booking-create-utils.js +67 -0
  10. package/dist/components/booking-list.d.ts +2 -1
  11. package/dist/components/booking-list.d.ts.map +1 -1
  12. package/dist/components/booking-list.js +5 -1
  13. package/dist/components/bookings-page.d.ts +2 -1
  14. package/dist/components/bookings-page.d.ts.map +1 -1
  15. package/dist/components/bookings-page.js +2 -2
  16. package/dist/components/payment-schedule-section.d.ts +20 -0
  17. package/dist/components/payment-schedule-section.d.ts.map +1 -1
  18. package/dist/components/payment-schedule-section.js +27 -2
  19. package/dist/components/price-breakdown-section.d.ts +1 -0
  20. package/dist/components/price-breakdown-section.d.ts.map +1 -1
  21. package/dist/components/price-breakdown-section.js +2 -0
  22. package/dist/components/product-picker-section.d.ts.map +1 -1
  23. package/dist/components/product-picker-section.js +5 -2
  24. package/dist/components/shared-room-section.d.ts +2 -0
  25. package/dist/components/shared-room-section.d.ts.map +1 -1
  26. package/dist/components/shared-room-section.js +14 -2
  27. package/dist/components/travelers-section.d.ts +15 -10
  28. package/dist/components/travelers-section.d.ts.map +1 -1
  29. package/dist/components/travelers-section.js +96 -14
  30. package/dist/i18n/en.d.ts +24 -0
  31. package/dist/i18n/en.d.ts.map +1 -1
  32. package/dist/i18n/en.js +24 -0
  33. package/dist/i18n/messages.d.ts +24 -0
  34. package/dist/i18n/messages.d.ts.map +1 -1
  35. package/dist/i18n/provider.d.ts +48 -0
  36. package/dist/i18n/provider.d.ts.map +1 -1
  37. package/dist/i18n/ro.d.ts +24 -0
  38. package/dist/i18n/ro.d.ts.map +1 -1
  39. package/dist/i18n/ro.js +24 -0
  40. package/package.json +24 -24
@@ -18,7 +18,7 @@ export interface BookingCreateFormProps {
18
18
  * Operator booking-create dialog. Composes the booking-create picker
19
19
  * sections — product, departure, rooms, person, shared-room, travelers,
20
20
  * price breakdown, voucher, payment schedule — and submits via the atomic
21
- * `POST /v1/bookings/quick-create` endpoint so partial failures can't
21
+ * `POST /v1/bookings/create` endpoint so partial failures can't
22
22
  * leave orphan state.
23
23
  *
24
24
  * Normally consumed via `BookingDialog` which delegates here when no
@@ -1 +1 @@
1
- {"version":3,"file":"booking-create-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-dialog.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,0BAA0B,CAAA;AAuJjC,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,EAAE,wBAAwB,2CAqB1B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,gBAAgB,EAChB,OAAc,EACd,QAAQ,GACT,EAAE,sBAAsB,2CAycxB"}
1
+ {"version":3,"file":"booking-create-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-dialog.tsx"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,aAAa,EAGnB,MAAM,0BAA0B,CAAA;AAsMjC,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,EAAE,wBAAwB,2CAqB1B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,gBAAgB,EAChB,OAAc,EACd,QAAQ,GACT,EAAE,sBAAsB,2CAkgBxB"}
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useSlots, useSlotUnitAvailability } from "@voyantjs/availability-react";
4
- import { useBookingQuickCreateMutation, useBookingStatusByIdMutation, } from "@voyantjs/bookings-react";
5
- import { Button, Checkbox, Dialog, DialogContent, DialogHeader, DialogTitle, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyantjs/ui/components";
4
+ import { useBookingCreateMutation, useBookingStatusByIdMutation, } from "@voyantjs/bookings-react";
5
+ import { Button, Checkbox, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyantjs/ui/components";
6
6
  import { Loader2 } from "lucide-react";
7
7
  import * as React from "react";
8
8
  import { formatMessage, useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault, } from "../i18n/provider.js";
9
+ import { getBookableDepartureSlots, getSelectedSharedRoomUnitId, itemLinesToRows, } from "./booking-create-utils.js";
9
10
  import { emptyPaymentScheduleValue, PaymentScheduleSection, } from "./payment-schedule-section.js";
10
11
  import { emptyPersonPickerValue, PersonPickerSection, } from "./person-picker-section.js";
11
12
  import { PriceBreakdownSection } from "./price-breakdown-section.js";
@@ -30,10 +31,11 @@ function paymentScheduleToRows(value, currency, totalAmountCents) {
30
31
  return [
31
32
  {
32
33
  scheduleType: "balance",
33
- status: "due",
34
+ status: value.fullAlreadyPaid ? "paid" : "due",
34
35
  dueDate: value.fullDueDate,
35
36
  currency,
36
37
  amountCents: totalAmountCents,
38
+ notes: paidScheduleNotes(value.fullAlreadyPaid, value.fullPaymentDate, value.fullPaymentMethod, value.fullPaymentReference),
37
39
  },
38
40
  ];
39
41
  }
@@ -43,10 +45,11 @@ function paymentScheduleToRows(value, currency, totalAmountCents) {
43
45
  const rows = [
44
46
  {
45
47
  scheduleType: "deposit",
46
- status: "due",
48
+ status: value.advanceAlreadyPaid ? "paid" : "due",
47
49
  dueDate: value.advanceDueDate,
48
50
  currency,
49
51
  amountCents: value.advanceAmountCents,
52
+ notes: paidScheduleNotes(value.advanceAlreadyPaid, value.advancePaymentDate, value.advancePaymentMethod, value.advancePaymentReference),
50
53
  },
51
54
  ];
52
55
  if (totalAmountCents !== null && totalAmountCents > value.advanceAmountCents) {
@@ -65,25 +68,38 @@ function paymentScheduleToRows(value, currency, totalAmountCents) {
65
68
  if (value.splitFirstDueDate && value.splitFirstAmountCents != null) {
66
69
  rows.push({
67
70
  scheduleType: "installment",
68
- status: "due",
71
+ status: value.splitFirstAlreadyPaid ? "paid" : "due",
69
72
  dueDate: value.splitFirstDueDate,
70
73
  currency,
71
74
  amountCents: value.splitFirstAmountCents,
75
+ notes: paidScheduleNotes(value.splitFirstAlreadyPaid, value.splitFirstPaymentDate, value.splitFirstPaymentMethod, value.splitFirstPaymentReference),
72
76
  });
73
77
  }
74
78
  if (value.splitSecondDueDate && value.splitSecondAmountCents != null) {
75
79
  rows.push({
76
80
  scheduleType: "installment",
77
- status: "pending",
81
+ status: value.splitSecondAlreadyPaid ? "paid" : "pending",
78
82
  dueDate: value.splitSecondDueDate,
79
83
  currency,
80
84
  amountCents: value.splitSecondAmountCents,
85
+ notes: paidScheduleNotes(value.splitSecondAlreadyPaid, value.splitSecondPaymentDate, value.splitSecondPaymentMethod, value.splitSecondPaymentReference),
81
86
  });
82
87
  }
83
88
  return rows;
84
89
  }
90
+ function paidScheduleNotes(alreadyPaid, paymentDate, paymentMethod, paymentReference) {
91
+ if (!alreadyPaid)
92
+ return null;
93
+ return JSON.stringify({
94
+ alreadyPaid: true,
95
+ paymentDate,
96
+ paymentMethod,
97
+ paymentReference: paymentReference.trim() || null,
98
+ });
99
+ }
85
100
  function travelersToRows(value) {
86
101
  return value.travelers.map((traveler) => ({
102
+ personId: traveler.personId,
87
103
  firstName: traveler.firstName.trim(),
88
104
  lastName: traveler.lastName.trim(),
89
105
  email: traveler.email.trim() || null,
@@ -103,7 +119,7 @@ function travelersToRows(value) {
103
119
  * Operator booking-create dialog. Composes the booking-create picker
104
120
  * sections — product, departure, rooms, person, shared-room, travelers,
105
121
  * price breakdown, voucher, payment schedule — and submits via the atomic
106
- * `POST /v1/bookings/quick-create` endpoint so partial failures can't
122
+ * `POST /v1/bookings/create` endpoint so partial failures can't
107
123
  * leave orphan state.
108
124
  *
109
125
  * Normally consumed via `BookingDialog` which delegates here when no
@@ -130,6 +146,8 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
130
146
  const [voucher, setVoucher] = React.useState(emptyVoucherPickerValue);
131
147
  const [pricing, setPricing] = React.useState(null);
132
148
  const [paymentSchedule, setPaymentSchedule] = React.useState(emptyPaymentScheduleValue);
149
+ const [generateContractDocument, setGenerateContractDocument] = React.useState(false);
150
+ const [generateInvoiceDocument, setGenerateInvoiceDocument] = React.useState(false);
133
151
  const [notes, setNotes] = React.useState("");
134
152
  /**
135
153
  * Optional post-create transition: set status to `confirmed` right after
@@ -153,6 +171,8 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
153
171
  setVoucher(emptyVoucherPickerValue);
154
172
  setPricing(null);
155
173
  setPaymentSchedule(emptyPaymentScheduleValue);
174
+ setGenerateContractDocument(false);
175
+ setGenerateInvoiceDocument(false);
156
176
  setNotes("");
157
177
  setConfirmAfterCreate(false);
158
178
  setError(null);
@@ -167,24 +187,26 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
167
187
  React.useEffect(() => {
168
188
  setSlotId(null);
169
189
  setRooms(emptyRoomsStepperValue);
190
+ setSharedRoom(emptySharedRoomValue);
170
191
  }, [product.productId, product.optionId]);
192
+ const [slotsFromIso, setSlotsFromIso] = React.useState(() => new Date().toISOString());
193
+ React.useEffect(() => {
194
+ if (enabled && product.productId)
195
+ setSlotsFromIso(new Date().toISOString());
196
+ }, [enabled, product.productId]);
171
197
  const { data: slotsData } = useSlots({
172
198
  productId: product.productId || undefined,
173
199
  status: "open",
200
+ startsAtFrom: slotsFromIso,
174
201
  limit: 100,
175
202
  enabled: enabled && Boolean(product.productId),
176
203
  });
177
204
  const slots = React.useMemo(() => {
178
- const nowIso = new Date().toISOString();
179
- return (slotsData?.data ?? [])
180
- .filter((slot) => slot.startsAt >= nowIso)
181
- .filter((slot) => {
182
- if (!product.optionId)
183
- return true;
184
- return slot.optionId === null || slot.optionId === product.optionId;
185
- })
186
- .sort((a, b) => a.startsAt.localeCompare(b.startsAt));
187
- }, [slotsData, product.optionId]);
205
+ return getBookableDepartureSlots(slotsData?.data ?? [], {
206
+ nowIso: slotsFromIso,
207
+ optionId: product.optionId,
208
+ });
209
+ }, [slotsData?.data, slotsFromIso, product.optionId]);
188
210
  const formatSlotLabel = React.useCallback((slot) => {
189
211
  const date = formatDate(slot.startsAt, {
190
212
  year: "numeric",
@@ -224,7 +246,7 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
224
246
  const currency = messages.bookingCreateDialog.labels.currency;
225
247
  const pricingCurrency = pricing?.currency ?? currency;
226
248
  const pricingTotalAmountCents = pricing?.confirmedAmountCents ?? undefined;
227
- const quickCreateMutation = useBookingQuickCreateMutation();
249
+ const createBookingMutation = useBookingCreateMutation();
228
250
  const statusMutation = useBookingStatusByIdMutation();
229
251
  const handleSubmit = async () => {
230
252
  setError(null);
@@ -262,6 +284,7 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
262
284
  return;
263
285
  }
264
286
  const paymentSchedules = paymentScheduleToRows(paymentSchedule, pricingCurrency, confirmedSellAmountCents);
287
+ const itemLines = itemLinesToRows(rooms.quantities, slotUnitAvailability.data?.data ?? [], pricing);
265
288
  const travelerRows = travelersToRows(travelers);
266
289
  const voucherRedemption = voucher.picked && voucher.picked.remainingAmountCents != null
267
290
  ? {
@@ -269,6 +292,7 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
269
292
  amountCents: voucher.picked.remainingAmountCents,
270
293
  }
271
294
  : undefined;
295
+ const selectedSharedRoomUnitId = getSelectedSharedRoomUnitId(rooms.quantities);
272
296
  const groupMembership = sharedRoom.enabled
273
297
  ? sharedRoom.mode === "create"
274
298
  ? {
@@ -276,14 +300,14 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
276
300
  kind: "shared_room",
277
301
  label: sharedRoom.groupLabel?.trim() ||
278
302
  `${messages.bookingCreateDialog.labels.sharedRoomGeneratedLabelPrefix} - ${bookingNumber}`,
279
- optionUnitId: product.optionId,
303
+ optionUnitId: selectedSharedRoomUnitId,
280
304
  makeBookingPrimary: true,
281
305
  }
282
306
  : sharedRoom.groupId
283
307
  ? { action: "join", groupId: sharedRoom.groupId, role: "shared" }
284
308
  : undefined
285
309
  : undefined;
286
- const { booking } = await quickCreateMutation.mutateAsync({
310
+ const { booking } = await createBookingMutation.mutateAsync({
287
311
  productId: product.productId,
288
312
  bookingNumber,
289
313
  optionId: product.optionId,
@@ -294,10 +318,15 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
294
318
  catalogSellAmountCents,
295
319
  confirmedSellAmountCents,
296
320
  priceOverrideReason: priceOverrideReason || null,
321
+ itemLines: itemLines.length > 0 ? itemLines : undefined,
297
322
  travelers: travelerRows.length > 0 ? travelerRows : undefined,
298
323
  paymentSchedules: paymentSchedules.length > 0 ? paymentSchedules : undefined,
299
324
  voucherRedemption,
300
325
  groupMembership,
326
+ documentGeneration: {
327
+ contractDocument: generateContractDocument,
328
+ invoiceDocument: generateInvoiceDocument,
329
+ },
301
330
  });
302
331
  // Optional post-create confirm. If the app has autoConfirmAndDispatch
303
332
  // wired on the notifications module, the status transition triggers
@@ -329,8 +358,8 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
329
358
  setError(err instanceof Error ? err.message : messages.bookingCreateDialog.validation.createFailed);
330
359
  }
331
360
  };
332
- const isSubmitting = quickCreateMutation.isPending || statusMutation.isPending;
333
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-4", children: [_jsx(ProductPickerSection, { value: product, onChange: setProduct, enabled: enabled, lockProduct: Boolean(defaultProductId), labels: {
361
+ const isSubmitting = createBookingMutation.isPending || statusMutation.isPending;
362
+ return (_jsxs(_Fragment, { children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsx(ProductPickerSection, { value: product, onChange: setProduct, enabled: enabled, lockProduct: Boolean(defaultProductId), labels: {
334
363
  optionNone: messages.bookingCreateDialog.labels.noSpecificOption,
335
364
  } }), 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: enabled, labels: {
336
365
  heading: messages.bookingCreateDialog.labels.roomsHeading,
@@ -349,9 +378,16 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
349
378
  selectPlaceholder: messages.bookingCreateDialog.labels.sharedRoomSelectPlaceholder,
350
379
  noGroups: messages.bookingCreateDialog.labels.sharedRoomNoGroups,
351
380
  createHint: messages.bookingCreateDialog.labels.sharedRoomCreateHint,
352
- } }), product.productId ? (_jsx(TravelersSection, { value: travelers, onChange: setTravelers, roomUnits: roomUnitOptions.length > 0 ? roomUnitOptions : undefined, labels: {
381
+ remove: messages.bookingCreateDialog.labels.sharedRoomRemove,
382
+ } }), product.productId ? (_jsx(TravelersSection, { value: travelers, onChange: setTravelers, roomUnits: roomUnitOptions.length > 0 ? roomUnitOptions : undefined, billingPersonId: (person.billTo ?? "person") === "person" ? person.personId : null, labels: {
353
383
  heading: messages.bookingCreateDialog.labels.travelerHeading,
354
384
  addTraveler: messages.bookingCreateDialog.labels.addTraveler,
385
+ person: messages.bookingCreateDialog.labels.travelerPerson,
386
+ personSearchPlaceholder: messages.bookingCreateDialog.labels.travelerPersonSearchPlaceholder,
387
+ personEmpty: messages.bookingCreateDialog.labels.travelerPersonEmpty,
388
+ createNewPerson: messages.bookingCreateDialog.labels.createNewPerson,
389
+ createPersonSheetTitle: messages.bookingCreateDialog.labels.createPersonSheetTitle,
390
+ addBillingPerson: messages.bookingCreateDialog.labels.addBillingPersonAsTraveler,
355
391
  role: messages.bookingCreateDialog.labels.travelerRole,
356
392
  roleLead: messages.bookingCreateDialog.labels.travelerLead,
357
393
  roleAdult: messages.bookingCreateDialog.labels.travelerAdult,
@@ -393,5 +429,9 @@ export function BookingCreateForm({ onCreated, defaultProductId, enabled = true,
393
429
  secondInstallment: messages.bookingCreateDialog.labels.paymentSecondInstallment,
394
430
  preset5050: messages.bookingCreateDialog.labels.paymentPreset5050,
395
431
  unpaidHint: messages.bookingCreateDialog.labels.paymentUnpaidHint,
396
- } }), _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: "new-booking-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: "new-booking-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("div", { className: "mt-4 flex justify-end gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onCancel, 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] })] })] }));
432
+ alreadyPaid: messages.bookingCreateDialog.labels.paymentAlreadyPaid,
433
+ paymentDate: messages.bookingCreateDialog.labels.paymentDate,
434
+ paymentMethod: messages.bookingCreateDialog.labels.paymentMethod,
435
+ paymentReference: messages.bookingCreateDialog.labels.paymentReference,
436
+ } }), _jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsx(Label, { children: messages.bookingCreateDialog.labels.documentGenerationHeading }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-generate-contract-document", checked: generateContractDocument, onCheckedChange: (value) => setGenerateContractDocument(value === true) }), _jsx(Label, { htmlFor: "new-booking-generate-contract-document", className: "cursor-pointer", children: messages.bookingCreateDialog.labels.generateContractDocument })] }), _jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-generate-invoice-document", checked: generateInvoiceDocument, onCheckedChange: (value) => setGenerateInvoiceDocument(value === true) }), _jsx(Label, { htmlFor: "new-booking-generate-invoice-document", className: "cursor-pointer", children: messages.bookingCreateDialog.labels.generateInvoiceDocument })] })] })] }), _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: "new-booking-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: "new-booking-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: onCancel, 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] })] })] }));
397
437
  }
@@ -1,11 +1,12 @@
1
1
  import type { BookingRecord } from "@voyantjs/bookings-react";
2
2
  export interface BookingCreatePageProps {
3
3
  onCreated?: (booking: BookingRecord) => void;
4
+ onCancel?: () => void;
4
5
  /** When provided, pre-selects this product and hides the product picker. */
5
6
  defaultProductId?: string;
6
7
  }
7
8
  /**
8
9
  * Full-page booking create surface for route-based booking creation.
9
10
  */
10
- export declare function BookingCreatePage({ onCreated, defaultProductId }: BookingCreatePageProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function BookingCreatePage({ onCreated, onCancel, defaultProductId, }: BookingCreatePageProps): import("react/jsx-runtime").JSX.Element;
11
12
  //# sourceMappingURL=booking-create-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"booking-create-page.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAI7D,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,sBAAsB,2CAgBxF"}
1
+ {"version":3,"file":"booking-create-page.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAI7D,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,EAAE,sBAAsB,2CAoBxB"}
@@ -5,7 +5,7 @@ import { BookingCreateForm } from "./booking-create-dialog.js";
5
5
  /**
6
6
  * Full-page booking create surface for route-based booking creation.
7
7
  */
8
- export function BookingCreatePage({ onCreated, defaultProductId }) {
8
+ export function BookingCreatePage({ onCreated, onCancel, defaultProductId, }) {
9
9
  const messages = useBookingsUiMessagesOrDefault();
10
- return (_jsxs("main", { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 px-4 py-6 sm:px-6 lg:px-8", children: [_jsxs("header", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-normal", children: messages.bookingCreatePage.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.bookingCreatePage.description })] }), _jsx("section", { className: "flex flex-col gap-4", children: _jsx(BookingCreateForm, { onCreated: onCreated, defaultProductId: defaultProductId }) })] }));
10
+ return (_jsxs("main", { className: "mx-auto flex w-full max-w-4xl flex-col gap-6 px-4 py-6 sm:px-6 lg:px-8", children: [_jsxs("header", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-normal", children: messages.bookingCreatePage.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.bookingCreatePage.description })] }), _jsx("section", { className: "flex flex-col gap-4", children: _jsx(BookingCreateForm, { onCreated: onCreated, onCancel: onCancel, defaultProductId: defaultProductId }) })] }));
11
11
  }
@@ -0,0 +1,33 @@
1
+ import type { BookingCreateItemLineInput } from "@voyantjs/bookings-react";
2
+ import type { ProductRecord } from "@voyantjs/products-react";
3
+ export type ProductPickerSearchRecord = Pick<ProductRecord, "description" | "name" | "sellCurrency">;
4
+ export interface DepartureSlotSearchRecord {
5
+ id: string;
6
+ optionId: string | null;
7
+ startsAt: string;
8
+ status?: string;
9
+ }
10
+ export interface BookingCreateUnitLineRecord {
11
+ optionUnitId: string;
12
+ unitName: string;
13
+ }
14
+ export interface BookingCreatePricingLineRecord {
15
+ unitId: string;
16
+ label: string;
17
+ unitAmountCents: number | null;
18
+ totalAmountCents: number | null;
19
+ }
20
+ export interface BookingCreatePricingRecord {
21
+ confirmedAmountCents: number | null;
22
+ lines: BookingCreatePricingLineRecord[];
23
+ }
24
+ export declare function normalizeBookingSearchText(value: string): string;
25
+ export declare function matchesBookingSearchText(value: string | null | undefined, query: string): boolean;
26
+ export declare function productMatchesPickerSearch(product: ProductPickerSearchRecord | null | undefined, query: string): boolean;
27
+ export declare function getBookableDepartureSlots<TSlot extends DepartureSlotSearchRecord>(slots: readonly TSlot[], options: {
28
+ nowIso: string;
29
+ optionId: string | null;
30
+ }): TSlot[];
31
+ export declare function itemLinesToRows(quantities: Record<string, number>, units: BookingCreateUnitLineRecord[], pricing: BookingCreatePricingRecord | null): BookingCreateItemLineInput[];
32
+ export declare function getSelectedSharedRoomUnitId(quantities: Record<string, number>): string | null;
33
+ //# sourceMappingURL=booking-create-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"booking-create-utils.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,MAAM,GAAG,cAAc,CAAC,CAAA;AAEpG,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,KAAK,EAAE,8BAA8B,EAAE,CAAA;CACxC;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIjG;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,SAAS,EACrD,KAAK,EAAE,MAAM,GACZ,OAAO,CAKT;AAED,wBAAgB,yBAAyB,CAAC,KAAK,SAAS,yBAAyB,EAC/E,KAAK,EAAE,SAAS,KAAK,EAAE,EACvB,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,GACA,KAAK,EAAE,CAST;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,KAAK,EAAE,2BAA2B,EAAE,EACpC,OAAO,EAAE,0BAA0B,GAAG,IAAI,GACzC,0BAA0B,EAAE,CAuC9B;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAE7F"}
@@ -0,0 +1,67 @@
1
+ export function normalizeBookingSearchText(value) {
2
+ return value
3
+ .normalize("NFKD")
4
+ .replace(/[\u0300-\u036f]/g, "")
5
+ .trim()
6
+ .toLowerCase();
7
+ }
8
+ export function matchesBookingSearchText(value, query) {
9
+ const normalizedQuery = normalizeBookingSearchText(query);
10
+ if (!normalizedQuery)
11
+ return true;
12
+ return normalizeBookingSearchText(value ?? "").includes(normalizedQuery);
13
+ }
14
+ export function productMatchesPickerSearch(product, query) {
15
+ if (!product)
16
+ return false;
17
+ return [product.name, product.description, product.sellCurrency].some((value) => matchesBookingSearchText(value, query));
18
+ }
19
+ export function getBookableDepartureSlots(slots, options) {
20
+ return slots
21
+ .filter((slot) => !slot.status || slot.status === "open")
22
+ .filter((slot) => slot.startsAt >= options.nowIso)
23
+ .filter((slot) => {
24
+ if (!options.optionId)
25
+ return true;
26
+ return slot.optionId === null || slot.optionId === options.optionId;
27
+ })
28
+ .sort((left, right) => left.startsAt.localeCompare(right.startsAt));
29
+ }
30
+ export function itemLinesToRows(quantities, units, pricing) {
31
+ const unitNames = new Map(units.map((unit) => [unit.optionUnitId, unit.unitName]));
32
+ const pricedLines = new Map((pricing?.lines ?? []).map((line) => [line.unitId, line]));
33
+ const selectedLines = Object.entries(quantities).filter(([, quantity]) => quantity > 0);
34
+ const pricedTotal = selectedLines.reduce((sum, [optionUnitId]) => {
35
+ const total = pricedLines.get(optionUnitId)?.totalAmountCents;
36
+ return total == null ? sum : sum + total;
37
+ }, 0);
38
+ const unpricedLines = selectedLines.filter(([optionUnitId]) => pricedLines.get(optionUnitId)?.totalAmountCents == null);
39
+ const unpricedQuantity = unpricedLines.reduce((sum, [, quantity]) => sum + quantity, 0);
40
+ const manualRemainder = pricing?.confirmedAmountCents != null && unpricedLines.length > 0
41
+ ? Math.max(0, pricing.confirmedAmountCents - pricedTotal)
42
+ : null;
43
+ let allocatedManualTotal = 0;
44
+ return selectedLines.map(([optionUnitId, quantity]) => {
45
+ const pricedLine = pricedLines.get(optionUnitId);
46
+ let totalSellAmountCents = pricedLine?.totalAmountCents ?? null;
47
+ if (totalSellAmountCents == null && manualRemainder != null && unpricedQuantity > 0) {
48
+ const isLastUnpriced = unpricedLines[unpricedLines.length - 1]?.[0] === optionUnitId;
49
+ totalSellAmountCents = isLastUnpriced
50
+ ? manualRemainder - allocatedManualTotal
51
+ : Math.floor((manualRemainder * quantity) / unpricedQuantity);
52
+ allocatedManualTotal += totalSellAmountCents;
53
+ }
54
+ const unitSellAmountCents = pricedLine?.unitAmountCents ??
55
+ (totalSellAmountCents != null ? Math.floor(totalSellAmountCents / quantity) : null);
56
+ return {
57
+ optionUnitId,
58
+ quantity,
59
+ title: pricedLine?.label ?? unitNames.get(optionUnitId) ?? null,
60
+ unitSellAmountCents,
61
+ totalSellAmountCents,
62
+ };
63
+ });
64
+ }
65
+ export function getSelectedSharedRoomUnitId(quantities) {
66
+ return Object.entries(quantities).find(([, quantity]) => quantity > 0)?.[0] ?? null;
67
+ }
@@ -2,6 +2,7 @@ import { type BookingRecord } from "@voyantjs/bookings-react";
2
2
  export interface BookingListProps {
3
3
  pageSize?: number;
4
4
  onSelectBooking?: (booking: BookingRecord) => void;
5
+ onCreateBooking?: () => void;
5
6
  }
6
- export declare function BookingList({ pageSize, onSelectBooking }?: BookingListProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function BookingList({ pageSize, onSelectBooking, onCreateBooking, }?: BookingListProps): import("react/jsx-runtime").JSX.Element;
7
8
  //# sourceMappingURL=booking-list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"booking-list.d.ts","sourceRoot":"","sources":["../../src/components/booking-list.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,0BAA0B,CAAA;AAyBjC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;CACnD;AAgBD,wBAAgB,WAAW,CAAC,EAAE,QAAa,EAAE,eAAe,EAAE,GAAE,gBAAqB,2CAmVpF"}
1
+ {"version":3,"file":"booking-list.d.ts","sourceRoot":"","sources":["../../src/components/booking-list.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,0BAA0B,CAAA;AAyBjC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAClD,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAC7B;AAgBD,wBAAgB,WAAW,CAAC,EAC1B,QAAa,EACb,eAAe,EACf,eAAe,GAChB,GAAE,gBAAqB,2CAuVvB"}
@@ -22,7 +22,7 @@ const SORTABLE_COLUMNS = {
22
22
  };
23
23
  const SKELETON_ROW_COUNT = 6;
24
24
  const TABLE_COLUMN_COUNT = 7;
25
- export function BookingList({ pageSize = 25, onSelectBooking } = {}) {
25
+ export function BookingList({ pageSize = 25, onSelectBooking, onCreateBooking, } = {}) {
26
26
  const [search, setSearch] = React.useState("");
27
27
  const [status, setStatus] = React.useState(BOOKING_STATUS_ALL);
28
28
  const [productId, setProductId] = React.useState(null);
@@ -121,6 +121,10 @@ export function BookingList({ pageSize = 25, onSelectBooking } = {}) {
121
121
  setSearch(event.target.value);
122
122
  resetOffset();
123
123
  }, className: "pl-9" })] }), _jsx(BookingListFiltersPopover, { open: filterPopoverOpen, onOpenChange: setFilterPopoverOpen, activeFilterCount: activeFilterCount, status: status, onStatusChange: setStatus, productId: productId, onProductIdChange: setProductId, optionId: optionId, onOptionIdChange: setOptionId, supplierId: supplierId, onSupplierIdChange: setSupplierId, productCategoryId: productCategoryId, onProductCategoryIdChange: setProductCategoryId, personId: personId, onPersonIdChange: setPersonId, organizationId: organizationId, onOrganizationIdChange: setOrganizationId, dateRange: dateRange, onDateRangeChange: setDateRange, paxMin: paxMin, onPaxMinChange: setPaxMin, paxMax: paxMax, onPaxMaxChange: setPaxMax, onFiltersChanged: resetOffset }), hasActiveFilters && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: clearFilters, children: [_jsx(X, { className: "mr-1 size-4" }), filterMessages.clear] })), _jsx("div", { className: "ml-auto", children: _jsxs(Button, { onClick: () => {
124
+ if (onCreateBooking) {
125
+ onCreateBooking();
126
+ return;
127
+ }
124
128
  setEditing(undefined);
125
129
  setDialogOpen(true);
126
130
  }, children: [_jsx(Plus, { className: "mr-2 size-4" }), messages.bookingList.newBooking] }) })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.bookingNumber, field: SORTABLE_COLUMNS.bookingNumber, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) }), _jsx(TableHead, { children: columnMessages.whatBooked }), _jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.status, field: SORTABLE_COLUMNS.status, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) }), _jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.sellAmount, field: SORTABLE_COLUMNS.sellAmount, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) }), _jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.pax, field: SORTABLE_COLUMNS.pax, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) }), _jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.startDate, field: SORTABLE_COLUMNS.startDate, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) }), _jsx(TableHead, { children: _jsx(SortHeader, { label: columnMessages.endDate, field: SORTABLE_COLUMNS.endDate, sortBy: sortBy, sortDir: sortDir, onSort: handleSort }) })] }) }), _jsx(TableBody, { children: showSkeleton ? (_jsx(BookingTableSkeleton, { rows: SKELETON_ROW_COUNT })) : isError ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: TABLE_COLUMN_COUNT, className: "h-24 text-center text-sm text-destructive", children: messages.bookingList.loadingError }) })) : bookings.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: TABLE_COLUMN_COUNT, className: "h-24 text-center text-sm text-muted-foreground", children: messages.bookingList.empty }) })) : (bookings.map((booking) => (_jsxs(TableRow, { onClick: () => handleSelect(booking), className: "cursor-pointer", children: [_jsx(TableCell, { className: "font-medium", children: booking.bookingNumber }), _jsx(TableCell, { children: formatBookingItems(booking, messages.bookingList.itemsMore) }), _jsx(TableCell, { children: _jsx(Badge, { variant: bookingStatusBadgeVariant[booking.status], children: statusLabels[booking.status] }) }), _jsx(TableCell, { children: booking.sellAmountCents == null
@@ -2,7 +2,8 @@ import type { BookingRecord } from "@voyantjs/bookings-react";
2
2
  export interface BookingsPageProps {
3
3
  pageSize?: number;
4
4
  onBookingOpen?: (booking: BookingRecord) => void;
5
+ onCreateBooking?: () => void;
5
6
  className?: string;
6
7
  }
7
- export declare function BookingsPage({ pageSize, onBookingOpen, className }?: BookingsPageProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function BookingsPage({ pageSize, onBookingOpen, onCreateBooking, className, }?: BookingsPageProps): import("react/jsx-runtime").JSX.Element;
8
9
  //# sourceMappingURL=bookings-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bookings-page.d.ts","sourceRoot":"","sources":["../../src/components/bookings-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAK7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,GAAE,iBAAsB,2CAa1F"}
1
+ {"version":3,"file":"bookings-page.d.ts","sourceRoot":"","sources":["../../src/components/bookings-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAK7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAChD,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,aAAa,EACb,eAAe,EACf,SAAS,GACV,GAAE,iBAAsB,2CAiBxB"}
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { cn } from "@voyantjs/ui/lib/utils";
4
4
  import { useBookingsUiMessagesOrDefault } from "../i18n/index.js";
5
5
  import { BookingList } from "./booking-list.js";
6
- export function BookingsPage({ pageSize, onBookingOpen, className } = {}) {
6
+ export function BookingsPage({ pageSize, onBookingOpen, onCreateBooking, className, } = {}) {
7
7
  const messages = useBookingsUiMessagesOrDefault().bookingsPage;
8
- return (_jsxs("div", { "data-slot": "bookings-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(BookingList, { pageSize: pageSize, onSelectBooking: onBookingOpen })] }));
8
+ return (_jsxs("div", { "data-slot": "bookings-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: messages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: messages.description })] }), _jsx(BookingList, { pageSize: pageSize, onSelectBooking: onBookingOpen, onCreateBooking: onCreateBooking })] }));
9
9
  }
@@ -11,6 +11,22 @@ export interface PaymentScheduleValue {
11
11
  splitFirstDueDate: string | null;
12
12
  splitSecondAmountCents: number | null;
13
13
  splitSecondDueDate: string | null;
14
+ fullAlreadyPaid: boolean;
15
+ fullPaymentDate: string | null;
16
+ fullPaymentMethod: string;
17
+ fullPaymentReference: string;
18
+ advanceAlreadyPaid: boolean;
19
+ advancePaymentDate: string | null;
20
+ advancePaymentMethod: string;
21
+ advancePaymentReference: string;
22
+ splitFirstAlreadyPaid: boolean;
23
+ splitFirstPaymentDate: string | null;
24
+ splitFirstPaymentMethod: string;
25
+ splitFirstPaymentReference: string;
26
+ splitSecondAlreadyPaid: boolean;
27
+ splitSecondPaymentDate: string | null;
28
+ splitSecondPaymentMethod: string;
29
+ splitSecondPaymentReference: string;
14
30
  }
15
31
  export declare const emptyPaymentScheduleValue: PaymentScheduleValue;
16
32
  export interface PaymentScheduleSectionProps {
@@ -36,6 +52,10 @@ export interface PaymentScheduleSectionProps {
36
52
  secondInstallment?: string;
37
53
  preset5050?: string;
38
54
  unpaidHint?: string;
55
+ alreadyPaid?: string;
56
+ paymentDate?: string;
57
+ paymentMethod?: string;
58
+ paymentReference?: string;
39
59
  };
40
60
  }
41
61
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"payment-schedule-section.d.ts","sourceRoot":"","sources":["../../src/components/payment-schedule-section.tsx"],"names":[],"mappings":"AAOA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;AAEzE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,mBAAmB,CAAA;IACzB,wEAAwE;IACxE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,wEAAwE;IACxE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,qDAAqD;IACrD,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED,eAAO,MAAM,yBAAyB,EAAE,oBASvC,CAAA;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,oBAAoB,CAAA;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC/C;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,QAAQ,EACR,MAAM,GACP,EAAE,2BAA2B,2CAmH7B"}
1
+ {"version":3,"file":"payment-schedule-section.d.ts","sourceRoot":"","sources":["../../src/components/payment-schedule-section.tsx"],"names":[],"mappings":"AAiBA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;AAEzE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,mBAAmB,CAAA;IACzB,wEAAwE;IACxE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,wEAAwE;IACxE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,qDAAqD;IACrD,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,eAAe,EAAE,OAAO,CAAA;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,MAAM,CAAA;IAC5B,uBAAuB,EAAE,MAAM,CAAA;IAC/B,qBAAqB,EAAE,OAAO,CAAA;IAC9B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,uBAAuB,EAAE,MAAM,CAAA;IAC/B,0BAA0B,EAAE,MAAM,CAAA;IAClC,sBAAsB,EAAE,OAAO,CAAA;IAC/B,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,wBAAwB,EAAE,MAAM,CAAA;IAChC,2BAA2B,EAAE,MAAM,CAAA;CACpC;AAED,eAAO,MAAM,yBAAyB,EAAE,oBAyBvC,CAAA;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,oBAAoB,CAAA;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC/C;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,QAAQ,EACR,gBAAgB,EAChB,QAAQ,EACR,MAAM,GACP,EAAE,2BAA2B,2CA8L7B"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Button, Label } from "@voyantjs/ui/components";
3
+ import { Button, Checkbox, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/ui/components";
4
4
  import { CurrencyInput } from "@voyantjs/ui/components/currency-input";
5
5
  import { DatePicker } from "@voyantjs/ui/components/date-picker";
6
6
  import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
@@ -13,6 +13,22 @@ export const emptyPaymentScheduleValue = {
13
13
  splitFirstDueDate: null,
14
14
  splitSecondAmountCents: null,
15
15
  splitSecondDueDate: null,
16
+ fullAlreadyPaid: false,
17
+ fullPaymentDate: null,
18
+ fullPaymentMethod: "bank_transfer",
19
+ fullPaymentReference: "",
20
+ advanceAlreadyPaid: false,
21
+ advancePaymentDate: null,
22
+ advancePaymentMethod: "bank_transfer",
23
+ advancePaymentReference: "",
24
+ splitFirstAlreadyPaid: false,
25
+ splitFirstPaymentDate: null,
26
+ splitFirstPaymentMethod: "bank_transfer",
27
+ splitFirstPaymentReference: "",
28
+ splitSecondAlreadyPaid: false,
29
+ splitSecondPaymentDate: null,
30
+ splitSecondPaymentMethod: "bank_transfer",
31
+ splitSecondPaymentReference: "",
16
32
  };
17
33
  /**
18
34
  * Payment schedule picker for booking-create flows. Operators choose one of
@@ -55,5 +71,14 @@ export function PaymentScheduleSection({ value, onChange, totalAmountCents, curr
55
71
  splitSecondAmountCents: totalAmountCents - half,
56
72
  });
57
73
  };
58
- return (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsx("div", { className: "flex flex-wrap items-center gap-2", children: modes.map((mode) => (_jsx(Button, { type: "button", size: "sm", variant: value.mode === mode.id ? "default" : "ghost", onClick: () => set({ mode: mode.id }), children: mode.label }, mode.id))) }), value.mode === "unpaid" && (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.unpaidHint })), value.mode === "full" && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.dueDate }), _jsx(DatePicker, { value: value.fullDueDate ?? "", onChange: (nextValue) => set({ fullDueDate: nextValue }) })] })), value.mode === "advance" && (_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.amount }), _jsx(CurrencyInput, { value: value.advanceAmountCents, onChange: (next) => set({ advanceAmountCents: next }), currency: currency })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.dueDate }), _jsx(DatePicker, { value: value.advanceDueDate ?? "", onChange: (nextValue) => set({ advanceDueDate: nextValue }) })] })] })), value.mode === "split" && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium", children: merged.firstInstallment }), totalAmountCents ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: handlePreset5050, children: merged.preset5050 })) : null] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(CurrencyInput, { placeholder: merged.amount, value: value.splitFirstAmountCents, onChange: (next) => set({ splitFirstAmountCents: next }), currency: currency }), _jsx(DatePicker, { value: value.splitFirstDueDate ?? "", onChange: (nextValue) => set({ splitFirstDueDate: nextValue }) })] }), _jsx("div", { className: "text-xs font-medium", children: merged.secondInstallment }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(CurrencyInput, { placeholder: merged.amount, value: value.splitSecondAmountCents, onChange: (next) => set({ splitSecondAmountCents: next }), currency: currency }), _jsx(DatePicker, { value: value.splitSecondDueDate ?? "", onChange: (nextValue) => set({ splitSecondDueDate: nextValue }) })] })] }))] }));
74
+ const paymentMethodLabels = messages.bookingPaymentsSummary.paymentMethodLabels;
75
+ const renderPaidFields = (prefix, checked) => {
76
+ const paymentDateKey = `${prefix}PaymentDate`;
77
+ const paymentMethodKey = `${prefix}PaymentMethod`;
78
+ const paymentReferenceKey = `${prefix}PaymentReference`;
79
+ const checkedKey = `${prefix}AlreadyPaid`;
80
+ const checkboxId = `payment-schedule-${prefix}-already-paid`;
81
+ return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border border-dashed p-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: checkboxId, checked: checked, onCheckedChange: (next) => set({ [checkedKey]: next === true }) }), _jsx(Label, { htmlFor: checkboxId, className: "cursor-pointer text-xs", children: merged.alreadyPaid })] }), checked ? (_jsxs("div", { className: "grid gap-2 sm:grid-cols-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.paymentDate }), _jsx(DatePicker, { value: value[paymentDateKey] ?? "", onChange: (nextValue) => set({ [paymentDateKey]: nextValue }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.paymentMethod }), _jsxs(Select, { value: value[paymentMethodKey] ?? "bank_transfer", onValueChange: (nextValue) => set({ [paymentMethodKey]: nextValue ?? "bank_transfer" }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: ["bank_transfer", "credit_card", "cash", "voucher", "other"].map((method) => (_jsx(SelectItem, { value: method, children: paymentMethodLabels[method === "credit_card" ? "card" : method] }, method))) })] })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.paymentReference }), _jsx(Input, { value: value[paymentReferenceKey] ?? "", onChange: (event) => set({ [paymentReferenceKey]: event.target.value }) })] })] })) : null] }));
82
+ };
83
+ return (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsx("div", { className: "flex flex-wrap items-center gap-2", children: modes.map((mode) => (_jsx(Button, { type: "button", size: "sm", variant: value.mode === mode.id ? "default" : "ghost", onClick: () => set({ mode: mode.id }), children: mode.label }, mode.id))) }), value.mode === "unpaid" && (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.unpaidHint })), value.mode === "full" && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.dueDate }), _jsx(DatePicker, { value: value.fullDueDate ?? "", onChange: (nextValue) => set({ fullDueDate: nextValue }) })] }), renderPaidFields("full", value.fullAlreadyPaid)] })), value.mode === "advance" && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.amount }), _jsx(CurrencyInput, { value: value.advanceAmountCents, onChange: (next) => set({ advanceAmountCents: next }), currency: currency })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.dueDate }), _jsx(DatePicker, { value: value.advanceDueDate ?? "", onChange: (nextValue) => set({ advanceDueDate: nextValue }) })] })] }), renderPaidFields("advance", value.advanceAlreadyPaid)] })), value.mode === "split" && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium", children: merged.firstInstallment }), totalAmountCents ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: handlePreset5050, children: merged.preset5050 })) : null] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(CurrencyInput, { placeholder: merged.amount, value: value.splitFirstAmountCents, onChange: (next) => set({ splitFirstAmountCents: next }), currency: currency }), _jsx(DatePicker, { value: value.splitFirstDueDate ?? "", onChange: (nextValue) => set({ splitFirstDueDate: nextValue }) })] }), renderPaidFields("splitFirst", value.splitFirstAlreadyPaid), _jsx("div", { className: "text-xs font-medium", children: merged.secondInstallment }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(CurrencyInput, { placeholder: merged.amount, value: value.splitSecondAmountCents, onChange: (next) => set({ splitSecondAmountCents: next }), currency: currency }), _jsx(DatePicker, { value: value.splitSecondDueDate ?? "", onChange: (nextValue) => set({ splitSecondDueDate: nextValue }) })] }), renderPaidFields("splitSecond", value.splitSecondAlreadyPaid)] }))] }));
59
84
  }
@@ -20,6 +20,7 @@ export interface PriceBreakdownValue {
20
20
  priceOverrideReason: string;
21
21
  isManualOverride: boolean;
22
22
  requiresReason: boolean;
23
+ lines: PriceBreakdownLine[];
23
24
  }
24
25
  export interface PriceBreakdownSectionProps {
25
26
  productId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"price-breakdown-section.d.ts","sourceRoot":"","sources":["../../src/components/price-breakdown-section.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gBAAgB,EAAE,OAAO,CAAA;IACzB,cAAc,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,yBAAyB,CAAC,EAAE,MAAM,CAAA;QAClC,sBAAsB,CAAC,EAAE,MAAM,CAAA;KAChC,CAAA;IACD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAChD;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,cAAc,EACd,SAAS,EACT,MAAM,EACN,QAAQ,GACT,EAAE,0BAA0B,kDAoQ5B"}
1
+ {"version":3,"file":"price-breakdown-section.d.ts","sourceRoot":"","sources":["../../src/components/price-breakdown-section.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gBAAgB,EAAE,OAAO,CAAA;IACzB,cAAc,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,yBAAyB,CAAC,EAAE,MAAM,CAAA;QAClC,sBAAsB,CAAC,EAAE,MAAM,CAAA;KAChC,CAAA;IACD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAChD;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,cAAc,EACd,SAAS,EACT,MAAM,EACN,QAAQ,GACT,EAAE,0BAA0B,kDAsQ5B"}
@@ -167,11 +167,13 @@ export function PriceBreakdownSection({ productId, optionId, unitQuantities, cat
167
167
  priceOverrideReason: overrideReason,
168
168
  isManualOverride,
169
169
  requiresReason,
170
+ lines,
170
171
  });
171
172
  }, [
172
173
  confirmedAmountCents,
173
174
  currency,
174
175
  isManualOverride,
176
+ lines,
175
177
  onChange,
176
178
  overrideReason,
177
179
  requiresReason,