@ticketboothapp/booking 1.2.122 → 1.2.124

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 (112) hide show
  1. package/CHANGE_BOOKING_BE_HANDOFF.md +15 -4
  2. package/package.json +1 -1
  3. package/src/components/booking/AdminChangeBookingContent.tsx +276 -0
  4. package/src/components/booking/AdminChangeBookingFlow.tsx +647 -6157
  5. package/src/components/booking/AdminChangeCheckoutDialogs.tsx +105 -0
  6. package/src/components/booking/AdminChangeCheckoutPanel.tsx +307 -0
  7. package/src/components/booking/AdminChangePricingPanel.tsx +244 -0
  8. package/src/components/booking/AdminChangeProductSwitcher.tsx +50 -0
  9. package/src/components/booking/AdminChangeReceiptComparison.tsx +167 -0
  10. package/src/components/booking/ChangeBookingCalendarPanel.tsx +126 -0
  11. package/src/components/booking/ChangeBookingCheckoutPanel.tsx +204 -0
  12. package/src/components/booking/ChangeBookingFlow.tsx +576 -4648
  13. package/src/components/booking/ChangeBookingItineraryPanel.tsx +115 -0
  14. package/src/components/booking/ChangeBookingQuoteStatusPlaceholder.tsx +57 -0
  15. package/src/components/booking/ChangeBookingSelectionControlsPanel.tsx +157 -0
  16. package/src/components/booking/ChangeBookingTicketsAndAddOnsPanel.tsx +102 -0
  17. package/src/components/booking/CheckoutModal.tsx +68 -49
  18. package/src/components/booking/NewBookingFlow.tsx +485 -3505
  19. package/src/components/booking/PriceBreakdown.tsx +17 -3
  20. package/src/components/booking/PriceSummary.tsx +21 -3
  21. package/src/components/booking/PrivateShuttleAddOnsSection.tsx +102 -0
  22. package/src/components/booking/PrivateShuttleBookingFlow.tsx +407 -2788
  23. package/src/components/booking/PrivateShuttleCheckoutDialogs.tsx +106 -0
  24. package/src/components/booking/PrivateShuttleCheckoutSection.tsx +333 -0
  25. package/src/components/booking/PrivateShuttleItinerarySection.tsx +95 -0
  26. package/src/components/booking/PrivateShuttleMediaIntro.tsx +62 -0
  27. package/src/components/booking/PrivateShuttleOptionSection.tsx +81 -0
  28. package/src/components/booking/PrivateShuttlePassengerSection.tsx +148 -0
  29. package/src/components/booking/PrivateShuttlePickupSection.tsx +91 -0
  30. package/src/components/booking/PrivateShuttlePreferencesSection.tsx +75 -0
  31. package/src/components/booking/PrivateShuttleStartTimeSection.tsx +88 -0
  32. package/src/components/booking/StandardBookingCheckoutDialogs.tsx +106 -0
  33. package/src/components/booking/StandardBookingCheckoutSection.tsx +185 -0
  34. package/src/components/booking/StandardBookingItineraryPanel.tsx +125 -0
  35. package/src/components/booking/StandardBookingMediaIntro.tsx +69 -0
  36. package/src/components/booking/StandardBookingSelectionControlsPanel.tsx +236 -0
  37. package/src/components/booking/admin-change-customer-quote-runner.ts +119 -0
  38. package/src/components/booking/admin-change-flow-state-helpers.ts +124 -0
  39. package/src/components/booking/admin-change-payment-choice-runner.ts +172 -0
  40. package/src/components/booking/admin-change-provider-payload.ts +101 -0
  41. package/src/components/booking/change-booking-checkout-builders.ts +185 -0
  42. package/src/components/booking/change-booking-checkout-quote-runner.ts +207 -0
  43. package/src/components/booking/change-booking-flow-helpers.ts +706 -0
  44. package/src/components/booking/change-booking-payment-modal-builders.ts +151 -0
  45. package/src/components/booking/change-booking-quote-guards.ts +223 -0
  46. package/src/components/booking/change-booking-quote-state.ts +64 -0
  47. package/src/components/booking/pricing-v2-checkout-summary.ts +144 -0
  48. package/src/components/booking/private-shuttle-availability.ts +111 -0
  49. package/src/components/booking/private-shuttle-checkout-builders.ts +264 -0
  50. package/src/components/booking/private-shuttle-checkout-controller.ts +744 -0
  51. package/src/components/booking/private-shuttle-payment-choice-runner.ts +271 -0
  52. package/src/components/booking/private-shuttle-provider-change-runner.ts +73 -0
  53. package/src/components/booking/private-shuttle-reservation-runner.ts +260 -0
  54. package/src/components/booking/standard-booking-availability.ts +305 -0
  55. package/src/components/booking/standard-booking-checkout-builders.ts +289 -0
  56. package/src/components/booking/standard-booking-checkout-controller.ts +659 -0
  57. package/src/components/booking/standard-booking-payment-choice-runner.ts +274 -0
  58. package/src/components/booking/standard-booking-reservation-runner.ts +229 -0
  59. package/src/components/booking/use-private-shuttle-availability.ts +602 -0
  60. package/src/components/booking/use-standard-booking-availability.ts +806 -0
  61. package/src/components/booking/useActiveProductOptions.ts +26 -0
  62. package/src/components/booking/useAdminChangeCheckoutController.ts +806 -0
  63. package/src/components/booking/useAdminChangeOrderSummaryModel.ts +246 -0
  64. package/src/components/booking/useAdminChangePriceSummary.ts +416 -0
  65. package/src/components/booking/useAdminChangePricingDebugPanel.tsx +178 -0
  66. package/src/components/booking/useAdminChangeProductReset.ts +60 -0
  67. package/src/components/booking/useAdminChangeProducts.ts +102 -0
  68. package/src/components/booking/useAdminChangePromoDiscount.ts +235 -0
  69. package/src/components/booking/useAdminChangeProtectedPricing.ts +280 -0
  70. package/src/components/booking/useAdminChangeQuoteDisplayState.tsx +437 -0
  71. package/src/components/booking/useAdminChangeQuotePreview.ts +506 -0
  72. package/src/components/booking/useAdminChangeReceiptDerivation.ts +203 -0
  73. package/src/components/booking/useAdminCustomReceiptLines.ts +57 -0
  74. package/src/components/booking/useAdminProviderPricingAdjustments.ts +146 -0
  75. package/src/components/booking/useBookingAvailabilityAddOns.ts +54 -0
  76. package/src/components/booking/useBookingPromoAndQuantityController.ts +163 -0
  77. package/src/components/booking/useBookingQuantityCapTrim.ts +56 -0
  78. package/src/components/booking/useBookingViewItemAnalytics.ts +30 -0
  79. package/src/components/booking/useChangeBookingAddOnFloorController.ts +109 -0
  80. package/src/components/booking/useChangeBookingAutoSelections.ts +148 -0
  81. package/src/components/booking/useChangeBookingAvailabilities.ts +692 -0
  82. package/src/components/booking/useChangeBookingCheckoutController.ts +461 -0
  83. package/src/components/booking/useChangeBookingInitialHydration.ts +204 -0
  84. package/src/components/booking/useChangeBookingItineraryUiState.ts +133 -0
  85. package/src/components/booking/useChangeBookingPickupItinerary.ts +472 -0
  86. package/src/components/booking/useChangeBookingPriceSummary.ts +199 -0
  87. package/src/components/booking/useChangeBookingPromoDiscount.ts +218 -0
  88. package/src/components/booking/useChangeBookingProtectedPricing.ts +256 -0
  89. package/src/components/booking/useChangeBookingQuotePreview.ts +442 -0
  90. package/src/components/booking/useChangeBookingReceiptDerivation.ts +128 -0
  91. package/src/components/booking/useChangeBookingReceiptFloorController.ts +449 -0
  92. package/src/components/booking/useChangeBookingSelection.ts +362 -0
  93. package/src/components/booking/useChangeBookingSelectionDetails.ts +200 -0
  94. package/src/components/booking/useChangeBookingSummaryLines.ts +169 -0
  95. package/src/components/booking/usePrivateShuttlePriceSummary.ts +513 -0
  96. package/src/components/booking/usePrivateShuttlePromoController.ts +143 -0
  97. package/src/components/booking/usePrivateShuttlePromoDiscount.ts +124 -0
  98. package/src/components/booking/useSeedPromoCodeInput.ts +13 -0
  99. package/src/components/booking/useStandardBookingAutoSelections.ts +224 -0
  100. package/src/components/booking/useStandardBookingPickupItinerary.ts +473 -0
  101. package/src/components/booking/useStandardBookingPriceSummary.ts +438 -0
  102. package/src/components/booking/useStandardBookingPromoController.ts +258 -0
  103. package/src/components/booking/useStandardBookingPromoDiscount.ts +203 -0
  104. package/src/data/products-config.json +1 -1
  105. package/src/lib/booking/change-booking-server-preview.ts +134 -20
  106. package/src/lib/booking/change-flow-pricing.ts +31 -11
  107. package/src/lib/booking/checkout-breakdown.ts +66 -1
  108. package/src/lib/booking/pricing-config.ts +10 -0
  109. package/src/lib/booking/source-metadata.ts +58 -0
  110. package/src/lib/booking-api.ts +154 -3
  111. package/src/lib/pricing-v2-shadow.ts +272 -0
  112. package/test/change-booking-helpers.test.ts +206 -0
