@ticketboothapp/booking 1.2.25 → 1.2.27

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 (142) hide show
  1. package/package.json +11 -29
  2. package/src/components/booking/AddOnsSection.tsx +2 -2
  3. package/src/components/booking/AdminPaymentChoiceModal.tsx +1 -1
  4. package/src/components/booking/BookingDialog.tsx +31 -13
  5. package/src/components/booking/BookingFlow.tsx +32 -27
  6. package/src/components/booking/BookingFlowCollage.tsx +10 -6
  7. package/src/components/booking/BookingFlowPlaceholder.tsx +1 -1
  8. package/src/components/booking/BookingFlowPreview.tsx +18 -9
  9. package/src/components/booking/BookingProductGrid.tsx +55 -19
  10. package/src/components/booking/Calendar.module.css +19 -4
  11. package/src/components/booking/Calendar.tsx +13 -8
  12. package/src/components/booking/CancellationPolicySelector.tsx +2 -2
  13. package/src/components/booking/ChangeBookingDialog.tsx +22 -12
  14. package/src/components/booking/CheckoutForm.module.css +10 -0
  15. package/src/components/booking/CheckoutForm.tsx +10 -2
  16. package/src/components/booking/CheckoutModal.tsx +16 -14
  17. package/src/components/booking/DapFlowCollage.tsx +5 -2
  18. package/src/components/booking/DapTourDescription.tsx +4 -4
  19. package/src/components/booking/DependentAddOnBookingDialog.tsx +23 -16
  20. package/src/components/booking/DependentAddOnPaymentForm.tsx +10 -7
  21. package/src/components/booking/ItineraryBox.tsx +6 -6
  22. package/src/components/booking/ItineraryBuilder.tsx +1 -1
  23. package/src/components/booking/MealDrinkAddOnSelector.tsx +3 -3
  24. package/src/components/booking/PickupLocationSelector.tsx +20 -18
  25. package/src/components/booking/PickupTimeSelector.tsx +3 -3
  26. package/src/components/booking/PriceBreakdown.tsx +5 -5
  27. package/src/components/booking/PriceSummary.module.css +7 -0
  28. package/src/components/booking/PriceSummary.tsx +8 -7
  29. package/src/components/booking/PrivateShuttleBookingFlow.tsx +28 -19
  30. package/src/components/booking/PromoCodeInput.module.css +31 -25
  31. package/src/components/booking/PromoCodeInput.tsx +36 -24
  32. package/src/components/booking/ReturnTimeSelector.tsx +3 -3
  33. package/src/components/booking/TermsAcceptance.tsx +7 -2
  34. package/src/components/booking/TicketSelector.tsx +1 -1
  35. package/src/components/booking/TourDescription.tsx +11 -6
  36. package/src/components/booking/booking-flow.css +65 -4
  37. package/src/hooks/useBookingSourceMetadataFromLocation.ts +1 -1
  38. package/src/hooks/useIsBookingLaunchLive.ts +1 -1
  39. package/src/index.ts +26 -64
  40. package/src/providers/booking-dialog-provider.tsx +62 -53
  41. package/src/runtime/BookingHostContext.tsx +39 -0
  42. package/src/runtime/index.ts +13 -0
  43. package/src/runtime/types.ts +86 -0
  44. package/tsconfig.json +3 -5
  45. package/src/assets/icons/minus.svg +0 -7
  46. package/src/assets/icons/partner-logos/getyourguide.svg +0 -8
  47. package/src/assets/icons/plus.svg +0 -3
  48. package/src/colours.css +0 -23
  49. package/src/components/BookingDetails.module.css +0 -1591
  50. package/src/components/BookingDetails.tsx +0 -2264
  51. package/src/components/BookingWidget.tsx +0 -305
  52. package/src/components/ManageBookingView.tsx +0 -437
  53. package/src/components/PhoneInputWithCountry.module.css +0 -131
  54. package/src/components/PhoneInputWithCountry.tsx +0 -44
  55. package/src/components/PickupLocationDialog.module.css +0 -360
  56. package/src/components/PickupLocationDialog.tsx +0 -357
  57. package/src/components/PostBookingDependentAddOnUpsell.module.css +0 -174
  58. package/src/components/PostBookingDependentAddOnUpsell.tsx +0 -407
  59. package/src/components/button.css +0 -245
  60. package/src/components/button.tsx +0 -152
  61. package/src/components/colorable-svg.tsx +0 -29
  62. package/src/components/image.css +0 -29
  63. package/src/components/image.tsx +0 -113
  64. package/src/components/partner/PartnerBookingPage.module.css +0 -130
  65. package/src/components/partner/PartnerBookingPage.tsx +0 -390
  66. package/src/components/partner/PartnerBookingPageWithBrowserMetadata.tsx +0 -45
  67. package/src/components/product-tag.module.css +0 -30
  68. package/src/components/product-tag.tsx +0 -34
  69. package/src/components/product-theme-pages/image-modal.tsx +0 -248
  70. package/src/components/product-theme-pages/photo-gallery.module.css +0 -200
  71. package/src/components/terms/TermsContent.tsx +0 -178
  72. package/src/components/value-pill.module.css +0 -59
  73. package/src/components/value-pill.tsx +0 -46
  74. package/src/constants/images.ts +0 -556
  75. package/src/constants/pill-values.ts +0 -210
  76. package/src/constants/products.ts +0 -155
  77. package/src/contexts/AvailabilitiesCacheContext.tsx +0 -125
  78. package/src/contexts/CompanyContext.tsx +0 -70
  79. package/src/data/dap-descriptions/session-couples-families-friends.en.json +0 -61
  80. package/src/data/dap-descriptions/session-elopements.en.json +0 -60
  81. package/src/data/dap-descriptions/session-proposals.en.json +0 -60
  82. package/src/data/product-descriptions/afternoon-delight.en.json +0 -35
  83. package/src/data/product-descriptions/emerald-lake-escape.en.json +0 -68
  84. package/src/data/product-descriptions/lake-louise-adventure.en.json +0 -74
  85. package/src/data/product-descriptions/moraine-lake-adventure.en.json +0 -78
  86. package/src/data/product-descriptions/moraine-lake-sunrise-lake-louise-golden-hour.en.json +0 -65
  87. package/src/data/product-descriptions/moraine-lake-sunrise.en.json +0 -64
  88. package/src/data/product-descriptions/private-tour.en.json +0 -80
  89. package/src/data/product-descriptions/two-lakes-combo.en.json +0 -65
  90. package/src/data/products-config.json +0 -101
  91. package/src/lib/analytics.ts +0 -197
  92. package/src/lib/booking/booking-source.ts +0 -51
  93. package/src/lib/booking/checkout-breakdown.ts +0 -69
  94. package/src/lib/booking/correlation-id.ts +0 -46
  95. package/src/lib/booking/i18n/config.ts +0 -21
  96. package/src/lib/booking/i18n/index.tsx +0 -144
  97. package/src/lib/booking/i18n/messages/en.json +0 -236
  98. package/src/lib/booking/i18n/messages/fr.json +0 -236
  99. package/src/lib/booking/itinerary-display.ts +0 -36
  100. package/src/lib/booking/itinerary-labels.ts +0 -70
  101. package/src/lib/booking/location-calculations.ts +0 -43
  102. package/src/lib/booking/location-utils.ts +0 -165
  103. package/src/lib/booking/map-utils.ts +0 -153
  104. package/src/lib/booking/marker-icons.ts +0 -113
  105. package/src/lib/booking/normalize-booking-product-id.ts +0 -21
  106. package/src/lib/booking/pickup-location-types.ts +0 -25
  107. package/src/lib/booking/places-api.ts +0 -154
  108. package/src/lib/booking/pricing.ts +0 -466
  109. package/src/lib/booking/product-option-id.ts +0 -35
  110. package/src/lib/booking/source-metadata.ts +0 -226
  111. package/src/lib/booking/sunday-week.ts +0 -14
  112. package/src/lib/booking/theme.ts +0 -83
  113. package/src/lib/booking/trace-context.ts +0 -62
  114. package/src/lib/booking/utils.ts +0 -9
  115. package/src/lib/booking-api.ts +0 -1793
  116. package/src/lib/booking-constants.ts +0 -23
  117. package/src/lib/booking-ref.ts +0 -13
  118. package/src/lib/booking-types.ts +0 -36
  119. package/src/lib/currency.ts +0 -81
  120. package/src/lib/dap-descriptions.ts +0 -50
  121. package/src/lib/dap-itinerary-preview.ts +0 -315
  122. package/src/lib/dependent-add-on-api.ts +0 -434
  123. package/src/lib/env.ts +0 -96
  124. package/src/lib/firebase.ts +0 -20
  125. package/src/lib/job-application-api.ts +0 -83
  126. package/src/lib/manage-booking-embed-print.ts +0 -16
  127. package/src/lib/manage-booking-post-checkout.ts +0 -68
  128. package/src/lib/photo-dap-config.ts +0 -228
  129. package/src/lib/photo-packages.ts +0 -75
  130. package/src/lib/pickup/map-utils.ts +0 -56
  131. package/src/lib/pickup/marker-icons.ts +0 -19
  132. package/src/lib/product-descriptions.ts +0 -66
  133. package/src/lib/products-config.ts +0 -73
  134. package/src/providers/dependent-add-on-dialog-provider.tsx +0 -105
  135. package/src/radius.css +0 -5
  136. package/src/spacing.css +0 -7
  137. package/src/strings/en.json +0 -1774
  138. package/src/strings/es.json +0 -1573
  139. package/src/strings/fr.json +0 -1573
  140. package/src/strings/index.js +0 -23
  141. package/src/text-style.css +0 -56
  142. package/src/utils/currency-converter.ts +0 -101
