@voyantjs/bookings-ui 0.81.14 → 0.81.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/booking-billing-dialog.d.ts.map +1 -1
- package/dist/components/booking-billing-dialog.js +2 -2
- package/dist/components/booking-create-dialog.d.ts.map +1 -1
- package/dist/components/booking-create-dialog.js +53 -67
- package/dist/components/booking-detail-page.d.ts +44 -6
- package/dist/components/booking-detail-page.d.ts.map +1 -1
- package/dist/components/booking-detail-page.js +117 -42
- package/dist/components/booking-guarantee-list.d.ts.map +1 -1
- package/dist/components/booking-guarantee-list.js +66 -28
- package/dist/components/booking-item-list.d.ts +8 -1
- package/dist/components/booking-item-list.d.ts.map +1 -1
- package/dist/components/booking-item-list.js +157 -96
- package/dist/components/booking-list-filters.d.ts +3 -1
- package/dist/components/booking-list-filters.d.ts.map +1 -1
- package/dist/components/booking-list-filters.js +5 -3
- package/dist/components/booking-list.d.ts.map +1 -1
- package/dist/components/booking-list.js +12 -8
- package/dist/components/booking-payment-schedule-dialog.d.ts.map +1 -1
- package/dist/components/booking-payment-schedule-dialog.js +23 -8
- package/dist/components/booking-payment-schedule-list.d.ts +6 -1
- package/dist/components/booking-payment-schedule-list.d.ts.map +1 -1
- package/dist/components/booking-payment-schedule-list.js +131 -27
- package/dist/components/booking-payments-summary.d.ts +15 -7
- package/dist/components/booking-payments-summary.d.ts.map +1 -1
- package/dist/components/booking-payments-summary.js +99 -74
- package/dist/components/icon-action-button.d.ts +18 -0
- package/dist/components/icon-action-button.d.ts.map +1 -0
- package/dist/components/icon-action-button.js +13 -0
- package/dist/components/payment-schedule-section.d.ts +41 -46
- package/dist/components/payment-schedule-section.d.ts.map +1 -1
- package/dist/components/payment-schedule-section.js +150 -58
- package/dist/components/status-badge.d.ts +24 -0
- package/dist/components/status-badge.d.ts.map +1 -0
- package/dist/components/status-badge.js +65 -0
- package/dist/components/supplier-status-list.d.ts.map +1 -1
- package/dist/components/supplier-status-list.js +64 -27
- package/dist/components/traveler-dialog.d.ts.map +1 -1
- package/dist/components/traveler-dialog.js +10 -5
- package/dist/components/traveler-list.d.ts.map +1 -1
- package/dist/components/traveler-list.js +194 -80
- package/dist/i18n/en.d.ts +98 -5
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +101 -8
- package/dist/i18n/messages.d.ts +108 -5
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/provider.d.ts +196 -10
- package/dist/i18n/provider.d.ts.map +1 -1
- package/dist/i18n/ro.d.ts +98 -5
- package/dist/i18n/ro.d.ts.map +1 -1
- package/dist/i18n/ro.js +101 -8
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +34 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-billing-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-billing-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"booking-billing-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-billing-dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,0BAA0B,CAAA;AAsCjF,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,OAAO,EAAE,aAAa,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,SAAS,GACV,EAAE,yBAAyB,2CA2J3B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useBookingMutation } from "@voyantjs/bookings-react";
|
|
4
|
-
import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label,
|
|
4
|
+
import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, } from "@voyantjs/ui/components";
|
|
5
5
|
import { CountryCombobox } from "@voyantjs/ui/components/country-combobox";
|
|
6
6
|
import { PhoneInput } from "@voyantjs/ui/components/phone-input";
|
|
7
7
|
import { zodResolver } from "@voyantjs/ui/lib/zod-resolver";
|
|
@@ -87,7 +87,7 @@ export function BookingBillingDialog({ open, onOpenChange, booking, onSuccess, }
|
|
|
87
87
|
onOpenChange(false);
|
|
88
88
|
onSuccess?.();
|
|
89
89
|
};
|
|
90
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.title }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.firstName }), _jsx(Input, { ...form.register("contactFirstName") })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.lastName }), _jsx(Input, { ...form.register("contactLastName") })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.email }), _jsx(Input, { type: "email", ...form.register("contactEmail") }), form.formState.errors.contactEmail ? (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.contactEmail.message })) : null] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.phone }), _jsx(PhoneInput, { value: form.watch("contactPhone") ?? "", onChange: (next) => form.setValue("contactPhone", next, { shouldDirty: true }) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.addressLine1 }), _jsx(
|
|
90
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: messages.title }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-1 flex-col overflow-hidden", children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.firstName }), _jsx(Input, { ...form.register("contactFirstName") })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.lastName }), _jsx(Input, { ...form.register("contactLastName") })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.email }), _jsx(Input, { type: "email", ...form.register("contactEmail") }), form.formState.errors.contactEmail ? (_jsx("p", { className: "text-xs text-destructive", children: form.formState.errors.contactEmail.message })) : null] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.phone }), _jsx(PhoneInput, { value: form.watch("contactPhone") ?? "", onChange: (next) => form.setValue("contactPhone", next, { shouldDirty: true }) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.addressLine1 }), _jsx(Input, { ...form.register("contactAddressLine1") })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.addressLine2 }), _jsx(Input, { ...form.register("contactAddressLine2") })] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.city }), _jsx(Input, { ...form.register("contactCity") })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.region }), _jsx(Input, { ...form.register("contactRegion") })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.postalCode }), _jsx(Input, { ...form.register("contactPostalCode") })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.fields.country }), _jsx(CountryCombobox, { value: form.watch("contactCountry") || null, onChange: (next) => form.setValue("contactCountry", next ?? "", {
|
|
91
91
|
shouldDirty: true,
|
|
92
92
|
shouldValidate: true,
|
|
93
93
|
}) })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false), children: messages.actions.cancel }), _jsxs(Button, { type: "submit", size: "sm", disabled: update.isPending, children: [update.isPending ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null, messages.actions.save] })] })] })] }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-create-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,EAKL,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"booking-create-dialog.d.ts","sourceRoot":"","sources":["../../src/components/booking-create-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,EAKL,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAA;AAiPjC,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,aAAa,GACd,EAAE,wBAAwB,2CAsB1B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,OAAc,EACd,QAAQ,GACT,EAAE,sBAAsB,2CAg8BxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useQueries, useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { getSlotQueryOptions, useSlots, useSlotUnitAvailability, useVoyantAvailabilityContext, } from "@voyantjs/availability-react";
|
|
5
5
|
import { resolveBookingDraft, resolveBookingExtraLines, travelersToRows, } from "@voyantjs/bookings/pricing-assignment";
|
|
@@ -32,39 +32,35 @@ function generateBookingNumber() {
|
|
|
32
32
|
}
|
|
33
33
|
function paymentScheduleToRows(value, currency, totalAmountCents) {
|
|
34
34
|
if (value.mode === "full") {
|
|
35
|
-
|
|
35
|
+
const installment = value.installments[0];
|
|
36
|
+
if (!installment?.dueDate || totalAmountCents === null)
|
|
36
37
|
return [];
|
|
37
38
|
return [
|
|
38
39
|
{
|
|
39
40
|
scheduleType: "balance",
|
|
40
|
-
status:
|
|
41
|
-
dueDate:
|
|
41
|
+
status: installment.alreadyPaid ? "paid" : "due",
|
|
42
|
+
dueDate: installment.dueDate,
|
|
42
43
|
currency,
|
|
43
44
|
amountCents: totalAmountCents,
|
|
44
|
-
notes: paidScheduleNotes(
|
|
45
|
+
notes: paidScheduleNotes(installment.alreadyPaid, installment.paymentDate, installment.paymentMethod, installment.paymentReference),
|
|
45
46
|
},
|
|
46
47
|
];
|
|
47
48
|
}
|
|
48
|
-
// split
|
|
49
|
+
// split — N installments
|
|
49
50
|
const rows = [];
|
|
50
|
-
|
|
51
|
+
for (const [idx, installment] of value.installments.entries()) {
|
|
52
|
+
if (!installment.dueDate || installment.amountCents == null)
|
|
53
|
+
continue;
|
|
51
54
|
rows.push({
|
|
52
55
|
scheduleType: "installment",
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
// First installment defaults to `due` (immediately collectable),
|
|
57
|
+
// subsequent ones to `pending` so the dashboard's "next due" picker
|
|
58
|
+
// doesn't flag them all at once.
|
|
59
|
+
status: installment.alreadyPaid ? "paid" : idx === 0 ? "due" : "pending",
|
|
60
|
+
dueDate: installment.dueDate,
|
|
55
61
|
currency,
|
|
56
|
-
amountCents:
|
|
57
|
-
notes: paidScheduleNotes(
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
if (value.splitSecondDueDate && value.splitSecondAmountCents != null) {
|
|
61
|
-
rows.push({
|
|
62
|
-
scheduleType: "installment",
|
|
63
|
-
status: value.splitSecondAlreadyPaid ? "paid" : "pending",
|
|
64
|
-
dueDate: value.splitSecondDueDate,
|
|
65
|
-
currency,
|
|
66
|
-
amountCents: value.splitSecondAmountCents,
|
|
67
|
-
notes: paidScheduleNotes(value.splitSecondAlreadyPaid, value.splitSecondPaymentDate, value.splitSecondPaymentMethod, value.splitSecondPaymentReference),
|
|
62
|
+
amountCents: installment.amountCents,
|
|
63
|
+
notes: paidScheduleNotes(installment.alreadyPaid, installment.paymentDate, installment.paymentMethod, installment.paymentReference),
|
|
68
64
|
});
|
|
69
65
|
}
|
|
70
66
|
return rows;
|
|
@@ -101,14 +97,7 @@ function stripUnitSuffix(name) {
|
|
|
101
97
|
* `confirmed`; otherwise it lands in `awaiting_payment`.
|
|
102
98
|
*/
|
|
103
99
|
function hasAnyPaidPayment(schedule) {
|
|
104
|
-
|
|
105
|
-
case "full":
|
|
106
|
-
return schedule.fullAlreadyPaid;
|
|
107
|
-
case "split":
|
|
108
|
-
return schedule.splitFirstAlreadyPaid || schedule.splitSecondAlreadyPaid;
|
|
109
|
-
default:
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
100
|
+
return schedule.installments.some((installment) => installment.alreadyPaid);
|
|
112
101
|
}
|
|
113
102
|
/**
|
|
114
103
|
* Inverse of stripUnitSuffix — strip the leading "Option name - " so
|
|
@@ -195,18 +184,24 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
195
184
|
const [voucher, setVoucher] = React.useState(emptyVoucherPickerValue);
|
|
196
185
|
const [pricing, setPricing] = React.useState(null);
|
|
197
186
|
const [paymentSchedule, setPaymentSchedule] = React.useState(emptyPaymentScheduleValue);
|
|
198
|
-
const [generateContractDocument, setGenerateContractDocument] = React.useState(false);
|
|
199
|
-
const [generateInvoiceDocument, setGenerateInvoiceDocument] = React.useState(false);
|
|
200
|
-
const [notes, setNotes] = React.useState("");
|
|
201
187
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* or `awaiting_payment` (when nothing is paid yet). The override
|
|
206
|
-
* exists so an operator can still capture a half-configured
|
|
207
|
-
* booking without committing it to the lifecycle.
|
|
188
|
+
* Mutually-exclusive document toggles. "Proforma" issues a single
|
|
189
|
+
* placeholder invoice; "Invoice + contract" issues a final invoice
|
|
190
|
+
* alongside the customer contract. Either off → no documents.
|
|
208
191
|
*/
|
|
209
|
-
const [
|
|
192
|
+
const [generateProforma, setGenerateProformaState] = React.useState(false);
|
|
193
|
+
const [generateInvoiceAndContract, setGenerateInvoiceAndContractState] = React.useState(false);
|
|
194
|
+
const setGenerateProforma = (next) => {
|
|
195
|
+
setGenerateProformaState(next);
|
|
196
|
+
if (next)
|
|
197
|
+
setGenerateInvoiceAndContractState(false);
|
|
198
|
+
};
|
|
199
|
+
const setGenerateInvoiceAndContract = (next) => {
|
|
200
|
+
setGenerateInvoiceAndContractState(next);
|
|
201
|
+
if (next)
|
|
202
|
+
setGenerateProformaState(false);
|
|
203
|
+
};
|
|
204
|
+
const [notes, setNotes] = React.useState("");
|
|
210
205
|
// Only relevant when the derived status is `confirmed`: when off,
|
|
211
206
|
// the status transition carries `suppressNotifications: true` so
|
|
212
207
|
// the auto-dispatch subscriber skips the customer email + document
|
|
@@ -239,10 +234,9 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
239
234
|
setVoucher(emptyVoucherPickerValue);
|
|
240
235
|
setPricing(null);
|
|
241
236
|
setPaymentSchedule(emptyPaymentScheduleValue);
|
|
242
|
-
|
|
243
|
-
|
|
237
|
+
setGenerateProformaState(false);
|
|
238
|
+
setGenerateInvoiceAndContractState(false);
|
|
244
239
|
setNotes("");
|
|
245
|
-
setCreateAsDraft(false);
|
|
246
240
|
setNotifyTraveler(true);
|
|
247
241
|
setError(null);
|
|
248
242
|
setPayloadMismatchUnitIds([]);
|
|
@@ -610,15 +604,12 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
610
604
|
// Smart-default status from payment state — any payment marked
|
|
611
605
|
// "Already paid" implies the booking is effectively confirmed,
|
|
612
606
|
// otherwise it lands in `awaiting_payment` so the operator can
|
|
613
|
-
// dispatch a payment link.
|
|
614
|
-
// "Create as draft" checkbox. The server commits this status in
|
|
607
|
+
// dispatch a payment link. The server commits this status in
|
|
615
608
|
// the create transaction and emits `booking.confirmed`
|
|
616
609
|
// post-commit when applicable — no second roundtrip.
|
|
617
|
-
const initialStatus =
|
|
618
|
-
?
|
|
619
|
-
:
|
|
620
|
-
? "confirmed"
|
|
621
|
-
: "awaiting_payment";
|
|
610
|
+
const initialStatus = hasAnyPaidPayment(paymentSchedule)
|
|
611
|
+
? "confirmed"
|
|
612
|
+
: "awaiting_payment";
|
|
622
613
|
// Build the billing-contact snapshot from whichever CRM record
|
|
623
614
|
// the operator picked, plus the primary identity address when
|
|
624
615
|
// present. Falls back to nulls when a record is missing — the
|
|
@@ -670,10 +661,15 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
670
661
|
paymentSchedules: paymentSchedules.length > 0 ? paymentSchedules : undefined,
|
|
671
662
|
voucherRedemption,
|
|
672
663
|
groupMembership,
|
|
673
|
-
documentGeneration:
|
|
674
|
-
contractDocument:
|
|
675
|
-
|
|
676
|
-
|
|
664
|
+
documentGeneration: generateProforma
|
|
665
|
+
? { contractDocument: false, invoiceDocument: true, invoiceType: "proforma" }
|
|
666
|
+
: generateInvoiceAndContract
|
|
667
|
+
? {
|
|
668
|
+
contractDocument: true,
|
|
669
|
+
invoiceDocument: true,
|
|
670
|
+
invoiceType: "invoice",
|
|
671
|
+
}
|
|
672
|
+
: { contractDocument: false, invoiceDocument: false },
|
|
677
673
|
initialStatus,
|
|
678
674
|
// Suppression only matters when transitioning to `confirmed` —
|
|
679
675
|
// `awaiting_payment` doesn't trigger the auto-dispatch
|
|
@@ -749,19 +745,9 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
749
745
|
noRoom: messages.bookingCreateDialog.labels.travelerNoRoom,
|
|
750
746
|
remove: messages.bookingCreateDialog.labels.travelerRemove,
|
|
751
747
|
empty: messages.bookingCreateDialog.labels.travelerEmpty,
|
|
752
|
-
} })) : null, product.productId && slotId ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingCreateDialog.fields.internalNotes }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: messages.bookingCreateDialog.placeholders.internalNotes })] })) : null, product.productId && slotId ? (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: messages.bookingCreateDialog.labels.documentGenerationHeading }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-generate-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
? messages.common.bookingStatusLabels.draft
|
|
756
|
-
: wouldBeConfirmed
|
|
757
|
-
? messages.common.bookingStatusLabels.confirmed
|
|
758
|
-
: messages.common.bookingStatusLabels.awaiting_payment;
|
|
759
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Checkbox, { id: "new-booking-create-as-draft", checked: createAsDraft, onCheckedChange: (v) => setCreateAsDraft(v === true), className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "new-booking-create-as-draft", className: "cursor-pointer text-sm", children: messages.bookingCreateDialog.fields.createAsDraft }), _jsx("p", { className: "text-xs text-muted-foreground", children: formatMessage(messages.bookingCreateDialog.fields.createAsDraftHint, { status: derivedStatusLabel }) })] })] }), !createAsDraft && wouldBeConfirmed ? (_jsxs("div", { className: "flex items-start gap-2 pl-6", children: [_jsx(Checkbox, { id: "new-booking-notify-traveler", checked: notifyTraveler, onCheckedChange: (v) => setNotifyTraveler(v === true), className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "new-booking-notify-traveler", className: "cursor-pointer text-sm", children: messages.bookingCreateDialog.fields.notifyTraveler }), _jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingCreateDialog.fields.notifyTravelerHint })] })] })) : null] }));
|
|
760
|
-
})() })] })] })) : null] }), error ? (_jsx("div", { role: "alert", className: "mt-3 rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error })) : null, _jsxs("div", { className: "mt-4 flex items-center justify-end gap-2 border-t px-1 pt-3", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onCancel, disabled: isSubmitting, children: messages.common.cancel }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || !product.productId || !slotId || !hasSelectedUnits, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), createAsDraft
|
|
761
|
-
? messages.bookingCreateDialog.actions.createDraftBooking
|
|
762
|
-
: hasAnyPaidPayment(paymentSchedule)
|
|
763
|
-
? messages.bookingCreateDialog.actions.createConfirmedBooking
|
|
764
|
-
: messages.bookingCreateDialog.actions.createAwaitingPaymentBooking] })] })] }), _jsxs("div", { className: "flex flex-col gap-4 lg:col-span-4", children: [_jsx(BookingPreviewCard, { productId: product.productId, optionId: product.optionId, slotId: slotId, slotLabel: (() => {
|
|
748
|
+
} })) : null, product.productId && slotId ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: messages.bookingCreateDialog.fields.internalNotes }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: messages.bookingCreateDialog.placeholders.internalNotes })] })) : null, product.productId && slotId ? (_jsxs("div", { className: "flex flex-col gap-3 rounded-md border p-3", children: [_jsx(Label, { children: messages.bookingCreateDialog.labels.documentGenerationHeading }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-generate-proforma", checked: generateProforma, onCheckedChange: (value) => setGenerateProforma(value === true) }), _jsx(Label, { htmlFor: "new-booking-generate-proforma", className: "cursor-pointer", children: messages.bookingCreateDialog.labels.generateProforma })] }), _jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-generate-invoice-and-contract", checked: generateInvoiceAndContract, onCheckedChange: (value) => setGenerateInvoiceAndContract(value === true) }), _jsx(Label, { htmlFor: "new-booking-generate-invoice-and-contract", className: "cursor-pointer", children: messages.bookingCreateDialog.labels.generateInvoiceAndContract })] }), hasAnyPaidPayment(paymentSchedule) ? (_jsxs("div", { className: "flex items-start gap-2 border-t pt-2 text-sm", children: [_jsx(Checkbox, { id: "new-booking-notify-traveler", checked: notifyTraveler, onCheckedChange: (v) => setNotifyTraveler(v === true), className: "mt-0.5" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { htmlFor: "new-booking-notify-traveler", className: "cursor-pointer text-sm", children: messages.bookingCreateDialog.fields.notifyTraveler }), _jsx("p", { className: "text-xs text-muted-foreground", children: messages.bookingCreateDialog.fields.notifyTravelerHint })] })] })) : null] })] })) : null] }), error ? (_jsx("div", { role: "alert", className: "mt-3 rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: error })) : null, _jsxs("div", { className: "mt-4 flex items-center justify-end gap-2 border-t px-1 pt-3", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onCancel, disabled: isSubmitting, children: messages.common.cancel }), _jsxs(Button, { type: "button", size: "sm", onClick: handleSubmit, disabled: isSubmitting || !product.productId || !slotId || !hasSelectedUnits, children: [isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), hasAnyPaidPayment(paymentSchedule)
|
|
749
|
+
? messages.bookingCreateDialog.actions.createConfirmedBooking
|
|
750
|
+
: messages.bookingCreateDialog.actions.createAwaitingPaymentBooking] })] })] }), _jsxs("div", { className: "flex flex-col gap-4 lg:col-span-4", children: [_jsx(BookingPreviewCard, { productId: product.productId, optionId: product.optionId, slotId: slotId, slotLabel: (() => {
|
|
765
751
|
const slot = slots.find((s) => s.id === slotId);
|
|
766
752
|
return slot ? formatSlotLabel(slot) : null;
|
|
767
753
|
})(), unitQuantities: displayQuantities, unitLabels: roomUnitLabels, extraLines: displayExtraLines, travelers: travelers.travelers, messages: messages, onPricingChange: setPricing }), product.productId && slotId ? (_jsx(VoucherPickerSection, { value: voucher, onChange: setVoucher, currency: currency, labels: {
|
|
@@ -771,7 +757,7 @@ export function BookingCreateForm({ onCreated, defaultProductId, defaultSlotId,
|
|
|
771
757
|
clear: messages.bookingCreateDialog.labels.voucherClear,
|
|
772
758
|
remainingLabel: messages.bookingCreateDialog.labels.voucherRemainingLabel,
|
|
773
759
|
invalidLabel: messages.bookingCreateDialog.labels.voucherInvalidLabel,
|
|
774
|
-
} })) : null, product.productId && slotId ? (_jsx(PaymentScheduleSection, { value: paymentSchedule, onChange: setPaymentSchedule, currency: pricingCurrency, totalAmountCents: pricingTotalAmountCents, labels: {
|
|
760
|
+
} })) : null, product.productId && slotId ? (_jsx(PaymentScheduleSection, { value: paymentSchedule, onChange: setPaymentSchedule, currency: pricingCurrency, totalAmountCents: pricingTotalAmountCents, departureDate: selectedSlot?.startsAt?.slice(0, 10) ?? null, labels: {
|
|
775
761
|
heading: messages.bookingCreateDialog.labels.paymentHeading,
|
|
776
762
|
modeUnpaid: messages.bookingCreateDialog.labels.paymentModeUnpaid,
|
|
777
763
|
modeFull: messages.bookingCreateDialog.labels.paymentModeFull,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type BookingRecord } from "@voyantjs/bookings-react";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
|
+
import { type BookingItemResourceKind } from "./booking-item-list.js";
|
|
3
4
|
import { type BookingPaymentsSummaryRow } from "./booking-payments-summary.js";
|
|
4
5
|
/**
|
|
5
6
|
* Optional extra tab. When provided, the canonical layout renders a
|
|
@@ -40,12 +41,45 @@ export interface BookingDetailPageProps {
|
|
|
40
41
|
* (use when the host shell already renders breadcrumbs). */
|
|
41
42
|
hideBreadcrumb?: boolean;
|
|
42
43
|
onBack?: () => void;
|
|
44
|
+
/**
|
|
45
|
+
* Forwarded to the finance-tab `BookingPaymentsSummary` header as a
|
|
46
|
+
* `Record payment` action button.
|
|
47
|
+
*/
|
|
48
|
+
onRecordPayment?: (booking: BookingRecord) => void;
|
|
49
|
+
/**
|
|
50
|
+
* When set, the Record payment header button renders disabled and its
|
|
51
|
+
* tooltip shows this reason. Use for "nothing left to pay" states.
|
|
52
|
+
*/
|
|
53
|
+
recordPaymentDisabledReason?: string | null;
|
|
54
|
+
/**
|
|
55
|
+
* When set, the Add schedule button in the payment-schedule section
|
|
56
|
+
* renders disabled and its tooltip shows this reason.
|
|
57
|
+
*/
|
|
58
|
+
addScheduleDisabledReason?: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Amount the customer has paid so far against this booking, in cents
|
|
61
|
+
* of `booking.sellCurrency`. When provided, a `Paid` stat is shown
|
|
62
|
+
* next to `Total`. Resolution (invoices vs. raw payments) is left to
|
|
63
|
+
* the host template — `bookings-ui` doesn't fetch finance data.
|
|
64
|
+
*/
|
|
65
|
+
paidAmountCents?: number | null;
|
|
66
|
+
/**
|
|
67
|
+
* Open a linked resource referenced by a booking item (product or
|
|
68
|
+
* availability slot) in the host app. When omitted, the item-snapshot
|
|
69
|
+
* sheet renders the names as plain text.
|
|
70
|
+
*/
|
|
71
|
+
onItemResourceOpen?: (kind: BookingItemResourceKind, id: string) => void;
|
|
72
|
+
/** Open the linked CRM person's detail page (used by the Payer card). */
|
|
43
73
|
onPersonOpen?: (personId: string) => void;
|
|
74
|
+
/** Open the linked CRM organization's detail page (used by the Payer card). */
|
|
44
75
|
onOrganizationOpen?: (organizationId: string) => void;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Open an invoice in-place when the operator clicks the invoice
|
|
78
|
+
* number in the Payments row. Typically wired to a `Sheet` that
|
|
79
|
+
* renders the invoice-detail view so the admin doesn't leave the
|
|
80
|
+
* booking screen.
|
|
81
|
+
*/
|
|
82
|
+
onInvoiceOpen?: (invoiceId: string, row: BookingPaymentsSummaryRow) => void;
|
|
49
83
|
/** Forwarded to the finance-tab `BookingPaymentsSummary` row menu. */
|
|
50
84
|
onViewPayment?: (row: BookingPaymentsSummaryRow) => void;
|
|
51
85
|
/** Forwarded to the finance-tab `BookingPaymentsSummary` row menu. */
|
|
@@ -54,7 +88,7 @@ export interface BookingDetailPageProps {
|
|
|
54
88
|
onDeletePayment?: (row: BookingPaymentsSummaryRow) => Promise<void> | void;
|
|
55
89
|
slots?: BookingDetailPageSlots;
|
|
56
90
|
}
|
|
57
|
-
export declare function BookingDetailPage({ id, className, locale, hideBreadcrumb, onBack, onPersonOpen, onOrganizationOpen,
|
|
91
|
+
export declare function BookingDetailPage({ id, className, locale, hideBreadcrumb, onBack, onRecordPayment, recordPaymentDisabledReason, addScheduleDisabledReason, paidAmountCents, onItemResourceOpen, onPersonOpen, onOrganizationOpen, onInvoiceOpen, onViewPayment, onEditPayment, onDeletePayment, slots, }: BookingDetailPageProps): import("react/jsx-runtime").JSX.Element;
|
|
58
92
|
/**
|
|
59
93
|
* Billing/contact card for the Travelers tab. Snapshot fields on the
|
|
60
94
|
* booking row are the source of truth (they capture contact info at
|
|
@@ -63,7 +97,11 @@ export declare function BookingDetailPage({ id, className, locale, hideBreadcrum
|
|
|
63
97
|
* person / organization so the operator still sees who they're
|
|
64
98
|
* billing.
|
|
65
99
|
*/
|
|
66
|
-
export declare function BookingBillingContextCard({ booking }: {
|
|
100
|
+
export declare function BookingBillingContextCard({ booking, onPersonOpen, onOrganizationOpen, }: {
|
|
67
101
|
booking: BookingRecord;
|
|
102
|
+
/** Open the linked CRM person's detail page. */
|
|
103
|
+
onPersonOpen?: (personId: string) => void;
|
|
104
|
+
/** Open the linked CRM organization's detail page. */
|
|
105
|
+
onOrganizationOpen?: (organizationId: string) => void;
|
|
68
106
|
}): import("react/jsx-runtime").JSX.Element;
|
|
69
107
|
//# sourceMappingURL=booking-detail-page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/booking-detail-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"booking-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/booking-detail-page.tsx"],"names":[],"mappings":"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"}
|