@voyantjs/bookings-ui 0.52.1 → 0.52.2

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 (55) hide show
  1. package/dist/components/booking-billing-dialog.d.ts +16 -0
  2. package/dist/components/booking-billing-dialog.d.ts.map +1 -0
  3. package/dist/components/booking-billing-dialog.js +90 -0
  4. package/dist/components/booking-create-dialog.d.ts.map +1 -1
  5. package/dist/components/booking-create-dialog.js +512 -151
  6. package/dist/components/booking-create-page.js +1 -1
  7. package/dist/components/booking-document-dialog.d.ts.map +1 -1
  8. package/dist/components/booking-document-dialog.js +16 -14
  9. package/dist/components/booking-guarantee-dialog.d.ts.map +1 -1
  10. package/dist/components/booking-guarantee-dialog.js +10 -8
  11. package/dist/components/booking-item-dialog.d.ts.map +1 -1
  12. package/dist/components/booking-item-dialog.js +18 -9
  13. package/dist/components/booking-item-travelers.d.ts.map +1 -1
  14. package/dist/components/booking-item-travelers.js +9 -7
  15. package/dist/components/booking-payment-schedule-dialog.d.ts.map +1 -1
  16. package/dist/components/booking-payment-schedule-dialog.js +10 -8
  17. package/dist/components/booking-payment-schedule-list.d.ts.map +1 -1
  18. package/dist/components/booking-payment-schedule-list.js +32 -3
  19. package/dist/components/{rooms-stepper-section.d.ts → option-units-stepper-section.d.ts} +17 -9
  20. package/dist/components/option-units-stepper-section.d.ts.map +1 -0
  21. package/dist/components/option-units-stepper-section.js +172 -0
  22. package/dist/components/payment-schedule-section.d.ts +1 -1
  23. package/dist/components/payment-schedule-section.d.ts.map +1 -1
  24. package/dist/components/payment-schedule-section.js +5 -11
  25. package/dist/components/person-picker-section.d.ts +4 -0
  26. package/dist/components/person-picker-section.d.ts.map +1 -1
  27. package/dist/components/person-picker-section.js +27 -5
  28. package/dist/components/price-breakdown-section.d.ts +8 -2
  29. package/dist/components/price-breakdown-section.d.ts.map +1 -1
  30. package/dist/components/price-breakdown-section.js +17 -5
  31. package/dist/components/status-change-dialog.d.ts.map +1 -1
  32. package/dist/components/status-change-dialog.js +6 -5
  33. package/dist/components/supplier-status-dialog.d.ts.map +1 -1
  34. package/dist/components/supplier-status-dialog.js +6 -5
  35. package/dist/components/traveler-list.d.ts.map +1 -1
  36. package/dist/components/traveler-list.js +12 -1
  37. package/dist/components/travelers-section.d.ts +62 -3
  38. package/dist/components/travelers-section.d.ts.map +1 -1
  39. package/dist/components/travelers-section.js +290 -23
  40. package/dist/i18n/en.d.ts +63 -0
  41. package/dist/i18n/en.d.ts.map +1 -1
  42. package/dist/i18n/en.js +68 -5
  43. package/dist/i18n/messages.d.ts +63 -0
  44. package/dist/i18n/messages.d.ts.map +1 -1
  45. package/dist/i18n/provider.d.ts +126 -0
  46. package/dist/i18n/provider.d.ts.map +1 -1
  47. package/dist/i18n/ro.d.ts +63 -0
  48. package/dist/i18n/ro.d.ts.map +1 -1
  49. package/dist/i18n/ro.js +68 -5
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +1 -1
  53. package/package.json +26 -24
  54. package/dist/components/rooms-stepper-section.d.ts.map +0 -1
  55. package/dist/components/rooms-stepper-section.js +0 -111
@@ -1 +1 @@
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,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,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,2CAkO7B"}
1
+ {"version":3,"file":"payment-schedule-section.d.ts","sourceRoot":"","sources":["../../src/components/payment-schedule-section.tsx"],"names":[],"mappings":"AAsBA,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,CAAA;AAElD,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,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,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,2CAiM7B"}
@@ -5,7 +5,7 @@ import { CurrencyInput } from "@voyantjs/ui/components/currency-input";
5
5
  import { DatePicker } from "@voyantjs/ui/components/date-picker";
6
6
  import { useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
7
7
  export const emptyPaymentScheduleValue = {
8
- mode: "unpaid",
8
+ mode: "full",
9
9
  fullDueDate: null,
10
10
  advanceAmountCents: null,
11
11
  advanceDueDate: null,
@@ -56,9 +56,7 @@ export function PaymentScheduleSection({ value, onChange, totalAmountCents, curr
56
56
  const merged = { ...messages.paymentScheduleSection.labels, ...labels };
57
57
  const set = (patch) => onChange({ ...value, ...patch });
58
58
  const modes = [
59
- { id: "unpaid", label: merged.modeUnpaid },
60
59
  { id: "full", label: merged.modeFull },
61
- { id: "advance", label: merged.modeAdvance },
62
60
  { id: "split", label: merged.modeSplit },
63
61
  ];
64
62
  const handlePreset5050 = () => {
@@ -73,13 +71,9 @@ export function PaymentScheduleSection({ value, onChange, totalAmountCents, curr
73
71
  });
74
72
  };
75
73
  const total = typeof totalAmountCents === "number" ? totalAmountCents : null;
76
- const scheduledTotal = value.mode === "unpaid"
77
- ? 0
78
- : value.mode === "full"
79
- ? (total ?? 0)
80
- : value.mode === "advance"
81
- ? (value.advanceAmountCents ?? 0)
82
- : (value.splitFirstAmountCents ?? 0) + (value.splitSecondAmountCents ?? 0);
74
+ const scheduledTotal = value.mode === "full"
75
+ ? (total ?? 0)
76
+ : (value.splitFirstAmountCents ?? 0) + (value.splitSecondAmountCents ?? 0);
83
77
  const remaining = total === null ? null : Math.max(0, total - scheduledTotal);
84
78
  const formatAmount = (cents) => {
85
79
  if (cents === null)
@@ -100,5 +94,5 @@ export function PaymentScheduleSection({ value, onChange, totalAmountCents, curr
100
94
  const checkboxId = `payment-schedule-${prefix}-already-paid`;
101
95
  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] }));
102
96
  };
103
- return (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsxs("div", { className: "grid gap-2 rounded-md bg-muted/40 p-2 text-xs sm:grid-cols-3", children: [_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.totalDue }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(total) })] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.scheduledTotal }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(scheduledTotal) })] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.remaining }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(remaining) })] })] }), _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)] }))] }));
97
+ return (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsxs("div", { className: "grid gap-2 rounded-md bg-muted/40 p-2 text-xs sm:grid-cols-3", children: [_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.totalDue }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(total) })] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.scheduledTotal }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(scheduledTotal) })] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground", children: merged.remaining }), _jsx("span", { className: "font-medium tabular-nums", children: formatAmount(remaining) })] })] }), _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 === "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 === "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)] }))] }));
104
98
  }
