@voyantjs/bookings-ui 0.50.5 → 0.50.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/booking-create-dialog.d.ts +1 -1
- package/dist/components/booking-create-dialog.d.ts.map +1 -1
- package/dist/components/booking-create-dialog.js +64 -24
- package/dist/components/booking-create-page.d.ts +2 -1
- package/dist/components/booking-create-page.d.ts.map +1 -1
- package/dist/components/booking-create-page.js +2 -2
- package/dist/components/booking-create-utils.d.ts +33 -0
- package/dist/components/booking-create-utils.d.ts.map +1 -0
- package/dist/components/booking-create-utils.js +67 -0
- package/dist/components/booking-list.d.ts +2 -1
- package/dist/components/booking-list.d.ts.map +1 -1
- package/dist/components/booking-list.js +5 -1
- package/dist/components/bookings-page.d.ts +2 -1
- package/dist/components/bookings-page.d.ts.map +1 -1
- package/dist/components/bookings-page.js +2 -2
- package/dist/components/payment-schedule-section.d.ts +20 -0
- package/dist/components/payment-schedule-section.d.ts.map +1 -1
- package/dist/components/payment-schedule-section.js +27 -2
- package/dist/components/price-breakdown-section.d.ts +1 -0
- package/dist/components/price-breakdown-section.d.ts.map +1 -1
- package/dist/components/price-breakdown-section.js +2 -0
- package/dist/components/product-picker-section.d.ts.map +1 -1
- package/dist/components/product-picker-section.js +5 -2
- package/dist/components/shared-room-section.d.ts +2 -0
- package/dist/components/shared-room-section.d.ts.map +1 -1
- package/dist/components/shared-room-section.js +14 -2
- package/dist/components/travelers-section.d.ts +15 -10
- package/dist/components/travelers-section.d.ts.map +1 -1
- package/dist/components/travelers-section.js +96 -14
- package/dist/i18n/en.d.ts +24 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +24 -0
- package/dist/i18n/messages.d.ts +24 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/provider.d.ts +48 -0
- package/dist/i18n/provider.d.ts.map +1 -1
- package/dist/i18n/ro.d.ts +24 -0
- package/dist/i18n/ro.d.ts.map +1 -1
- package/dist/i18n/ro.js +24 -0
- package/package.json +24 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/product-picker-section.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"product-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/product-picker-section.tsx"],"names":[],"mappings":"AA+BA,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,kBAAkB,CAAA;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC7C,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qGAAqG;IACrG,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,QAAQ,EACR,OAAc,EACd,WAAmB,EACnB,MAAM,GACP,EAAE,yBAAyB,2CAmI3B"}
|
|
@@ -5,6 +5,7 @@ import { Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, }
|
|
|
5
5
|
import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
|
|
8
|
+
import { productMatchesPickerSearch } from "./booking-create-utils.js";
|
|
8
9
|
const OPTION_NONE = "__none__";
|
|
9
10
|
/**
|
|
10
11
|
* Controlled product + option picker. Splits `value` + `onChange` so apps can
|
|
@@ -13,6 +14,7 @@ const OPTION_NONE = "__none__";
|
|
|
13
14
|
*/
|
|
14
15
|
export function ProductPickerSection({ value, onChange, enabled = true, lockProduct = false, labels, }) {
|
|
15
16
|
const [productSearch, setProductSearch] = React.useState("");
|
|
17
|
+
const cachedProductsRef = React.useRef(new Map());
|
|
16
18
|
const messages = useBookingsUiMessagesOrDefault();
|
|
17
19
|
const merged = { ...messages.productPickerSection.labels, ...labels };
|
|
18
20
|
const { data: productsData } = useProducts({
|
|
@@ -24,11 +26,12 @@ export function ProductPickerSection({ value, onChange, enabled = true, lockProd
|
|
|
24
26
|
enabled: enabled && Boolean(value.productId),
|
|
25
27
|
});
|
|
26
28
|
const products = React.useMemo(() => {
|
|
27
|
-
const map = new Map();
|
|
29
|
+
const map = new Map(cachedProductsRef.current);
|
|
28
30
|
for (const product of productsData?.data ?? [])
|
|
29
31
|
map.set(product.id, product);
|
|
30
32
|
if (selectedProductQuery.data)
|
|
31
33
|
map.set(selectedProductQuery.data.id, selectedProductQuery.data);
|
|
34
|
+
cachedProductsRef.current = map;
|
|
32
35
|
return Array.from(map.values());
|
|
33
36
|
}, [productsData?.data, selectedProductQuery.data]);
|
|
34
37
|
const productMap = React.useMemo(() => new Map(products.map((product) => [product.id, product])), [products]);
|
|
@@ -44,7 +47,7 @@ export function ProductPickerSection({ value, onChange, enabled = true, lockProd
|
|
|
44
47
|
enabled: enabled && Boolean(value.productId),
|
|
45
48
|
});
|
|
46
49
|
const options = optionsData?.data ?? [];
|
|
47
|
-
return (_jsxs(_Fragment, { children: [!lockProduct && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs(Label, { children: [merged.product, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs(Combobox, { items: products.map((product) => product.id), value: value.productId || null, inputValue: productInputValue, autoHighlight: true, disabled: !enabled, itemToStringValue: (id) => productMap.get(id)?.name ?? "", onInputValueChange: (next) => {
|
|
50
|
+
return (_jsxs(_Fragment, { children: [!lockProduct && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs(Label, { children: [merged.product, " ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsxs(Combobox, { items: products.map((product) => product.id), value: value.productId || null, inputValue: productInputValue, autoHighlight: true, disabled: !enabled, filter: (id, query) => productMatchesPickerSearch(productMap.get(id), query), itemToStringValue: (id) => productMap.get(id)?.name ?? "", onInputValueChange: (next) => {
|
|
48
51
|
setProductInputValue(next);
|
|
49
52
|
setProductSearch(next);
|
|
50
53
|
if (!next)
|
|
@@ -8,6 +8,7 @@ export interface SharedRoomValue {
|
|
|
8
8
|
groupLabel?: string;
|
|
9
9
|
}
|
|
10
10
|
export declare const emptySharedRoomValue: SharedRoomValue;
|
|
11
|
+
export declare function clearSharedRoomValue(): SharedRoomValue;
|
|
11
12
|
export interface SharedRoomSectionProps {
|
|
12
13
|
value: SharedRoomValue;
|
|
13
14
|
onChange: (value: SharedRoomValue) => void;
|
|
@@ -28,6 +29,7 @@ export interface SharedRoomSectionProps {
|
|
|
28
29
|
groupLabel?: string;
|
|
29
30
|
groupLabelPlaceholder?: string;
|
|
30
31
|
createAction?: string;
|
|
32
|
+
remove?: string;
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-room-section.d.ts","sourceRoot":"","sources":["../../src/components/shared-room-section.tsx"],"names":[],"mappings":"AA2BA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,cAAc,CAAA;IACpB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,oBAAoB,EAAE,eAKlC,CAAA;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,eAAe,CAAA;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"shared-room-section.d.ts","sourceRoot":"","sources":["../../src/components/shared-room-section.tsx"],"names":[],"mappings":"AA2BA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,cAAc,CAAA;IACpB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,oBAAoB,EAAE,eAKlC,CAAA;AAED,wBAAgB,oBAAoB,IAAI,eAAe,CAEtD;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,eAAe,CAAA;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,SAAS,EACT,OAAc,EACd,MAAM,GACP,EAAE,sBAAsB,2CAyKxB"}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useBookingGroups } from "@voyantjs/bookings-react";
|
|
4
4
|
import { Button, Input, Label, Sheet, SheetBody, SheetContent, SheetFooter, SheetHeader, SheetTitle, } from "@voyantjs/ui/components";
|
|
5
5
|
import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
|
|
6
|
-
import { Link2, Plus } from "lucide-react";
|
|
6
|
+
import { Link2, Plus, X } from "lucide-react";
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
|
|
9
9
|
export const emptySharedRoomValue = {
|
|
@@ -12,6 +12,9 @@ export const emptySharedRoomValue = {
|
|
|
12
12
|
groupId: "",
|
|
13
13
|
groupLabel: "",
|
|
14
14
|
};
|
|
15
|
+
export function clearSharedRoomValue() {
|
|
16
|
+
return { ...emptySharedRoomValue };
|
|
17
|
+
}
|
|
15
18
|
/**
|
|
16
19
|
* Shared-room (partaj) attachment section. Operators can create a new group in
|
|
17
20
|
* a sheet or join an existing product-scoped group with an async combobox.
|
|
@@ -47,6 +50,15 @@ export function SharedRoomSection({ value, onChange, productId, enabled = true,
|
|
|
47
50
|
setDraftGroupLabel(value.groupLabel ?? "");
|
|
48
51
|
}, [createSheetOpen, value.groupLabel]);
|
|
49
52
|
const set = (patch) => onChange({ ...value, ...patch });
|
|
53
|
+
const clear = () => {
|
|
54
|
+
if (!enabled)
|
|
55
|
+
return;
|
|
56
|
+
setCreateSheetOpen(false);
|
|
57
|
+
setDraftGroupLabel("");
|
|
58
|
+
setGroupInputValue("");
|
|
59
|
+
setGroupSearch("");
|
|
60
|
+
onChange(clearSharedRoomValue());
|
|
61
|
+
};
|
|
50
62
|
const selectCreateMode = () => {
|
|
51
63
|
if (!enabled)
|
|
52
64
|
return;
|
|
@@ -66,7 +78,7 @@ export function SharedRoomSection({ value, onChange, productId, enabled = true,
|
|
|
66
78
|
});
|
|
67
79
|
setCreateSheetOpen(false);
|
|
68
80
|
};
|
|
69
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { children: merged.toggle }), value.enabled && value.mode === "create" && value.groupLabel ? (_jsx("p", { className: "text-xs text-muted-foreground", children: value.groupLabel })) : value.enabled && value.mode === "create" ? (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.createHint })) : null] }), _jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs(Button, { type: "button", size: "sm", variant: value.enabled && value.mode === "create" ? "default" : "outline", onClick: selectCreateMode, disabled: !enabled, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), merged.createMode] }), _jsxs(Button, { type: "button", size: "sm", variant: value.enabled && value.mode === "join" ? "default" : "outline", onClick: selectJoinMode, disabled: !enabled || !productId, children: [_jsx(Link2, { className: "mr-2 h-4 w-4" }), merged.joinMode] })] }), value.enabled && value.mode === "join" ? (_jsxs(Combobox, { items: existingGroups.map((group) => group.id), value: value.groupId || null, inputValue: groupInputValue, autoHighlight: true, disabled: !enabled || !productId, itemToStringValue: (id) => groupsMap.get(id)?.label ?? "", onInputValueChange: (next) => {
|
|
81
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx(Label, { children: merged.toggle }), value.enabled && value.mode === "create" && value.groupLabel ? (_jsx("p", { className: "truncate text-xs text-muted-foreground", children: value.groupLabel })) : value.enabled && value.mode === "create" ? (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.createHint })) : null] }), value.enabled ? (_jsxs(Button, { type: "button", size: "sm", variant: "ghost", onClick: clear, disabled: !enabled, children: [_jsx(X, { className: "mr-2 h-4 w-4" }), merged.remove] })) : null] }), _jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs(Button, { type: "button", size: "sm", variant: value.enabled && value.mode === "create" ? "default" : "outline", onClick: selectCreateMode, disabled: !enabled, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), merged.createMode] }), _jsxs(Button, { type: "button", size: "sm", variant: value.enabled && value.mode === "join" ? "default" : "outline", onClick: selectJoinMode, disabled: !enabled || !productId, children: [_jsx(Link2, { className: "mr-2 h-4 w-4" }), merged.joinMode] })] }), value.enabled && value.mode === "join" ? (_jsxs(Combobox, { items: existingGroups.map((group) => group.id), value: value.groupId || null, inputValue: groupInputValue, autoHighlight: true, disabled: !enabled || !productId, itemToStringValue: (id) => groupsMap.get(id)?.label ?? "", onInputValueChange: (next) => {
|
|
70
82
|
setGroupInputValue(next);
|
|
71
83
|
setGroupSearch(next);
|
|
72
84
|
if (!next)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type TravelerRole = "lead" | "adult" | "child" | "infant";
|
|
2
2
|
export interface TravelerEntry {
|
|
3
|
+
personId: string | null;
|
|
3
4
|
firstName: string;
|
|
4
5
|
lastName: string;
|
|
5
6
|
email: string;
|
|
@@ -31,6 +32,7 @@ export interface TravelersSectionProps {
|
|
|
31
32
|
* When provided, each traveler gets a room-assignment dropdown.
|
|
32
33
|
*/
|
|
33
34
|
roomUnits?: RoomUnitOption[];
|
|
35
|
+
billingPersonId?: string | null;
|
|
34
36
|
labels?: {
|
|
35
37
|
heading?: string;
|
|
36
38
|
addTraveler?: string;
|
|
@@ -46,27 +48,30 @@ export interface TravelersSectionProps {
|
|
|
46
48
|
noRoom?: string;
|
|
47
49
|
remove?: string;
|
|
48
50
|
empty?: string;
|
|
51
|
+
person?: string;
|
|
52
|
+
personSearchPlaceholder?: string;
|
|
53
|
+
personEmpty?: string;
|
|
54
|
+
createNewPerson?: string;
|
|
55
|
+
createPersonSheetTitle?: string;
|
|
56
|
+
addBillingPerson?: string;
|
|
49
57
|
};
|
|
50
58
|
}
|
|
51
59
|
/**
|
|
52
|
-
* Traveler list for booking-create flows. Each row
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* booking detail page afterwards, consistent with the lead-person picker's
|
|
56
|
-
* edit-after-create story.
|
|
60
|
+
* Traveler list for booking-create flows. Each row can point at an existing
|
|
61
|
+
* CRM person, create a new CRM person, or carry manual name/email details,
|
|
62
|
+
* plus role and optional room assignment.
|
|
57
63
|
*
|
|
58
64
|
* ### Parent contract
|
|
59
65
|
*
|
|
60
66
|
* At submit time, the parent:
|
|
61
|
-
* 1.
|
|
62
|
-
* (email match + name, or skip when the operator intentionally left
|
|
63
|
-
* email blank).
|
|
64
|
-
* 2. Inserts a `booking_travelers` row per traveler with `participantType`
|
|
67
|
+
* 1. Inserts a `booking_travelers` row per traveler with `participantType`
|
|
65
68
|
* derived from the role (`lead` / `adult` → traveler; `child` / `infant`
|
|
66
69
|
* → traveler with travelerCategory set).
|
|
70
|
+
* 2. Carries `personId` through when the traveler is tied to CRM, including
|
|
71
|
+
* when the payer is also traveling.
|
|
67
72
|
* 3. Exactly one row should have `role: "lead"` — enforced at submit, not
|
|
68
73
|
* here. The UI lets the operator pick whichever layout they want, then
|
|
69
74
|
* the submit handler errors if the invariant isn't met.
|
|
70
75
|
*/
|
|
71
|
-
export declare function TravelersSection({ value, onChange, roomUnits, labels }: TravelersSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
76
|
+
export declare function TravelersSection({ value, onChange, roomUnits, billingPersonId, labels, }: TravelersSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
72
77
|
//# 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":"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,38 +1,42 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { usePeople, usePerson } from "@voyantjs/crm-react";
|
|
4
|
+
import { PersonForm } from "@voyantjs/crm-ui";
|
|
5
|
+
import { Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, } from "@voyantjs/ui/components";
|
|
6
|
+
import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
|
|
7
|
+
import { Trash2, UserPlus } from "lucide-react";
|
|
8
|
+
import * as React from "react";
|
|
5
9
|
import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
|
|
6
10
|
const ALL_ROLES = ["lead", "adult", "child", "infant"];
|
|
7
11
|
export const emptyTravelerListValue = { travelers: [] };
|
|
8
12
|
/** Factory for a blank row — `role` defaults to `adult` unless the list is empty. */
|
|
9
13
|
export function createBlankTraveler(role = "adult") {
|
|
10
|
-
return { firstName: "", lastName: "", email: "", role, roomUnitId: null };
|
|
14
|
+
return { personId: null, firstName: "", lastName: "", email: "", role, roomUnitId: null };
|
|
11
15
|
}
|
|
12
16
|
const NO_ROOM = "__unassigned__";
|
|
13
17
|
/**
|
|
14
|
-
* Traveler list for booking-create flows. Each row
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* booking detail page afterwards, consistent with the lead-person picker's
|
|
18
|
-
* edit-after-create story.
|
|
18
|
+
* Traveler list for booking-create flows. Each row can point at an existing
|
|
19
|
+
* CRM person, create a new CRM person, or carry manual name/email details,
|
|
20
|
+
* plus role and optional room assignment.
|
|
19
21
|
*
|
|
20
22
|
* ### Parent contract
|
|
21
23
|
*
|
|
22
24
|
* At submit time, the parent:
|
|
23
|
-
* 1.
|
|
24
|
-
* (email match + name, or skip when the operator intentionally left
|
|
25
|
-
* email blank).
|
|
26
|
-
* 2. Inserts a `booking_travelers` row per traveler with `participantType`
|
|
25
|
+
* 1. Inserts a `booking_travelers` row per traveler with `participantType`
|
|
27
26
|
* derived from the role (`lead` / `adult` → traveler; `child` / `infant`
|
|
28
27
|
* → traveler with travelerCategory set).
|
|
28
|
+
* 2. Carries `personId` through when the traveler is tied to CRM, including
|
|
29
|
+
* when the payer is also traveling.
|
|
29
30
|
* 3. Exactly one row should have `role: "lead"` — enforced at submit, not
|
|
30
31
|
* here. The UI lets the operator pick whichever layout they want, then
|
|
31
32
|
* the submit handler errors if the invariant isn't met.
|
|
32
33
|
*/
|
|
33
|
-
export function TravelersSection({ value, onChange, roomUnits, labels }) {
|
|
34
|
+
export function TravelersSection({ value, onChange, roomUnits, billingPersonId, labels, }) {
|
|
34
35
|
const messages = useBookingsUiMessagesOrDefault();
|
|
35
36
|
const merged = { ...messages.travelersSection.labels, ...labels };
|
|
37
|
+
const billingPerson = usePerson(billingPersonId ?? undefined, {
|
|
38
|
+
enabled: Boolean(billingPersonId),
|
|
39
|
+
});
|
|
36
40
|
const roleLabels = {
|
|
37
41
|
lead: merged.roleLead,
|
|
38
42
|
adult: merged.roleAdult,
|
|
@@ -52,9 +56,87 @@ export function TravelersSection({ value, onChange, roomUnits, labels }) {
|
|
|
52
56
|
const role = value.travelers.length === 0 ? "lead" : "adult";
|
|
53
57
|
onChange({ travelers: [...value.travelers, createBlankTraveler(role)] });
|
|
54
58
|
};
|
|
55
|
-
|
|
59
|
+
const addBillingPerson = () => {
|
|
60
|
+
if (!billingPerson.data)
|
|
61
|
+
return;
|
|
62
|
+
const role = value.travelers.length === 0 ? "lead" : "adult";
|
|
63
|
+
onChange({
|
|
64
|
+
travelers: [...value.travelers, createTravelerFromPerson(billingPerson.data, role)],
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
const hasBillingPersonTraveler = Boolean(billingPersonId && value.travelers.some((traveler) => traveler.personId === billingPersonId));
|
|
68
|
+
return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { children: merged.heading }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: addRow, children: merged.addTraveler })] }), billingPersonId && !hasBillingPersonTraveler ? (_jsx("div", { children: _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addBillingPerson, disabled: !billingPerson.data, children: [_jsx(UserPlus, { className: "mr-1 h-3.5 w-3.5" }), merged.addBillingPerson] }) })) : null, value.travelers.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty })) : (_jsx("div", { className: "flex flex-col gap-2", children: value.travelers.map((traveler, index) => (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-2", children: [_jsx(TravelerPersonPicker, { personId: traveler.personId, labels: merged, pinnedPeople: billingPerson.data ? [billingPerson.data] : [], onSelect: (person) => updateAt(index, {
|
|
69
|
+
personId: person.id,
|
|
70
|
+
firstName: person.firstName,
|
|
71
|
+
lastName: person.lastName,
|
|
72
|
+
email: person.email ?? "",
|
|
73
|
+
}), onClear: () => updateAt(index, { personId: null }) }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(Input, { placeholder: merged.firstName, value: traveler.firstName, onChange: (e) => updateAt(index, { firstName: e.target.value }) }), _jsx(Input, { placeholder: merged.lastName, value: traveler.lastName, onChange: (e) => updateAt(index, { lastName: e.target.value }) })] }), _jsx(Input, { type: "email", placeholder: merged.email, value: traveler.email, onChange: (e) => updateAt(index, { email: e.target.value }) }), _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.role }), _jsxs(Select, { value: traveler.role, onValueChange: (v) => updateAt(index, { role: (v ?? "adult") }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: ALL_ROLES.map((role) => (_jsx(SelectItem, { value: role, children: roleLabels[role] }, role))) })] })] }), roomUnits && roomUnits.length > 0 ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.room }), _jsxs(Select, { value: traveler.roomUnitId ?? NO_ROOM, onValueChange: (v) => updateAt(index, { roomUnitId: v === NO_ROOM ? null : (v ?? null) }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: NO_ROOM, children: merged.noRoom }), roomUnits.map((unit) => (_jsx(SelectItem, { value: unit.unitId,
|
|
56
74
|
// Only disable other rooms at-capacity — the room the
|
|
57
75
|
// traveler is *already* in should stay selectable so
|
|
58
76
|
// re-renders don't strip the selection.
|
|
59
77
|
disabled: unit.remainingCapacity <= 0 && traveler.roomUnitId !== unit.unitId, children: unit.unitName }, unit.unitId)))] })] })] })) : null] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 text-destructive", onClick: () => removeAt(index), "aria-label": merged.remove, children: [_jsx(Trash2, { className: "mr-1 h-3.5 w-3.5" }), merged.remove] }) })] }, index))) }))] }));
|
|
60
78
|
}
|
|
79
|
+
function TravelerPersonPicker({ personId, labels, pinnedPeople = [], onSelect, onClear, }) {
|
|
80
|
+
const [search, setSearch] = React.useState("");
|
|
81
|
+
const [inputValue, setInputValue] = React.useState("");
|
|
82
|
+
const [sheetOpen, setSheetOpen] = React.useState(false);
|
|
83
|
+
const peopleQuery = usePeople({ search: search || undefined, limit: 20 });
|
|
84
|
+
const selectedPersonQuery = usePerson(personId ?? undefined, { enabled: Boolean(personId) });
|
|
85
|
+
const people = React.useMemo(() => {
|
|
86
|
+
const map = new Map();
|
|
87
|
+
for (const person of peopleQuery.data?.data ?? [])
|
|
88
|
+
map.set(person.id, person);
|
|
89
|
+
for (const person of pinnedPeople)
|
|
90
|
+
map.set(person.id, person);
|
|
91
|
+
if (selectedPersonQuery.data)
|
|
92
|
+
map.set(selectedPersonQuery.data.id, selectedPersonQuery.data);
|
|
93
|
+
return Array.from(map.values());
|
|
94
|
+
}, [peopleQuery.data?.data, pinnedPeople, selectedPersonQuery.data]);
|
|
95
|
+
const peopleMap = React.useMemo(() => new Map(people.map((person) => [person.id, person])), [people]);
|
|
96
|
+
const selectedLabel = personId ? formatPerson(peopleMap.get(personId)) : "";
|
|
97
|
+
React.useEffect(() => {
|
|
98
|
+
if (selectedLabel)
|
|
99
|
+
setInputValue(selectedLabel);
|
|
100
|
+
}, [selectedLabel]);
|
|
101
|
+
return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs", children: labels.person }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7", onClick: () => setSheetOpen(true), children: [_jsx(UserPlus, { className: "mr-1 h-3.5 w-3.5" }), labels.createNewPerson] })] }), _jsxs(Combobox, { items: people.map((person) => person.id), value: personId, inputValue: inputValue, autoHighlight: true, itemToStringValue: (id) => formatPerson(peopleMap.get(id)), onInputValueChange: (next) => {
|
|
102
|
+
setInputValue(next);
|
|
103
|
+
setSearch(next);
|
|
104
|
+
if (!next)
|
|
105
|
+
onClear();
|
|
106
|
+
}, onValueChange: (next) => {
|
|
107
|
+
const nextPerson = peopleMap.get(next ?? "");
|
|
108
|
+
if (nextPerson)
|
|
109
|
+
onSelect(nextPerson);
|
|
110
|
+
setInputValue(nextPerson ? formatPerson(nextPerson) : "");
|
|
111
|
+
}, children: [_jsx(ComboboxInput, { placeholder: labels.personSearchPlaceholder, showClear: !!personId }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: labels.personEmpty }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
|
|
112
|
+
const person = peopleMap.get(id);
|
|
113
|
+
if (!person)
|
|
114
|
+
return null;
|
|
115
|
+
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));
|
|
116
|
+
} }) })] })] }), _jsx(Sheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: _jsxs(SheetContent, { side: "right", size: "lg", children: [_jsx(SheetHeader, { children: _jsx(SheetTitle, { children: labels.createPersonSheetTitle }) }), _jsx(SheetBody, { children: _jsx(PersonForm, { mode: { kind: "create" }, onCancel: () => setSheetOpen(false), onSuccess: (saved) => {
|
|
117
|
+
onSelect(saved);
|
|
118
|
+
setInputValue(formatPerson(saved));
|
|
119
|
+
setSheetOpen(false);
|
|
120
|
+
} }) })] }) })] }));
|
|
121
|
+
}
|
|
122
|
+
function createTravelerFromPerson(person, role) {
|
|
123
|
+
return {
|
|
124
|
+
personId: person.id,
|
|
125
|
+
firstName: person.firstName,
|
|
126
|
+
lastName: person.lastName,
|
|
127
|
+
email: person.email ?? "",
|
|
128
|
+
role,
|
|
129
|
+
roomUnitId: null,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function formatPersonName(person) {
|
|
133
|
+
if (!person)
|
|
134
|
+
return "";
|
|
135
|
+
return [person.firstName, person.lastName].filter(Boolean).join(" ").trim();
|
|
136
|
+
}
|
|
137
|
+
function formatPerson(person) {
|
|
138
|
+
if (!person)
|
|
139
|
+
return "";
|
|
140
|
+
const name = formatPersonName(person);
|
|
141
|
+
return person.email ? `${name} · ${person.email}` : name;
|
|
142
|
+
}
|
package/dist/i18n/en.d.ts
CHANGED
|
@@ -391,6 +391,12 @@ export declare const bookingsUiEn: {
|
|
|
391
391
|
noRoom: string;
|
|
392
392
|
remove: string;
|
|
393
393
|
empty: string;
|
|
394
|
+
person: string;
|
|
395
|
+
personSearchPlaceholder: string;
|
|
396
|
+
personEmpty: string;
|
|
397
|
+
createNewPerson: string;
|
|
398
|
+
createPersonSheetTitle: string;
|
|
399
|
+
addBillingPerson: string;
|
|
394
400
|
};
|
|
395
401
|
};
|
|
396
402
|
paymentScheduleSection: {
|
|
@@ -406,6 +412,10 @@ export declare const bookingsUiEn: {
|
|
|
406
412
|
secondInstallment: string;
|
|
407
413
|
preset5050: string;
|
|
408
414
|
unpaidHint: string;
|
|
415
|
+
alreadyPaid: string;
|
|
416
|
+
paymentDate: string;
|
|
417
|
+
paymentMethod: string;
|
|
418
|
+
paymentReference: string;
|
|
409
419
|
};
|
|
410
420
|
};
|
|
411
421
|
roomsStepperSection: {
|
|
@@ -431,6 +441,7 @@ export declare const bookingsUiEn: {
|
|
|
431
441
|
groupLabel: string;
|
|
432
442
|
groupLabelPlaceholder: string;
|
|
433
443
|
createAction: string;
|
|
444
|
+
remove: string;
|
|
434
445
|
};
|
|
435
446
|
};
|
|
436
447
|
priceBreakdownSection: {
|
|
@@ -1021,6 +1032,11 @@ export declare const bookingsUiEn: {
|
|
|
1021
1032
|
travelerNoRoom: string;
|
|
1022
1033
|
travelerRemove: string;
|
|
1023
1034
|
travelerEmpty: string;
|
|
1035
|
+
travelerPerson: string;
|
|
1036
|
+
travelerPersonSearchPlaceholder: string;
|
|
1037
|
+
travelerPersonEmpty: string;
|
|
1038
|
+
createPersonSheetTitle: string;
|
|
1039
|
+
addBillingPersonAsTraveler: string;
|
|
1024
1040
|
roomsHeading: string;
|
|
1025
1041
|
roomsNoSlot: string;
|
|
1026
1042
|
roomsNoUnits: string;
|
|
@@ -1032,6 +1048,7 @@ export declare const bookingsUiEn: {
|
|
|
1032
1048
|
sharedRoomSelectPlaceholder: string;
|
|
1033
1049
|
sharedRoomNoGroups: string;
|
|
1034
1050
|
sharedRoomCreateHint: string;
|
|
1051
|
+
sharedRoomRemove: string;
|
|
1035
1052
|
sharedRoomGeneratedLabelPrefix: string;
|
|
1036
1053
|
voucherHeading: string;
|
|
1037
1054
|
voucherCodePlaceholder: string;
|
|
@@ -1050,6 +1067,13 @@ export declare const bookingsUiEn: {
|
|
|
1050
1067
|
paymentSecondInstallment: string;
|
|
1051
1068
|
paymentPreset5050: string;
|
|
1052
1069
|
paymentUnpaidHint: string;
|
|
1070
|
+
paymentAlreadyPaid: string;
|
|
1071
|
+
paymentDate: string;
|
|
1072
|
+
paymentMethod: string;
|
|
1073
|
+
paymentReference: string;
|
|
1074
|
+
documentGenerationHeading: string;
|
|
1075
|
+
generateContractDocument: string;
|
|
1076
|
+
generateInvoiceDocument: string;
|
|
1053
1077
|
breakdownHeading: string;
|
|
1054
1078
|
breakdownTotal: string;
|
|
1055
1079
|
breakdownOnRequest: string;
|
package/dist/i18n/en.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAssCK,CAAA"}
|
package/dist/i18n/en.js
CHANGED
|
@@ -391,6 +391,12 @@ export const bookingsUiEn = {
|
|
|
391
391
|
noRoom: "Unassigned",
|
|
392
392
|
remove: "Remove traveler",
|
|
393
393
|
empty: "No travelers yet. Add at least one.",
|
|
394
|
+
person: "Existing person",
|
|
395
|
+
personSearchPlaceholder: "Search people...",
|
|
396
|
+
personEmpty: "No people found.",
|
|
397
|
+
createNewPerson: "Create new",
|
|
398
|
+
createPersonSheetTitle: "Create traveler",
|
|
399
|
+
addBillingPerson: "Add billing person as traveler",
|
|
394
400
|
},
|
|
395
401
|
},
|
|
396
402
|
paymentScheduleSection: {
|
|
@@ -406,6 +412,10 @@ export const bookingsUiEn = {
|
|
|
406
412
|
secondInstallment: "Second installment",
|
|
407
413
|
preset5050: "50 / 50",
|
|
408
414
|
unpaidHint: "No payment schedule will be created. Operator will invoice manually.",
|
|
415
|
+
alreadyPaid: "Already paid",
|
|
416
|
+
paymentDate: "Payment date",
|
|
417
|
+
paymentMethod: "Method",
|
|
418
|
+
paymentReference: "Reference",
|
|
409
419
|
},
|
|
410
420
|
},
|
|
411
421
|
roomsStepperSection: {
|
|
@@ -431,6 +441,7 @@ export const bookingsUiEn = {
|
|
|
431
441
|
groupLabel: "Shared room label",
|
|
432
442
|
groupLabelPlaceholder: "e.g. Smith + Jones, Room 204",
|
|
433
443
|
createAction: "Use shared room",
|
|
444
|
+
remove: "Remove shared room",
|
|
434
445
|
},
|
|
435
446
|
},
|
|
436
447
|
priceBreakdownSection: {
|
|
@@ -1021,6 +1032,11 @@ export const bookingsUiEn = {
|
|
|
1021
1032
|
travelerNoRoom: "Unassigned",
|
|
1022
1033
|
travelerRemove: "Remove traveler",
|
|
1023
1034
|
travelerEmpty: "No travelers yet. Add at least one.",
|
|
1035
|
+
travelerPerson: "Existing person",
|
|
1036
|
+
travelerPersonSearchPlaceholder: "Search people...",
|
|
1037
|
+
travelerPersonEmpty: "No people found.",
|
|
1038
|
+
createPersonSheetTitle: "Create traveler",
|
|
1039
|
+
addBillingPersonAsTraveler: "Add billing person as traveler",
|
|
1024
1040
|
roomsHeading: "Rooms",
|
|
1025
1041
|
roomsNoSlot: "Pick a departure first to see available rooms.",
|
|
1026
1042
|
roomsNoUnits: "This departure has no per-unit availability configured.",
|
|
@@ -1032,6 +1048,7 @@ export const bookingsUiEn = {
|
|
|
1032
1048
|
sharedRoomSelectPlaceholder: "Search shared rooms...",
|
|
1033
1049
|
sharedRoomNoGroups: "No shared rooms found for this product.",
|
|
1034
1050
|
sharedRoomCreateHint: "A new shared room will be created with this booking as the primary member.",
|
|
1051
|
+
sharedRoomRemove: "Remove shared room",
|
|
1035
1052
|
sharedRoomGeneratedLabelPrefix: "Shared room",
|
|
1036
1053
|
voucherHeading: "Voucher (optional)",
|
|
1037
1054
|
voucherCodePlaceholder: "Enter voucher code...",
|
|
@@ -1050,6 +1067,13 @@ export const bookingsUiEn = {
|
|
|
1050
1067
|
paymentSecondInstallment: "Second installment",
|
|
1051
1068
|
paymentPreset5050: "50 / 50",
|
|
1052
1069
|
paymentUnpaidHint: "No payment schedule will be created. Operator will invoice manually.",
|
|
1070
|
+
paymentAlreadyPaid: "Already paid",
|
|
1071
|
+
paymentDate: "Payment date",
|
|
1072
|
+
paymentMethod: "Method",
|
|
1073
|
+
paymentReference: "Reference",
|
|
1074
|
+
documentGenerationHeading: "Document generation",
|
|
1075
|
+
generateContractDocument: "Generate contract document",
|
|
1076
|
+
generateInvoiceDocument: "Generate invoice document",
|
|
1053
1077
|
breakdownHeading: "Price breakdown",
|
|
1054
1078
|
breakdownTotal: "Total",
|
|
1055
1079
|
breakdownOnRequest: "On request",
|
package/dist/i18n/messages.d.ts
CHANGED
|
@@ -320,6 +320,12 @@ export type BookingsUiMessages = {
|
|
|
320
320
|
noRoom: string;
|
|
321
321
|
remove: string;
|
|
322
322
|
empty: string;
|
|
323
|
+
person: string;
|
|
324
|
+
personSearchPlaceholder: string;
|
|
325
|
+
personEmpty: string;
|
|
326
|
+
createNewPerson: string;
|
|
327
|
+
createPersonSheetTitle: string;
|
|
328
|
+
addBillingPerson: string;
|
|
323
329
|
};
|
|
324
330
|
};
|
|
325
331
|
paymentScheduleSection: {
|
|
@@ -335,6 +341,10 @@ export type BookingsUiMessages = {
|
|
|
335
341
|
secondInstallment: string;
|
|
336
342
|
preset5050: string;
|
|
337
343
|
unpaidHint: string;
|
|
344
|
+
alreadyPaid: string;
|
|
345
|
+
paymentDate: string;
|
|
346
|
+
paymentMethod: string;
|
|
347
|
+
paymentReference: string;
|
|
338
348
|
};
|
|
339
349
|
};
|
|
340
350
|
roomsStepperSection: {
|
|
@@ -360,6 +370,7 @@ export type BookingsUiMessages = {
|
|
|
360
370
|
groupLabel: string;
|
|
361
371
|
groupLabelPlaceholder: string;
|
|
362
372
|
createAction: string;
|
|
373
|
+
remove: string;
|
|
363
374
|
};
|
|
364
375
|
};
|
|
365
376
|
priceBreakdownSection: {
|
|
@@ -895,6 +906,11 @@ export type BookingsUiMessages = {
|
|
|
895
906
|
travelerNoRoom: string;
|
|
896
907
|
travelerRemove: string;
|
|
897
908
|
travelerEmpty: string;
|
|
909
|
+
travelerPerson: string;
|
|
910
|
+
travelerPersonSearchPlaceholder: string;
|
|
911
|
+
travelerPersonEmpty: string;
|
|
912
|
+
createPersonSheetTitle: string;
|
|
913
|
+
addBillingPersonAsTraveler: string;
|
|
898
914
|
roomsHeading: string;
|
|
899
915
|
roomsNoSlot: string;
|
|
900
916
|
roomsNoUnits: string;
|
|
@@ -906,6 +922,7 @@ export type BookingsUiMessages = {
|
|
|
906
922
|
sharedRoomSelectPlaceholder: string;
|
|
907
923
|
sharedRoomNoGroups: string;
|
|
908
924
|
sharedRoomCreateHint: string;
|
|
925
|
+
sharedRoomRemove: string;
|
|
909
926
|
sharedRoomGeneratedLabelPrefix: string;
|
|
910
927
|
voucherHeading: string;
|
|
911
928
|
voucherCodePlaceholder: string;
|
|
@@ -924,6 +941,13 @@ export type BookingsUiMessages = {
|
|
|
924
941
|
paymentSecondInstallment: string;
|
|
925
942
|
paymentPreset5050: string;
|
|
926
943
|
paymentUnpaidHint: string;
|
|
944
|
+
paymentAlreadyPaid: string;
|
|
945
|
+
paymentDate: string;
|
|
946
|
+
paymentMethod: string;
|
|
947
|
+
paymentReference: string;
|
|
948
|
+
documentGenerationHeading: string;
|
|
949
|
+
generateContractDocument: string;
|
|
950
|
+
generateInvoiceDocument: string;
|
|
927
951
|
breakdownHeading: string;
|
|
928
952
|
breakdownTotal: string;
|
|
929
953
|
breakdownOnRequest: string;
|