@@ -23,23 +23,23 @@ import {
23
23
  isInsufficientCapacityReserveError,
24
24
  describePrivateShuttleCapacityConflictMessage,
25
25
  reportReserveCapacityConflictClientContext,
26
- } from '@/lib/booking-api';
26
+ } from '../../../../../src/lib/booking-api';
27
27
  import {
28
28
  EARLIEST_AVAILABILITY_DATE,
29
29
  LATEST_AVAILABILITY_DATE,
30
30
  INITIAL_FETCH_WEEKS,
31
- } from '@/lib/booking-constants';
32
- import { formatCurrencyAmount } from '@/lib/currency';
33
- import { formatBookingRefForDisplay } from '@/lib/booking-ref';
34
- import { buildCheckoutBreakdown } from '@/lib/booking/checkout-breakdown';
35
- import type { PricingConfig, PrecomputedPricesByCategory } from '@/lib/booking-api';
31
+ } from '../../../../../src/lib/booking-constants';
32
+ import { formatCurrencyAmount } from '../../../../../src/lib/currency';
33
+ import { formatBookingRefForDisplay } from '../../../../../src/lib/booking-ref';
34
+ import { buildCheckoutBreakdown } from '../../../../../src/lib/booking/checkout-breakdown';
35
+ import type { PricingConfig, PrecomputedPricesByCategory } from '../../../../../src/lib/booking-api';
36
36
  import { Calendar } from './Calendar';