@@ -33,6 +33,10 @@ export interface PersonPickerSectionProps {
33
33
  createNewOrganization?: string;
34
34
  createPersonSheetTitle?: string;
35
35
  createOrganizationSheetTitle?: string;
36
+ editPerson?: string;
37
+ editOrganization?: string;
38
+ editPersonSheetTitle?: string;
39
+ editOrganizationSheetTitle?: string;
36
40
  selectExistingPerson?: string;
37
41
  personSearchPlaceholder?: string;
38
42
  personSelectPlaceholder?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"person-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/person-picker-section.tsx"],"names":[],"mappings":"AAiCA,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,KAAK,CAAA;AACjD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,cAAc,CAAA;AAEzD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,IAAI,EAAE,gBAAgB,CAAA;IACtB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,SAAS,EAAE,cAAc,CAAA;IACzB,yCAAyC;IACzC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,eAAO,MAAM,cAAc,EAAE,cAK5B,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,iBAMpC,CAAA;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,iBAAiB,CAAA;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,4BAA4B,CAAC,EAAE,MAAM,CAAA;QACrC,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,6BAA6B,CAAC,EAAE,MAAM,CAAA;QACtC,6BAA6B,CAAC,EAAE,MAAM,CAAA;QACtC,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,OAAc,EACd,gBAAuB,EACvB,MAAM,GACP,EAAE,wBAAwB,2CA+Q1B"}
1
+ {"version":3,"file":"person-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/person-picker-section.tsx"],"names":[],"mappings":"AAiCA,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,KAAK,CAAA;AACjD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,cAAc,CAAA;AAEzD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,IAAI,EAAE,gBAAgB,CAAA;IACtB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,SAAS,EAAE,cAAc,CAAA;IACzB,yCAAyC;IACzC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,eAAO,MAAM,cAAc,EAAE,cAK5B,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,iBAMpC,CAAA;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,iBAAiB,CAAA;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,4BAA4B,CAAC,EAAE,MAAM,CAAA;QACrC,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,0BAA0B,CAAC,EAAE,MAAM,CAAA;QACnC,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,6BAA6B,CAAC,EAAE,MAAM,CAAA;QACtC,6BAA6B,CAAC,EAAE,MAAM,CAAA;QACtC,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,OAAc,EACd,gBAAuB,EACvB,MAAM,GACP,EAAE,wBAAwB,2CA2U1B"}
@@ -4,7 +4,7 @@ import { useOrganization, useOrganizations, usePeople, usePerson, } from "@voyan
4
4
  import { OrganizationForm, PersonForm } from "@voyantjs/crm-ui";
5
5
  import { Button, Label, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, } from "@voyantjs/ui/components";
6
6
  import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
7
- import { Building2, User, UserPlus } from "lucide-react";
7
+ import { Building2, Pencil, User, UserPlus } from "lucide-react";
8
8
  import * as React from "react";
9
9
  import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
