@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.
- package/dist/components/booking-billing-dialog.d.ts +16 -0
- package/dist/components/booking-billing-dialog.d.ts.map +1 -0
- package/dist/components/booking-billing-dialog.js +90 -0
- package/dist/components/booking-create-dialog.d.ts.map +1 -1
- package/dist/components/booking-create-dialog.js +512 -151
- package/dist/components/booking-create-page.js +1 -1
- package/dist/components/booking-document-dialog.d.ts.map +1 -1
- package/dist/components/booking-document-dialog.js +16 -14
- package/dist/components/booking-guarantee-dialog.d.ts.map +1 -1
- package/dist/components/booking-guarantee-dialog.js +10 -8
- package/dist/components/booking-item-dialog.d.ts.map +1 -1
- package/dist/components/booking-item-dialog.js +18 -9
- package/dist/components/booking-item-travelers.d.ts.map +1 -1
- package/dist/components/booking-item-travelers.js +9 -7
- package/dist/components/booking-payment-schedule-dialog.d.ts.map +1 -1
- package/dist/components/booking-payment-schedule-dialog.js +10 -8
- package/dist/components/booking-payment-schedule-list.d.ts.map +1 -1
- package/dist/components/booking-payment-schedule-list.js +32 -3
- package/dist/components/{rooms-stepper-section.d.ts → option-units-stepper-section.d.ts} +17 -9
- package/dist/components/option-units-stepper-section.d.ts.map +1 -0
- package/dist/components/option-units-stepper-section.js +172 -0
- package/dist/components/payment-schedule-section.d.ts +1 -1
- package/dist/components/payment-schedule-section.d.ts.map +1 -1
- package/dist/components/payment-schedule-section.js +5 -11
- package/dist/components/person-picker-section.d.ts +4 -0
- package/dist/components/person-picker-section.d.ts.map +1 -1
- package/dist/components/person-picker-section.js +27 -5
- package/dist/components/price-breakdown-section.d.ts +8 -2
- package/dist/components/price-breakdown-section.d.ts.map +1 -1
- package/dist/components/price-breakdown-section.js +17 -5
- package/dist/components/status-change-dialog.d.ts.map +1 -1
- package/dist/components/status-change-dialog.js +6 -5
- package/dist/components/supplier-status-dialog.d.ts.map +1 -1
- package/dist/components/supplier-status-dialog.js +6 -5
- package/dist/components/traveler-list.d.ts.map +1 -1
- package/dist/components/traveler-list.js +12 -1
- package/dist/components/travelers-section.d.ts +62 -3
- package/dist/components/travelers-section.d.ts.map +1 -1
- package/dist/components/travelers-section.js +290 -23
- package/dist/i18n/en.d.ts +63 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +68 -5
- package/dist/i18n/messages.d.ts +63 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/provider.d.ts +126 -0
- package/dist/i18n/provider.d.ts.map +1 -1
- package/dist/i18n/ro.d.ts +63 -0
- package/dist/i18n/ro.d.ts.map +1 -1
- package/dist/i18n/ro.js +68 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +26 -24
- package/dist/components/rooms-stepper-section.d.ts.map +0 -1
- 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":"
|
|
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: "
|
|
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 === "
|
|
77
|
-
? 0
|
|
78
|
-
: value.
|
|
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 === "
|
|
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,
|
|
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(
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
|
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,
|
|
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,
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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),
|
|
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,
|
|
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),
|
|
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":"
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
|
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":"
|
|
1
|
+
{"version":3,"file":"travelers-section.d.ts","sourceRoot":"","sources":["../../src/components/travelers-section.tsx"],"names":[],"mappings":"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"}
|