@voyantjs/bookings-ui 0.108.0 → 0.109.0
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/admin/booking-contract-dialog.d.ts +22 -0
- package/dist/admin/booking-contract-dialog.d.ts.map +1 -0
- package/dist/admin/booking-contract-dialog.js +161 -0
- package/dist/admin/booking-detail-host.d.ts +123 -0
- package/dist/admin/booking-detail-host.d.ts.map +1 -0
- package/dist/admin/booking-detail-host.js +143 -0
- package/dist/admin/booking-detail-skeleton.d.ts +7 -0
- package/dist/admin/booking-detail-skeleton.d.ts.map +1 -0
- package/dist/admin/booking-detail-skeleton.js +24 -0
- package/dist/admin/booking-documents-table.d.ts +13 -0
- package/dist/admin/booking-documents-table.d.ts.map +1 -0
- package/dist/admin/booking-documents-table.js +258 -0
- package/dist/admin/booking-invoice-sheet.d.ts +18 -0
- package/dist/admin/booking-invoice-sheet.d.ts.map +1 -0
- package/dist/admin/booking-invoice-sheet.js +101 -0
- package/dist/admin/bookings-host.d.ts +26 -0
- package/dist/admin/bookings-host.d.ts.map +1 -0
- package/dist/admin/bookings-host.js +18 -0
- package/dist/admin/bookings-list-skeleton.d.ts +10 -0
- package/dist/admin/bookings-list-skeleton.d.ts.map +1 -0
- package/dist/admin/bookings-list-skeleton.js +25 -0
- package/dist/admin/index.d.ts +197 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +187 -0
- package/dist/admin/person-bookings-widget.d.ts +13 -0
- package/dist/admin/person-bookings-widget.d.ts.map +1 -0
- package/dist/admin/person-bookings-widget.js +48 -0
- package/dist/admin/use-booking-action-ledger-events.d.ts +15 -0
- package/dist/admin/use-booking-action-ledger-events.d.ts.map +1 -0
- package/dist/admin/use-booking-action-ledger-events.js +66 -0
- package/package.json +38 -31
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { type AdminExtension } from "@voyantjs/admin";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { BookingDetailTabValue } from "../components/booking-detail-page.js";
|
|
4
|
+
import type { BookingListFiltersState } from "../components/booking-list.js";
|
|
5
|
+
/**
|
|
6
|
+
* Semantic destinations the bookings admin surfaces navigate to
|
|
7
|
+
* (packaged-admin RFC §4.7). The booking pages link into routes they do not
|
|
8
|
+
* own — the CRM person/organization pages, the product editor, the finance
|
|
9
|
+
* payment/invoice pages — so instead of importing a host route tree they
|
|
10
|
+
* resolve these keys through `useAdminHref`/`useAdminNavigate` from
|
|
11
|
+
* `@voyantjs/admin`. Hosts register one resolver per key
|
|
12
|
+
* (`satisfies AdminDestinationResolvers`).
|
|
13
|
+
*
|
|
14
|
+
* `booking.detail`/`booking.list`/`booking.create` are declared here even
|
|
15
|
+
* though bookings pages are their first consumers: other domains' packaged
|
|
16
|
+
* pages navigate TO bookings through the same keys.
|
|
17
|
+
*/
|
|
18
|
+
declare module "@voyantjs/admin" {
|
|
19
|
+
interface AdminDestinations {
|
|
20
|
+
/** The bookings list page. */
|
|
21
|
+
"booking.list": Record<string, never>;
|
|
22
|
+
/** A booking's detail page; `tab` deep-links a specific tab. */
|
|
23
|
+
"booking.detail": {
|
|
24
|
+
bookingId: string;
|
|
25
|
+
tab?: BookingDetailTabValue;
|
|
26
|
+
};
|
|
27
|
+
/** The "New booking" entry point (product picker → unified journey). */
|
|
28
|
+
"booking.create": Record<string, never>;
|
|
29
|
+
/** A CRM person's detail page. */
|
|
30
|
+
"person.detail": {
|
|
31
|
+
personId: string;
|
|
32
|
+
};
|
|
33
|
+
/** A CRM organization's detail page. */
|
|
34
|
+
"organization.detail": {
|
|
35
|
+
organizationId: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The owned-product editor/detail page. Also declared by
|
|
39
|
+
* `@voyantjs/catalog-ui/admin` — interface merging requires the member
|
|
40
|
+
* shape to stay identical across packages.
|
|
41
|
+
*/
|
|
42
|
+
"product.detail": {
|
|
43
|
+
productId: string;
|
|
44
|
+
};
|
|
45
|
+
/** An availability slot's detail page. */
|
|
46
|
+
"availabilitySlot.detail": {
|
|
47
|
+
slotId: string;
|
|
48
|
+
};
|
|
49
|
+
/** A payment's detail page in the finance area. */
|
|
50
|
+
"payment.detail": {
|
|
51
|
+
paymentId: string;
|
|
52
|
+
};
|
|
53
|
+
/** An invoice's full detail page in the finance area. */
|
|
54
|
+
"invoice.detail": {
|
|
55
|
+
invoiceId: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* A legal contract's detail page. Also declared by
|
|
59
|
+
* `@voyantjs/legal-ui/admin` — interface merging requires the member
|
|
60
|
+
* shape to stay identical across packages. Declared here because the
|
|
61
|
+
* booking Documents tab links contract rows to their detail page.
|
|
62
|
+
*/
|
|
63
|
+
"contract.detail": {
|
|
64
|
+
contractId: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export { BookingContractDialog, type BookingContractDialogProps, } from "./booking-contract-dialog.js";
|
|
69
|
+
export { BookingDetailHost, type BookingDetailHostProps, type BookingDetailHostSlot, type BookingDetailHostSlotContext, type BookingDetailHostSlots, bookingDetailFinanceEndSlot, bookingDetailFinanceStartSlot, bookingDetailInvoicesTabSlot, } from "./booking-detail-host.js";
|
|
70
|
+
export { BookingDetailSkeleton } from "./booking-detail-skeleton.js";
|
|
71
|
+
export { BookingDocumentsTable, type BookingDocumentsTableProps, } from "./booking-documents-table.js";
|
|
72
|
+
export { BookingInvoiceSheet, type BookingInvoiceSheetProps, } from "./booking-invoice-sheet.js";
|
|
73
|
+
export { BookingsHost, type BookingsHostProps } from "./bookings-host.js";
|
|
74
|
+
export { BookingsListSkeleton } from "./bookings-list-skeleton.js";
|
|
75
|
+
export { PersonBookingsWidget, type PersonBookingsWidgetProps, } from "./person-bookings-widget.js";
|
|
76
|
+
export { useBookingActionLedgerEvents } from "./use-booking-action-ledger-events.js";
|
|
77
|
+
/**
|
|
78
|
+
* Search contract for the bookings list page: the URL projection of
|
|
79
|
+
* `BookingListFiltersState` (filters, sort, paging). Package-owned so the
|
|
80
|
+
* route file, the host, and the extension contribution validate the same
|
|
81
|
+
* shape. Defaults are absent from the URL — see
|
|
82
|
+
* {@link bookingsFiltersToSearch}.
|
|
83
|
+
*/
|
|
84
|
+
export declare const bookingsIndexSearchSchema: z.ZodObject<{
|
|
85
|
+
search: z.ZodOptional<z.ZodString>;
|
|
86
|
+
status: z.ZodOptional<z.ZodString>;
|
|
87
|
+
productId: z.ZodOptional<z.ZodString>;
|
|
88
|
+
optionId: z.ZodOptional<z.ZodString>;
|
|
89
|
+
supplierId: z.ZodOptional<z.ZodString>;
|
|
90
|
+
productCategoryId: z.ZodOptional<z.ZodString>;
|
|
91
|
+
personId: z.ZodOptional<z.ZodString>;
|
|
92
|
+
organizationId: z.ZodOptional<z.ZodString>;
|
|
93
|
+
availabilitySlotId: z.ZodOptional<z.ZodString>;
|
|
94
|
+
dateFrom: z.ZodOptional<z.ZodString>;
|
|
95
|
+
dateTo: z.ZodOptional<z.ZodString>;
|
|
96
|
+
paxMin: z.ZodOptional<z.ZodString>;
|
|
97
|
+
paxMax: z.ZodOptional<z.ZodString>;
|
|
98
|
+
sortBy: z.ZodOptional<z.ZodEnum<{
|
|
99
|
+
createdAt: "createdAt";
|
|
100
|
+
bookingNumber: "bookingNumber";
|
|
101
|
+
status: "status";
|
|
102
|
+
sellAmount: "sellAmount";
|
|
103
|
+
pax: "pax";
|
|
104
|
+
startDate: "startDate";
|
|
105
|
+
endDate: "endDate";
|
|
106
|
+
}>>;
|
|
107
|
+
sortDir: z.ZodOptional<z.ZodEnum<{
|
|
108
|
+
asc: "asc";
|
|
109
|
+
desc: "desc";
|
|
110
|
+
}>>;
|
|
111
|
+
offset: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
export type BookingsIndexSearchParams = z.infer<typeof bookingsIndexSearchSchema>;
|
|
114
|
+
/** URL search params → `BookingList` initial state. Empty / `"all"` /
|
|
115
|
+
* default values are absent in the URL; we let `BookingList`'s defaults
|
|
116
|
+
* fill them in. */
|
|
117
|
+
export declare function bookingsSearchToFilters(search: BookingsIndexSearchParams): Partial<BookingListFiltersState>;
|
|
118
|
+
/** Project the filter snapshot back into URL search params, dropping
|
|
119
|
+
* any value that matches the component's default so the URL stays
|
|
120
|
+
* clean when the operator is viewing the unfiltered list. */
|
|
121
|
+
export declare function bookingsFiltersToSearch(filters: BookingListFiltersState): BookingsIndexSearchParams;
|
|
122
|
+
/** Tab values of the canonical `BookingDetailPage`, as a search-param schema. */
|
|
123
|
+
export declare const bookingDetailTabSchema: z.ZodEnum<{
|
|
124
|
+
activity: "activity";
|
|
125
|
+
metadata: "metadata";
|
|
126
|
+
items: "items";
|
|
127
|
+
travelers: "travelers";
|
|
128
|
+
documents: "documents";
|
|
129
|
+
suppliers: "suppliers";
|
|
130
|
+
invoices: "invoices";
|
|
131
|
+
finance: "finance";
|
|
132
|
+
}>;
|
|
133
|
+
/**
|
|
134
|
+
* Search contract for the booking detail page. `productId`/`slotId` only
|
|
135
|
+
* matter for the `"new"` pseudo-id: a deep link with a product pre-chosen
|
|
136
|
+
* redirects into the unified booking journey (host route concern).
|
|
137
|
+
*/
|
|
138
|
+
export declare const bookingDetailSearchSchema: z.ZodObject<{
|
|
139
|
+
productId: z.ZodOptional<z.ZodString>;
|
|
140
|
+
slotId: z.ZodOptional<z.ZodString>;
|
|
141
|
+
tab: z.ZodOptional<z.ZodEnum<{
|
|
142
|
+
activity: "activity";
|
|
143
|
+
metadata: "metadata";
|
|
144
|
+
items: "items";
|
|
145
|
+
travelers: "travelers";
|
|
146
|
+
documents: "documents";
|
|
147
|
+
suppliers: "suppliers";
|
|
148
|
+
invoices: "invoices";
|
|
149
|
+
finance: "finance";
|
|
150
|
+
}>>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
export type BookingDetailSearchParams = z.infer<typeof bookingDetailSearchSchema>;
|
|
153
|
+
export interface CreateBookingsAdminExtensionOptions {
|
|
154
|
+
/** Mount path of the bookings pages inside the admin workspace. Default `/bookings`. */
|
|
155
|
+
basePath?: string;
|
|
156
|
+
/** Localized page titles. Defaults are the English operator nav labels. */
|
|
157
|
+
labels?: {
|
|
158
|
+
bookings?: string;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The bookings admin contribution (packaged-admin RFC Phase 3,
|
|
163
|
+
* `@voyantjs/<domain>-ui/admin` convention).
|
|
164
|
+
*
|
|
165
|
+
* NAVIGATION: deliberately none. The Bookings nav item is part of the BASE
|
|
166
|
+
* operator navigation — see `createOperatorAdminNavigation` in
|
|
167
|
+
* `@voyantjs/admin` — so contributing nav entries here would duplicate it.
|
|
168
|
+
* If the base nav ever drops the bookings item, this extension is where the
|
|
169
|
+
* entry moves.
|
|
170
|
+
*
|
|
171
|
+
* ROUTES: contributions are metadata + the package-owned search contracts
|
|
172
|
+
* ({@link bookingsIndexSearchSchema} for the list,
|
|
173
|
+
* {@link bookingDetailSearchSchema} for the detail page). The PAGES are
|
|
174
|
+
* package-owned too: {@link BookingsHost} and {@link BookingDetailHost}
|
|
175
|
+
* bind the canonical bookings pages to their data wiring (bookings/finance
|
|
176
|
+
* provider context) and resolve every cross-route link through the semantic
|
|
177
|
+
* destinations declared above — no app RPC client, no host route tree.
|
|
178
|
+
*
|
|
179
|
+
* `component:` is intentionally NOT attached to these contributions yet:
|
|
180
|
+
* the contribution contract renders zero-prop pages (route components read
|
|
181
|
+
* params via the router, per RFC §4.2), while both bookings hosts take
|
|
182
|
+
* route params/search state as props. Host route files stay the thin
|
|
183
|
+
* binding layer (`Route.useParams()`/`Route.useSearch()` → host props)
|
|
184
|
+
* until the §4.2 code-based route assembly gives packaged pages a
|
|
185
|
+
* router-agnostic way to read route state.
|
|
186
|
+
*
|
|
187
|
+
* WIDGETS: the crm-ui ↔ bookings-ui cycle resolution (RFC §4.7). The CRM
|
|
188
|
+
* person detail page mounts a Bookings tab, but this package depends on
|
|
189
|
+
* `@voyantjs/crm-ui`, so crm-ui's host cannot import the bookings-owned
|
|
190
|
+
* card. Instead this extension contributes {@link PersonBookingsWidget} on
|
|
191
|
+
* the `person.details.bookings-tab` slot crm-ui's `PersonDetailHost`
|
|
192
|
+
* exposes; the host mounts its Bookings tab whenever a contribution targets
|
|
193
|
+
* that slot and hands the widget its typed slot context
|
|
194
|
+
* (`PersonDetailBookingsTabContext`) as props.
|
|
195
|
+
*/
|
|
196
|
+
export declare function createBookingsAdminExtension(options?: CreateBookingsAdminExtensionOptions): AdminExtension;
|
|
197
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { defineAdminExtension, } from "@voyantjs/admin";
|
|
2
|
+
// Importing the slot id also binds the crm-ui `AdminDestinations`
|
|
3
|
+
// augmentation (`person.list`, `organization.list`, ...) into this program;
|
|
4
|
+
// this package already peer-depends on `@voyantjs/crm-ui`.
|
|
5
|
+
import { personDetailBookingsTabSlot } from "@voyantjs/crm-ui/admin";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { PersonBookingsWidget } from "./person-bookings-widget.js";
|
|
8
|
+
// Packaged admin hosts (packaged-admin RFC Phase 3): the bookings pages
|
|
9
|
+
// bound to their data wiring + semantic-destination navigation. Host route
|
|
10
|
+
// files only bind route params/search state onto these.
|
|
11
|
+
export { BookingContractDialog, } from "./booking-contract-dialog.js";
|
|
12
|
+
export { BookingDetailHost, bookingDetailFinanceEndSlot, bookingDetailFinanceStartSlot, bookingDetailInvoicesTabSlot, } from "./booking-detail-host.js";
|
|
13
|
+
export { BookingDetailSkeleton } from "./booking-detail-skeleton.js";
|
|
14
|
+
export { BookingDocumentsTable, } from "./booking-documents-table.js";
|
|
15
|
+
export { BookingInvoiceSheet, } from "./booking-invoice-sheet.js";
|
|
16
|
+
export { BookingsHost } from "./bookings-host.js";
|
|
17
|
+
export { BookingsListSkeleton } from "./bookings-list-skeleton.js";
|
|
18
|
+
export { PersonBookingsWidget, } from "./person-bookings-widget.js";
|
|
19
|
+
export { useBookingActionLedgerEvents } from "./use-booking-action-ledger-events.js";
|
|
20
|
+
const bookingsListSortBySchema = z.enum([
|
|
21
|
+
"bookingNumber",
|
|
22
|
+
"status",
|
|
23
|
+
"sellAmount",
|
|
24
|
+
"pax",
|
|
25
|
+
"startDate",
|
|
26
|
+
"endDate",
|
|
27
|
+
"createdAt",
|
|
28
|
+
]);
|
|
29
|
+
const bookingsListSortDirSchema = z.enum(["asc", "desc"]);
|
|
30
|
+
/**
|
|
31
|
+
* Search contract for the bookings list page: the URL projection of
|
|
32
|
+
* `BookingListFiltersState` (filters, sort, paging). Package-owned so the
|
|
33
|
+
* route file, the host, and the extension contribution validate the same
|
|
34
|
+
* shape. Defaults are absent from the URL — see
|
|
35
|
+
* {@link bookingsFiltersToSearch}.
|
|
36
|
+
*/
|
|
37
|
+
export const bookingsIndexSearchSchema = z.object({
|
|
38
|
+
search: z.string().optional(),
|
|
39
|
+
status: z.string().optional(),
|
|
40
|
+
productId: z.string().optional(),
|
|
41
|
+
optionId: z.string().optional(),
|
|
42
|
+
supplierId: z.string().optional(),
|
|
43
|
+
productCategoryId: z.string().optional(),
|
|
44
|
+
personId: z.string().optional(),
|
|
45
|
+
organizationId: z.string().optional(),
|
|
46
|
+
availabilitySlotId: z.string().optional(),
|
|
47
|
+
dateFrom: z.string().optional(),
|
|
48
|
+
dateTo: z.string().optional(),
|
|
49
|
+
paxMin: z.string().optional(),
|
|
50
|
+
paxMax: z.string().optional(),
|
|
51
|
+
sortBy: bookingsListSortBySchema.optional(),
|
|
52
|
+
sortDir: bookingsListSortDirSchema.optional(),
|
|
53
|
+
offset: z.coerce.number().int().min(0).optional(),
|
|
54
|
+
});
|
|
55
|
+
/** URL search params → `BookingList` initial state. Empty / `"all"` /
|
|
56
|
+
* default values are absent in the URL; we let `BookingList`'s defaults
|
|
57
|
+
* fill them in. */
|
|
58
|
+
export function bookingsSearchToFilters(search) {
|
|
59
|
+
return {
|
|
60
|
+
search: search.search,
|
|
61
|
+
status: search.status,
|
|
62
|
+
productId: search.productId ?? null,
|
|
63
|
+
optionId: search.optionId ?? null,
|
|
64
|
+
supplierId: search.supplierId ?? null,
|
|
65
|
+
productCategoryId: search.productCategoryId ?? null,
|
|
66
|
+
personId: search.personId ?? null,
|
|
67
|
+
organizationId: search.organizationId ?? null,
|
|
68
|
+
availabilitySlotId: search.availabilitySlotId ?? null,
|
|
69
|
+
dateFrom: search.dateFrom ?? null,
|
|
70
|
+
dateTo: search.dateTo ?? null,
|
|
71
|
+
paxMin: search.paxMin,
|
|
72
|
+
paxMax: search.paxMax,
|
|
73
|
+
sortBy: search.sortBy,
|
|
74
|
+
sortDir: search.sortDir,
|
|
75
|
+
offset: search.offset,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Project the filter snapshot back into URL search params, dropping
|
|
79
|
+
* any value that matches the component's default so the URL stays
|
|
80
|
+
* clean when the operator is viewing the unfiltered list. */
|
|
81
|
+
export function bookingsFiltersToSearch(filters) {
|
|
82
|
+
return {
|
|
83
|
+
search: filters.search || undefined,
|
|
84
|
+
status: filters.status === "all" ? undefined : filters.status,
|
|
85
|
+
productId: filters.productId ?? undefined,
|
|
86
|
+
optionId: filters.optionId ?? undefined,
|
|
87
|
+
supplierId: filters.supplierId ?? undefined,
|
|
88
|
+
productCategoryId: filters.productCategoryId ?? undefined,
|
|
89
|
+
personId: filters.personId ?? undefined,
|
|
90
|
+
organizationId: filters.organizationId ?? undefined,
|
|
91
|
+
availabilitySlotId: filters.availabilitySlotId ?? undefined,
|
|
92
|
+
dateFrom: filters.dateFrom ?? undefined,
|
|
93
|
+
dateTo: filters.dateTo ?? undefined,
|
|
94
|
+
paxMin: filters.paxMin || undefined,
|
|
95
|
+
paxMax: filters.paxMax || undefined,
|
|
96
|
+
sortBy: filters.sortBy === "createdAt" ? undefined : filters.sortBy,
|
|
97
|
+
sortDir: filters.sortDir === "desc" ? undefined : filters.sortDir,
|
|
98
|
+
offset: filters.offset === 0 ? undefined : filters.offset,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Tab values of the canonical `BookingDetailPage`, as a search-param schema. */
|
|
102
|
+
export const bookingDetailTabSchema = z.enum([
|
|
103
|
+
"items",
|
|
104
|
+
"travelers",
|
|
105
|
+
"finance",
|
|
106
|
+
"invoices",
|
|
107
|
+
"documents",
|
|
108
|
+
"suppliers",
|
|
109
|
+
"activity",
|
|
110
|
+
"metadata",
|
|
111
|
+
]);
|
|
112
|
+
/**
|
|
113
|
+
* Search contract for the booking detail page. `productId`/`slotId` only
|
|
114
|
+
* matter for the `"new"` pseudo-id: a deep link with a product pre-chosen
|
|
115
|
+
* redirects into the unified booking journey (host route concern).
|
|
116
|
+
*/
|
|
117
|
+
export const bookingDetailSearchSchema = z.object({
|
|
118
|
+
productId: z.string().optional(),
|
|
119
|
+
slotId: z.string().optional(),
|
|
120
|
+
tab: bookingDetailTabSchema.optional(),
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* The bookings admin contribution (packaged-admin RFC Phase 3,
|
|
124
|
+
* `@voyantjs/<domain>-ui/admin` convention).
|
|
125
|
+
*
|
|
126
|
+
* NAVIGATION: deliberately none. The Bookings nav item is part of the BASE
|
|
127
|
+
* operator navigation — see `createOperatorAdminNavigation` in
|
|
128
|
+
* `@voyantjs/admin` — so contributing nav entries here would duplicate it.
|
|
129
|
+
* If the base nav ever drops the bookings item, this extension is where the
|
|
130
|
+
* entry moves.
|
|
131
|
+
*
|
|
132
|
+
* ROUTES: contributions are metadata + the package-owned search contracts
|
|
133
|
+
* ({@link bookingsIndexSearchSchema} for the list,
|
|
134
|
+
* {@link bookingDetailSearchSchema} for the detail page). The PAGES are
|
|
135
|
+
* package-owned too: {@link BookingsHost} and {@link BookingDetailHost}
|
|
136
|
+
* bind the canonical bookings pages to their data wiring (bookings/finance
|
|
137
|
+
* provider context) and resolve every cross-route link through the semantic
|
|
138
|
+
* destinations declared above — no app RPC client, no host route tree.
|
|
139
|
+
*
|
|
140
|
+
* `component:` is intentionally NOT attached to these contributions yet:
|
|
141
|
+
* the contribution contract renders zero-prop pages (route components read
|
|
142
|
+
* params via the router, per RFC §4.2), while both bookings hosts take
|
|
143
|
+
* route params/search state as props. Host route files stay the thin
|
|
144
|
+
* binding layer (`Route.useParams()`/`Route.useSearch()` → host props)
|
|
145
|
+
* until the §4.2 code-based route assembly gives packaged pages a
|
|
146
|
+
* router-agnostic way to read route state.
|
|
147
|
+
*
|
|
148
|
+
* WIDGETS: the crm-ui ↔ bookings-ui cycle resolution (RFC §4.7). The CRM
|
|
149
|
+
* person detail page mounts a Bookings tab, but this package depends on
|
|
150
|
+
* `@voyantjs/crm-ui`, so crm-ui's host cannot import the bookings-owned
|
|
151
|
+
* card. Instead this extension contributes {@link PersonBookingsWidget} on
|
|
152
|
+
* the `person.details.bookings-tab` slot crm-ui's `PersonDetailHost`
|
|
153
|
+
* exposes; the host mounts its Bookings tab whenever a contribution targets
|
|
154
|
+
* that slot and hands the widget its typed slot context
|
|
155
|
+
* (`PersonDetailBookingsTabContext`) as props.
|
|
156
|
+
*/
|
|
157
|
+
export function createBookingsAdminExtension(options = {}) {
|
|
158
|
+
const { basePath = "/bookings", labels = {} } = options;
|
|
159
|
+
const { bookings = "Bookings" } = labels;
|
|
160
|
+
return defineAdminExtension({
|
|
161
|
+
id: "bookings",
|
|
162
|
+
routes: [
|
|
163
|
+
{
|
|
164
|
+
id: "bookings-index",
|
|
165
|
+
path: basePath,
|
|
166
|
+
title: bookings,
|
|
167
|
+
validateSearch: (search) => bookingsIndexSearchSchema.parse(search),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "bookings-detail",
|
|
171
|
+
path: `${basePath}/$id`,
|
|
172
|
+
title: bookings,
|
|
173
|
+
validateSearch: (search) => bookingDetailSearchSchema.parse(search),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
widgets: [
|
|
177
|
+
{
|
|
178
|
+
id: "bookings-person-bookings",
|
|
179
|
+
slot: personDetailBookingsTabSlot,
|
|
180
|
+
// The widget registry is untyped (`Record<string, unknown>` props);
|
|
181
|
+
// the typed contract is `PersonDetailBookingsTabContext`, which
|
|
182
|
+
// crm-ui's person detail host passes verbatim to this slot's widgets.
|
|
183
|
+
component: PersonBookingsWidget,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PersonDetailBookingsTabContext } from "@voyantjs/crm-ui/admin";
|
|
2
|
+
export type PersonBookingsWidgetProps = PersonDetailBookingsTabContext;
|
|
3
|
+
/**
|
|
4
|
+
* The person detail page's Bookings tab, contributed as a widget on
|
|
5
|
+
* crm-ui's `person.details.bookings-tab` slot (packaged-admin RFC §4.7
|
|
6
|
+
* cycle resolution): this package depends on `@voyantjs/crm-ui`, so the
|
|
7
|
+
* person detail host cannot import this card — the contribution travels
|
|
8
|
+
* the widget seam instead. Receives the slot's typed context
|
|
9
|
+
* (`PersonDetailBookingsTabContext`) as props and opens rows through the
|
|
10
|
+
* semantic `booking.detail` destination.
|
|
11
|
+
*/
|
|
12
|
+
export declare function PersonBookingsWidget({ personId }: PersonBookingsWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=person-bookings-widget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"person-bookings-widget.d.ts","sourceRoot":"","sources":["../../src/admin/person-bookings-widget.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAA;AAY5E,MAAM,MAAM,yBAAyB,GAAG,8BAA8B,CAAA;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,2CAmF3E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useAdminNavigate, useOperatorAdminMessages } from "@voyantjs/admin";
|
|
4
|
+
import { bookingStatusBadgeVariant, useBookings } from "@voyantjs/bookings-react";
|
|
5
|
+
import { Badge } from "@voyantjs/ui/components/badge";
|
|
6
|
+
import { Skeleton } from "@voyantjs/ui/components/skeleton";
|
|
7
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components/table";
|
|
8
|
+
/**
|
|
9
|
+
* The person detail page's Bookings tab, contributed as a widget on
|
|
10
|
+
* crm-ui's `person.details.bookings-tab` slot (packaged-admin RFC §4.7
|
|
11
|
+
* cycle resolution): this package depends on `@voyantjs/crm-ui`, so the
|
|
12
|
+
* person detail host cannot import this card — the contribution travels
|
|
13
|
+
* the widget seam instead. Receives the slot's typed context
|
|
14
|
+
* (`PersonDetailBookingsTabContext`) as props and opens rows through the
|
|
15
|
+
* semantic `booking.detail` destination.
|
|
16
|
+
*/
|
|
17
|
+
export function PersonBookingsWidget({ personId }) {
|
|
18
|
+
const adminMessages = useOperatorAdminMessages();
|
|
19
|
+
const messages = adminMessages.bookings.list;
|
|
20
|
+
const navigateTo = useAdminNavigate();
|
|
21
|
+
const bookingsQuery = useBookings({ personId, limit: 50 });
|
|
22
|
+
const bookings = bookingsQuery.data?.data ?? [];
|
|
23
|
+
if (bookingsQuery.isPending) {
|
|
24
|
+
return (_jsxs("div", { className: "space-y-2 p-4", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] }));
|
|
25
|
+
}
|
|
26
|
+
if (bookingsQuery.isError) {
|
|
27
|
+
return (_jsx("div", { className: "p-6 text-center text-destructive text-sm", children: adminMessages.crm.personDetail.notFound }));
|
|
28
|
+
}
|
|
29
|
+
if (bookings.length === 0) {
|
|
30
|
+
return (_jsx("div", { className: "p-6 text-center text-muted-foreground text-sm", children: messages.relatedEmpty }));
|
|
31
|
+
}
|
|
32
|
+
return (_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: messages.tableBookingNumber }), _jsx(TableHead, { children: messages.tableItems }), _jsx(TableHead, { children: messages.tableStatus }), _jsx(TableHead, { children: messages.tableSellAmount }), _jsx(TableHead, { children: messages.tablePax }), _jsx(TableHead, { children: messages.tableStartDate })] }) }), _jsx(TableBody, { children: bookings.map((booking) => {
|
|
33
|
+
const firstItem = booking.items?.[0];
|
|
34
|
+
const itemLabel = firstItem?.productName ?? firstItem?.title ?? "—";
|
|
35
|
+
const extraItems = Math.max((booking.items?.length ?? 0) - 1, 0);
|
|
36
|
+
return (_jsxs(TableRow, { onClick: () => navigateTo("booking.detail", { bookingId: booking.id }), className: "cursor-pointer", children: [_jsx(TableCell, { className: "font-medium", children: booking.bookingNumber }), _jsx(TableCell, { children: _jsxs("div", { className: "max-w-[280px] truncate", title: itemLabel, children: [itemLabel, extraItems > 0 ? (_jsxs("span", { className: "ml-1 text-muted-foreground text-xs", children: ["+", extraItems] })) : null] }) }), _jsx(TableCell, { children: _jsx(Badge, { variant: bookingStatusBadgeVariant[booking.status], children: booking.status }) }), _jsx(TableCell, { children: booking.sellAmountCents == null
|
|
37
|
+
? "—"
|
|
38
|
+
: `${(booking.sellAmountCents / 100).toFixed(2)} ${booking.sellCurrency}` }), _jsx(TableCell, { children: booking.pax ?? "—" }), _jsx(TableCell, { children: formatBookingDate(booking.startsAt ?? booking.startDate) })] }, booking.id));
|
|
39
|
+
}) })] }) }));
|
|
40
|
+
}
|
|
41
|
+
function formatBookingDate(value) {
|
|
42
|
+
if (!value)
|
|
43
|
+
return "—";
|
|
44
|
+
const date = new Date(/^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}T00:00:00` : value);
|
|
45
|
+
if (Number.isNaN(date.getTime()))
|
|
46
|
+
return "—";
|
|
47
|
+
return date.toLocaleDateString();
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TimelineEvent } from "../components/booking-activity-timeline.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fetch the booking's central action-ledger entries and map them into
|
|
4
|
+
* `TimelineEvent`s so they can be merged into `BookingActivityTimeline`.
|
|
5
|
+
* Replaces the standalone Ledger tab — operators see one chronological
|
|
6
|
+
* activity feed instead of two sibling tabs.
|
|
7
|
+
*
|
|
8
|
+
* Returns a "Load more" `footer` element when the cursor pager hasn't
|
|
9
|
+
* exhausted yet so the timeline can render it below the event list.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useBookingActionLedgerEvents(bookingId: string): {
|
|
12
|
+
events: TimelineEvent[];
|
|
13
|
+
footer: React.ReactNode | null;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=use-booking-action-ledger-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-booking-action-ledger-events.d.ts","sourceRoot":"","sources":["../../src/admin/use-booking-action-ledger-events.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAA;AAE/E;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG;IAC/D,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,MAAM,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAA;CAC/B,CAgDA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useOperatorAdminMessages } from "@voyantjs/admin";
|
|
4
|
+
import { useBookingActionLedger, } from "@voyantjs/bookings-react";
|
|
5
|
+
import { Button } from "@voyantjs/ui/components/button";
|
|
6
|
+
import { ScrollText } from "lucide-react";
|
|
7
|
+
import { useMemo } from "react";
|
|
8
|
+
/**
|
|
9
|
+
* Fetch the booking's central action-ledger entries and map them into
|
|
10
|
+
* `TimelineEvent`s so they can be merged into `BookingActivityTimeline`.
|
|
11
|
+
* Replaces the standalone Ledger tab — operators see one chronological
|
|
12
|
+
* activity feed instead of two sibling tabs.
|
|
13
|
+
*
|
|
14
|
+
* Returns a "Load more" `footer` element when the cursor pager hasn't
|
|
15
|
+
* exhausted yet so the timeline can render it below the event list.
|
|
16
|
+
*/
|
|
17
|
+
export function useBookingActionLedgerEvents(bookingId) {
|
|
18
|
+
const t = useOperatorAdminMessages().bookings.detail.actionLedger;
|
|
19
|
+
const ledgerQuery = useBookingActionLedger(bookingId);
|
|
20
|
+
const pages = useMemo(() => ledgerQuery.data?.pages ?? [], [ledgerQuery.data]);
|
|
21
|
+
const travelers = pages[0]?.travelers ?? [];
|
|
22
|
+
const travelersById = useMemo(() => new Map(travelers.map((traveler) => [traveler.id, traveler])), [travelers]);
|
|
23
|
+
const events = useMemo(() => {
|
|
24
|
+
const all = [];
|
|
25
|
+
for (const page of pages) {
|
|
26
|
+
for (const entry of page.data) {
|
|
27
|
+
const traveler = travelersById.get(entry.targetId) ?? null;
|
|
28
|
+
all.push({
|
|
29
|
+
id: `action:${entry.id}`,
|
|
30
|
+
source: "action",
|
|
31
|
+
title: formatActionName(entry.actionName),
|
|
32
|
+
description: formatLedgerDescription(entry, traveler, t.travelerFallback, t.targetBooking),
|
|
33
|
+
actorId: entry.principalId,
|
|
34
|
+
timestamp: entry.occurredAt,
|
|
35
|
+
icon: ScrollText,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return all;
|
|
40
|
+
}, [pages, travelersById, t.targetBooking, t.travelerFallback]);
|
|
41
|
+
const footer = ledgerQuery.hasNextPage ? (_jsx(Button, { type: "button", variant: "outline", size: "sm", disabled: ledgerQuery.isFetchingNextPage, onClick: () => void ledgerQuery.fetchNextPage(), children: ledgerQuery.isFetchingNextPage ? t.loadingMore : t.loadMore })) : null;
|
|
42
|
+
return { events, footer };
|
|
43
|
+
}
|
|
44
|
+
function formatActionName(value) {
|
|
45
|
+
return value.replaceAll(".", " / ").replaceAll("_", " ");
|
|
46
|
+
}
|
|
47
|
+
function formatTarget(entry, traveler, travelerFallback, bookingFallback) {
|
|
48
|
+
if (traveler) {
|
|
49
|
+
return [traveler.firstName, traveler.lastName].filter(Boolean).join(" ") || travelerFallback;
|
|
50
|
+
}
|
|
51
|
+
if (entry.targetType === "booking")
|
|
52
|
+
return bookingFallback;
|
|
53
|
+
return entry.targetType.replaceAll("_", " ");
|
|
54
|
+
}
|
|
55
|
+
function formatLedgerDescription(entry, traveler, travelerFallback, bookingFallback) {
|
|
56
|
+
// status / target / risk are machine-readable enum strings the
|
|
57
|
+
// ledger ships unmodified (matches the standalone panel behaviour).
|
|
58
|
+
const parts = [
|
|
59
|
+
entry.status,
|
|
60
|
+
formatTarget(entry, traveler, travelerFallback, bookingFallback),
|
|
61
|
+
entry.evaluatedRisk,
|
|
62
|
+
];
|
|
63
|
+
if (entry.routeOrToolName)
|
|
64
|
+
parts.push(entry.routeOrToolName);
|
|
65
|
+
return parts.join(" · ");
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/bookings-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.109.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"import": "./dist/journey/index.js",
|
|
39
39
|
"default": "./dist/journey/index.js"
|
|
40
40
|
},
|
|
41
|
+
"./admin": {
|
|
42
|
+
"types": "./dist/admin/index.d.ts",
|
|
43
|
+
"import": "./dist/admin/index.js",
|
|
44
|
+
"default": "./dist/admin/index.js"
|
|
45
|
+
},
|
|
41
46
|
"./components/*": {
|
|
42
47
|
"types": "./dist/components/*.d.ts",
|
|
43
48
|
"import": "./dist/components/*.js",
|
|
@@ -52,21 +57,22 @@
|
|
|
52
57
|
"react-dom": "^19.0.0",
|
|
53
58
|
"react-hook-form": "^7.60.0",
|
|
54
59
|
"zod": "^4.3.6",
|
|
55
|
-
"@voyantjs/
|
|
56
|
-
"@voyantjs/
|
|
57
|
-
"@voyantjs/bookings
|
|
58
|
-
"@voyantjs/
|
|
59
|
-
"@voyantjs/catalog
|
|
60
|
-
"@voyantjs/
|
|
61
|
-
"@voyantjs/crm-
|
|
62
|
-
"@voyantjs/
|
|
63
|
-
"@voyantjs/
|
|
64
|
-
"@voyantjs/
|
|
65
|
-
"@voyantjs/
|
|
66
|
-
"@voyantjs/
|
|
67
|
-
"@voyantjs/
|
|
68
|
-
"@voyantjs/
|
|
69
|
-
"@voyantjs/
|
|
60
|
+
"@voyantjs/admin": "^0.106.0",
|
|
61
|
+
"@voyantjs/availability-react": "^0.106.0",
|
|
62
|
+
"@voyantjs/bookings": "^0.109.0",
|
|
63
|
+
"@voyantjs/bookings-react": "^0.109.0",
|
|
64
|
+
"@voyantjs/catalog": "^0.107.0",
|
|
65
|
+
"@voyantjs/catalog-react": "^0.107.0",
|
|
66
|
+
"@voyantjs/crm-react": "^0.109.0",
|
|
67
|
+
"@voyantjs/crm-ui": "^0.109.0",
|
|
68
|
+
"@voyantjs/extras-react": "^0.109.0",
|
|
69
|
+
"@voyantjs/finance-react": "^0.109.0",
|
|
70
|
+
"@voyantjs/identity-react": "^0.109.0",
|
|
71
|
+
"@voyantjs/legal-react": "^0.109.0",
|
|
72
|
+
"@voyantjs/pricing-react": "^0.109.0",
|
|
73
|
+
"@voyantjs/products-react": "^0.109.0",
|
|
74
|
+
"@voyantjs/suppliers-react": "^0.106.0",
|
|
75
|
+
"@voyantjs/ui": "^0.106.0"
|
|
70
76
|
},
|
|
71
77
|
"dependencies": {
|
|
72
78
|
"sonner": "^2.0.7",
|
|
@@ -85,21 +91,22 @@
|
|
|
85
91
|
"typescript": "^6.0.2",
|
|
86
92
|
"vitest": "^4.1.2",
|
|
87
93
|
"zod": "^4.3.6",
|
|
88
|
-
"@voyantjs/
|
|
89
|
-
"@voyantjs/
|
|
90
|
-
"@voyantjs/bookings
|
|
91
|
-
"@voyantjs/
|
|
92
|
-
"@voyantjs/catalog
|
|
93
|
-
"@voyantjs/
|
|
94
|
-
"@voyantjs/crm-
|
|
95
|
-
"@voyantjs/
|
|
96
|
-
"@voyantjs/finance-react": "^0.
|
|
97
|
-
"@voyantjs/identity-react": "^0.
|
|
98
|
-
"@voyantjs/legal-react": "^0.
|
|
99
|
-
"@voyantjs/pricing-react": "^0.
|
|
100
|
-
"@voyantjs/products-react": "^0.
|
|
101
|
-
"@voyantjs/suppliers-react": "^0.
|
|
102
|
-
"@voyantjs/
|
|
94
|
+
"@voyantjs/admin": "^0.106.0",
|
|
95
|
+
"@voyantjs/availability-react": "^0.106.0",
|
|
96
|
+
"@voyantjs/bookings": "^0.109.0",
|
|
97
|
+
"@voyantjs/bookings-react": "^0.109.0",
|
|
98
|
+
"@voyantjs/catalog": "^0.107.0",
|
|
99
|
+
"@voyantjs/catalog-react": "^0.107.0",
|
|
100
|
+
"@voyantjs/crm-react": "^0.109.0",
|
|
101
|
+
"@voyantjs/crm-ui": "^0.109.0",
|
|
102
|
+
"@voyantjs/finance-react": "^0.109.0",
|
|
103
|
+
"@voyantjs/identity-react": "^0.109.0",
|
|
104
|
+
"@voyantjs/legal-react": "^0.109.0",
|
|
105
|
+
"@voyantjs/pricing-react": "^0.109.0",
|
|
106
|
+
"@voyantjs/products-react": "^0.109.0",
|
|
107
|
+
"@voyantjs/suppliers-react": "^0.106.0",
|
|
108
|
+
"@voyantjs/extras-react": "^0.109.0",
|
|
109
|
+
"@voyantjs/ui": "^0.106.0",
|
|
103
110
|
"@voyantjs/voyant-typescript-config": "^0.1.0"
|
|
104
111
|
},
|
|
105
112
|
"files": [
|