10
10
  export const emptyNewPerson = {
@@ -34,7 +34,9 @@ export function PersonPickerSection({ value, onChange, enabled = true, showOrgan
34
34
  const [personInputValue, setPersonInputValue] = React.useState("");
35
35
  const [orgInputValue, setOrgInputValue] = React.useState("");
36
36
  const [personSheetOpen, setPersonSheetOpen] = React.useState(false);
37
+ const [personSheetMode, setPersonSheetMode] = React.useState("create");
37
38
  const [orgSheetOpen, setOrgSheetOpen] = React.useState(false);
39
+ const [orgSheetMode, setOrgSheetMode] = React.useState("create");
38
40
  const messages = useBookingsUiMessagesOrDefault();
39
41
  const merged = { ...messages.personPickerSection.labels, ...labels };
40
42
  const billingTarget = value.billTo ?? "person";
@@ -87,7 +89,13 @@ export function PersonPickerSection({ value, onChange, enabled = true, showOrgan
87
89
  if (selectedOrgLabel)
88
90
  setOrgInputValue(selectedOrgLabel);
89
91
  }, [selectedOrgLabel]);
90
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: merged.billTo }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs(Button, { type: "button", variant: billingTarget === "person" ? "default" : "outline", onClick: () => setPerson({ billTo: "person", organizationId: null }), disabled: !enabled, children: [_jsx(User, { className: "mr-2 h-4 w-4" }), merged.billToPerson] }), _jsxs(Button, { type: "button", variant: billingTarget === "organization" ? "default" : "outline", onClick: () => setPerson({ billTo: "organization", personId: "" }), disabled: !enabled || !showOrganization, children: [_jsx(Building2, { className: "mr-2 h-4 w-4" }), merged.billToOrganization] })] })] }), billingTarget === "person" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { children: [merged.person, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => setPersonSheetOpen(true), disabled: !enabled, children: [_jsx(UserPlus, { className: "mr-1 h-3.5 w-3.5" }), merged.createNewPerson] })] }), _jsxs(Combobox, { items: people.map((person) => person.id), value: value.personId || null, inputValue: personInputValue, autoHighlight: true, disabled: !enabled, itemToStringLabel: (id) => resolvePersonLabel(id) || id, itemToStringValue: (id) => id, onInputValueChange: (next) => {
92
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: merged.billTo }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs(Button, { type: "button", variant: billingTarget === "person" ? "default" : "outline", onClick: () => setPerson({ billTo: "person", organizationId: null }), disabled: !enabled, children: [_jsx(User, { className: "mr-2 h-4 w-4" }), merged.billToPerson] }), _jsxs(Button, { type: "button", variant: billingTarget === "organization" ? "default" : "outline", onClick: () => setPerson({ billTo: "organization", personId: "" }), disabled: !enabled || !showOrganization, children: [_jsx(Building2, { className: "mr-2 h-4 w-4" }), merged.billToOrganization] })] })] }), billingTarget === "person" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { children: [merged.person, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [value.personId ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => {
93
+ setPersonSheetMode("edit");
94
+ setPersonSheetOpen(true);
95
+ }, disabled: !enabled || !selectedPersonQuery.data, children: [_jsx(Pencil, { className: "mr-1 h-3.5 w-3.5" }), merged.editPerson] })) : null, _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => {
96
+ setPersonSheetMode("create");
97
+ setPersonSheetOpen(true);
98
+ }, disabled: !enabled, children: [_jsx(UserPlus, { className: "mr-1 h-3.5 w-3.5" }), merged.createNewPerson] })] })] }), _jsxs(Combobox, { items: people.map((person) => person.id), value: value.personId || null, inputValue: personInputValue, autoHighlight: true, disabled: !enabled, itemToStringLabel: (id) => resolvePersonLabel(id) || id, itemToStringValue: (id) => id, onInputValueChange: (next) => {
91
99
  setPersonInputValue(next);
92
100
  setPersonSearch(next);
93
101
  if (!next)
@@ -101,7 +109,13 @@ export function PersonPickerSection({ value, onChange, enabled = true, showOrgan
101
109
  if (!person)
102
110
  return null;
103
111
  return (_jsx(ComboboxItem, { value: person.id, children: _jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate font-medium", children: formatPersonName(person) }), person.email ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: person.email })) : null] }) }, person.id));
104
- } }) })] })] })] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { children: [merged.organization, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => setOrgSheetOpen(true), disabled: !enabled, children: [_jsx(Building2, { className: "mr-1 h-3.5 w-3.5" }), merged.createNewOrganization] })] }), _jsxs(Combobox, { items: orgs.map((org) => org.id), value: value.organizationId ?? null, inputValue: orgInputValue, autoHighlight: true, disabled: !enabled, itemToStringLabel: (id) => resolveOrgLabel(id) || id, itemToStringValue: (id) => id, onInputValueChange: (next) => {
112
+ } }) })] })] })] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { children: [merged.organization, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [value.organizationId ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => {
113
+ setOrgSheetMode("edit");
114
+ setOrgSheetOpen(true);
115
+ }, disabled: !enabled || !selectedOrgQuery.data, children: [_jsx(Pencil, { className: "mr-1 h-3.5 w-3.5" }), merged.editOrganization] })) : null, _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => {
116
+ setOrgSheetMode("create");
117
+ setOrgSheetOpen(true);
118
+ }, disabled: !enabled, children: [_jsx(Building2, { className: "mr-1 h-3.5 w-3.5" }), merged.createNewOrganization] })] })] }), _jsxs(Combobox, { items: orgs.map((org) => org.id), value: value.organizationId ?? null, inputValue: orgInputValue, autoHighlight: true, disabled: !enabled, itemToStringLabel: (id) => resolveOrgLabel(id) || id, itemToStringValue: (id) => id, onInputValueChange: (next) => {
105
119
  setOrgInputValue(next);
106
120
  setOrgSearch(next);
107
121
  if (!next)
@@ -115,11 +129,19 @@ export function PersonPickerSection({ value, onChange, enabled = true, showOrgan
115
129
  if (!org)
116
130
  return null;
117
131
  return (_jsx(ComboboxItem, { value: org.id, children: _jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate font-medium", children: org.name }), org.legalName ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: org.legalName })) : null] }) }, org.id));
118
- } }) })] })] })] })), _jsx(Sheet, { open: personSheetOpen, onOpenChange: setPersonSheetOpen, children: _jsxs(SheetContent, { side: "right", size: "lg", children: [_jsx(SheetHeader, { children: _jsx(SheetTitle, { children: merged.createPersonSheetTitle }) }), _jsx(SheetBody, { children: _jsx(PersonForm, { mode: { kind: "create" }, onCancel: () => setPersonSheetOpen(false), onSuccess: (saved) => {
132
+ } }) })] })] })] })), _jsx(Sheet, { open: personSheetOpen, onOpenChange: setPersonSheetOpen, children: _jsxs(SheetContent, { side: "right", size: "lg", children: [_jsx(SheetHeader, { children: _jsx(SheetTitle, { children: personSheetMode === "edit"
133
+ ? merged.editPersonSheetTitle
134
+ : merged.createPersonSheetTitle }) }), _jsx(SheetBody, { children: _jsx(PersonForm, { mode: personSheetMode === "edit" && selectedPersonQuery.data
135
+ ? { kind: "edit", person: selectedPersonQuery.data }
136
+ : { kind: "create" }, onCancel: () => setPersonSheetOpen(false), onSuccess: (saved) => {
119
137
  setPerson({ billTo: "person", personId: saved.id, organizationId: null });
120
138
  setPersonInputValue(formatPerson(saved));
121
139
  setPersonSheetOpen(false);
122
- } }) })] }) }), _jsx(Sheet, { open: orgSheetOpen, onOpenChange: setOrgSheetOpen, children: _jsxs(SheetContent, { side: "right", size: "lg", children: [_jsx(SheetHeader, { children: _jsx(SheetTitle, { children: merged.createOrganizationSheetTitle }) }), _jsx(SheetBody, { children: _jsx(OrganizationForm, { mode: { kind: "create" }, onCancel: () => setOrgSheetOpen(false), onSuccess: (saved) => {
140
+ } }) })] }) }), _jsx(Sheet, { open: orgSheetOpen, onOpenChange: setOrgSheetOpen, children: _jsxs(SheetContent, { side: "right", size: "lg", children: [_jsx(SheetHeader, { children: _jsx(SheetTitle, { children: orgSheetMode === "edit"
141
+ ? merged.editOrganizationSheetTitle
142
+ : merged.createOrganizationSheetTitle }) }), _jsx(SheetBody, { children: _jsx(OrganizationForm, { mode: orgSheetMode === "edit" && selectedOrgQuery.data
143
+ ? { kind: "edit", organization: selectedOrgQuery.data }
144
+ : { kind: "create" }, onCancel: () => setOrgSheetOpen(false), onSuccess: (saved) => {
123
145
  setPerson({ billTo: "organization", personId: "", organizationId: saved.id });
124
146
  setOrgInputValue(saved.name);
125
147
  setOrgSheetOpen(false);
@@ -25,7 +25,7 @@ export interface PriceBreakdownValue {
25
25
  export interface PriceBreakdownSectionProps {
26
26
  productId?: string;
27
27
  optionId?: string | null;
28
- /** Quantity per option_unit id, typically from RoomsStepperSection. */
28
+ /** Quantity per option_unit id, typically from OptionUnitsStepperSection. */
29
29
  unitQuantities: Record<string, number>;
30
30
  /** Display labels keyed by option_unit id. */
31
31
  unitLabels?: Record<string, string>;
@@ -49,6 +49,12 @@ export interface PriceBreakdownSectionProps {
49
49
  overrideReasonRequired?: string;
50
50
  };
51
51
  onChange?: (value: PriceBreakdownValue) => void;
52
+ /**
53
+ * When true, the section drops its bordered card wrapper and the
54
+ * heading label — for embedding inside another card (e.g. the
55
+ * booking-summary panel) where the parent owns the chrome.
56
+ */
57
+ flat?: boolean;
52
58
  }
53
59
  /**
54
60
  * Live price-breakdown preview for booking-create flows. Read-only — uses
@@ -62,5 +68,5 @@ export interface PriceBreakdownSectionProps {
62
68
  * - `free` / `included` — render 0.00 without an on-request badge.
63
69
  * - `on_request` / anything else — render "On request"; total excludes it.
64
70
  */
65
- export declare function PriceBreakdownSection({ productId, optionId, unitQuantities, unitLabels, catalogId, labels, onChange, }: PriceBreakdownSectionProps): import("react/jsx-runtime").JSX.Element | null;
71
+ export declare function PriceBreakdownSection({ productId, optionId, unitQuantities, unitLabels, catalogId, labels, onChange, flat, }: PriceBreakdownSectionProps): import("react/jsx-runtime").JSX.Element | null;
66
72
  //# sourceMappingURL=price-breakdown-section.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"price-breakdown-section.d.ts","sourceRoot":"","sources":["../../src/components/price-breakdown-section.tsx"],"names":[],"mappings":"AASA,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,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;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,UAAU,EACV,SAAS,EACT,MAAM,EACN,QAAQ,GACT,EAAE,0BAA0B,kDAoS5B"}
1
+ {"version":3,"file":"price-breakdown-section.d.ts","sourceRoot":"","sources":["../../src/components/price-breakdown-section.tsx"],"names":[],"mappings":"AASA,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,6EAA6E;IAC7E,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;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;IAC/C;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,cAAc,EACd,UAAU,EACV,SAAS,EACT,MAAM,EACN,QAAQ,EACR,IAAY,GACb,EAAE,0BAA0B,kDAiT5B"}
@@ -34,7 +34,7 @@ function matchTier(tiers, qty) {
34
34
  * - `free` / `included` — render 0.00 without an on-request badge.
35
35
  * - `on_request` / anything else — render "On request"; total excludes it.
36
36
  */
37
- export function PriceBreakdownSection({ productId, optionId, unitQuantities, unitLabels, catalogId, labels, onChange, }) {
37
+ export function PriceBreakdownSection({ productId, optionId, unitQuantities, unitLabels, catalogId, labels, onChange, flat = false, }) {
38
38
  const { formatCurrency, formatNumber } = useBookingsUiI18nOrDefault();
39
39
  const messages = useBookingsUiMessagesOrDefault();
40
40
  const merged = { ...messages.priceBreakdownSection.labels, ...labels };
@@ -209,17 +209,29 @@ export function PriceBreakdownSection({ productId, optionId, unitQuantities, uni
209
209
  requiresReason,
210
210
  total,
211
211
  ]);
212
- const manualTotalControls = (_jsxs("div", { className: "flex flex-col gap-2 border-t pt-2", children: [_jsxs("div", { className: "grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-end", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.manualTotal }), _jsx(CurrencyInput, { value: manualAmountCents, onChange: setManualAmountCents, currency: currency ?? undefined, placeholder: total === null ? merged.onRequest : formatAmount(total) })] }), manualAmountCents != null ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setManualAmountCents(null), children: merged.useCatalogTotal })) : null] }), isManualOverride ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.overrideReason }), _jsx(Textarea, { value: overrideReason, onChange: (event) => setOverrideReason(event.target.value), placeholder: merged.overrideReasonPlaceholder, rows: 2 }), requiresReason ? (_jsx("p", { className: "text-xs text-destructive", children: merged.overrideReasonRequired })) : null] })) : null] }));
212
+ const manualTotalControls = (_jsxs("div", { className: "flex flex-col gap-2 border-t pt-2", children: [_jsxs("div", { className: "grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-end", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.manualTotal }), _jsx(CurrencyInput, { value: manualAmountCents, onChange: setManualAmountCents, currency: currency ?? undefined,
213
+ // CurrencyInput already renders the currency symbol + code
214
+ // as addons; the placeholder must be the bare number so we
215
+ // don't end up with `€ €790.00 EUR` showing.
216
+ placeholder: total === null
217
+ ? merged.onRequest
218
+ : formatNumber(total / 100, {
219
+ minimumFractionDigits: 2,
220
+ maximumFractionDigits: 2,
221
+ }) })] }), manualAmountCents != null ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setManualAmountCents(null), children: merged.useCatalogTotal })) : null] }), isManualOverride ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.overrideReason }), _jsx(Textarea, { value: overrideReason, onChange: (event) => setOverrideReason(event.target.value), placeholder: merged.overrideReasonPlaceholder, rows: 2 }), requiresReason ? (_jsx("p", { className: "text-xs text-destructive", children: merged.overrideReasonRequired })) : null] })) : null] }));
213
222
  // Empty states
