@voyantjs/bookings-ui 0.107.0 → 0.108.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.
Files changed (67) hide show
  1. package/dist/components/option-units-stepper-section.d.ts +9 -1
  2. package/dist/components/option-units-stepper-section.d.ts.map +1 -1
  3. package/dist/components/option-units-stepper-section.js +10 -2
  4. package/dist/components/person-picker-section.d.ts +7 -1
  5. package/dist/components/person-picker-section.d.ts.map +1 -1
  6. package/dist/components/person-picker-section.js +2 -2
  7. package/dist/i18n/en.d.ts +37 -1
  8. package/dist/i18n/en.d.ts.map +1 -1
  9. package/dist/i18n/en.js +40 -4
  10. package/dist/i18n/messages.d.ts +37 -1
  11. package/dist/i18n/messages.d.ts.map +1 -1
  12. package/dist/i18n/provider.d.ts +74 -2
  13. package/dist/i18n/provider.d.ts.map +1 -1
  14. package/dist/i18n/ro.d.ts +37 -1
  15. package/dist/i18n/ro.d.ts.map +1 -1
  16. package/dist/i18n/ro.js +39 -3
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -1
  20. package/dist/journey/components/booking-journey.d.ts.map +1 -1
  21. package/dist/journey/components/booking-journey.js +270 -27
  22. package/dist/journey/components/journey-steps/accommodation-step.d.ts +3 -0
  23. package/dist/journey/components/journey-steps/accommodation-step.d.ts.map +1 -0
  24. package/dist/journey/components/journey-steps/accommodation-step.js +71 -0
  25. package/dist/journey/components/journey-steps/addons-step.d.ts +3 -0
  26. package/dist/journey/components/journey-steps/addons-step.d.ts.map +1 -0
  27. package/dist/journey/components/journey-steps/addons-step.js +40 -0
  28. package/dist/journey/components/journey-steps/billing-step.d.ts +8 -0
  29. package/dist/journey/components/journey-steps/billing-step.d.ts.map +1 -0
  30. package/dist/journey/components/journey-steps/billing-step.js +78 -0
  31. package/dist/journey/components/journey-steps/configure-steps.d.ts +28 -0
  32. package/dist/journey/components/journey-steps/configure-steps.d.ts.map +1 -0
  33. package/dist/journey/components/journey-steps/configure-steps.js +231 -0
  34. package/dist/journey/components/journey-steps/documents-step.d.ts +11 -0
  35. package/dist/journey/components/journey-steps/documents-step.d.ts.map +1 -0
  36. package/dist/journey/components/journey-steps/documents-step.js +36 -0
  37. package/dist/journey/components/journey-steps/payment-step.d.ts +29 -0
  38. package/dist/journey/components/journey-steps/payment-step.d.ts.map +1 -0
  39. package/dist/journey/components/journey-steps/payment-step.js +224 -0
  40. package/dist/journey/components/journey-steps/review-step.d.ts +27 -0
  41. package/dist/journey/components/journey-steps/review-step.d.ts.map +1 -0
  42. package/dist/journey/components/journey-steps/review-step.js +18 -0
  43. package/dist/journey/components/journey-steps/shared.d.ts +75 -0
  44. package/dist/journey/components/journey-steps/shared.d.ts.map +1 -0
  45. package/dist/journey/components/journey-steps/shared.js +108 -0
  46. package/dist/journey/components/journey-steps/travelers-step.d.ts +7 -0
  47. package/dist/journey/components/journey-steps/travelers-step.d.ts.map +1 -0
  48. package/dist/journey/components/journey-steps/travelers-step.js +201 -0
  49. package/dist/journey/components/journey-steps.d.ts +13 -39
  50. package/dist/journey/components/journey-steps.d.ts.map +1 -1
  51. package/dist/journey/components/journey-steps.js +16 -613
  52. package/dist/journey/components/side-panel.d.ts +7 -2
  53. package/dist/journey/components/side-panel.d.ts.map +1 -1
  54. package/dist/journey/components/side-panel.js +73 -24
  55. package/dist/journey/index.d.ts +2 -2
  56. package/dist/journey/index.d.ts.map +1 -1
  57. package/dist/journey/index.js +1 -1
  58. package/dist/journey/lib/pax-band-dependencies.d.ts +27 -0
  59. package/dist/journey/lib/pax-band-dependencies.d.ts.map +1 -0
  60. package/dist/journey/lib/pax-band-dependencies.js +50 -0
  61. package/dist/journey/lib/payment-schedule.d.ts +19 -0
  62. package/dist/journey/lib/payment-schedule.d.ts.map +1 -0
  63. package/dist/journey/lib/payment-schedule.js +90 -0
  64. package/dist/journey/types.d.ts +141 -8
  65. package/dist/journey/types.d.ts.map +1 -1
  66. package/dist/journey/types.js +3 -1
  67. package/package.json +32 -32
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  /**
4
4
  * `<BookingJourney />` — the unified booking journey shell.
5
5
  *
@@ -18,17 +18,26 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { DEFAULT_PAX_BANDS, defaultBookingFields, defaultDraftShapeFlags, defaultTravelerFields, paxBandsAllowedTotalFrom, } from "@voyantjs/catalog/booking-engine";
19
19
  import { useBookingCommit, useBookingDraft, useBookingDraftShape, useBookingHold, useBookingQuote, } from "@voyantjs/catalog-react/booking-engine";
20
20
  import { Button } from "@voyantjs/ui/components/button";
21
+ import { Card, CardContent, CardHeader } from "@voyantjs/ui/components/card";
22
+ import { Skeleton } from "@voyantjs/ui/components/skeleton";
23
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@voyantjs/ui/components/tooltip";
24
+ import { Loader2, Lock } from "lucide-react";
21
25
  import { useEffect, useMemo, useRef, useState } from "react";
22
26
  import { formatMessage, useBookingsUiMessagesOrDefault } from "../../i18n/index.js";
23
27
  import { emptyDraft, totalPax } from "../lib/draft-state.js";
28
+ import { evaluatePaxBandDependencies } from "../lib/pax-band-dependencies.js";
24
29
  import { JOURNEY_STEP_ORDER, } from "../types.js";
25
30
  import { ContractPreviewDialog } from "./contract-preview-dialog.js";
26
- import { AccommodationStep, AddonsStep, BillingStep, ConfigureStep, PaymentStep, ReviewStep, TravelersStep, } from "./journey-steps.js";
31
+ import { AccommodationStep, AddonsStep, BillingStep, DepartureStep, DocumentsStep, FinalizeControls, OptionsStep, PaymentStep, ReviewStep, TravelersStep, } from "./journey-steps.js";
27
32
  import { PriceSidePanel } from "./side-panel.js";
28
33
  import { StepHeader } from "./step-header.js";
29
34
  export function BookingJourney(props) {
30
35
  const messages = useBookingsUiMessagesOrDefault();
31
36
  const surface = props.surface ?? "admin";
37
+ // Admin books on a single stacked page (nothing hidden); the storefront
38
+ // keeps the guided one-step-at-a-time wizard. Two deliberately separate
39
+ // flows — see BookingJourneyProps.layout.
40
+ const layout = props.layout ?? (surface === "admin" ? "stacked" : "wizard");
32
41
  const [draft, setDraft] = useState(() => {
33
42
  const base = emptyDraft({
34
43
  module: props.entityModule,
@@ -77,33 +86,43 @@ export function BookingJourney(props) {
77
86
  // Step navigation — only show steps the descriptor says are relevant.
78
87
  const hideConfigure = props.hideConfigure === true;
79
88
  const steps = useMemo(() => JOURNEY_STEP_ORDER.filter((s) => {
80
- if (hideConfigure && s === "configure")
89
+ // `hideConfigure` skips the configure phase — now split across the
90
+ // Departure + Options steps.
91
+ if (hideConfigure && (s === "departure" || s === "options"))
92
+ return false;
93
+ // Internal notes + document generation are operator-only.
94
+ if (s === "documents" && surface !== "admin")
81
95
  return false;
82
96
  return isStepVisible(s, shape);
83
- }), [shape, hideConfigure]);
84
- const [currentStep, setCurrentStep] = useState(() => steps[0] ?? "configure");
85
- const [visited, setVisited] = useState(() => new Set([steps[0] ?? "configure"]));
97
+ }), [shape, hideConfigure, surface]);
98
+ // The stacked admin layout drops the Review block — the side panel shows the
99
+ // live summary + Confirm at all times, so a separate review section is
100
+ // redundant.
101
+ const stackedSteps = useMemo(() => steps.filter((s) => s !== "review"), [steps]);
102
+ const [currentStep, setCurrentStep] = useState(() => steps[0] ?? "departure");
103
+ const [visited, setVisited] = useState(() => new Set([steps[0] ?? "departure"]));
86
104
  // If the descriptor changes and removes the current step, reset to
87
105
  // the first available step. (Edge case: shape goes from
88
106
  // owned→sourced and the relevant step set narrows.)
89
107
  useEffect(() => {
90
108
  if (!steps.includes(currentStep)) {
91
- setCurrentStep(steps[0] ?? "configure");
109
+ setCurrentStep(steps[0] ?? "departure");
92
110
  }
93
111
  }, [steps, currentStep]);
94
- // PUT the draft to the server every time the user transitions
95
- // steps. Keeps the recovery surface fresh without saving on every
96
- // keystroke. The mutation reads the latest draft + quote from the
97
- // closure on each fire adding them to the deps array would defeat
98
- // the "save on step change only" semantics.
99
- // biome-ignore lint/correctness/useExhaustiveDependencies: intentional fires on step transition only
112
+ // PUT the draft to the server to keep the recovery surface fresh
113
+ // without saving on every keystroke. Wizard saves on each step
114
+ // transition; the stacked admin page has no steps, so it saves on
115
+ // each settled quote (a natural, debounced cadence). The mutation
116
+ // reads the latest draft + quote from the closure on each fire.
117
+ const saveTrigger = layout === "wizard" ? currentStep : (quote.data?.quoteId ?? "");
118
+ // biome-ignore lint/correctness/useExhaustiveDependencies: intentional — fires on save trigger only
100
119
  useEffect(() => {
101
120
  draftSync.save.mutate({
102
121
  draft: { ...draft, quoteId: quote.data?.quoteId },
103
122
  currentStep,
104
123
  currentQuoteId: quote.data?.quoteId,
105
124
  });
106
- }, [currentStep]);
125
+ }, [saveTrigger]);
107
126
  // Commit
108
127
  const commit = useBookingCommit({
109
128
  surface,
@@ -120,7 +139,12 @@ export function BookingJourney(props) {
120
139
  const holdSignature = makeHoldSignature(draft, props.entityModule, props.entityId);
121
140
  // biome-ignore lint/correctness/useExhaustiveDependencies: signature change is the only trigger; refs + closure read latest values
122
141
  useEffect(() => {
123
- if (currentStep === "configure" || !holdSignature)
142
+ // Wizard: don't hold while still on the configure steps. Stacked:
143
+ // everything's on one page, so the signature (slot + pax present)
144
+ // is the trigger.
145
+ if (layout === "wizard" && (currentStep === "departure" || currentStep === "options"))
146
+ return;
147
+ if (!holdSignature)
124
148
  return;
125
149
  if (holdState.current.signature === holdSignature)
126
150
  return;
@@ -154,8 +178,17 @@ export function BookingJourney(props) {
154
178
  .catch(() => { });
155
179
  }
156
180
  }, [holdSignature, currentStep]);
157
- const canAdvance = canAdvanceFromStep(currentStep, draft, shape, quote.data?.available !== false);
181
+ const available = quote.data?.available !== false;
182
+ const canAdvance = canAdvanceFromStep(currentStep, draft, shape, available);
158
183
  const warnings = warningsForStep(currentStep, draft, shape, messages);
184
+ // Stacked layout: there's no "current" step, but the section nav still
185
+ // nudges toward the first thing that isn't done yet, and the final
186
+ // Confirm is gated until every section passes its check.
187
+ const firstIncomplete = useMemo(() => stackedSteps.find((s) => !stackedStepComplete(s, draft, shape, available)) ??
188
+ stackedSteps[stackedSteps.length - 1] ??
189
+ stackedSteps[0] ??
190
+ "departure", [stackedSteps, draft, shape, available]);
191
+ const canCommit = useMemo(() => stackedSteps.every((s) => canAdvanceFromStep(s, draft, shape, available)), [stackedSteps, draft, shape, available]);
159
192
  const [isAdvanceGuardPending, setIsAdvanceGuardPending] = useState(false);
160
193
  const [advanceGuardError, setAdvanceGuardError] = useState(null);
161
194
  const idx = steps.indexOf(currentStep);
@@ -235,6 +268,10 @@ export function BookingJourney(props) {
235
268
  await commit.mutateAsync({
236
269
  draft: { ...draft, quoteId: quote.data.quoteId },
237
270
  quoteId: quote.data.quoteId,
271
+ // The owned commit reads the buyer + travelers off `party`, not the
272
+ // draft — without this the create rejects with "no billing person/org".
273
+ party: buildCommitParty(draft),
274
+ initialStatus: resolveInitialStatus(draft),
238
275
  paymentIntent: { type: draft.payment.intent === "card" ? "card" : "hold" },
239
276
  });
240
277
  };
@@ -278,11 +315,66 @@ export function BookingJourney(props) {
278
315
  setContractDialogOpen(false);
279
316
  await handleAccepted(acceptance);
280
317
  };
281
- return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-8 md:items-start", children: [_jsxs("div", { className: "space-y-6 md:col-span-5", children: [_jsx(StepHeader, { current: currentStep, visited: [...visited], steps: steps, shape: shape, onJumpTo: jumpTo }), currentStep === "configure" ? (_jsx(ConfigureStep, { draft: draft, setDraft: setDraft, shape: shape })) : null, currentStep === "billing" ? (_jsx(BillingStep, { draft: draft, setDraft: setDraft, shape: shape, renderLeadContactPicker: props.renderLeadContactPicker, renderExtras: props.renderBillingExtras })) : null, currentStep === "travelers" ? (_jsx(TravelersStep, { draft: draft, setDraft: setDraft, shape: shape, renderTravelerContactPicker: props.renderTravelerContactPicker })) : null, currentStep === "accommodation" ? (_jsx(AccommodationStep, { draft: draft, setDraft: setDraft, shape: shape })) : null, currentStep === "addons" ? (_jsx(AddonsStep, { draft: draft, setDraft: setDraft, shape: shape })) : null, currentStep === "payment" ? (_jsx(PaymentStep, { draft: draft, setDraft: setDraft, shape: shape, capabilities: props.paymentCapabilities ?? {
318
+ // Bind the picked lead + departure into the billing-extras slot so the
319
+ // template can run lead-aware checks (e.g. duplicate-departure warning).
320
+ const billingExtrasSlot = props.renderBillingExtras
321
+ ? () => props.renderBillingExtras?.({
322
+ buyerType: draft.billing.buyerType,
323
+ personId: draft.billing.contact.personId,
324
+ organizationId: draft.billing.organizationId,
325
+ productId: props.entityId,
326
+ departureSlotId: draft.configure.departureSlotId,
327
+ departureDate: draft.configure.departureDate,
328
+ })
329
+ : undefined;
330
+ // Renders one step's content. Shared by both layouts — the wizard shows
331
+ // exactly one at a time; the stacked page renders them all in sections.
332
+ const renderStep = (step) => {
333
+ switch (step) {
334
+ case "departure":
335
+ // First load: the descriptor arrives with the first quote. Show a
336
+ // skeleton rather than the generic fallback, which would flash and
337
+ // then shift into the real layout.
338
+ return !quote.data && quote.isQuoting ? (_jsx(ConfigureStepSkeleton, {})) : (_jsx(DepartureStep, { draft: draft, setDraft: setDraft, shape: shape, productId: props.entityId, renderDeparturePicker: props.renderDeparturePicker }));
339
+ case "options":
340
+ return (_jsx(OptionsStep, { draft: draft, setDraft: setDraft, shape: shape, productId: props.entityId, renderUnitsPicker: props.renderUnitsPicker }));
341
+ case "billing":
342
+ return (_jsx(BillingStep, { draft: draft, setDraft: setDraft, shape: shape, renderLeadContactPicker: props.renderLeadContactPicker, renderExtras: billingExtrasSlot, warnings: warningsForStep("billing", draft, shape, messages) }));
343
+ case "travelers":
344
+ return (_jsx(TravelersStep, { draft: draft, setDraft: setDraft, shape: shape, renderTravelerContactPicker: props.renderTravelerContactPicker, warnings: warningsForStep("travelers", draft, shape, messages) }));
345
+ case "accommodation":
346
+ return _jsx(AccommodationStep, { draft: draft, setDraft: setDraft, shape: shape });
347
+ case "addons":
348
+ return _jsx(AddonsStep, { draft: draft, setDraft: setDraft, shape: shape });
349
+ case "payment":
350
+ return (_jsx(PaymentStep, { draft: draft, setDraft: setDraft, shape: shape, capabilities: props.paymentCapabilities ?? {
351
+ acceptsCard: false,
352
+ acceptsHold: true,
353
+ acceptsTicketOnCredit: false,
354
+ }, renderProviderStep: props.renderPaymentProviderStep, surface: surface, pricing: quote.data?.pricing ?? null }));
355
+ case "documents":
356
+ return _jsx(DocumentsStep, { draft: draft, setDraft: setDraft });
357
+ case "review":
358
+ return (_jsx(ReviewStep, { draft: draft, setDraft: setDraft, isCommitting: commit.isPending || isHandlingCheckout, onConfirm: onConfirm,
359
+ // Stacked has no per-step gates, so the Confirm button enforces
360
+ // the whole-booking validity itself.
361
+ canConfirm: layout === "stacked" ? canCommit : undefined, renderExtras: props.renderReviewExtras, surface: surface, pricing: quote.data?.pricing ?? null, warnings: warningsForStep("review", draft, shape, messages) }));
362
+ }
363
+ };
364
+ if (layout === "stacked") {
365
+ return (_jsx(StackedJourney, { className: props.className, steps: stackedSteps, renderStep: renderStep, isStepComplete: (s) => stackedStepComplete(s, draft, shape, available), commitError: commit.error, onCancel: props.onCancelled, onConfirm: onConfirm, isCommitting: commit.isPending || isHandlingCheckout, canConfirm: canCommit, sidePanel: _jsx(PriceSidePanel, { pricing: quote.data?.pricing ?? null, isQuoting: quote.isQuoting, invalidReason: quote.data?.invalidReason, entitySummary: props.entitySummary, currentStep: firstIncomplete, steps: stackedSteps, shape: shape, draft: draft, className: props.sidePanelClassName,
366
+ // Price override + voucher live with the pricing, not in Payment.
367
+ pricingExtras: _jsx(FinalizeControls, { draft: draft, setDraft: setDraft, pricing: quote.data?.pricing ?? null, renderVoucherPicker: props.renderVoucherPicker }) }), contractDialog: contractConfig ? (_jsx(ContractPreviewDialog, { open: contractDialogOpen, onOpenChange: setContractDialogOpen, previewUrl: contractConfig.previewUrl, acceptLanguage: contractConfig.acceptLanguage, variables: contractVariables, marketingLabel: contractConfig.marketingLabel, termsLabel: contractConfig.termsLabel, onAccept: onContractAccept })) : null }));
368
+ }
369
+ return (_jsxs("div", { className: props.className, children: [_jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-8 md:items-start", children: [_jsxs("div", { className: "space-y-6 md:col-span-5", children: [_jsx(StepHeader, { current: currentStep, visited: [...visited], steps: steps, shape: shape, onJumpTo: jumpTo }), currentStep === "departure" ? (
370
+ // First load: the descriptor arrives with the first quote. Show a
371
+ // skeleton rather than the generic fallback, which would flash
372
+ // and then shift into the real layout.
373
+ !quote.data && quote.isQuoting ? (_jsx(ConfigureStepSkeleton, {})) : (_jsx(DepartureStep, { draft: draft, setDraft: setDraft, shape: shape, productId: props.entityId, renderDeparturePicker: props.renderDeparturePicker }))) : null, currentStep === "options" ? (_jsx(OptionsStep, { draft: draft, setDraft: setDraft, shape: shape, productId: props.entityId, renderUnitsPicker: props.renderUnitsPicker })) : null, currentStep === "billing" ? (_jsx(BillingStep, { draft: draft, setDraft: setDraft, shape: shape, renderLeadContactPicker: props.renderLeadContactPicker, renderExtras: billingExtrasSlot })) : null, currentStep === "travelers" ? (_jsx(TravelersStep, { draft: draft, setDraft: setDraft, shape: shape, renderTravelerContactPicker: props.renderTravelerContactPicker })) : null, currentStep === "accommodation" ? (_jsx(AccommodationStep, { draft: draft, setDraft: setDraft, shape: shape })) : null, currentStep === "addons" ? (_jsx(AddonsStep, { draft: draft, setDraft: setDraft, shape: shape })) : null, currentStep === "payment" ? (_jsx(PaymentStep, { draft: draft, setDraft: setDraft, shape: shape, capabilities: props.paymentCapabilities ?? {
282
374
  acceptsCard: false,
283
375
  acceptsHold: true,
284
376
  acceptsTicketOnCredit: false,
285
- }, renderProviderStep: props.renderPaymentProviderStep })) : null, currentStep === "review" ? (_jsx(ReviewStep, { draft: draft, setDraft: setDraft, isCommitting: commit.isPending || isHandlingCheckout, onConfirm: onConfirm, renderExtras: props.renderReviewExtras, surface: surface })) : null, warnings.length > 0 ? (_jsx("ul", { className: "space-y-1 rounded border border-amber-300 bg-amber-50 p-3 text-amber-900 text-sm dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100", children: warnings.map((w) => (_jsxs("li", { children: ["\u26A0 ", w] }, w))) })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "outline", disabled: isAdvanceGuardPending, onClick: () => {
377
+ }, renderProviderStep: props.renderPaymentProviderStep, surface: surface, pricing: quote.data?.pricing ?? null })) : null, currentStep === "review" ? (_jsx(ReviewStep, { draft: draft, setDraft: setDraft, isCommitting: commit.isPending || isHandlingCheckout, onConfirm: onConfirm, renderExtras: props.renderReviewExtras, surface: surface, pricing: quote.data?.pricing ?? null })) : null, warnings.length > 0 ? (_jsx("ul", { className: "space-y-1 rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-900 text-sm dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100", children: warnings.map((w) => (_jsxs("li", { children: ["\u26A0 ", w] }, w))) })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "outline", disabled: isAdvanceGuardPending, onClick: () => {
286
378
  if (prev)
287
379
  goBack();
288
380
  else
@@ -291,10 +383,101 @@ export function BookingJourney(props) {
291
383
  ? messages.bookingJourney.navigation.checking
292
384
  : messages.bookingJourney.navigation.next })) : null] }), advanceGuardError ? (_jsx("p", { className: "text-destructive text-sm", role: "alert", "aria-live": "polite", children: advanceGuardError })) : null, commit.error ? (_jsx("p", { className: "text-destructive text-sm", children: commit.error instanceof Error ? commit.error.message : String(commit.error) })) : null] }), _jsx("aside", { className: "md:sticky md:top-4 md:col-span-3", children: _jsx(PriceSidePanel, { pricing: quote.data?.pricing ?? null, isQuoting: quote.isQuoting, invalidReason: quote.data?.invalidReason, entitySummary: props.entitySummary, currentStep: currentStep, steps: steps, shape: shape, draft: draft, className: props.sidePanelClassName }) })] }), contractConfig ? (_jsx(ContractPreviewDialog, { open: contractDialogOpen, onOpenChange: setContractDialogOpen, previewUrl: contractConfig.previewUrl, acceptLanguage: contractConfig.acceptLanguage, variables: contractVariables, marketingLabel: contractConfig.marketingLabel, termsLabel: contractConfig.termsLabel, onAccept: onContractAccept })) : null] }));
293
385
  }
386
+ /**
387
+ * The buyer + travelers the owned commit reads off `request.party` (the draft
388
+ * carries them but `extractBillingParty` only inspects `party`). B2C supplies
389
+ * `personId`; B2B supplies `organizationId`; traveler person links thread
390
+ * through so the booking attaches to the right CRM records.
391
+ */
392
+ function buildCommitParty(draft) {
393
+ const c = draft.billing.contact;
394
+ return {
395
+ personId: c.personId,
396
+ organizationId: draft.billing.organizationId,
397
+ billing: {
398
+ personId: c.personId,
399
+ organizationId: draft.billing.organizationId,
400
+ contact: {
401
+ firstName: c.firstName,
402
+ lastName: c.lastName,
403
+ email: c.email,
404
+ phone: c.phone,
405
+ },
406
+ },
407
+ travelerParty: {
408
+ travelers: draft.travelers.map((t) => ({ personId: t.personId })),
409
+ },
410
+ };
411
+ }
412
+ /**
413
+ * Initial booking status from the operator's choices: an explicit "save as
414
+ * draft", else live — confirmed when the payment is fully marked paid,
415
+ * otherwise awaiting payment.
416
+ */
417
+ function resolveInitialStatus(draft) {
418
+ if (draft.saveAsDraft)
419
+ return "draft";
420
+ const schedules = draft.paymentSchedules ?? [];
421
+ const fullyPaid = schedules.length > 0 && schedules.every((s) => s.status === "paid");
422
+ return fullyPaid ? "confirmed" : "awaiting_payment";
423
+ }
424
+ const sectionId = (step) => `bj-section-${step}`;
425
+ /**
426
+ * The sequential gates in the stacked layout: each must be filled before the
427
+ * next sections unlock. Once all three are done, the remaining sections
428
+ * (options, extras, payment) all open together.
429
+ */
430
+ const GATE_STEPS = new Set(["departure", "billing", "travelers"]);
431
+ /**
432
+ * The admin's guided single-page layout — every section is a block on one
433
+ * page, but content stays collapsed until the previous section is complete,
434
+ * so the operator fills them in sequence and focuses on one at a time.
435
+ *
436
+ * - LOCKED (a prior section isn't done): a muted, disabled summary row.
437
+ * - ACTIVE (the first not-yet-done section): expanded with its full
438
+ * content + a "Continue" button (enabled once the section is valid).
439
+ * - DONE (passed via Continue): collapses to a one-line summary row with a
440
+ * check — click to re-open and edit, so nothing entered is ever lost.
441
+ *
442
+ * Completeness derives from the same per-step gate the wizard uses; the
443
+ * final Review section's Confirm is gated on the whole booking.
444
+ */
445
+ function StackedJourney({ className, steps, renderStep, isStepComplete, commitError, onCancel, onConfirm, isCommitting, canConfirm, sidePanel, contractDialog, }) {
446
+ const messages = useBookingsUiMessagesOrDefault();
447
+ const nav = messages.bookingJourney.navigation;
448
+ // Progressive unlock gated only on the SEQUENTIAL gates (departure →
449
+ // billing → travelers). Once those are filled, the remaining sections
450
+ // (options, extras, payment) all unlock together — they're independent
451
+ // refinements, not a strict sequence. Unlocked sections stay open so the
452
+ // operator keeps full context of everything they've filled.
453
+ const firstIncompleteGate = steps.find((s) => GATE_STEPS.has(s) && !isStepComplete(s));
454
+ const unlockThroughIndex = firstIncompleteGate
455
+ ? steps.indexOf(firstIncompleteGate)
456
+ : steps.length - 1;
457
+ return (_jsxs("div", { className: className, children: [_jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-8 md:items-start", children: [_jsxs("div", { className: "space-y-3 md:col-span-5", children: [steps.map((step, i) => {
458
+ // Locked: a section beyond the active gate — a muted, disabled row
459
+ // until the operator clears the gates above it.
460
+ if (i > unlockThroughIndex) {
461
+ return (_jsxs("div", { id: sectionId(step), className: "flex w-full scroll-mt-4 items-center gap-3 rounded-md border p-4 opacity-60", children: [_jsx("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground text-xs", children: i + 1 }), _jsx("div", { className: "min-w-0 flex-1 font-medium text-sm", children: messages.bookingJourney.steps[step] }), _jsx(Lock, { className: "h-4 w-4 text-muted-foreground" })] }, step));
462
+ }
463
+ // Unlocked: full section content, stays open once reached. Its
464
+ // warnings render inside the step's own card (scoped to the block).
465
+ return (_jsx("section", { id: sectionId(step), className: "scroll-mt-4", children: renderStep(step) }, step));
466
+ }), commitError ? (_jsx("p", { className: "text-destructive text-sm", children: commitError instanceof Error ? commitError.message : String(commitError) })) : null, _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onCancel?.(), children: nav.cancel }), onConfirm ? (canConfirm === false ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx("span", { className: "ml-auto inline-flex" }), children: _jsx(Button, { type: "button", disabled: true, children: messages.bookingJourney.review.confirmBooking }) }), _jsx(TooltipContent, { children: messages.bookingJourney.review.completeToConfirm })] })) : (_jsx(Button, { type: "button", className: "ml-auto", onClick: onConfirm, disabled: isCommitting === true, children: isCommitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), messages.bookingJourney.review.confirming] })) : (messages.bookingJourney.review.confirmBooking) }))) : null] })] }), _jsx("aside", { className: "md:sticky md:top-4 md:col-span-3", children: sidePanel })] }), contractDialog] }));
467
+ }
294
468
  function isStepVisible(step, shape) {
469
+ const subSteps = shape.configureSubSteps ?? [];
295
470
  switch (step) {
296
- case "configure":
471
+ case "departure":
472
+ // The departure step shows whenever the journey has a configure phase
473
+ // (owned products always pick a departure; storefront free-date too).
297
474
  return shape.showsConfigure;
475
+ case "options":
476
+ // The options step shows only when there's something to choose —
477
+ // a product option, room/unit selection, or another configure
478
+ // sub-step (cabin, date-range, air). Simple per-person tours skip it.
479
+ return (shape.showsConfigure &&
480
+ subSteps.some((s) => s.kind !== "departure" && s.kind !== "occupancy"));
298
481
  case "billing":
299
482
  return shape.showsBilling;
300
483
  case "travelers":
@@ -305,34 +488,94 @@ function isStepVisible(step, shape) {
305
488
  return shape.showsAddons;
306
489
  case "payment":
307
490
  return shape.showsPayment;
491
+ case "documents":
492
+ // Operator-only block; shown whenever a real booking is being finalized
493
+ // (gated to the admin surface in the step list above).
494
+ return shape.showsReview;
308
495
  case "review":
309
496
  return shape.showsReview;
310
497
  }
311
498
  }
499
+ /**
500
+ * First-load placeholder for the Configure step. Mirrors the real layout
501
+ * (departure, travelers, option) closely enough that swapping to the live
502
+ * descriptor causes minimal layout shift.
503
+ */
504
+ function ConfigureStepSkeleton() {
505
+ return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(Skeleton, { className: "h-5 w-28" }) }), _jsxs(CardContent, { className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-24" }), _jsx(Skeleton, { className: "h-10 w-full" })] }), _jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-4 w-20" }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", children: [_jsx(Skeleton, { className: "h-16 w-full" }), _jsx(Skeleton, { className: "h-16 w-full" }), _jsx(Skeleton, { className: "h-16 w-full" })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-16" }), _jsx(Skeleton, { className: "h-12 w-full" })] })] })] }));
506
+ }
312
507
  function canAdvanceFromStep(step, draft, shape, available) {
313
508
  if (!available)
314
509
  return false;
315
510
  switch (step) {
316
- case "configure": {
317
- const total = totalPax(draft);
318
- return total >= shape.paxBandsAllowedTotal.min && total <= shape.paxBandsAllowedTotal.max;
511
+ case "departure": {
512
+ // Require a departure when the descriptor marks it required.
513
+ const requiresDeparture = (shape.configureSubSteps ?? []).some((s) => s.kind === "departure" && s.required);
514
+ if (!requiresDeparture)
515
+ return true;
516
+ return Boolean(draft.configure.departureSlotId || draft.configure.departureDate);
517
+ }
518
+ case "options": {
519
+ // Room products (an `option-units` sub-step) can't be booked — or
520
+ // priced — without at least one room, so block confirm until one is
521
+ // picked. Per-person products have nothing to require here.
522
+ const isRoomProduct = (shape.configureSubSteps ?? []).some((s) => s.kind === "option-units");
523
+ if (!isRoomProduct)
524
+ return true;
525
+ const rooms = (draft.configure.optionSelections ?? []).reduce((sum, s) => sum + (s.quantity ?? 0), 0);
526
+ return rooms > 0;
319
527
  }
320
528
  case "billing": {
529
+ // B2B: the picked organization is the bill-to. The CRM org picker doesn't
530
+ // collect an individual contact name (and the manual contact inputs are
531
+ // hidden), so requiring one would lock the step with no way to satisfy it.
532
+ if (draft.billing.buyerType === "B2B") {
533
+ return Boolean(draft.billing.organizationId);
534
+ }
321
535
  const c = draft.billing.contact;
322
536
  return c.firstName.length > 0 && c.lastName.length > 0 && c.email.length > 0;
323
537
  }
324
538
  case "travelers": {
325
- // Hard-reject only on canonical traveler fields (firstName,
326
- // lastName) those are always required regardless of
327
- // descriptor configuration. All other required fields surface
328
- // as warnings so operators can complete the journey and fill
329
- // them in later from the booking detail page.
539
+ // Pax counts are set on this step now: require the allowed total and
540
+ // that occupancy rules (e.g. "Child under 6 requires an Adult") hold.
541
+ const total = totalPax(draft);
542
+ if (total < shape.paxBandsAllowedTotal.min || total > shape.paxBandsAllowedTotal.max) {
543
+ return false;
544
+ }
545
+ if (evaluatePaxBandDependencies(draft.configure.pax, shape.paxBandDependencies, shape.paxBands)
546
+ .length > 0) {
547
+ return false;
548
+ }
549
+ // Hard-reject only on canonical traveler fields (firstName, lastName);
550
+ // other required fields surface as warnings, fillable later.
330
551
  return draft.travelers.every((t) => t.firstName && t.lastName);
331
552
  }
332
553
  default:
333
554
  return true;
334
555
  }
335
556
  }
557
+ /**
558
+ * Completeness for the stacked admin accordion's AUTO-advance — stricter
559
+ * than `canAdvanceFromStep` so the flow pauses on sections that need a
560
+ * deliberate choice even though they're not hard-required to commit:
561
+ * - options: a product option must be picked (when the product has them);
562
+ * - payment: an intent must be chosen.
563
+ * Everything else defers to the shared gate. Kept separate so the wizard's
564
+ * Next gating (which uses `canAdvanceFromStep`) is unchanged.
565
+ */
566
+ function stackedStepComplete(step, draft, shape, available) {
567
+ switch (step) {
568
+ case "options": {
569
+ const hasOptions = (shape.configureSubSteps ?? []).some((s) => s.kind === "product-option");
570
+ // No options to choose → nothing to wait for. Otherwise require a pick.
571
+ return hasOptions ? Boolean(draft.configure.variantId) : true;
572
+ }
573
+ case "payment":
574
+ return Boolean(draft.payment.intent);
575
+ default:
576
+ return canAdvanceFromStep(step, draft, shape, available);
577
+ }
578
+ }
336
579
  /**
337
580
  * Soft warnings for the current step — surfaced inline above the
338
581
  * Next button. Don't block advancement; they're hints. Per
@@ -0,0 +1,3 @@
1
+ import type { StepCommonProps } from "./shared.js";
2
+ export declare function AccommodationStep({ draft, setDraft, shape }: StepCommonProps): React.ReactElement;
3
+ //# sourceMappingURL=accommodation-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accommodation-step.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/accommodation-step.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAMlD,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CAgIjG"}
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Separator } from "@voyantjs/ui/components";
4
+ import { Button } from "@voyantjs/ui/components/button";
5
+ import { Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components/card";
6
+ import { Label } from "@voyantjs/ui/components/label";
7
+ import { formatMessage, useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
8
+ import { setAccommodation } from "../../lib/draft-state.js";
9
+ // ─────────────────────────────────────────────────────────────────
10
+ // Accommodation
11
+ // ─────────────────────────────────────────────────────────────────
12
+ export function AccommodationStep({ draft, setDraft, shape }) {
13
+ const messages = useBookingsUiMessagesOrDefault();
14
+ const subSteps = shape.accommodation?.subSteps ?? [];
15
+ const rooms = shape.accommodation?.roomOptions ?? [];
16
+ const accommodation = draft.accommodation ?? {
17
+ rooms: [],
18
+ travelerAssignments: {},
19
+ };
20
+ return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: messages.bookingJourney.accommodation.title }) }), _jsx(Separator, {}), _jsx(CardContent, { className: "space-y-4", children: rooms.length === 0 && subSteps.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: messages.bookingJourney.accommodation.empty })) : (_jsxs("div", { className: "space-y-3", children: [rooms.map((room) => {
21
+ const current = accommodation.rooms.find((r) => r.optionUnitId === room.id);
22
+ const ratePlans = room.ratePlans ?? [];
23
+ return (_jsxs("div", { className: "space-y-3 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: room.name }), room.description ? (_jsx("div", { className: "text-muted-foreground text-xs", children: room.description })) : null] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", type: "button", onClick: () => {
24
+ const list = accommodation.rooms.filter((r) => r.optionUnitId !== room.id);
25
+ const qty = (current?.quantity ?? 0) - 1;
26
+ if (qty > 0) {
27
+ list.push({
28
+ optionUnitId: room.id,
29
+ quantity: qty,
30
+ ratePlanId: current?.ratePlanId,
31
+ });
32
+ }
33
+ setDraft(setAccommodation(draft, {
34
+ ...accommodation,
35
+ rooms: list,
36
+ }));
37
+ }, children: "\u2212" }), _jsx("span", { className: "min-w-6 text-center", children: current?.quantity ?? 0 }), _jsx(Button, { variant: "outline", size: "sm", type: "button", onClick: () => {
38
+ const list = accommodation.rooms.filter((r) => r.optionUnitId !== room.id);
39
+ const qty = (current?.quantity ?? 0) + 1;
40
+ // Auto-select the only rate plan when there's
41
+ // exactly one — saves a click on the common case.
42
+ const ratePlanId = current?.ratePlanId ??
43
+ (ratePlans.length === 1 ? ratePlans[0]?.id : undefined);
44
+ list.push({
45
+ optionUnitId: room.id,
46
+ quantity: qty,
47
+ ratePlanId,
48
+ });
49
+ setDraft(setAccommodation(draft, {
50
+ ...accommodation,
51
+ rooms: list,
52
+ }));
53
+ }, children: "+" })] })] }), current && current.quantity > 0 && ratePlans.length > 0 ? (_jsx(RatePlanPicker, { roomId: room.id, ratePlans: ratePlans, selected: current.ratePlanId, onSelect: (planId) => {
54
+ const list = accommodation.rooms.map((r) => r.optionUnitId === room.id ? { ...r, ratePlanId: planId } : r);
55
+ setDraft(setAccommodation(draft, {
56
+ ...accommodation,
57
+ rooms: list,
58
+ }));
59
+ } })) : null] }, room.id));
60
+ }), subSteps.map((sub) => sub.kind === "extensions" ? (_jsx("div", { className: "rounded-md border p-3 text-muted-foreground text-sm", children: formatMessage(messages.bookingJourney.accommodation.extensionsAvailable, {
61
+ count: sub.options.length,
62
+ plural: sub.options.length === 1 ? "" : "s",
63
+ }) }, "extensions")) : null)] })) })] }));
64
+ }
65
+ function RatePlanPicker({ roomId, ratePlans, selected, onSelect, }) {
66
+ const messages = useBookingsUiMessagesOrDefault();
67
+ return (_jsxs("div", { className: "space-y-2 border-t pt-3", children: [_jsx(Label, { htmlFor: `bj-rate-plan-${roomId}`, children: messages.bookingJourney.accommodation.ratePlan }), _jsx("div", { className: "space-y-2", children: ratePlans.map((plan) => {
68
+ const isSelected = plan.id === selected;
69
+ return (_jsxs("button", { type: "button", onClick: () => onSelect(plan.id), className: `w-full rounded-md border p-2 text-left text-sm ${isSelected ? "border-primary ring-2 ring-primary" : ""}`, children: [_jsx("div", { className: "font-medium", children: plan.name }), plan.description ? (_jsx("div", { className: "text-muted-foreground text-xs", children: plan.description })) : null, plan.cancellationPolicy ? (_jsxs("div", { className: "text-muted-foreground text-xs", children: [messages.bookingJourney.accommodation.cancellationPrefix, " ", plan.cancellationPolicy] })) : null, plan.inclusions && plan.inclusions.length > 0 ? (_jsxs("div", { className: "text-muted-foreground text-xs", children: [messages.bookingJourney.accommodation.includesPrefix, " ", plan.inclusions.join(", ")] })) : null] }, plan.id));
70
+ }) })] }));
71
+ }
@@ -0,0 +1,3 @@
1
+ import { type StepCommonProps } from "./shared.js";
2
+ export declare function AddonsStep({ draft, setDraft, shape }: StepCommonProps): React.ReactElement;
3
+ //# sourceMappingURL=addons-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addons-step.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/addons-step.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAM5D,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CAmD1F"}
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Separator } from "@voyantjs/ui/components";
4
+ import { Button } from "@voyantjs/ui/components/button";
5
+ import { Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components/card";
6
+ import { useBookingsUiMessagesOrDefault } from "../../../i18n/index.js";
7
+ import { setAddons } from "../../lib/draft-state.js";
8
+ import { bucketBy } from "./shared.js";
9
+ // ─────────────────────────────────────────────────────────────────
10
+ // Add-ons
11
+ // ─────────────────────────────────────────────────────────────────
12
+ export function AddonsStep({ draft, setDraft, shape }) {
13
+ const messages = useBookingsUiMessagesOrDefault();
14
+ const flat = shape.addons?.catalog ?? [];
15
+ const groups = shape.addons?.groups ?? [];
16
+ const all = [...flat, ...groups.flatMap((g) => g.items)];
17
+ return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: messages.bookingJourney.addons.title }) }), _jsx(Separator, {}), _jsxs(CardContent, { className: "space-y-4", children: [all.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: messages.bookingJourney.addons.empty })) : null, groups.map((group) => {
18
+ // Group by port/day when the descriptor asks — cruise
19
+ // excursions arrive grouped by port name.
20
+ const buckets = group.groupBy === "port" || group.groupBy === "day"
21
+ ? bucketBy(group.items, (i) => i.groupKey ?? messages.bookingJourney.addons.otherBucket)
22
+ : new Map([["", group.items]]);
23
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "font-medium text-sm", children: group.label }), [...buckets.entries()].map(([bucket, items]) => (_jsxs("div", { className: "space-y-2", children: [bucket ? (_jsx("div", { className: "text-muted-foreground text-xs uppercase", children: bucket })) : null, items.map((item) => (_jsx(AddonRow, { draft: draft, setDraft: setDraft, item: item }, item.id)))] }, bucket || "all")))] }, group.label));
24
+ }), flat.length > 0 && groups.length === 0 ? (_jsx("div", { className: "space-y-2", children: flat.map((item) => (_jsx(AddonRow, { draft: draft, setDraft: setDraft, item: item }, item.id))) })) : null] })] }));
25
+ }
26
+ function AddonRow({ draft, setDraft, item, }) {
27
+ const current = draft.addons.find((a) => a.extraId === item.id);
28
+ return (_jsxs("div", { className: "flex items-center justify-between rounded-md border p-3", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: item.name }), item.description ? (_jsx("div", { className: "text-muted-foreground text-xs", children: item.description })) : null] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", type: "button", onClick: () => {
29
+ const list = draft.addons.filter((a) => a.extraId !== item.id);
30
+ const qty = (current?.quantity ?? 0) - 1;
31
+ if (qty > 0)
32
+ list.push({ extraId: item.id, quantity: qty });
33
+ setDraft(setAddons(draft, list));
34
+ }, children: "\u2212" }), _jsx("span", { className: "min-w-6 text-center", children: current?.quantity ?? 0 }), _jsx(Button, { variant: "outline", size: "sm", type: "button", onClick: () => {
35
+ const list = draft.addons.filter((a) => a.extraId !== item.id);
36
+ const qty = (current?.quantity ?? 0) + 1;
37
+ list.push({ extraId: item.id, quantity: qty });
38
+ setDraft(setAddons(draft, list));
39
+ }, children: "+" })] })] }));
40
+ }
@@ -0,0 +1,8 @@
1
+ import type { LeadContactPickerProps } from "../../types.js";
2
+ import { type StepCommonProps } from "./shared.js";
3
+ export declare function BillingStep({ draft, setDraft, renderLeadContactPicker, renderExtras, warnings, }: StepCommonProps & {
4
+ renderLeadContactPicker?: (props: LeadContactPickerProps) => React.ReactNode;
5
+ renderExtras?: () => React.ReactNode;
6
+ warnings?: ReadonlyArray<string>;
7
+ }): React.ReactElement;
8
+ //# sourceMappingURL=billing-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-step.d.ts","sourceRoot":"","sources":["../../../../src/journey/components/journey-steps/billing-step.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAsC,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAMtF,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,uBAAuB,EACvB,YAAY,EACZ,QAAQ,GACT,EAAE,eAAe,GAAG;IACnB,uBAAuB,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,KAAK,CAAC,SAAS,CAAA;IAC5E,YAAY,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAA;IACpC,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACjC,GAAG,KAAK,CAAC,YAAY,CAyOrB"}