@@ -130,8 +130,16 @@ export function PriceBreakdown({
130
130
  );
131
131
  }
132
132
 
133
+ const editableHoverHandlers =
134
+ editable && canShowBreakdown
135
+ ? {
136
+ onMouseEnter: () => setShowTooltip(true),
137
+ onMouseLeave: () => setShowTooltip(false),
138
+ }
139
+ : {};
140
+
133
141
  return (
134
- <div className="flex items-center justify-between gap-3 min-w-0">
142
+ <div className="flex items-center justify-between gap-3 min-w-0" {...editableHoverHandlers}>
135
143
  {editable && onEditableLabelChange ? (
136
144
  <input
137
145
  type="text"
@@ -141,7 +149,13 @@ export function PriceBreakdown({
141
149
  aria-label={`Edit ${category} label`}
142
150
  />
143
151
  ) : (
144
- <span className="text-sm text-stone-600 min-w-0 truncate">
152
+ <span
153
+ className={
154
+ editable && canShowBreakdown
155
+ ? 'text-sm text-stone-600 min-w-0 truncate cursor-help underline decoration-dotted underline-offset-2'
156
+ : 'text-sm text-stone-600 min-w-0 truncate'
157
+ }
158
+ >
145
159
  {category} {qty > 1 ? `× ${qty}` : ''}
146
160
  </span>
147
161
  )}
@@ -194,7 +208,7 @@ export function PriceBreakdown({
194
208
  )}
195
209
  </span>
196
210
  )}
197
- {!editable && canShowBreakdown && showTooltip && (
211
+ {canShowBreakdown && showTooltip && (
198
212
  <div className="absolute right-0 top-full mt-2 w-72 p-3 bg-stone-900 text-white text-xs rounded-lg shadow-xl z-50">
199
213
  <div className="font-semibold mb-2 pb-2 border-b border-stone-700">
200
214
  Price Breakdown ({category})
@@ -86,7 +86,12 @@ export interface PriceSummaryProps {
86
86
  }
87
87
 
88
88
  function getLineAmountClass(type: string | undefined, amount: number): string {
89
- const isDiscount = amount < 0 || type === 'PROMO_CODE' || type === 'DISCOUNT' || type === 'GIFT_CARD';
89
+ const isDiscount =
90
+ amount < 0 ||
91
+ type === 'PROMO_CODE' ||
92
+ type === 'DISCOUNT' ||
93
+ type === 'GIFT_CARD' ||
94
+ type === 'PAYMENT_CREDIT';
90
95
  const isAddOn = (type === 'RETURN_OPTION' || type === 'return') && amount > 0;
91
96
  if (isDiscount) return 'font-medium text-red-600';
92
97
  if (isAddOn) return 'font-medium text-emerald-600';
@@ -106,6 +111,18 @@ function formatLineAmount(
106
111
  return formatted;
107
112
  }
108
113
 
114
+ function displaySummaryLineLabel(label: string, type: string | undefined): string {
115
+ const normalizedType = String(type ?? '').trim().toUpperCase();
116
+ const normalizedLabel = label.trim().toLowerCase();
117
+ if (
118
+ (normalizedType === 'GIFT_CARD' || normalizedType === 'PAYMENT_CREDIT') &&
119
+ (normalizedLabel === 'gift card' || normalizedLabel === 'payment credit')
120
+ ) {
121
+ return 'Gift card comp';
122
+ }
123
+ return label;
124
+ }
125
+
109
126
  function shouldAppendQuantitySuffix(type: string | undefined, label: string, quantity: number | null | undefined): boolean {
110
127
  if (quantity == null || quantity <= 1) return false;
111
128
  const normalizedType = String(type ?? '').trim().toUpperCase();
@@ -223,6 +240,7 @@ export function PriceSummary({
223
240
  );
224
241
  }
225
242
  const { lineKey, label, amount, type, quantity, tooltip, editable } = row;
243
+ const shownLabel = displaySummaryLineLabel(label, type);
226
244
  // Receipt mode: insert Subtotal row before first TAX line
227
245
  const isTaxLine = type === 'TAX';
228
246
  const showSubtotalBeforeTax = isTaxLine && subtotal != null && subtotal > 0 && !subtotalShown;
@@ -250,8 +268,8 @@ export function PriceSummary({
250
268
  />
251
269
  ) : (
252
270
  <span className="min-w-0 truncate">
253
- {label}
254
- {shouldAppendQuantitySuffix(type, label, quantity) ? ` (x${quantity})` : ''}
271
+ {shownLabel}
272
+ {shouldAppendQuantitySuffix(type, shownLabel, quantity) ? ` (x${quantity})` : ''}
255
273
  </span>
256
274
  )}
257
275
  {tooltip && <InfoTooltip text={tooltip} />}
@@ -0,0 +1,102 @@
1
+ import type { AddOn } from '../../lib/booking-api';
2
+ import { formatCurrencyAmount } from '../../lib/currency';
3
+ import type { Locale } from '../../lib/booking/i18n/config';
4
+ import type { Currency } from './CurrencySwitcher';
5
+ import { MealDrinkAddOnSelector, canUseMealDrinkSelector } from './MealDrinkAddOnSelector';
6
+ import styles from './PrivateShuttleBookingFlow.module.css';
7
+
8
+ export type PrivateShuttleAddOnSelection = {
9
+ addOnId: string;
10
+ variantId?: string;
11
+ quantity?: number;
12
+ };
13
+ type PrivateShuttleAddOnSelectionUpdate =
14
+ | PrivateShuttleAddOnSelection[]
15
+ | ((prev: PrivateShuttleAddOnSelection[]) => PrivateShuttleAddOnSelection[]);
16
+
17
+ export interface PrivateShuttleAddOnsSectionProps {
18
+ passengerCount: number;
19
+ addOns: AddOn[];
20
+ addOnSelections: PrivateShuttleAddOnSelection[];
21
+ selectedDestinationIds: string[];
22
+ currency: Currency;
23
+ locale: Locale;
24
+ onAddOnSelectionsChange: (update: PrivateShuttleAddOnSelectionUpdate) => void;
25
+ }
26
+
27
+ export function PrivateShuttleAddOnsSection({
28
+ passengerCount,
29
+ addOns,
30
+ addOnSelections,
31
+ selectedDestinationIds,
32
+ currency,
33
+ locale,
34
+ onAddOnSelectionsChange,
35
+ }: PrivateShuttleAddOnsSectionProps) {
36
+ if (passengerCount <= 0 || addOns.length === 0) return null;
37
+
38
+ const animalsAddOn = addOns.find((addOn) => addOn.addOnId === 'addon_animals');
39
+ const isAnimalsSelected = addOnSelections.some((selection) => selection.addOnId === 'addon_animals');
40
+ const lunchAddOn = selectedDestinationIds.includes('emerald_lake')
41
+ ? addOns.find((addOn) => addOn.addOnId === 'addon_el_lunch')
42
+ : null;
43
+
44
+ return (
45
+ <div className={styles.section}>
46
+ {lunchAddOn && canUseMealDrinkSelector(lunchAddOn) ? (
47
+ <MealDrinkAddOnSelector
48
+ addOn={lunchAddOn}
49
+ selections={addOnSelections}
50
+ onSelectionsChange={(updater) =>
51
+ onAddOnSelectionsChange((prev) => updater(prev))
52
+ }
53
+ currency={currency}
54
+ locale={locale}
55
+ />
56
+ ) : null}
57
+ {animalsAddOn ? (
58
+ <div>
59
+ <label className={`${styles.sectionLabel} private-shuttle-section-label`}>
60
+ Traveling with animals?
61
+ </label>
62
+ <p className="text-sm text-stone-500 mb-2">
63
+ {animalsAddOn.description || 'Cleaning fee for traveling with animals'}
64
+ </p>
65
+ <div className="flex flex-wrap gap-2">
66
+ <button
67
+ type="button"
68
+ onClick={() =>
69
+ onAddOnSelectionsChange(
70
+ addOnSelections.filter((selection) => selection.addOnId !== 'addon_animals'),
71
+ )
72
+ }
73
+ className={`${styles.btnTime} private-shuttle-btn-time ${
74
+ !isAnimalsSelected ? styles.btnTimeSelected : styles.btnTimeDefault
75
+ }`}
76
+ >
77
+ No animals
78
+ </button>
79
+ <button
80
+ type="button"
81
+ onClick={() => {
82
+ if (isAnimalsSelected) return;
83
+ onAddOnSelectionsChange([
84
+ ...addOnSelections,
85
+ { addOnId: 'addon_animals', quantity: 1 },
86
+ ]);
87
+ }}
88
+ className={`${styles.btnTime} private-shuttle-btn-time flex items-center gap-2 ${
89
+ isAnimalsSelected ? styles.btnTimeSelected : styles.btnTimeDefault
90
+ }`}
91
+ >
92
+ <span>Yes, traveling with animals</span>
93
+ <span className="text-sm font-semibold opacity-90">
94
+ +{formatCurrencyAmount(animalsAddOn.price || 0, currency, locale)}
95
+ </span>
96
+ </button>
97
+ </div>
98
+ </div>
99
+ ) : null}
100
+ </div>
101
+ );
102
+ }