@ticketboothapp/booking 0.1.19 → 0.1.22

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 (106) hide show
  1. package/package.json +2 -1
  2. package/src/components/BookingWidget.tsx +282 -26
  3. package/src/components/ManageBookingView.tsx +75 -23
  4. package/src/components/PostBookingDependentAddOnUpsell.tsx +1 -1
  5. package/src/components/booking/BookingProductGrid.tsx +1 -1
  6. package/src/components/booking/Calendar.module.css +3 -3
  7. package/src/components/booking/CheckoutForm.tsx +1 -1
  8. package/src/components/booking/InfoTooltip.tsx +2 -13
  9. package/src/components/booking/PickupLocationSelector.tsx +2 -2
  10. package/src/components/booking/PriceBreakdown.tsx +11 -34
  11. package/src/index.ts +3 -1
  12. package/tsconfig.json +1 -1
  13. package/src/components/JobApplicationDialog.module.css +0 -440
  14. package/src/components/JobApplicationDialog.tsx +0 -620
  15. package/src/components/PickupLocationMap.tsx +0 -110
  16. package/src/components/accordion.css +0 -27
  17. package/src/components/accordion.tsx +0 -29
  18. package/src/components/analytics/AnalyticsConsentRestore.tsx +0 -19
  19. package/src/components/analytics/AnalyticsScripts.tsx +0 -106
  20. package/src/components/analytics/CookieConsentBanner.css +0 -86
  21. package/src/components/analytics/CookieConsentBanner.tsx +0 -102
  22. package/src/components/bottom-sheet.module.css +0 -78
  23. package/src/components/bottom-sheet.tsx +0 -60
  24. package/src/components/breadcrumb.module.css +0 -40
  25. package/src/components/breadcrumb.tsx +0 -36
  26. package/src/components/client-bottom-sheet.tsx +0 -14
  27. package/src/components/conditional-footer.tsx +0 -27
  28. package/src/components/contact-us.module.css +0 -147
  29. package/src/components/contact-us.tsx +0 -49
  30. package/src/components/email-signup.css +0 -151
  31. package/src/components/email-signup.tsx +0 -63
  32. package/src/components/faq-wrapper.module.css +0 -47
  33. package/src/components/faq-wrapper.tsx +0 -15
  34. package/src/components/footer.css +0 -187
  35. package/src/components/footer.tsx +0 -143
  36. package/src/components/global-simple-modal.tsx +0 -33
  37. package/src/components/google-review-summary.module.css +0 -77
  38. package/src/components/google-review-summary.tsx +0 -50
  39. package/src/components/hero-image.css +0 -13
  40. package/src/components/hero-image.tsx +0 -44
  41. package/src/components/language-aware-link.tsx +0 -72
  42. package/src/components/language-switcher.module.css +0 -124
  43. package/src/components/language-switcher.tsx +0 -75
  44. package/src/components/map-section.css +0 -59
  45. package/src/components/map-section.tsx +0 -63
  46. package/src/components/navbar.module.css +0 -152
  47. package/src/components/navbar.tsx +0 -125
  48. package/src/components/parallax-provider.tsx +0 -11
  49. package/src/components/product-theme-pages/best-option.module.css +0 -70
  50. package/src/components/product-theme-pages/best-option.tsx +0 -35
  51. package/src/components/product-theme-pages/extended-tour-options.module.css +0 -22
  52. package/src/components/product-theme-pages/extended-tour-options.tsx +0 -11
  53. package/src/components/product-theme-pages/photo-gallery.tsx +0 -90
  54. package/src/components/product-theme-pages/product-theme-page-layout.module.css +0 -13
  55. package/src/components/product-theme-pages/product-theme-page-layout.tsx +0 -67
  56. package/src/components/product-theme-pages/top-of-fold.module.css +0 -179
  57. package/src/components/product-theme-pages/top-of-fold.tsx +0 -80
  58. package/src/components/product-tile/image-only-product-tile-desktop.module.css +0 -106
  59. package/src/components/product-tile/image-only-product-tile-desktop.tsx +0 -56
  60. package/src/components/product-tile/image-only-product-tile-mobile.module.css +0 -122
  61. package/src/components/product-tile/image-only-product-tile-mobile.tsx +0 -89
  62. package/src/components/product-tile/image-only-product-tile.tsx +0 -44
  63. package/src/components/product-tile/product-tile-card.module.css +0 -84
  64. package/src/components/product-tile/product-tile-card.tsx +0 -61
  65. package/src/components/review-highlights-section.css +0 -85
  66. package/src/components/review-highlights-section.tsx +0 -127
  67. package/src/components/season-closure-overlay.module.css +0 -99
  68. package/src/components/season-closure-overlay.tsx +0 -98
  69. package/src/components/simple-modal.tsx +0 -69
  70. package/src/components/simple-top-of-fold.module.css +0 -76
  71. package/src/components/simple-top-of-fold.tsx +0 -34
  72. package/src/components/spacer.css +0 -41
  73. package/src/components/spacer.tsx +0 -23
  74. package/src/components/star-rating.module.css +0 -74
  75. package/src/components/star-rating.tsx +0 -48
  76. package/src/components/title-subtitle.module.css +0 -10
  77. package/src/components/title-subtitle.tsx +0 -30
  78. package/src/components/translatable-reviews.tsx +0 -75
  79. package/src/components/value-props.css +0 -185
  80. package/src/components/value-props.tsx +0 -88
  81. package/src/constants/booking-guide-quiz.ts +0 -64
  82. package/src/constants/contact-info.ts +0 -2
  83. package/src/constants/faq.ts +0 -44
  84. package/src/constants/json-ld/faq-json-ld.tsx +0 -170
  85. package/src/constants/json-ld/homepage-json-ld.tsx +0 -138
  86. package/src/constants/json-ld/job-posting-json-ld.tsx +0 -92
  87. package/src/constants/json-ld/organization-json-ld.tsx +0 -62
  88. package/src/constants/json-ld/page-json-ld.tsx +0 -6
  89. package/src/constants/json-ld/product-json-ld.tsx +0 -154
  90. package/src/constants/json-ld/review-json-ld.tsx +0 -377
  91. package/src/constants/navigation-links/footer-links.ts +0 -48
  92. package/src/constants/navigation-links/nav-bar-links.ts +0 -41
  93. package/src/constants/navigation-links/navigation-link.ts +0 -6
  94. package/src/constants/quiz-recommendations.ts +0 -506
  95. package/src/constants/reviews.ts +0 -75
  96. package/src/constants/staff.ts +0 -197
  97. package/src/constants/value-props.ts +0 -58
  98. package/src/hooks/use-bottom-sheet.tsx +0 -15
  99. package/src/hooks/use-simple-modal.tsx +0 -27
  100. package/src/hooks/useEmailSubscription.tsx +0 -103
  101. package/src/hooks/useEmbeddedInIframe.ts +0 -16
  102. package/src/hooks/useQuiz.tsx +0 -210
  103. package/src/providers/bottom-sheet-provider.tsx +0 -40
  104. package/src/types/fareharbor.d.ts +0 -12
  105. package/src/types/quiz.ts +0 -59
  106. /package/src/{app/photo-sessions → lib}/photo-packages.ts +0 -0