214
223
  if (!productId)
215
224
  return null;
225
+ const wrapperClassName = flat
226
+ ? "flex flex-col gap-2" // i18n-literal-ok: tailwind utilities
227
+ : "flex flex-col gap-2 rounded-md border p-3"; // i18n-literal-ok: tailwind utilities
216
228
  if ((preview.isError || (preview.isSuccess && !snapshot)) && fallbackUnitAmountCents === null) {
217
- return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsx("p", { className: "text-xs text-muted-foreground", children: merged.noPricing }), manualTotalControls] }));
229
+ return (_jsxs("div", { className: wrapperClassName, children: [flat ? null : _jsx(Label, { children: merged.heading }), _jsx("p", { className: "text-xs text-muted-foreground", children: merged.noPricing }), manualTotalControls] }));
218
230
  }
219
231
  if (lines.length === 0) {
220
- return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty }), manualTotalControls] }));
232
+ return (_jsxs("div", { className: wrapperClassName, children: [flat ? null : _jsx(Label, { children: merged.heading }), _jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty }), manualTotalControls] }));
221
233
  }
222
- return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsx("div", { className: "flex flex-col gap-1.5", children: lines.map((line) => (_jsxs("div", { className: "flex items-baseline justify-between text-sm", children: [_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsxs("span", { className: "tabular-nums", children: [formatNumber(line.quantity), "x"] }), _jsx("span", { children: line.label }), line.tierLabel ? (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["\u00B7 ", line.tierLabel] })) : null] }), _jsx("div", { className: "tabular-nums", children: line.totalAmountCents === null
234
+ return (_jsxs("div", { className: wrapperClassName, children: [flat ? null : _jsx(Label, { children: merged.heading }), _jsx("div", { className: "flex flex-col gap-1.5", children: lines.map((line) => (_jsxs("div", { className: "flex items-baseline justify-between text-sm", children: [_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsxs("span", { className: "tabular-nums", children: [formatNumber(line.quantity), "x"] }), _jsx("span", { children: line.label }), line.tierLabel ? (_jsxs("span", { className: "text-xs text-muted-foreground", children: ["\u00B7 ", line.tierLabel] })) : null] }), _jsx("div", { className: "tabular-nums", children: line.totalAmountCents === null
223
235
  ? merged.onRequest
224
236
  : formatAmount(line.totalAmountCents) })] }, line.unitId))) }), _jsxs("div", { className: "mt-1 flex items-baseline justify-between border-t pt-2 text-sm font-medium", children: [_jsx("span", { children: merged.total }), _jsx("span", { className: "tabular-nums", children: total === null ? merged.onRequest : formatAmount(total) })] }), _jsxs("div", { className: "flex items-baseline justify-between text-sm font-medium", children: [_jsx("span", { children: merged.confirmedTotal }), _jsx("span", { className: "tabular-nums", children: confirmedAmountCents === null ? merged.onRequest : formatAmount(confirmedAmountCents) })] }), manualTotalControls] }));
225
237
  }
