@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.
Files changed (40) hide show
  1. package/dist/components/booking-create-dialog.d.ts +1 -1
  2. package/dist/components/booking-create-dialog.d.ts.map +1 -1
  3. package/dist/components/booking-create-dialog.js +64 -24
  4. package/dist/components/booking-create-page.d.ts +2 -1
  5. package/dist/components/booking-create-page.d.ts.map +1 -1
  6. package/dist/components/booking-create-page.js +2 -2
  7. package/dist/components/booking-create-utils.d.ts +33 -0
  8. package/dist/components/booking-create-utils.d.ts.map +1 -0
  9. package/dist/components/booking-create-utils.js +67 -0
  10. package/dist/components/booking-list.d.ts +2 -1
  11. package/dist/components/booking-list.d.ts.map +1 -1
  12. package/dist/components/booking-list.js +5 -1
  13. package/dist/components/bookings-page.d.ts +2 -1
  14. package/dist/components/bookings-page.d.ts.map +1 -1
  15. package/dist/components/bookings-page.js +2 -2
  16. package/dist/components/payment-schedule-section.d.ts +20 -0
  17. package/dist/components/payment-schedule-section.d.ts.map +1 -1
  18. package/dist/components/payment-schedule-section.js +27 -2
  19. package/dist/components/price-breakdown-section.d.ts +1 -0
  20. package/dist/components/price-breakdown-section.d.ts.map +1 -1
  21. package/dist/components/price-breakdown-section.js +2 -0
  22. package/dist/components/product-picker-section.d.ts.map +1 -1
  23. package/dist/components/product-picker-section.js +5 -2
  24. package/dist/components/shared-room-section.d.ts +2 -0
  25. package/dist/components/shared-room-section.d.ts.map +1 -1
  26. package/dist/components/shared-room-section.js +14 -2
  27. package/dist/components/travelers-section.d.ts +15 -10
  28. package/dist/components/travelers-section.d.ts.map +1 -1
  29. package/dist/components/travelers-section.js +96 -14
  30. package/dist/i18n/en.d.ts +24 -0
  31. package/dist/i18n/en.d.ts.map +1 -1
  32. package/dist/i18n/en.js +24 -0
  33. package/dist/i18n/messages.d.ts +24 -0
  34. package/dist/i18n/messages.d.ts.map +1 -1
  35. package/dist/i18n/provider.d.ts +48 -0
  36. package/dist/i18n/provider.d.ts.map +1 -1
  37. package/dist/i18n/ro.d.ts +24 -0
  38. package/dist/i18n/ro.d.ts.map +1 -1
  39. package/dist/i18n/ro.js +24 -0
  40. package/package.json +24 -24
@@ -1 +1 @@
1
- {"version":3,"file":"product-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/product-picker-section.tsx"],"names":[],"mappings":"AA8BA,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,2CAgI3B"}
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;KACtB,CAAA;CACF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,SAAS,EACT,OAAc,EACd,MAAM,GACP,EAAE,sBAAsB,2CAyJxB"}
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 carries name + optional
53
- * email + role + optional room assignment. Inline-create only for now
54
- * operators who want to pick an existing CRM person can do so from the
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. Creates a CRM person for each row that doesn't match an existing one
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":"AAeA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;AAIhE,MAAM,WAAW,aAAa;IAC5B,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,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;KACf,CAAA;CACF;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,qBAAqB,2CA4I7F"}
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 { Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/ui/components";
4
- import { Trash2 } from "lucide-react";
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 carries name + optional
15
- * email + role + optional room assignment. Inline-create only for now
16
- * operators who want to pick an existing CRM person can do so from the
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. Creates a CRM person for each row that doesn't match an existing one
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
- 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 })] }), 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: [_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,
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;
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8qCK,CAAA"}
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",
@@ -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;