@@ -1,179 +0,0 @@
1
- .topOfFold {
2
- position: relative;
3
- width: 100vw;
4
- overflow: hidden;
5
- }
6
-
7
- .heroImageWrapper {
8
- position: absolute;
9
- top: 0;
10
- left: 0;
11
- width: 100%;
12
- height: 100%;
13
- z-index: 2;
14
- }
15
-
16
- .heroCenterText {
17
- position: absolute;
18
- top: 50%;
19
- left: 50%;
20
- transform: translate(-50%, -50%);
21
- z-index: 3;
22
- pointer-events: none;
23
- font-size: 3rem;
24
- line-height: 0.7;
25
- font-weight: 900;
26
- color: #fff;
27
- text-shadow: 0 0 8px rgba(0,0,0,0.4);
28
- font-family: 'Snell Roundhand', sans-serif;
29
- text-transform: lowercase;
30
- text-align: center;
31
- }
32
-
33
- .heroOverlayContent {
34
- position: absolute;
35
- top: 7rem;
36
- bottom: 4rem;
37
- left: 0.5rem;
38
- right: 0.5rem;
39
- left: 0;
40
- width: 100%;
41
- z-index: 2;
42
- display: flex;
43
- flex-direction: column;
44
- justify-content: space-between;
45
- align-items: center;
46
- }
47
-
48
- .heroTopContent {
49
- width: 100%;
50
- display: flex;
51
- flex-direction: column;
52
- align-items: center;
53
- display: flex;
54
- justify-content: center;
55
- }
56
-
57
- .heroBottomContent {
58
- width: 100%;
59
- display: flex;
60
- flex-direction: column;
61
- align-items: center;
62
- }
63
-
64
- .heroTitle {
65
- color: var(--accent-white);
66
- font-size: 5rem;
67
- line-height: 1.2;
68
- text-align: center;
69
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
70
- text-transform: none;
71
- }
72
-
73
- .heroSubtitle {
74
- color: var(--accent-white);
75
- font-size: 2rem;
76
- text-align: center;
77
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
78
- }
79
-
80
- .closureOverlayBackdrop {
81
- position: absolute;
82
- top: 0;
83
- left: 0;
84
- right: 0;
85
- bottom: 0;
86
- background: rgba(0, 0, 0, 0.5);
87
- backdrop-filter: blur(3px);
88
- z-index: 3;
89
- display: flex;
90
- align-items: center;
91
- justify-content: center;
92
- }
93
-
94
- .seasonClosureCallout {
95
- width: 90%;
96
- max-width: 500px;
97
- z-index: 4;
98
- display: flex;
99
- flex-direction: column;
100
- align-items: center;
101
- text-align: center;
102
- gap: 0.5rem;
103
- pointer-events: none;
104
- }
105
-
106
- .seasonClosureCallout * {
107
- pointer-events: auto;
108
- }
109
-
110
- .closureOverlayTop {
111
- display: flex;
112
- flex-direction: column;
113
- align-items: center;
114
- text-align: center;
115
- gap: 0.1rem;
116
- }
117
-
118
- .closureOverlayBottom {
119
- display: flex;
120
- flex-direction: column;
121
- align-items: center;
122
- text-align: center;
123
- }
124
-
125
- .closureTitle {
126
- font-size: 4rem;
127
- line-height: 0.7;
128
- font-weight: 900;
129
- color: #fff;
130
- text-shadow: 0 0 8px rgba(0,0,0,0.4);
131
- font-family: 'Snell Roundhand', sans-serif;
132
- text-transform: lowercase;
133
- text-align: center;
134
- margin-bottom: -0.2rem;
135
- }
136
-
137
- .closureSubtitle {
138
- font-size: 1.8rem;
139
- line-height: 1;
140
- font-weight: 400;
141
- color: #fff;
142
- text-shadow: 0 0 8px rgba(0,0,0,0.4);
143
- letter-spacing: 0.5px;
144
- font-family: 'Northlake', sans-serif;
145
- text-transform: lowercase;
146
- text-align: center;
147
- }
148
-
149
- .closureSubSubtitle {
150
- font-size: 1.2rem;
151
- line-height: 1.1;
152
- font-weight: 400;
153
- color: #fff;
154
- text-shadow: 0 0 8px rgba(0,0,0,0.4);
155
- letter-spacing: 0.5px;
156
- font-family: 'Northlake', sans-serif;
157
- text-transform: lowercase;
158
- text-align: center;
159
- }
160
-
161
- @media (min-width: 1024px) {
162
- .topOfFold {
163
- height: calc(100vh - 98px);
164
- }
165
- }
166
-
167
- @media (max-width: 1023px) {
168
- .heroTitle {
169
- font-size: 3rem;
170
- }
171
-
172
- .heroSubtitle {
173
- font-size: 1.2rem;
174
- }
175
-
176
- .topOfFold {
177
- height: 100vh;
178
- }
179
- }
@@ -1,80 +0,0 @@
1
- "use client";
2
-
3
- import styles from './top-of-fold.module.css';
4
- import { ImageData } from '@/constants/images';
5
- import HeroImage from '@/components/hero-image';
6
- import strings from '@/strings';
7
- import Button, { PresetButtonActions } from '@/components/button';
8
- import GoogleReviewSummary from '@/components/google-review-summary';
9
- import SeasonClosureOverlay from '@/components/season-closure-overlay';
10
- import {
11
- OPEN_BOOKING_FOR_PRODUCT,
12
- OPEN_BOOKING_WITH_FILTER,
13
- type ProductGridFilterId,
14
- } from '@/providers/booking-dialog-provider';
15
- import { useIsBookingLaunchLive } from '@/hooks/useIsBookingLaunchLive';
16
-
17
- export interface TopOfFoldProps {
18
- image: ImageData;
19
- title: string;
20
- subtitle: string;
21
- /** Open product grid with this filter pre-applied (e.g. 'moraine-lake', 'sunrise'). */
22
- bookFilterId?: ProductGridFilterId;
23
- /** Product slug to open directly. Use when page has a single primary product. */
24
- bookProductSlug?: string;
25
- /** Fallback when neither bookFilterId nor bookProductSlug (e.g. home page). */
26
- bookButtonAction?: PresetButtonActions;
27
- }
28
-
29
- export default function TopOfFold(props: TopOfFoldProps) {
30
- const { image, title, subtitle, bookFilterId, bookProductSlug, bookButtonAction = PresetButtonActions.BOOK_ALL } = props;
31
- const isLaunchLive = useIsBookingLaunchLive();
32
-
33
- const handleBookClick = () => {
34
- if (bookFilterId) {
35
- window.dispatchEvent(new CustomEvent(OPEN_BOOKING_WITH_FILTER, { detail: { filterId: bookFilterId } }));
36
- } else if (bookProductSlug) {
37
- window.dispatchEvent(new CustomEvent(OPEN_BOOKING_FOR_PRODUCT, { detail: { productId: bookProductSlug } }));
38
- } else {
39
- window.dispatchEvent(new CustomEvent('openSimpleModal'));
40
- }
41
- };
42
-
43
- const hasCustomBookAction = bookFilterId || bookProductSlug;
44
-
45
- return (
46
- <div className={`${styles.topOfFold} global-top-fold`}>
47
- {isLaunchLive && <div className={styles.heroCenterText}>{strings.home.hero.centerCallout}</div>}
48
- <div className={styles.heroImageWrapper}>
49
- <HeroImage
50
- imageId={image.id}
51
- alt={image.alt}
52
- />
53
- </div>
54
-
55
- <div className={styles.heroOverlayContent}>
56
- <div className={styles.heroTopContent}>
57
- <h1 className={styles.heroTitle}>{title}</h1>
58
- <h2 className={styles.heroSubtitle}>{subtitle}</h2>
59
- </div>
60
-
61
- <div className={styles.heroBottomContent}>
62
- <GoogleReviewSummary strings={strings} />
63
- {hasCustomBookAction ? (
64
- <button
65
- type="button"
66
- onClick={handleBookClick}
67
- className="button button-primary hover-white button-large"
68
- >
69
- {strings.common.bookNow}
70
- </button>
71
- ) : (
72
- <Button isLarge={true} action={bookButtonAction}>{strings.common.bookNow}</Button>
73
- )}
74
- </div>
75
- </div>
76
-
77
- {!isLaunchLive && <SeasonClosureOverlay strings={strings} />}
78
- </div>
79
- );
80
- }
@@ -1,106 +0,0 @@
1
- .productTile {
2
- height: 100%;
3
- width: 100%;
4
- text-decoration: none;
5
- position: relative;
6
- cursor: pointer;
7
- }
8
-
9
- .productTileImageContainer {
10
- width: 100%;
11
- height: 420px;
12
- position: relative;
13
- border-radius: 10px;
14
- overflow: hidden;
15
- }
16
-
17
- .productTileImage {
18
- width: 100%;
19
- height: 100%;
20
- position: relative;
21
- transition: transform 0.3s ease-in-out;
22
- will-change: transform;
23
- }
24
-
25
- .productTile:hover .productTileImage {
26
- transform: scale(1.1);
27
- }
28
-
29
- .productTileImage::after {
30
- content: '';
31
- position: absolute;
32
- bottom: 0;
33
- left: 0;
34
- right: 0;
35
- height: 30%;
36
- background: linear-gradient(to top, rgba(0,0,0,0.5), transparent);
37
- z-index: 1;
38
- }
39
-
40
- .productTileContentOverlay {
41
- position: absolute;
42
- top: 0;
43
- left: 0;
44
- right: 0;
45
- padding: var(--spacing-medium);
46
- z-index: 2;
47
- display: flex;
48
- flex-direction: column;
49
- }
50
-
51
- .productTileTags {
52
- display: flex;
53
- flex-direction: row;
54
- gap: var(--spacing-small);
55
- }
56
-
57
- .productTileTitle {
58
- margin: 0;
59
- color: white;
60
- text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
61
- line-height: 1.0;
62
- }
63
-
64
- .productStartTime {
65
- position: absolute;
66
- bottom: 0;
67
- right: 0;
68
- color: #FFFFFF;
69
- font-family: 'Northlake', sans-serif;
70
- font-weight: 400;
71
- font-size: 3rem;
72
- text-align: right;
73
- z-index: 2;
74
- line-height: 0.8;
75
- transform: translateZ(0);
76
- backface-visibility: hidden;
77
- -webkit-font-smoothing: antialiased;
78
- will-change: transform;
79
- }
80
-
81
- .productTilePillValuesView {
82
- position: absolute;
83
- top: 0;
84
- left: 0;
85
- width: 100%;
86
- height: 100%;
87
- display: flex;
88
- flex-direction: column;
89
- align-items: center;
90
- justify-content: center;
91
- gap: 8px;
92
- opacity: 0;
93
- transition: opacity 0.3s;
94
- background: rgba(0, 0, 0, 0.7);
95
- z-index: 3;
96
- }
97
-
98
- .productTileImageContainer:hover .productTilePillValuesView {
99
- opacity: 1;
100
- }
101
-
102
- .productTile:hover .productStartTime,
103
- .productTile:hover .productTileTitle {
104
- opacity: 0;
105
- transition: opacity 0.3s ease-in-out;
106
- }
@@ -1,56 +0,0 @@
1
- "use client";
2
-
3
- import { Product } from "@/constants/products"
4
- import ViaViaImage from "../image"
5
- import styles from "./image-only-product-tile-desktop.module.css"
6
- import { PillVariant } from "../value-pill"
7
- import ValuePill from "../value-pill"
8
- import ProductTag from "../product-tag"
9
- import { OPEN_BOOKING_FOR_PRODUCT } from "@/providers/booking-dialog-provider"
10
-
11
- export default function ProductTileDesktop({ product, strings }: { product: Product; strings?: any }) {
12
- const handleClick = (e: React.MouseEvent) => {
13
- e.preventDefault();
14
- window.dispatchEvent(
15
- new CustomEvent(OPEN_BOOKING_FOR_PRODUCT, { detail: { productId: product.id } })
16
- );
17
- };
18
-
19
- return (
20
- <div onClick={handleClick} className={styles.productTile} style={{ cursor: 'pointer' }}>
21
- <div className={styles.productTileImageContainer}>
22
- <ViaViaImage
23
- className={styles.productTileImage}
24
- imageId={product.images[0].id}
25
- alt={product.images[0].alt}
26
- context="GALLERY"
27
- />
28
- <div className={styles.productTileContentOverlay}>
29
- {/* Render tags if they exist */}
30
- {product.tags && (
31
- <div className={styles.productTileTags}>
32
- {product.tags.map((tag, index) => (
33
- <ProductTag
34
- key={`${tag.text}-${index}`}
35
- text={tag.text}
36
- style={tag.style}
37
- />
38
- ))}
39
- </div>
40
- )}
41
- <h3 className={styles.productTileTitle}>{product.shortName}</h3>
42
- </div>
43
- <span className={styles.productStartTime} dangerouslySetInnerHTML={{ __html: product.currentStartTime }} />
44
- <div className={styles.productTilePillValuesView}>
45
- {product.pillValues.map((pillValue, index) => (
46
- <ValuePill
47
- key={`${pillValue.label}-${index}`}
48
- variant={PillVariant.overlay}
49
- pillValue={pillValue}
50
- />
51
- ))}
52
- </div>
53
- </div>
54
- </div>
55
- );
56
- }
@@ -1,122 +0,0 @@
1
- .productTile {
2
- height: 100%;
3
- width: 100%;
4
- text-decoration: none;
5
- position: relative;
6
- margin-top: var(--spacing-large);
7
- }
8
-
9
- .card {
10
- width: 100%;
11
- height: 380px;
12
- perspective: 1000px;
13
- cursor: pointer;
14
- }
15
-
16
- .cardInner {
17
- position: relative;
18
- width: 100%;
19
- height: 100%;
20
- transition: transform 0.6s;
21
- transform-style: preserve-3d;
22
- }
23
-
24
- .card.isFlipped .cardInner {
25
- transform: rotateY(180deg);
26
- }
27
-
28
- .cardFaceFront,
29
- .cardFaceBack {
30
- position: absolute;
31
- width: 100%;
32
- height: 100%;
33
- -webkit-backface-visibility: hidden;
34
- backface-visibility: hidden;
35
- }
36
-
37
- .productTileImageContainer {
38
- width: 100%;
39
- height: 100%;
40
- position: relative;
41
- border-radius: var(--border-radius-small);
42
- overflow: hidden;
43
- border: 10px solid var(--accent-orange);
44
- box-sizing: border-box;
45
- }
46
-
47
- .cardFaceFront {
48
- transform: rotateY(0deg);
49
- }
50
-
51
- .cardFaceBack {
52
- transform: rotateY(180deg);
53
- height: 380px;
54
- background: var(--grey-text-dark-70);
55
- border-radius: var(--border-radius-small);
56
- }
57
-
58
- .productTilePillValuesView {
59
- height: 100%;
60
- display: flex;
61
- flex-direction: column;
62
- align-items: center;
63
- justify-content: center;
64
- gap: 8px;
65
- }
66
-
67
- .productTileImage {
68
- width: 100%;
69
- height: 100%;
70
- position: relative;
71
- }
72
-
73
- .productTileImage::after {
74
- content: '';
75
- position: absolute;
76
- bottom: 0;
77
- left: 0;
78
- right: 0;
79
- height: 30%;
80
- background: linear-gradient(to top, rgba(0,0,0,0.5), transparent);
81
- z-index: 1;
82
- }
83
-
84
- .productTileContentOverlay {
85
- position: absolute;
86
- top: 0;
87
- left: 0;
88
- right: 0;
89
- padding: 8px;
90
- z-index: 2;
91
- display: flex;
92
- flex-direction: column;
93
- }
94
-
95
- .productTileTags {
96
- display: flex;
97
- flex-direction: row;
98
- gap: var(--spacing-small);
99
- }
100
-
101
- .productTileTitle {
102
- margin: 0;
103
- color: white;
104
- text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
105
- }
106
-
107
- .productStartTime {
108
- position: absolute;
109
- bottom: 0;
110
- right: 0;
111
- color: #FFFFFF;
112
- font-family: 'Northlake', sans-serif;
113
- font-weight: 400;
114
- font-size: 2.5rem;
115
- text-align: right;
116
- z-index: 2;
117
- line-height: 0.8;
118
- }
119
-
120
- .backCardProductTileButton {
121
- margin-top: var(--spacing-small);
122
- }
@@ -1,89 +0,0 @@
1
- 'use client';
2
- import { Product } from "@/constants/products"
3
- import ViaViaImage from "../image"
4
- import styles from "./image-only-product-tile-mobile.module.css"
5
- import { PillVariant } from "../value-pill"
6
- import ValuePill from "../value-pill"
7
- import Button from "../button";
8
- import defaultStrings from "@/strings";
9
- import ProductTag from "../product-tag";
10
- import { OPEN_BOOKING_FOR_PRODUCT } from "@/providers/booking-dialog-provider";
11
-
12
- export default function ProductTileMobile({
13
- product,
14
- isFlipped,
15
- onFlip,
16
- strings = defaultStrings
17
- }: {
18
- product: Product;
19
- isFlipped: boolean;
20
- onFlip: () => void;
21
- strings?: any;
22
- }) {
23
- const handleClick = (e: React.MouseEvent) => {
24
- e.preventDefault();
25
- onFlip();
26
- };
27
-
28
- const handleMoreInfo = (e: React.MouseEvent) => {
29
- e.preventDefault();
30
- e.stopPropagation();
31
- window.dispatchEvent(
32
- new CustomEvent(OPEN_BOOKING_FOR_PRODUCT, { detail: { productId: product.id } })
33
- );
34
- };
35
-
36
- return (
37
- <div className={styles.productTile} onClick={handleClick}>
38
- <div className={`${styles.card} ${isFlipped ? styles.isFlipped : ''}`}>
39
- <div className={styles.cardInner}>
40
- <div className={styles.cardFaceFront}>
41
- <div className={styles.productTileImageContainer}>
42
- <ViaViaImage
43
- className={styles.productTileImage}
44
- imageId={product.images[0].id}
45
- alt={product.images[0].alt}
46
- context="GALLERY"
47
- />
48
- <div className={styles.productTileContentOverlay}>
49
- {/* Render tags if they exist */}
50
- {product.tags && (
51
- <div className={styles.productTileTags}>
52
- {product.tags.map((tag, index) => (
53
- <ProductTag
54
- key={`${tag.text}-${index}`}
55
- text={tag.text}
56
- style={tag.style}
57
- />
58
- ))}
59
- </div>
60
- )}
61
- <h3 className={styles.productTileTitle}>{product.shortName}</h3>
62
- </div>
63
- <span className={styles.productStartTime} dangerouslySetInnerHTML={{ __html: product.currentStartTime }} />
64
- </div>
65
- </div>
66
- <div className={styles.cardFaceBack}>
67
- <div className={styles.productTilePillValuesView}>
68
- {product.pillValues.map((pillValue, index) => (
69
- <ValuePill
70
- key={`${pillValue.label}-${index}`}
71
- variant={PillVariant.solid}
72
- pillValue={pillValue}
73
- />
74
- ))}
75
- <Button
76
- variant="outline"
77
- className={styles.backCardProductTileButton}
78
- action=""
79
- onClick={handleMoreInfo}
80
- >
81
- {strings.common.moreInfo}
82
- </Button>
83
- </div>
84
- </div>
85
- </div>
86
- </div>
87
- </div>
88
- );
89
- }
@@ -1,44 +0,0 @@
1
- 'use client';
2
- import { Product } from "@/constants/products"
3
- import { useState, useEffect } from "react";
4
- import ProductTileDesktop from "./image-only-product-tile-desktop";
5
- import ProductTileMobile from "./image-only-product-tile-mobile";
6
-
7
- export default function ProductTile({
8
- product,
9
- flippedProductId,
10
- onFlip,
11
- strings
12
- }: {
13
- product: Product;
14
- flippedProductId?: string;
15
- onFlip?: (productId: string) => void;
16
- strings?: any;
17
- }) {
18
- const [isMobile, setIsMobile] = useState(false); // Default to desktop view
19
- const [hasMounted, setHasMounted] = useState(false);
20
-
21
- useEffect(() => {
22
- setHasMounted(true);
23
- const checkMobile = () => setIsMobile(window.innerWidth < 1025);
24
- checkMobile();
25
- window.addEventListener('resize', checkMobile);
26
- return () => window.removeEventListener('resize', checkMobile);
27
- }, []);
28
-
29
- // Always render desktop version for SEO/initial render
30
- if (!hasMounted) {
31
- return <ProductTileDesktop product={product} strings={strings} />;
32
- }
33
-
34
- return isMobile ? (
35
- <ProductTileMobile
36
- product={product}
37
- isFlipped={flippedProductId === product.id}
38
- onFlip={() => onFlip?.(product.id)}
39
- strings={strings}
40
- />
41
- ) : (
42
- <ProductTileDesktop product={product} strings={strings} />
43
- );
44
- }