@ticketboothapp/booking 1.2.25-rc.0 → 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 -302
  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
@@ -1,245 +0,0 @@
1
- .button {
2
- padding: 8px 16px;
3
- border-radius: 24px;
4
- border: none;
5
- font-size: 1rem;
6
- cursor: pointer;
7
- transition: all 0.2s ease-in-out;
8
- font-weight: 500;
9
- position: relative;
10
- overflow: hidden;
11
- z-index: 1;
12
- font-family: 'Poppins', sans-serif;
13
- font-weight: 700;
14
- text-transform: lowercase;
15
- display: inline-block;
16
- }
17
-
18
- .button-primary {
19
- background-color: var(--accent-orange);
20
- color: var(--accent-white);
21
- }
22
-
23
- .button-secondary {
24
- background-color: var(--accent-white);
25
- color: var(--accent-orange);
26
- }
27
-
28
- .button-disabled {
29
- background-color: var(--grey-text);
30
- color: var(--accent-white);
31
- cursor: not-allowed;
32
- }
33
-
34
- .button-disabled:hover {
35
- background-color: var(--grey-text);
36
- color: var(--accent-white) !important;
37
- }
38
-
39
- .button-outline {
40
- background-color: transparent;
41
- color: var(--accent-white);
42
- border: 2px solid var(--accent-white);
43
- box-sizing: border-box;
44
- padding: 6px 14px;
45
- }
46
-
47
- .button-large {
48
- font-size: 1.2rem;
49
- padding: 1rem 2rem;
50
- border-radius: 40px;
51
- }
52
-
53
- /* Desktop hover */
54
- @media (min-width: 1024px) {
55
- .button::before {
56
- content: '';
57
- position: absolute;
58
- top: 0;
59
- left: -100%;
60
- width: 100%;
61
- height: 100%;
62
- border-radius: 24px;
63
- transition: all 0.3s ease-in-out;
64
- z-index: -1;
65
- }
66
-
67
- .button-primary:hover::before {
68
- left: 0;
69
- }
70
-
71
- .button-primary.hover-white::before {
72
- background-color: var(--accent-white);
73
- }
74
-
75
- .button-primary.hover-turquoise::before {
76
- background-color: var(--accent-turquoise);
77
- }
78
-
79
- .button-primary.hover-orange::before {
80
- background-color: var(--accent-orange);
81
- }
82
-
83
- .button-primary.hover-orange:hover {
84
- color: var(--accent-white);
85
- }
86
-
87
- .button-primary.hover-turquoise:hover {
88
- color: var(--accent-white);
89
- }
90
-
91
- .button-secondary:hover::before {
92
- left: 0;
93
- }
94
-
95
- .button-secondary::before {
96
- background-color: var(--accent-turquoise);
97
- }
98
-
99
- .button-secondary.hover-orange::before {
100
- background-color: var(--accent-orange);
101
- }
102
-
103
- .button-secondary.hover-orange:hover {
104
- color: var(--accent-white) !important;
105
- }
106
-
107
- .button-secondary:hover {
108
- color: var(--accent-white) !important;
109
- }
110
-
111
- .button-outline::before {
112
- background-color: var(--accent-white);
113
- }
114
-
115
- .button-outline:hover::before {
116
- left: 0;
117
- }
118
-
119
- .button:hover {
120
- color: var(--accent-orange);
121
- }
122
- }
123
-
124
- /* Focus state for accessibility */
125
- .button:focus {
126
- outline: 2px solid var(--accent-orange);
127
- outline-offset: 2px;
128
- }
129
-
130
- .button-menu {
131
- background-color: var(--accent-orange);
132
- border-radius: 50px;
133
- padding: 8px 20px;
134
- display: flex;
135
- align-items: center;
136
- gap: 8px;
137
- }
138
-
139
- .button-menu .menu-text {
140
- color: white;
141
- font-weight: 400;
142
- text-transform: lowercase;
143
- font-size: 0.8rem;
144
- padding: 0.2rem;
145
- }
146
-
147
- .button-menu .menu-icon {
148
- display: flex;
149
- flex-direction: column;
150
- gap: 3px;
151
- position: relative;
152
- width: 12px;
153
- height: 12px;
154
- transition: transform 0.3s ease;
155
- }
156
-
157
- .button-menu .menu-icon span {
158
- display: block;
159
- width: 12px;
160
- height: 1.5px;
161
- background-color: white;
162
- border-radius: 2px;
163
- position: absolute;
164
- transition: transform 0.3s ease, opacity 0.3s ease;
165
- }
166
-
167
- /* Position the lines */
168
- .button-menu .menu-icon span:nth-child(1) {
169
- top: 0;
170
- }
171
-
172
- .button-menu .menu-icon span:nth-child(2) {
173
- top: 50%;
174
- transform: translateY(-50%);
175
- }
176
-
177
- .button-menu .menu-icon span:nth-child(3) {
178
- bottom: 0;
179
- }
180
-
181
- /* X animation when open with full rotation */
182
- .button-menu.open .menu-icon {
183
- transform: rotate(360deg);
184
- }
185
-
186
- .button-menu.open .menu-icon span:nth-child(1) {
187
- top: 50%;
188
- transform: translateY(-50%) rotate(45deg);
189
- }
190
-
191
- .button-menu.open .menu-icon span:nth-child(2) {
192
- opacity: 0;
193
- }
194
-
195
- .button-menu.open .menu-icon span:nth-child(3) {
196
- top: 50%;
197
- transform: translateY(-50%) rotate(-45deg);
198
- }
199
-
200
- /* Override booking-flow-preflight so Button component styles apply inside the booking flow */
201
- .booking-flow-preflight button.button {
202
- padding: 8px 16px;
203
- border-radius: 24px;
204
- border: none;
205
- font-size: 1rem;
206
- cursor: pointer;
207
- transition: all 0.2s ease-in-out;
208
- font-weight: 700;
209
- position: relative;
210
- overflow: hidden;
211
- z-index: 1;
212
- font-family: 'Poppins', sans-serif;
213
- text-transform: lowercase;
214
- display: inline-block;
215
- }
216
-
217
- .booking-flow-preflight button.button-primary {
218
- background-color: var(--accent-orange);
219
- color: var(--accent-white);
220
- }
221
-
222
- .booking-flow-preflight button.button-secondary {
223
- background-color: var(--accent-white);
224
- color: var(--accent-orange);
225
- }
226
-
227
- .booking-flow-preflight button.button-disabled {
228
- background-color: var(--grey-text);
229
- color: var(--accent-white);
230
- cursor: not-allowed;
231
- }
232
-
233
- .booking-flow-preflight button.button-outline {
234
- background-color: transparent;
235
- color: var(--accent-white);
236
- border: 2px solid var(--accent-white);
237
- box-sizing: border-box;
238
- padding: 6px 14px;
239
- }
240
-
241
- .booking-flow-preflight button.button-large {
242
- font-size: 1.2rem;
243
- padding: 1rem 2rem;
244
- border-radius: 40px;
245
- }
@@ -1,152 +0,0 @@
1
- "use client";
2
-
3
- import './button.css';
4
- import Link from 'next/link';
5
- import { OPEN_BOOKING_FOR_PRODUCT } from '@/providers/booking-dialog-provider';
6
-
7
- enum ButtonHoverColor {
8
- White = 'white',
9
- Turquoise = 'turquoise',
10
- Orange = 'orange'
11
- }
12
-
13
- enum PresetButtonActions {
14
- BOOK_ALL = 'BOOK_ALL',
15
- BOOK_MORAINE_LAKE_SUNRISE = 'BOOK_MORAINE_LAKE_SUNRISE',
16
- BOOK_MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR = 'BOOK_MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR',
17
- BOOK_TWO_LAKES_COMBO = 'BOOK_TWO_LAKES_COMBO',
18
- BOOK_MORAINE_LAKE_ADVENTURE = 'BOOK_MORAINE_LAKE_ADVENTURE',
19
- BOOK_LAKE_LOUISE_ADVENTURE = 'BOOK_LAKE_LOUISE_ADVENTURE',
20
- BOOK_EMERALD_LAKE_ESCAPE = 'BOOK_EMERALD_LAKE_ESCAPE',
21
- BOOK_PRIVATE_TOUR = 'BOOK_PRIVATE_TOUR',
22
- BOOK_THEME_SUNRISE = 'BOOK_THEME_SUNRISE',
23
- BOOK_THEME_MORAINE_LAKE = 'BOOK_THEME_MORAINE_LAKE',
24
- BOOK_THEME_LAKE_LOUISE = 'BOOK_THEME_LAKE_LOUISE',
25
- }
26
-
27
- /** Maps preset booking actions to product slugs. null = open product grid. */
28
- const PRESET_ACTION_TO_PRODUCT_SLUG: Partial<Record<PresetButtonActions, string | null>> = {
29
- [PresetButtonActions.BOOK_ALL]: null,
30
- [PresetButtonActions.BOOK_MORAINE_LAKE_SUNRISE]: 'moraine-lake-sunrise',
31
- [PresetButtonActions.BOOK_MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR]: 'moraine-lake-sunrise-lake-louise-golden-hour',
32
- [PresetButtonActions.BOOK_TWO_LAKES_COMBO]: 'two-lakes-combo',
33
- [PresetButtonActions.BOOK_MORAINE_LAKE_ADVENTURE]: 'moraine-lake-adventure',
34
- [PresetButtonActions.BOOK_LAKE_LOUISE_ADVENTURE]: 'lake-louise-adventure',
35
- [PresetButtonActions.BOOK_EMERALD_LAKE_ESCAPE]: 'emerald-lake-escape',
36
- [PresetButtonActions.BOOK_PRIVATE_TOUR]: 'private-tour',
37
- [PresetButtonActions.BOOK_THEME_SUNRISE]: 'moraine-lake-sunrise-lake-louise-golden-hour',
38
- [PresetButtonActions.BOOK_THEME_MORAINE_LAKE]: 'moraine-lake-sunrise-lake-louise-golden-hour',
39
- [PresetButtonActions.BOOK_THEME_LAKE_LOUISE]: 'lake-louise-adventure',
40
- };
41
-
42
- interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
43
- children: React.ReactNode;
44
- variant?: 'primary' | 'secondary' | 'outline' | 'disabled';
45
- hoverColor?: ButtonHoverColor;
46
- isLarge?: boolean;
47
- action?: ButtonAction;
48
- shouldOpenInNewTab?: boolean;
49
- }
50
-
51
- type ButtonAction = PresetButtonActions | string;
52
-
53
- export default function Button({
54
- children,
55
- variant = 'primary',
56
- className,
57
- hoverColor = ButtonHoverColor.White,
58
- isLarge = false,
59
- action = '',
60
- shouldOpenInNewTab = false,
61
- ...props
62
- }: ButtonProps) {
63
- const finalAction = getFinalAction(action);
64
- const productSlug = getProductSlugForAction(action);
65
- const isBookingAction = isModalActionType(action);
66
-
67
- const handleClick = () => {
68
- if (isBookingAction) {
69
- if (productSlug) {
70
- window.dispatchEvent(new CustomEvent(OPEN_BOOKING_FOR_PRODUCT, { detail: { productId: productSlug } }));
71
- } else {
72
- window.dispatchEvent(new CustomEvent('openSimpleModal'));
73
- }
74
- }
75
- };
76
-
77
- return (
78
- <>
79
- {isBookingAction ? (
80
- <button
81
- onClick={handleClick}
82
- className={`button button-${variant} hover-${hoverColor} ${isLarge ? 'button-large' : ''} ${className}`}
83
- {...props}
84
- >
85
- {children}
86
- </button>
87
- ) : finalAction ? (
88
- <Link href={finalAction} target={shouldOpenInNewTab ? '_blank' : '_self'}>
89
- <button
90
- className={`button button-${variant} hover-${hoverColor} ${isLarge ? 'button-large' : ''} ${className}`}
91
- {...props}
92
- >
93
- {children}
94
- </button>
95
- </Link>
96
- ) : (
97
- <button
98
- className={`button button-${variant} hover-${hoverColor} ${isLarge ? 'button-large' : ''} ${className}`}
99
- {...props}
100
- >
101
- {children}
102
- </button>
103
- )}
104
- </>
105
- )
106
- }
107
-
108
- function isModalActionType(action: ButtonAction): boolean {
109
- return Object.values(PresetButtonActions).includes(action as PresetButtonActions);
110
- }
111
-
112
- function getProductSlugForAction(action: ButtonAction): string | null | undefined {
113
- if (Object.values(PresetButtonActions).includes(action as PresetButtonActions)) {
114
- return PRESET_ACTION_TO_PRODUCT_SLUG[action as PresetButtonActions] ?? null;
115
- }
116
- return undefined;
117
- }
118
-
119
- function getFinalAction(action: ButtonAction) {
120
- // Preset booking actions open the dialog (handled by handleClick)
121
- if (Object.values(PresetButtonActions).includes(action as PresetButtonActions)) {
122
- return null;
123
- }
124
-
125
- // Handle regular URLs (http or relative paths)
126
- if (typeof action === 'string' && (action.startsWith('http') || action.startsWith('/'))) {
127
- return action;
128
- }
129
-
130
- return null;
131
- }
132
-
133
- export { ButtonHoverColor, PresetButtonActions };
134
-
135
- interface MenuButtonProps {
136
- onClick?: () => void;
137
- isOpen?: boolean;
138
- strings?: any;
139
- }
140
-
141
- export function MenuButton({ onClick, isOpen = false, strings }: MenuButtonProps) {
142
- return (
143
- <button className={`button button-menu ${isOpen ? 'open' : ''}`} onClick={onClick}>
144
- <span className="menu-text">{strings.common.menu}</span>
145
- <div className="menu-icon">
146
- <span></span>
147
- <span></span>
148
- <span></span>
149
- </div>
150
- </button>
151
- );
152
- }
@@ -1,29 +0,0 @@
1
- import React from 'react';
2
-
3
- interface ColorableSvgProps {
4
- src: string;
5
- className?: string;
6
- width?: number;
7
- height?: number;
8
- }
9
-
10
- export default function ColorableSvg({ src, className, width = 24, height = 24 }: ColorableSvgProps) {
11
- const [svgContent, setSvgContent] = React.useState<string>('');
12
-
13
- React.useEffect(() => {
14
- fetch(src)
15
- .then(res => res.text())
16
- .then(text => {
17
- // Replace both the style attribute and width/height attributes
18
- const colorableSvg = text
19
- .replace(/style="[^"]*"/, 'style="fill: currentColor"')
20
- .replace(/width="[^"]*"/, `width="${width}"`)
21
- .replace(/height="[^"]*"/, `height="${height}"`);
22
- setSvgContent(colorableSvg);
23
- });
24
- }, [src, width, height]);
25
-
26
- return (
27
- <div className={className} dangerouslySetInnerHTML={{ __html: svgContent }} />
28
- );
29
- }
@@ -1,29 +0,0 @@
1
- .image-container {
2
- position: relative;
3
- width: 100%;
4
- height: 100%;
5
- }
6
-
7
- .image-natural {
8
- position: relative;
9
- width: 100%;
10
- height: auto;
11
- }
12
-
13
- /* Make sure images are responsive within their containers */
14
- .image-container img {
15
- width: 100%;
16
- height: 100%;
17
- object-fit: cover;
18
- /* This centers the image content vertically when cropped */
19
- object-position: 50% 50%;
20
- }
21
-
22
- .image-natural img {
23
- display: block;
24
- width: 100%;
25
- height: auto;
26
- max-width: 100%;
27
- max-height: 100%;
28
- object-fit: contain;
29
- }
@@ -1,113 +0,0 @@
1
- "use client";
2
-
3
- import Image from 'next/image';
4
- import './image.css';
5
-
6
- interface ImageWidths {
7
- mobile: number;
8
- tablet: number;
9
- desktop: number;
10
- }
11
-
12
- interface ImageWidthsMap {
13
- HERO: ImageWidths;
14
- GALLERY: ImageWidths;
15
- THUMBNAIL: ImageWidths;
16
- MODAL: ImageWidths;
17
- }
18
-
19
- const IMAGE_WIDTHS: ImageWidthsMap = {
20
- HERO: {
21
- mobile: 768,
22
- tablet: 1024,
23
- desktop: 1920
24
- },
25
- GALLERY: {
26
- mobile: 400,
27
- tablet: 600,
28
- desktop: 800
29
- },
30
- THUMBNAIL: {
31
- mobile: 200,
32
- tablet: 300,
33
- desktop: 400
34
- },
35
- MODAL: {
36
- mobile: 1024,
37
- tablet: 1280,
38
- desktop: 1920
39
- }
40
- };
41
-
42
- type ImageContext = 'HERO' | 'GALLERY' | 'THUMBNAIL' | 'MODAL';
43
-
44
- interface ImageProps {
45
- imageId: string;
46
- context?: ImageContext;
47
- alt: string;
48
- className?: string;
49
- maintainAspectRatio?: boolean;
50
- style?: React.CSSProperties;
51
- }
52
-
53
- // Pre-compute sizes strings for each context to ensure consistency
54
- const SIZES = {
55
- HERO: '(min-width: 1024px) 1920px, (min-width: 768px) 1024px, 768px',
56
- GALLERY: '(min-width: 1024px) 800px, (min-width: 768px) 600px, 400px',
57
- THUMBNAIL: '(min-width: 1024px) 400px, (min-width: 768px) 300px, 200px',
58
- MODAL: '(min-width: 1024px) 1920px, (min-width: 768px) 1280px, 1024px'
59
- };
60
-
61
- // Pre-compute quality values
62
- const QUALITY = {
63
- HERO: 85,
64
- GALLERY: 75,
65
- THUMBNAIL: 75,
66
- MODAL: 85
67
- };
68
-
69
- const ViaViaImage = ({
70
- className = '',
71
- imageId,
72
- context = 'THUMBNAIL',
73
- alt,
74
- maintainAspectRatio = false,
75
- style
76
- }: ImageProps) => {
77
- const normalizedContext = context.toUpperCase() as ImageContext;
78
- const widths = IMAGE_WIDTHS[normalizedContext];
79
-
80
- if (maintainAspectRatio) {
81
- return (
82
- <div className={`image-container image-natural ${className}`}>
83
- <Image
84
- src={imageId}
85
- alt={alt}
86
- fill={false}
87
- width={widths.desktop}
88
- height={widths.desktop * 9 / 16}
89
- sizes={SIZES[normalizedContext]}
90
- priority={normalizedContext === 'HERO'}
91
- quality={QUALITY[normalizedContext]}
92
- style={{ width: '100%', height: 'auto', ...style }}
93
- />
94
- </div>
95
- );
96
- }
97
-
98
- return (
99
- <div className={`image-container image-${normalizedContext.toLowerCase()} ${className}`}>
100
- <Image
101
- src={imageId}
102
- alt={alt}
103
- fill={true}
104
- sizes={SIZES[normalizedContext]}
105
- priority={normalizedContext === 'HERO'}
106
- quality={QUALITY[normalizedContext]}
107
- style={style}
108
- />
109
- </div>
110
- );
111
- };
112
-
113
- export default ViaViaImage;
@@ -1,130 +0,0 @@
1
- .root {
2
- display: flex;
3
- flex-direction: column;
4
- align-items: center;
5
- justify-content: flex-start;
6
- padding: 1.5rem 1rem 3rem;
7
- background-color: var(--light-orange-background);
8
- }
9
-
10
- .card {
11
- width: 100%;
12
- max-width: 1120px;
13
- background: var(--accent-white);
14
- border-radius: 1rem;
15
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
16
- display: flex;
17
- flex-direction: column;
18
- }
19
-
20
- .header {
21
- display: grid;
22
- grid-template-columns: auto 1fr auto;
23
- align-items: center;
24
- gap: 0.75rem;
25
- padding: 1rem 0.75rem;
26
- border-bottom: 1px solid #e5e7eb;
27
- }
28
-
29
- .headerLeft {
30
- display: flex;
31
- justify-content: flex-start;
32
- }
33
-
34
- .headerSpacer {
35
- display: block;
36
- width: 2.5rem;
37
- height: 2.5rem;
38
- }
39
-
40
- .backButton {
41
- display: flex;
42
- align-items: center;
43
- gap: 0.25rem;
44
- padding: 0.5rem;
45
- font-size: 0.875rem;
46
- font-family: 'Figtree', sans-serif;
47
- color: var(--accent-turquoise);
48
- background: none;
49
- border: none;
50
- cursor: pointer;
51
- font-weight: 500;
52
- }
53
-
54
- .backButton:hover {
55
- text-decoration: underline;
56
- }
57
-
58
- .title {
59
- font-size: 1.375rem;
60
- font-weight: 700;
61
- margin: 0;
62
- justify-self: center;
63
- text-align: center;
64
- }
65
-
66
- /* Book flow header (partner portal + provider dashboard embedded): matches marketing booking chrome */
67
- .titleBookFlow {
68
- font-size: 1.375rem;
69
- font-weight: 700;
70
- margin: 0;
71
- justify-self: center;
72
- text-align: center;
73
- font-family: 'Poppins', sans-serif;
74
- color: var(--accent-orange, #ff4d00);
75
- }
76
-
77
- .titleBookPrefix,
78
- .titleBookProduct {
79
- text-transform: lowercase;
80
- }
81
-
82
- .titleBookSeparator {
83
- font-weight: 700;
84
- }
85
-
86
- .titleProductGrid {
87
- font-size: 1.5rem;
88
- }
89
-
90
- .headerRight {
91
- display: flex;
92
- justify-content: flex-end;
93
- }
94
-
95
- .logoRow {
96
- display: flex;
97
- justify-content: center;
98
- align-items: center;
99
- gap: 1.25rem;
100
- padding: 0.75rem 1.5rem 1rem;
101
- }
102
-
103
- .logoDivider {
104
- font-size: 0.875rem;
105
- font-weight: 600;
106
- letter-spacing: 0.08em;
107
- text-transform: uppercase;
108
- color: #9ca3af;
109
- }
110
-
111
- .partnerLogo,
112
- .viaViaLogo {
113
- max-height: 100px;
114
- width: auto;
115
- }
116
-
117
- .content {
118
- padding: 1.25rem;
119
- }
120
-
121
- .contentEmbedded {
122
- padding: 0;
123
- }
124
-
125
- @media (min-width: 1024px) {
126
- .root {
127
- padding-top: 2rem;
128
- }
129
- }
130
-