37
37
  import { PickupLocationSelector } from './PickupLocationSelector';
38
- import { useTranslations, useLocale } from '@/lib/booking/i18n';
38
+ import { useTranslations, useLocale } from '../../../../../src/lib/booking/i18n';
39
39
  import { type Currency } from './CurrencySwitcher';
40
- import { useCompanyTimezone } from '@/contexts/CompanyContext';
41
- import { useBookingApp } from '@/contexts/BookingAppContext';
42
- import { useAvailabilitiesCache, buildAvailabilitiesCacheKey } from '@/contexts/AvailabilitiesCacheContext';
40
+ import { useCompanyTimezone } from '../../../../../src/contexts/CompanyContext';
41
+ import { useBookingApp } from '../../contexts/BookingAppContext';
42
+ import { useAvailabilitiesCache, buildAvailabilitiesCacheKey } from '../../../../../src/contexts/AvailabilitiesCacheContext';
43
43
  import { CheckoutModal, type CheckoutModalLineItem } from './CheckoutModal';
44
44
  import { CancellationPolicySelector } from './CancellationPolicySelector';
45
45
  import { PriceSummary } from './PriceSummary';
@@ -49,18 +49,16 @@ import { MealDrinkAddOnSelector, canUseMealDrinkSelector } from './MealDrinkAddO
49
49
  import { AdminPaymentChoiceModal } from './AdminPaymentChoiceModal';
50
50
  import { BookingFlowCollage } from './BookingFlowCollage';
51
51
  import { TourDescription } from './TourDescription';
52
- import { getProductByIdOrSlug } from '@/lib/products-config';
53
- import { getProducts } from '@/constants/products';
54
- import defaultStrings from '@/strings';
55
- import { trackViewItem } from '@/lib/analytics';
52
+ import { useBookingHost } from '../../runtime';
56
53
  import styles from './PrivateShuttleBookingFlow.module.css';
57
54
  import {
58
55
  buildBookingSourceContext,
59
56
  inferClientBookingSourceFromProductIds,
60
57
  type BookingSourceMetadata,
61
- } from '@/lib/booking/source-metadata';
58
+ } from '../../../../../src/lib/booking/source-metadata';
59
+ import type { VideoSources } from '../../../../../src/constants/products';
62
60
  import type { BookingFlowUiOptions } from './booking-flow-ui';
63
- import { BOOKING_FLOW_ABANDON_EVENT } from '@/providers/booking-dialog-provider';
61
+ import { BOOKING_FLOW_ABANDON_EVENT } from '../../providers/booking-dialog-provider';
64
62
 