@@ -1 +1 @@
1
- {"version":3,"file":"status-change-dialog.d.ts","sourceRoot":"","sources":["../../src/components/status-change-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAA;AAgCjC,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,aAAa,EACb,SAAS,GACV,EAAE,uBAAuB,2CA+FzB"}
1
+ {"version":3,"file":"status-change-dialog.d.ts","sourceRoot":"","sources":["../../src/components/status-change-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAA;AAgCjC,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,aAAa,EACb,SAAS,GACV,EAAE,uBAAuB,2CAoGzB"}
@@ -4,7 +4,7 @@ import { bookingStatusOptions, bookingStatusSchema, useBookingStatusMutation, }
4
4
  import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyantjs/ui/components";
5
5
  import { zodResolver } from "@voyantjs/ui/lib/zod-resolver";
6
6
  import { Loader2 } from "lucide-react";
7
- import { useEffect } from "react";
7
+ import { useEffect, useMemo } from "react";
8
8
  import { useForm } from "react-hook-form";
9
9
  import { z } from "zod/v4";
10
10
  import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
@@ -15,6 +15,10 @@ const statusChangeFormSchema = z.object({
15
15
  export function StatusChangeDialog({ open, onOpenChange, bookingId, currentStatus, onSuccess, }) {
16
16
  const mutation = useBookingStatusMutation(bookingId);
17
17
  const messages = useBookingsUiMessagesOrDefault();
18
+ const statusItems = useMemo(() => bookingStatusOptions.map((s) => ({
19
+ value: s.value,
20
+ label: messages.common.bookingStatusLabels[s.value] ?? s.value,
21
+ })), [messages.common.bookingStatusLabels]);
18
22
  const form = useForm({
19
23
  resolver: zodResolver(statusChangeFormSchema),
20
24
  defaultValues: {
@@ -39,8 +43,5 @@ export function StatusChangeDialog({ open, onOpenChange, bookingId, currentStatu
39
43
  onOpenChange(false);
40
44
  onSuccess?.();
41
45
  };
42
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.statusChangeDialog.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: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.statusChangeDialog.fields.status }), _jsxs(Select, { value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), items: bookingStatusOptions.map((status) => ({
43
- ...status,
44
- label: messages.common.bookingStatusLabels[status.value],
45
- })), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: bookingStatusOptions.map((status) => (_jsx(SelectItem, { value: status.value, children: messages.common.bookingStatusLabels[status.value] }, status.value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.statusChangeDialog.fields.note }), _jsx(Textarea, { ...form.register("note"), placeholder: messages.statusChangeDialog.placeholders.note })] })] }), _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: mutation.isPending, children: [mutation.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.statusChangeDialog.actions.updateStatus] })] })] })] }) }));
46
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.statusChangeDialog.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: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.statusChangeDialog.fields.status }), _jsxs(Select, { items: statusItems, value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: bookingStatusOptions.map((status) => (_jsx(SelectItem, { value: status.value, children: messages.common.bookingStatusLabels[status.value] }, status.value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.statusChangeDialog.fields.note }), _jsx(Textarea, { ...form.register("note"), placeholder: messages.statusChangeDialog.placeholders.note })] })] }), _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: mutation.isPending, children: [mutation.isPending && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.statusChangeDialog.actions.updateStatus] })] })] })] }) }));
46
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"supplier-status-dialog.d.ts","sourceRoot":"","sources":["../../src/components/supplier-status-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,0BAA0B,CAAA;AA8CjC,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,2BAA2B,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAUD,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,SAAS,GACV,EAAE,yBAAyB,2CAyK3B"}
1
+ {"version":3,"file":"supplier-status-dialog.d.ts","sourceRoot":"","sources":["../../src/components/supplier-status-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,0BAA0B,CAAA;AA8CjC,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,2BAA2B,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAUD,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,SAAS,GACV,EAAE,yBAAyB,2CA8K3B"}
@@ -6,7 +6,7 @@ import { CurrencyCombobox } from "@voyantjs/ui/components/currency-combobox";
6
6
  import { CurrencyInput } from "@voyantjs/ui/components/currency-input";
7
7
  import { zodResolver } from "@voyantjs/ui/lib/zod-resolver";
8
8
  import { Loader2 } from "lucide-react";
9
- import { useEffect } from "react";
9
+ import { useEffect, useMemo } from "react";
10
10
  import { useForm } from "react-hook-form";
11
11
  import { z } from "zod/v4";
12
12
  import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
@@ -35,6 +35,10 @@ export function SupplierStatusDialog({ open, onOpenChange, bookingId, supplierSt
35
35
  const { create, update } = useSupplierStatusMutation(bookingId);
36
36
  const messages = useBookingsUiMessagesOrDefault();
37
37
  const supplierStatusFormSchema = createSupplierStatusFormSchema(messages);
38
+ const statusItems = useMemo(() => CONFIRMATION_STATUSES.map((s) => ({
39
+ value: s.value,
40
+ label: messages.common.supplierStatusLabels[s.value],
41
+ })), [messages.common.supplierStatusLabels]);
38
42
  const form = useForm({
39
43
  resolver: zodResolver(supplierStatusFormSchema),
40
44
  defaultValues: {
@@ -82,10 +86,7 @@ export function SupplierStatusDialog({ open, onOpenChange, bookingId, supplierSt
82
86
  const isSubmitting = create.isPending || update.isPending;
83
87
  return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: isEditing
84
88
  ? messages.supplierStatusDialog.titles.edit
85
- : messages.supplierStatusDialog.titles.create }) }), _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.supplierStatusDialog.fields.serviceName }), _jsx(Input, { ...form.register("serviceName"), placeholder: messages.supplierStatusDialog.placeholders.serviceName, disabled: isEditing }), form.formState.errors.serviceName && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.serviceName.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.supplierStatusDialog.fields.status }), _jsxs(Select, { value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), items: CONFIRMATION_STATUSES.map((status) => ({
86
- ...status,
87
- label: messages.common.supplierStatusLabels[status.value],
88
- })), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: CONFIRMATION_STATUSES.map((status) => (_jsx(SelectItem, { value: status.value, children: messages.common.supplierStatusLabels[status.value] }, status.value))) })] })] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.supplierStatusDialog.fields.costCurrency }), _jsx(CurrencyCombobox, { value: form.watch("costCurrency") || null, onChange: (next) => form.setValue("costCurrency", next ?? DEFAULT_CURRENCY, {
89
+ : messages.supplierStatusDialog.titles.create }) }), _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.supplierStatusDialog.fields.serviceName }), _jsx(Input, { ...form.register("serviceName"), placeholder: messages.supplierStatusDialog.placeholders.serviceName, disabled: isEditing }), form.formState.errors.serviceName && (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.serviceName.message }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.supplierStatusDialog.fields.status }), _jsxs(Select, { items: statusItems, value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: CONFIRMATION_STATUSES.map((status) => (_jsx(SelectItem, { value: status.value, children: messages.common.supplierStatusLabels[status.value] }, status.value))) })] })] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.supplierStatusDialog.fields.costCurrency }), _jsx(CurrencyCombobox, { value: form.watch("costCurrency") || null, onChange: (next) => form.setValue("costCurrency", next ?? DEFAULT_CURRENCY, {
89
90
  shouldValidate: true,
90
91
  shouldDirty: true,
91
92
  }) })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.supplierStatusDialog.fields.costAmountCents }), _jsx(CurrencyInput, { value: form.watch("costAmountCents"), onChange: (next) => form.setValue("costAmountCents", next ?? 0, {
@@ -1 +1 @@
1
- {"version":3,"file":"traveler-list.d.ts","sourceRoot":"","sources":["../../src/components/traveler-list.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,UAAkB,EAAE,EAAE,iBAAiB,2CAqIhF"}
1
+ {"version":3,"file":"traveler-list.d.ts","sourceRoot":"","sources":["../../src/components/traveler-list.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,UAAkB,EAAE,EAAE,iBAAiB,2CAqIhF"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useBookingTravelerDocuments, useRevealTraveler, useTravelerMutation, useTravelers, } from "@voyantjs/bookings-react";
4
+ import { usePerson } from "@voyantjs/crm-react";
4
5
  import { Button, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
5
6
  import { Eye, EyeOff, Loader2, Pencil, Plus, Trash2, Users } from "lucide-react";
6
7
  import * as React from "react";
@@ -80,7 +81,17 @@ function TravelerRow({ bookingId, traveler, documents, revealed, onToggleReveal,
80
81
  const travelDetails = revealed && revealedTraveler ? revealedTraveler.travelDetails : null;
81
82
  const showLoading = revealed && reveal.isLoading;
82
83
  const revealError = revealed && reveal.error;
83
- return (_jsxs(_Fragment, { children: [_jsxs("tr", { className: "border-b", children: [_jsx("td", { className: "p-2", children: showLoading ? (_jsx(RowLoading, {})) : (`${display.firstName ?? ""} ${display.lastName ?? ""}`.trim()) }), _jsx("td", { className: "p-2", children: showLoading ? _jsx(RowLoading, {}) : (display.email ?? emailUnavailable) }), _jsx("td", { className: "p-2", children: showLoading ? _jsx(RowLoading, {}) : (display.phone ?? phoneUnavailable) }), _jsx("td", { className: "p-2", children: _jsxs("div", { className: "flex flex-wrap gap-1.5", children: [display.isPrimary ? _jsx(MiniPill, { children: messages.travelerList.roles.primary }) : null, travelDetails?.isLeadTraveler ? (_jsx(MiniPill, { children: messages.travelerList.roles.lead })) : null, display.travelerCategory ? _jsx(MiniPill, { children: display.travelerCategory }) : null] }) }), _jsx("td", { className: "p-2", children: showLoading ? (_jsx(RowLoading, {})) : (formatDobAge(travelDetails?.dateOfBirth, messages.travelerList.values.fieldUnavailable)) }), _jsx("td", { className: "p-2", children: documents.length > 0 ? (_jsxs("div", { className: "flex flex-wrap gap-1.5", children: [documents.slice(0, 2).map((document) => (_jsx(MiniPill, { children: document.type.replaceAll("_", " ") }, document.id))), documents.length > 2 ? _jsxs(MiniPill, { children: ["+", documents.length - 2] }) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: messages.travelerList.values.documentsUnavailable })) }), _jsxs("td", { className: "p-2", children: [_jsxs("div", { className: "flex items-center gap-1", children: [onToggleReveal ? (_jsx("button", { type: "button", onClick: onToggleReveal, className: "text-muted-foreground hover:text-foreground", title: revealed
84
+ // When the booking_traveler row didn't snapshot contact info (or DOB),
85
+ // hydrate from the linked CRM person so the list still shows useful
86
+ // data instead of dashes. The snapshot still wins when present —
87
+ // historical bookings keep the values they were created with.
88
+ const person = usePerson(traveler.personId ?? undefined, {
89
+ enabled: Boolean(traveler.personId),
90
+ }).data;
91
+ const resolvedEmail = display.email ?? person?.email ?? null;
92
+ const resolvedPhone = display.phone ?? person?.phone ?? null;
93
+ const resolvedDateOfBirth = travelDetails?.dateOfBirth ?? person?.dateOfBirth ?? null;
94
+ return (_jsxs(_Fragment, { children: [_jsxs("tr", { className: "border-b", children: [_jsx("td", { className: "p-2", children: showLoading ? (_jsx(RowLoading, {})) : (`${display.firstName ?? ""} ${display.lastName ?? ""}`.trim()) }), _jsx("td", { className: "p-2", children: showLoading ? _jsx(RowLoading, {}) : (resolvedEmail ?? emailUnavailable) }), _jsx("td", { className: "p-2", children: showLoading ? _jsx(RowLoading, {}) : (resolvedPhone ?? phoneUnavailable) }), _jsx("td", { className: "p-2", children: _jsxs("div", { className: "flex flex-wrap gap-1.5", children: [display.isPrimary ? _jsx(MiniPill, { children: messages.travelerList.roles.primary }) : null, travelDetails?.isLeadTraveler ? (_jsx(MiniPill, { children: messages.travelerList.roles.lead })) : null, display.travelerCategory ? _jsx(MiniPill, { children: display.travelerCategory }) : null] }) }), _jsx("td", { className: "p-2", children: showLoading ? (_jsx(RowLoading, {})) : (formatDobAge(resolvedDateOfBirth, messages.travelerList.values.fieldUnavailable)) }), _jsx("td", { className: "p-2", children: documents.length > 0 ? (_jsxs("div", { className: "flex flex-wrap gap-1.5", children: [documents.slice(0, 2).map((document) => (_jsx(MiniPill, { children: document.type.replaceAll("_", " ") }, document.id))), documents.length > 2 ? _jsxs(MiniPill, { children: ["+", documents.length - 2] }) : null] })) : (_jsx("span", { className: "text-muted-foreground", children: messages.travelerList.values.documentsUnavailable })) }), _jsxs("td", { className: "p-2", children: [_jsxs("div", { className: "flex items-center gap-1", children: [onToggleReveal ? (_jsx("button", { type: "button", onClick: onToggleReveal, className: "text-muted-foreground hover:text-foreground", title: revealed
84
95
  ? messages.travelerList.actions.hideContactDetails
85
96
  : messages.travelerList.actions.revealContactDetails, "aria-label": revealed
86
97
  ? messages.travelerList.actions.hideTravelerContactDetails
@@ -4,8 +4,14 @@ export interface TravelerEntry {
4
4
  firstName: string;
5
5
  lastName: string;
6
6
  email: string;
7
+ /** Snapshotted from the linked person at pick time. Optional. */
8
+ phone: string;
9
+ /** Snapshotted from the linked person at pick time. Optional. */
10
+ preferredLanguage: string;
7
11
  role: TravelerRole;
8
- /** option_unit_id the traveler is assigned to (matches RoomsStepper units). */
12
+ /** ISO `YYYY-MM-DD` date of birth. Drives age-derived unit assignment. */
13
+ dateOfBirth: string | null;
14
+ /** option_unit_id the traveler is assigned to (matches OptionUnitsStepper units). */
9
15
  roomUnitId: string | null;
10
16
  }
11
17
  export interface TravelerListValue {
@@ -14,6 +20,21 @@ export interface TravelerListValue {
14
20
  export declare const emptyTravelerListValue: TravelerListValue;
15
21
  /** Factory for a blank row — `role` defaults to `adult` unless the list is empty. */
16
22
  export declare function createBlankTraveler(role?: TravelerRole): TravelerEntry;
23
+ /**
24
+ * Compute integer age in full years from an ISO date-of-birth string.
25
+ * Returns null when the DOB is missing or unparseable.
26
+ */
27
+ export declare function computeAgeYears(dob: string | null, now?: Date): number | null;
28
+ /**
29
+ * Derive the age-banded traveler role from DOB. Falls back to `adult`
30
+ * when DOB is missing so partial entries still typecheck downstream.
31
+ *
32
+ * Thresholds:
33
+ * - infant: < 2
34
+ * - child: 2 – 17
35
+ * - adult: 18+
36
+ */
37
+ export declare function deriveTravelerRoleFromDob(dob: string | null): TravelerRole;
17
38
  export interface RoomUnitOption {
18
39
  unitId: string;
19
40
  unitName: string;
@@ -24,14 +45,46 @@ export interface RoomUnitOption {
24
45
  */
25
46
  remainingCapacity: number;
26
47
  }
48
+ /**
49
+ * Per-option breakdown of the actual age-banded units the product
50
+ * configures. Lets the row render dynamic category buttons (e.g.
51
+ * Adult/Child/Senior for one product, Adult/Child/Infant for another)
52
+ * rather than a hardcoded set.
53
+ */
54
+ export interface RoomGroupUnit {
55
+ unitId: string;
56
+ /** Short label — typically the unit's own name (Adult, Child, Senior). */
57
+ unitName: string;
58
+ /** Stable code (ADULT, CHILD, SENIOR, INFANT, …) when configured. */
59
+ unitCode: string | null;
60
+ minAge: number | null;
61
+ maxAge: number | null;
62
+ unitType: "person" | "group" | "room" | "vehicle" | "service" | "other" | null;
63
+ }
64
+ export interface RoomGroup {
65
+ /** option_id this group of units belongs to. */
66
+ optionId: string;
67
+ /** Display name for the option (e.g. "Standard double"). */
68
+ optionName: string;
69
+ /** Default unit when the option is first picked (typically the ADULT-coded row). */
70
+ primaryUnitId: string;
71
+ units: RoomGroupUnit[];
72
+ }
27
73
  export interface TravelersSectionProps {
28
74
  value: TravelerListValue;
29
75
  onChange: (value: TravelerListValue) => void;
30
76
  /**
31
- * Rooms the operator has selected (from RoomsStepperSection + occupancy).
77
+ * Rooms the operator has selected (from OptionUnitsStepperSection + occupancy).
32
78
  * When provided, each traveler gets a room-assignment dropdown.
33
79
  */
34
80
  roomUnits?: RoomUnitOption[];
81
+ /**
82
+ * Per-option breakdown of all units the product configures. Drives
83
+ * dynamic category buttons (Adult/Child/Senior or whatever the
84
+ * product configures) and DOB-aware unit pre-selection on attach.
85
+ * Required for category buttons to render.
86
+ */
87
+ roomGroups?: RoomGroup[];
35
88
  billingPersonId?: string | null;
36
89
  labels?: {
37
90
  heading?: string;
@@ -40,6 +93,8 @@ export interface TravelersSectionProps {
40
93
  lastName?: string;
41
94
  email?: string;
42
95
  role?: string;
96
+ category?: string;
97
+ dateOfBirth?: string;
43
98
  roleLead?: string;
44
99
  roleAdult?: string;
45
100
  roleChild?: string;
@@ -53,7 +108,11 @@ export interface TravelersSectionProps {
53
108
  personEmpty?: string;
54
109
  createNewPerson?: string;
55
110
  createPersonSheetTitle?: string;
111
+ editPerson?: string;
112
+ editPersonSheetTitle?: string;
56
113
  addBillingPerson?: string;
114
+ relatedPeopleHeading?: string;
115
+ addRelatedPerson?: string;
57
116
  };
58
117
  }
59
118
  /**
@@ -73,5 +132,5 @@ export interface TravelersSectionProps {
73
132
  * here. The UI lets the operator pick whichever layout they want, then
74
133
  * the submit handler errors if the invariant isn't met.
75
134
  */
76
- export declare function TravelersSection({ value, onChange, roomUnits, billingPersonId, labels, }: TravelersSectionProps): import("react/jsx-runtime").JSX.Element;
135
+ export declare function TravelersSection({ value, onChange, roomUnits, roomGroups, billingPersonId, labels, }: TravelersSectionProps): import("react/jsx-runtime").JSX.Element;
77
136
  //# sourceMappingURL=travelers-section.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"travelers-section.d.ts","sourceRoot":"","sources":["../../src/components/travelers-section.tsx"],"names":[],"mappings":"AAgCA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAIhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,YAAY,CAAA;IAClB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,aAAa,EAAE,CAAA;CAC3B;AAED,eAAO,MAAM,sBAAsB,EAAE,iBAAqC,CAAA;AAE1E,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,YAAsB,GAAG,aAAa,CAE/E;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,iBAAiB,CAAA;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAC5C;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,eAAe,EACf,MAAM,GACP,EAAE,qBAAqB,2CAuLvB"}
1
+ {"version":3,"file":"travelers-section.d.ts","sourceRoot":"","sources":["../../src/components/travelers-section.tsx"],"names":[],"mappings":"AAqCA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,EAAE,YAAY,CAAA;IAClB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,qFAAqF;IACrF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,aAAa,EAAE,CAAA;CAC3B;AAED,eAAO,MAAM,sBAAsB,EAAE,iBAAqC,CAAA;AAE1E,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,YAAsB,GAAG,aAAa,CAY/E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,GAAG,IAAI,CAUzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAM1E;AA+DD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI,CAAA;CAC/E;AAED,MAAM,WAAW,SAAS;IACxB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAA;IAClB,oFAAoF;IACpF,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,iBAAiB,CAAA;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAC5C;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAA;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,EAAE,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,uBAAuB,CAAC,EAAE,MAAM,CAAA;QAChC,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,EACT,UAAU,EACV,eAAe,EACf,MAAM,GACP,EAAE,qBAAqB,2CA0PvB"}