65
63
  interface PrivateShuttleBookingFlowProps {
66
64
  product: Product;
@@ -154,6 +152,7 @@ export function PrivateShuttleBookingFlow({
154
152
  availabilityCancellationPolicyProfileId,
155
153
  initialValues,
156
154
  }: PrivateShuttleBookingFlowProps) {
155
+ const { strings: defaultStrings, analytics, catalog } = useBookingHost();
157
156
  const { t } = useTranslations();
158
157
  const { locale } = useLocale();
159
158
  const companyTimezone = useCompanyTimezone();
@@ -296,7 +295,7 @@ export function PrivateShuttleBookingFlow({
296
295
  hasFiredViewItem.current = true;
297
296
  const id = productId || product.productId;
298
297
  const price = product.minPriceByCurrency?.[currency] ?? 0;
299
- trackViewItem(id, product.name, price, currency);
298
+ analytics.trackViewItem(id, product.name, price, currency);
300
299
  }
301
300
  }, [product, productId, currency]);
302
301
 
@@ -1773,8 +1772,18 @@ export function PrivateShuttleBookingFlow({
1773
1772
  );
1774
1773
  }
1775
1774
 
1776
- const config = productId ? getProductByIdOrSlug(productId) : null;
1777
- const displayProducts = getProducts(defaultStrings);
1775
+ const config = productId
1776
+ ? (catalog.getProductByIdOrSlug(productId) as {
1777
+ display?: {
1778
+ collageImageIds?: string[];
1779
+ imageIds?: string[];
1780
+ };
1781
+ } | null)
1782
+ : null;
1783
+ const displayProducts = catalog.getProducts(defaultStrings) as Record<
1784
+ string,
1785
+ { id: string; videoUrl?: VideoSources }
1786
+ >;
1778
1787
  const displayProduct = Object.values(displayProducts).find((p) => p.id === productId);
1779
1788
  const collageImageIds = config?.display?.collageImageIds ?? config?.display?.imageIds ?? [];
1780
1789
  const hasVideo = !!displayProduct?.videoUrl;
@@ -67,13 +67,13 @@
67
67
  }
68
68
  }
69
69
 
70
- /* Box with icons inside (x and check) */
70
+ /* Single bordered field — icons overlay the right padding (original look, no nested box). */
71
71
  .input {
72
72
  width: 100%;
73
73
  min-width: 0;
74
- padding: 0.375rem 2.25rem 0.375rem 0.5rem;
74
+ padding: 0.5rem 0.625rem;
75
75
  font-size: 0.875rem;
76
- border-radius: 0.25rem;
76
+ border-radius: 0.5rem;
77
77
  border: 1px solid var(--booking-stone-300, #d6d3d1);
78
78
  background: #fff;
79
79
  color: var(--booking-stone-900, #1c1917);
@@ -85,20 +85,37 @@
85
85
  border-color: var(--booking-stone-500, #78716c);
86
86
  }
87
87
 
88
- .input:read-only {
88
+ .inputMuted {
89
89
  background: var(--booking-stone-50, #fafaf9);
90
90
  cursor: default;
91
- padding-right: 3.5rem;
92
91
  }
93
92
 
94
- /* X and check icons inside the box - dashboard style */
95
- .removeBtn {
93
+ .inputPadSingle {
94
+ padding-right: 2rem;
95
+ }
96
+
97
+ .inputPadPair {
98
+ padding-right: 3.375rem;
99
+ }
100
+
101
+ .inputSuffix {
96
102
  position: absolute;
97
103
  right: 0.25rem;
98
104
  top: 50%;
99
105
  transform: translateY(-50%);
100
- width: 1.5rem;
101
- height: 1.5rem;
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 0.125rem;
109
+ pointer-events: none;
110
+ }
111
+
112
+ .inputSuffix button {
113
+ pointer-events: auto;
114
+ }
115
+
116
+ .removeBtn {
117
+ width: 1.375rem;
118
+ height: 1.375rem;
102
119
  padding: 0;
103
120
  border-radius: 9999px;
104
121
  color: var(--booking-stone-500, #78716c);
@@ -108,6 +125,7 @@
108
125
  display: flex;
109
126
  align-items: center;
110
127
  justify-content: center;
128
+ flex-shrink: 0;
111
129
  }
112
130
 
113
131
  .removeBtn:hover {
@@ -116,15 +134,12 @@
116
134
  }
117
135
 
118
136
  .loading {
119
- position: absolute;
120
- right: 0.5rem;
121
- top: 50%;
122
- transform: translateY(-50%);
123
137
  width: 1.25rem;
124
138
  height: 1.25rem;
125
139
  border-radius: 9999px;
126
140
  background: var(--booking-stone-100, #f5f5f4);
127
141
  animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
142
+ flex-shrink: 0;
128
143
  }
129
144
 
130
145
  @keyframes pulse {
@@ -133,10 +148,6 @@
133
148
  }
134
149
 
135
150
  .errorIcon {
136
- position: absolute;
137
- right: 0.5rem;
138
- top: 50%;
139
- transform: translateY(-50%);
140
151
  width: 1.25rem;
141
152
  height: 1.25rem;
142
153
  border-radius: 9999px;
@@ -145,16 +156,12 @@
145
156
  display: flex;
146
157
  align-items: center;
147
158
  justify-content: center;
159
+ flex-shrink: 0;
148
160
  }
149
161
 
150
- /* Check icon - inside box, next to remove btn */
151
162
  .appliedBadge {
152
- position: absolute;
153
- right: 2rem;
154
- top: 50%;
155
- transform: translateY(-50%);
156
- width: 1.5rem;
157
- height: 1.5rem;
163
+ width: 1.375rem;
164
+ height: 1.375rem;
158
165
  border-radius: 9999px;
159
166
  background: var(--booking-emerald-500, #10b981);
160
167
  color: #fff;
@@ -163,4 +170,3 @@
163
170
  justify-content: center;
164
171
  flex-shrink: 0;
165
172
  }
166
-
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { Check, X } from 'lucide-react';
4
- import { formatCurrencyAmount } from '@/lib/currency';
4
+ import { formatCurrencyAmount } from '../../../../../src/lib/currency';
5
5
  import type { Currency } from './CurrencySwitcher';
6
6
  import styles from './PromoCodeInput.module.css';
7
7
 
@@ -36,6 +36,11 @@ export function PromoCodeInput({
36
36
  onRemove,
37
37
  locked = false,
38
38
  }: PromoCodeInputProps) {
39
+ const showSuffix = !!(appliedPromoCode || promoCodeValidating || promoCodeError);
40
+ const suffixPadding =
41
+ appliedPromoCode && !locked ? styles.inputPadPair : showSuffix ? styles.inputPadSingle : '';
42
+ const inputMuted = locked || appliedPromoCode ? styles.inputMuted : '';
43
+
39
44
  return (
40
45
  <div className={styles.promoRow}>
41
46
  <label htmlFor="booking-promo-code" className={styles.promoLabel}>
@@ -59,31 +64,38 @@ export function PromoCodeInput({
59
64
  autoComplete="off"
60
65
  readOnly={locked || !!appliedPromoCode}
61
66
  disabled={locked}
62
- className={styles.input}
67
+ className={[styles.input, suffixPadding, inputMuted].filter(Boolean).join(' ')}
63
68
  />
64
- {appliedPromoCode ? (
65
- <>
66
- <span className={styles.appliedBadge} aria-label={t('booking.promoApplied', { code: appliedPromoCode })}>
67
- <Check className="w-3.5 h-3.5" strokeWidth={3} />
68
- </span>
69
- {!locked && (
70
- <button
71
- type="button"
72
- onClick={onRemove}
73
- className={styles.removeBtn}
74
- aria-label={t('booking.removePromo')}
75
- >
76
- <X className="w-4 h-4" strokeWidth={2.5} />
77
- </button>
69
+ {showSuffix && (
70
+ <div className={styles.inputSuffix}>
71
+ {appliedPromoCode ? (
72
+ <>
73
+ <span
74
+ className={styles.appliedBadge}
75
+ aria-label={t('booking.promoApplied', { code: appliedPromoCode })}
76
+ >
77
+ <Check className="w-3.5 h-3.5" strokeWidth={3} />
78
+ </span>
79
+ {!locked && (
80
+ <button
81
+ type="button"
82
+ onClick={onRemove}
83
+ className={styles.removeBtn}
84
+ aria-label={t('booking.removePromo')}
85
+ >
86
+ <X className="w-4 h-4" strokeWidth={2.5} />
87
+ </button>
88
+ )}
89
+ </>
90
+ ) : promoCodeValidating ? (
91
+ <span className={styles.loading} aria-hidden />
92
+ ) : (
93
+ <span className={styles.errorIcon} aria-label={promoCodeError}>
94
+ <X className="w-3 h-3" strokeWidth={3} />
95
+ </span>
78
96
  )}
79
- </>
80
- ) : promoCodeValidating ? (
81
- <span className={styles.loading} aria-hidden />
82
- ) : promoCodeError ? (
83
- <span className={styles.errorIcon} aria-label={promoCodeError}>
84
- <X className="w-3 h-3" strokeWidth={3} />
85
- </span>
86
- ) : null}
97
+ </div>
98
+ )}
87
99
  </div>
88
100
  {promoDiscountAmount > 0 && (
89
101
  <span className={styles.promoDiscount}>
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { parseISO } from 'date-fns';
4
4
  import { formatInTimeZone } from 'date-fns-tz';
5
- import { formatCurrencyAmount } from '@/lib/currency';
6
- import type { ReturnOption } from '@/lib/booking-api';
5
+ import { formatCurrencyAmount } from '../../../../../src/lib/currency';
6
+ import type { ReturnOption } from '../../../../../src/lib/booking-api';
7
7
  import type { Currency } from './CurrencySwitcher';
8
8
  import styles from './ReturnTimeSelector.module.css';
9
9
 
@@ -122,7 +122,7 @@ export function ReturnTimeSelector({
122
122
  {t('booking.soldOut')}
123
123
  </div>
124
124
  )}
125
- {isInsufficientForParty && !isAdmin && (
125
+ {isInsufficientForParty && !isSoldOut && !isAdmin && (
126
126
  <div className={styles.soldOut}>
127
127
  {`Only ${returnOption.vacancies} spot${returnOption.vacancies === 1 ? '' : 's'} left, decrease your ticket count below to select this time`}
128
128
  </div>
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState } from 'react';
4
- import { TermsContent } from '@/components/terms/TermsContent';
4
+ import { useBookingHost } from '../../runtime';
5
5
 
6
6
  export interface TermsAcceptanceProps {
7
7
  checked: boolean;
@@ -24,8 +24,13 @@ export function TermsAcceptance({
24
24
  t,
25
25
  termsContent,
26
26
  }: TermsAcceptanceProps) {
27
+ const { slots } = useBookingHost();
28
+ const TermsContent = slots.TermsContent;
27
29
  const [modalOpen, setModalOpen] = useState(false);
28
- const content = termsContent ?? <TermsContent className="text-xs [&_h1]:text-base [&_h2]:text-sm [&_h3]:text-xs [&_p]:text-xs" />;
30
+ const content =
31
+ termsContent ?? (
32
+ <TermsContent className="text-xs [&_h1]:text-base [&_h2]:text-sm [&_h3]:text-xs [&_p]:text-xs" />
33
+ );
29
34
 
30
35
  return (
31
36
  <>
@@ -4,7 +4,7 @@ import { useMemo } from 'react';
4
4
  import { parseISO } from 'date-fns';
5
5
  import { enUS, fr } from 'date-fns/locale';
6
6
  import { formatInTimeZone } from 'date-fns-tz';
7
- import { formatCurrencyAmount } from '@/lib/currency';
7
+ import { formatCurrencyAmount } from '../../../../../src/lib/currency';
8
8
  import type { Currency } from './CurrencySwitcher';
9
9
  import styles from './TicketSelector.module.css';
10
10
 
@@ -1,10 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useMemo } from 'react';
4
- import { useTranslations, useLocale } from '@/lib/booking/i18n';
5
- import { getProductDescription } from '@/lib/product-descriptions';
6
- import PlusIcon from '@/assets/icons/plus.svg';
7
- import MinusIcon from '@/assets/icons/minus.svg';
4
+ import { useTranslations, useLocale } from '../../../../../src/lib/booking/i18n';
5
+ import { useBookingHost } from '../../runtime';
8
6
  import styles from './TourDescription.module.css';
9
7
 
10
8
  export interface TourDescriptionReview {
@@ -126,6 +124,9 @@ export function TourDescription({
126
124
  sections: sectionsProp,
127
125
  defaultExpanded = false,
128
126
  }: TourDescriptionProps) {
127
+ const { catalog, slots } = useBookingHost();
128
+ const PlusIcon = slots.PlusIcon;
129
+ const MinusIcon = slots.MinusIcon;
129
130
  const { t } = useTranslations();
130
131
  const { locale: contextLocale } = useLocale();
131
132
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
@@ -135,10 +136,14 @@ export function TourDescription({
135
136
 
136
137
  const loadedContent = useMemo(() => {
137
138
  if (productSlug && locale) {
138
- return getProductDescription(productSlug, locale);
139
+ return catalog.getProductDescription(productSlug, locale) as {
140
+ paragraphs?: string[];
141
+ review?: TourDescriptionReview;
142
+ sections?: TourDescriptionSection[];
143
+ } | null;
139
144
  }
140
145
  return null;
141
- }, [productSlug, locale]);
146
+ }, [productSlug, locale, catalog]);
142
147
 
143
148
  const paragraphs = paragraphsProp ?? loadedContent?.paragraphs ?? [];
144
149
  const review = reviewProp ?? loadedContent?.review;
@@ -860,14 +860,37 @@
860
860
  }
861
861
 
862
862
  /* ========== Ticket +/- buttons - round ========== */
863
+ /* Explicit border/background: partner portal (HeroUI/host) can strip CSS-module button chrome; higher specificity below. */
863
864
  .booking-flow-preflight [class*="TicketSelector_qtyBtnDecrement"],
864
- .booking-flow-preflight [class*="TicketSelector_qtyBtnIncrement"] {
865
+ .booking-flow-preflight [class*="TicketSelector_qtyBtnIncrement"],
866
+ .booking-flow-root [class*="TicketSelector_qtyBtnDecrement"]:not(:disabled),
867
+ .booking-flow-root [class*="TicketSelector_qtyBtnIncrement"]:not(:disabled) {
865
868
  width: 2.5rem !important;
866
869
  height: 2.5rem !important;
867
870
  border-radius: 9999px !important;
868
871
  display: flex !important;
869
872
  align-items: center !important;
870
873
  justify-content: center !important;
874
+ border: 1px solid var(--booking-stone-300, #d6d3d1) !important;
875
+ background-color: #fff !important;
876
+ color: var(--booking-stone-600, #57534e) !important;
877
+ -webkit-appearance: none !important;
878
+ appearance: none !important;
879
+ }
880
+ .booking-flow-preflight [class*="TicketSelector_qtyBtnDecrement"]:disabled,
881
+ .booking-flow-preflight [class*="TicketSelector_qtyBtnIncrement"]:disabled,
882
+ .booking-flow-root [class*="TicketSelector_qtyBtnDecrement"]:disabled,
883
+ .booking-flow-root [class*="TicketSelector_qtyBtnIncrement"]:disabled {
884
+ border: 1px solid var(--booking-stone-200, #e7e5e4) !important;
885
+ background-color: var(--booking-stone-100, #f5f5f4) !important;
886
+ color: var(--booking-stone-400, #a8a29e) !important;
887
+ opacity: 0.5 !important;
888
+ }
889
+ .booking-flow-preflight [class*="TicketSelector_qtyBtnOverbook"],
890
+ .booking-flow-root [class*="TicketSelector_qtyBtnOverbook"] {
891
+ border: 2px solid #ef4444 !important;
892
+ background-color: #fee2e2 !important;
893
+ color: #b91c1c !important;
871
894
  }
872
895
 
873
896
  /* ========== Deposit notice - keep text small (preflight can inherit large sizes) ========== */
@@ -876,7 +899,7 @@
876
899
  font-size: 0.75rem !important;
877
900
  }
878
901
 
879
- /* ========== Receipt horizontal lines - preflight sets border-width: 0, restore separators ========== */
902
+ /* ========== Receipt / utilities: restore Tailwind border widths inside scoped preflight ========== */
880
903
  .booking-flow-preflight .border-t {
881
904
  border-top-width: 1px !important;
882
905
  }
@@ -884,12 +907,50 @@
884
907
  border-bottom-width: 1px !important;
885
908
  }
886
909
 
910
+ /* PriceSummary.ruleAbove — explicit module border beats preflight `* { border-width: 0 }` */
911
+ .booking-flow-preflight [class*="PriceSummary_ruleAbove"],
912
+ .booking-flow-root [class*="PriceSummary_ruleAbove"] {
913
+ border-top-width: 1px !important;
914
+ border-top-style: solid !important;
915
+ border-top-color: var(--booking-stone-200, #e7e5e4) !important;
916
+ }
917
+
918
+ /* Line above first receipt row (above ADULT etc.): CheckoutForm / private shuttle section wrappers */
919
+ .booking-flow-preflight [class*="CheckoutForm_section"],
920
+ .booking-flow-root [class*="CheckoutForm_section"],
921
+ .booking-flow-preflight [class*="PrivateShuttleBookingFlow_section"],
922
+ .booking-flow-root [class*="PrivateShuttleBookingFlow_section"] {
923
+ border-top-width: 1px !important;
924
+ border-top-style: solid !important;
925
+ border-top-color: var(--booking-stone-200, #e7e5e4) !important;
926
+ }
927
+
928
+ /* Line above “Promo / voucher / gift card” — PromoCodeInput.promoRow */
929
+ .booking-flow-preflight [class*="PromoCodeInput_promoRow"],
930
+ .booking-flow-root [class*="PromoCodeInput_promoRow"] {
931
+ border-top-width: 1px !important;
932
+ border-top-style: solid !important;
933
+ border-top-color: var(--booking-stone-200, #e7e5e4) !important;
934
+ }
935
+
887
936
  /* ========== Input fields - padding ========== */
888
937
  .booking-flow-preflight [class*="CheckoutForm_input"] {
889
938
  padding: 0.875rem 1.25rem !important;
890
939
  }
891
- .booking-flow-preflight [class*="PromoCodeInput_input"] {
892
- padding: 0.375rem 3.5rem 0.375rem 0.5rem !important;
940
+ /* Promo field: scope to <input> only — [class*="PromoCodeInput_input"] also matches inputWrap (…inputWrap…) and was drawing a second box */
941
+ .booking-flow-preflight input[class*="PromoCodeInput_input"] {
942
+ padding: 0.5rem 0.625rem !important;
943
+ border: 1px solid var(--booking-stone-300) !important;
944
+ border-radius: 0.5rem !important;
945
+ }
946
+ .booking-flow-preflight input[class*="PromoCodeInput_inputPadSingle"] {
947
+ padding-right: 2rem !important;
948
+ }
949
+ .booking-flow-preflight input[class*="PromoCodeInput_inputPadPair"] {
950
+ padding-right: 3.375rem !important;
951
+ }
952
+ .booking-flow-preflight input[class*="PromoCodeInput_inputMuted"] {
953
+ background-color: var(--booking-stone-50, #fafaf9) !important;
893
954
  }
894
955
  /* PrivateShuttleBookingFlow inputs - preflight resets padding (exclude passengerSelect, has its own) */
895
956
  .booking-flow-preflight [class*="PrivateShuttleBookingFlow_input"]:not([class*="passengerSelect"]) {
@@ -5,7 +5,7 @@ import { usePathname } from 'next/navigation';
5
5
  import {
6
6
  buildBookingSourceMetadataFromLocation,
7
7
  type BookingSourceMetadata,
8
- } from '@/lib/booking/source-metadata';
8
+ } from '../../../../src/lib/booking/source-metadata';
9
9
 
10
10
  /**
11
11
  * Re-reads URL-derived booking attribution when the **path** changes. Query-only updates on the
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect } from 'react';
4
- import { BOOKING_LAUNCH_AT } from '@/lib/booking-constants';
4
+ import { BOOKING_LAUNCH_AT } from '../../../../src/lib/booking-constants';
5
5
 
6
6
  /**
7
7
  * Returns whether the full booking flow is live (past launch time).
package/src/index.ts CHANGED
@@ -11,37 +11,35 @@ export {
11
11
  type PublicStaffPortalSignInOption,
12
12
  } from './public-partners';
13
13
 
14
- export {
15
- BookingAppProvider,
16
- useBookingApp,
17
- type BookingAppMode,
18
- type ViewerRole,
19
- type BookingAppPermissions,
20
- type BookingAppContextValue,
21
- type BookingAppProviderProps,
22
- type ManageParams,
14
+ /** Canonical Via Via booking UI — same modules as `@/components/booking/*` on the site. */
15
+ export { BookingFlow } from './components/booking/BookingFlow';
16
+ export { PrivateShuttleBookingFlow } from './components/booking/PrivateShuttleBookingFlow';
17
+ export type { BookingFlowUiOptions } from './components/booking/booking-flow-ui';
18
+ export { default as BookingDialog } from './components/booking/BookingDialog';
19
+ export { default as BookingProductGrid } from './components/booking/BookingProductGrid';
20
+
21
+ export type {
22
+ BookingAppMode,
23
+ ViewerRole,
24
+ BookingAppPermissions,
25
+ ManageParams,
26
+ BookingAppContextValue,
27
+ BookingAppProviderProps,
23
28
  } from './contexts/BookingAppContext';
29
+ export { BookingAppProvider, useBookingApp } from './contexts/BookingAppContext';
24
30
 
31
+ export type {
32
+ BookingRuntimeEnv,
33
+ BookingRuntimeValue,
34
+ BookingRuntimeAnalytics,
35
+ BookingRuntimeSlots,
36
+ BookingRuntimeCatalog,
37
+ } from './runtime/types';
25
38
  export {
26
- PARTNER_EMBEDDED_BOOKING_FLOW_UI_BASE,
27
- type BookingFlowUiOptions,
28
- } from './components/booking/booking-flow-ui';
29
-
30
- export {
31
- CompanyProvider,
32
- useCompany,
33
- useCompanyTimezone,
34
- } from './contexts/CompanyContext';
35
-
36
- export { type Company } from './lib/booking-api';
37
-
38
- export {
39
- AVAILABILITIES_CACHE_TTL_MS,
40
- AvailabilitiesCacheProvider,
41
- useAvailabilitiesCache,
42
- buildAvailabilitiesCacheKey,
43
- type CachedAvailabilitiesData,
44
- } from './contexts/AvailabilitiesCacheContext';
39
+ BookingHostProvider,
40
+ useBookingHost,
41
+ useBookingHostOptional,
42
+ } from './runtime';
45
43
 
46
44
  export {
47
45
  BookingDialogProvider,
@@ -53,39 +51,3 @@ export {
53
51
  type BookingScreen,
54
52
  type ProductGridRestoreState,
55
53
  } from './providers/booking-dialog-provider';
56
-
57
- export {
58
- setPartnerPortalBookingJwtGetter,
59
- type Product,
60
- } from './lib/booking-api';
61
-
62
- export {
63
- KnownBookingSource,
64
- DEFAULT_BOOKING_SOURCE,
65
- PARTNER_PORTAL_BOOKING_SOURCE,
66
- inferClientBookingSourceFromProductIds,
67
- mergedMetadataImpliesPartnerPortal,
68
- isPublicPartnerMarketingPath,
69
- isDedicatedPartnerBookingPortalHost,
70
- buildBookingSourceMetadataFromLocation,
71
- mergeBookingSourceMetadata,
72
- buildBookingSourceContext,
73
- type BookingSourceMetadata,
74
- type BuildBookingSourceContextOptions,
75
- } from './lib/booking/source-metadata';
76
-
77
- export {
78
- default as PartnerBookingPageWithBrowserMetadata,
79
- type PartnerBookingPageWithBrowserMetadataProps,
80
- } from './components/partner/PartnerBookingPageWithBrowserMetadata';
81
-
82
- export {
83
- BookingWidget,
84
- type BookingWidgetProps,
85
- } from './components/BookingWidget';
86
-
87
- export {
88
- ManageBookingView,
89
- type ManageBookingViewProps,
90
- type StaffBookingAttribution,
91
- } from './components/ManageBookingView';