@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,34 +0,0 @@
1
- import styles from './simple-top-of-fold.module.css';
2
- import { ImageData } from '@/constants/images';
3
- import HeroImage from '@/components/hero-image';
4
-
5
- export type ImagePosition = 'top' | 'center' | 'bottom';
6
-
7
- export interface SimpleTopOfFoldProps {
8
- image: ImageData;
9
- title: string;
10
- subtitle: string;
11
- subsubtitle?: string;
12
- imagePosition?: ImagePosition;
13
- }
14
-
15
- export default function SimpleTopOfFold(props: SimpleTopOfFoldProps) {
16
- const { image, title, subtitle, subsubtitle, imagePosition = 'center' } = props;
17
- return (
18
- <div className={`${styles.topOfFold} global-top-fold`}>
19
- <div className={`${styles.heroImageWrapper} ${styles[imagePosition]}`}>
20
- <HeroImage
21
- imageId={image.id}
22
- alt={image.alt}
23
- objectPosition={imagePosition}
24
- />
25
- </div>
26
-
27
- <div className={styles.heroOverlayContent}>
28
- <h1 className={styles.heroTitle}>{title}</h1>
29
- <h2 className={styles.heroSubtitle}>{subtitle}</h2>
30
- {subsubtitle && <h3 className={styles.heroSubsubtitle}>{subsubtitle}</h3>}
31
- </div>
32
- </div>
33
- );
34
- }
@@ -1,41 +0,0 @@
1
- .spacer {
2
- display: block;
3
- }
4
-
5
- .spacer-vertical {
6
- width: 100%;
7
- }
8
-
9
- .spacer-horizontal {
10
- height: 100%;
11
- display: inline-block;
12
- }
13
-
14
- /* Vertical spacing */
15
- .spacer-small {
16
- height: var(--spacing-small);
17
- }
18
-
19
- .spacer-medium {
20
- height: var(--spacing-medium);
21
- }
22
-
23
- .spacer-large {
24
- height: var(--spacing-large);
25
- }
26
-
27
- /* Horizontal spacing */
28
- .spacer-horizontal.spacer-small {
29
- width: var(--spacing-small);
30
- height: auto;
31
- }
32
-
33
- .spacer-horizontal.spacer-medium {
34
- width: var(--spacing-medium);
35
- height: auto;
36
- }
37
-
38
- .spacer-horizontal.spacer-large {
39
- width: var(--spacing-large);
40
- height: auto;
41
- }
@@ -1,23 +0,0 @@
1
- import './spacer.css';
2
-
3
- const SPACER_SIZES = {
4
- S: 'small',
5
- M: 'medium',
6
- L: 'large'
7
- } as const;
8
-
9
- type SpacerSize = keyof typeof SPACER_SIZES;
10
-
11
- interface SpacerProps {
12
- size?: SpacerSize;
13
- horizontal?: boolean;
14
- className?: string;
15
- }
16
-
17
- const Spacer = ({ className = '', size = 'M', horizontal = false }: SpacerProps) => {
18
- const spacerClass = `spacer spacer-${SPACER_SIZES[size]} ${horizontal ? 'spacer-horizontal' : 'spacer-vertical'} ${className}`;
19
-
20
- return <div className={spacerClass} />;
21
- };
22
-
23
- export default Spacer;
@@ -1,74 +0,0 @@
1
- .container {
2
- display: flex;
3
- align-items: center;
4
- gap: 8px;
5
- }
6
-
7
- .starRating {
8
- display: flex;
9
- gap: 2px;
10
- }
11
-
12
- .starRating.gradientSpacing {
13
- gap: 2px;
14
- }
15
-
16
- /* Add extra spacing around the large center star */
17
- .starRating.gradientSpacing .starLarge {
18
- margin: 0 4px; /* Additional margin on left and right of the center star */
19
- }
20
-
21
- .star {
22
- width: 16px;
23
- height: 16px;
24
- opacity: 0.3;
25
- }
26
-
27
- .star.filled {
28
- opacity: 1;
29
- }
30
-
31
- .verified {
32
- width: 16px;
33
- height: 16px;
34
- position: relative;
35
- }
36
-
37
- .verified:hover::after {
38
- content: "Trustindex verifies that the original source of the review is Google.";
39
- position: absolute;
40
- bottom: 100%;
41
- left: 50%;
42
- transform: translateX(-50%);
43
- background: rgba(0, 0, 0, 0.8);
44
- color: white;
45
- padding: 8px 12px;
46
- border-radius: 4px;
47
- font-size: 12px;
48
- white-space: nowrap;
49
- z-index: 1000;
50
- }
51
-
52
- .align-left {
53
- justify-content: flex-start;
54
- }
55
-
56
- .align-center {
57
- justify-content: center;
58
- }
59
-
60
- .align-right {
61
- justify-content: flex-end;
62
- }
63
-
64
- .starSmall {
65
- transform: scale(0.8);
66
- }
67
-
68
- .starMedium {
69
- transform: scale(1);
70
- }
71
-
72
- .starLarge {
73
- transform: scale(1.4);
74
- }
@@ -1,48 +0,0 @@
1
- import StarIcon from '@/assets/icons/star.svg';
2
- import VerifiedIcon from '@/assets/icons/verified.svg';
3
- import styles from './star-rating.module.css';
4
-
5
- interface StarRatingProps {
6
- rating: number; // Expects a number between 0-5
7
- showVerified?: boolean;
8
- align?: 'left' | 'center' | 'right';
9
- useGradientSize?: boolean; // New prop to control star size pattern
10
- }
11
-
12
- export default function StarRating({
13
- rating,
14
- showVerified = true,
15
- align = 'left',
16
- useGradientSize = false
17
- }: StarRatingProps) {
18
- // Helper function to get size class based on star position
19
- const getStarSizeClass = (position: number) => {
20
- if (!useGradientSize) return '';
21
-
22
- if (position === 3) return styles.starLarge;
23
- if (position === 2 || position === 4) return styles.starMedium;
24
- return styles.starSmall;
25
- };
26
-
27
- return (
28
- <div className={`${styles.container} ${styles[`align-${align}`]}`}>
29
- <div className={`${styles.starRating} ${useGradientSize ? styles.gradientSpacing : ''}`}>
30
- {[1, 2, 3, 4, 5].map((star) => (
31
- <StarIcon
32
- key={star}
33
- className={`
34
- ${styles.star}
35
- ${star <= rating ? styles.filled : styles.empty}
36
- ${getStarSizeClass(star)}
37
- `}
38
- />
39
- ))}
40
- </div>
41
- {showVerified && (
42
- <div className={styles.verified} title="Trustindex verifies that the original source of the review is Google.">
43
- <VerifiedIcon />
44
- </div>
45
- )}
46
- </div>
47
- );
48
- }
@@ -1,10 +0,0 @@
1
- .titleSubtitleSubtitle {
2
- text-align: center;
3
- color: var(--primary-text);
4
- font-size: 1rem;
5
- margin-bottom: 2rem;
6
- }
7
-
8
- .titleSubtitleDescription {
9
- text-align: justify;
10
- }
@@ -1,30 +0,0 @@
1
- import styles from "./title-subtitle.module.css"
2
- import containerStyles from "@/styles/container.module.css"
3
-
4
- export interface TitleSubtitleProps {
5
- title?: string
6
- subtitle?: string
7
- description?: string
8
- className?: string
9
- }
10
-
11
- export const createTitleSubtitleParams = (props: TitleSubtitleProps) => props;
12
-
13
- export default function TitleSubtitle({
14
- title,
15
- subtitle,
16
- description,
17
- className
18
- }: TitleSubtitleProps) {
19
- return (
20
- <div className={`${styles.titleSubtitle} ${className}`}>
21
- {title && <h2>{title}</h2>}
22
- {subtitle && <h3 className={styles.titleSubtitleSubtitle}>{subtitle}</h3>}
23
- {description && (
24
- <p className={styles.titleSubtitleDescription}
25
- dangerouslySetInnerHTML={{__html: description}}
26
- />
27
- )}
28
- </div>
29
- )
30
- }
@@ -1,75 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useEffect } from 'react';
4
- import { REVIEWS, Review } from '@/constants/reviews';
5
-
6
- interface TranslatableReviewsProps {
7
- children: (reviews: Review[], showOriginal: boolean, toggleOriginal: () => void) => React.ReactNode;
8
- language: 'en' | 'es' | 'fr';
9
- }
10
-
11
- export default function TranslatableReviews({ children, language }: TranslatableReviewsProps) {
12
- const [translatedReviews, setTranslatedReviews] = useState<Review[]>([]);
13
- const [showOriginal, setShowOriginal] = useState(false);
14
- const [isTranslating, setIsTranslating] = useState(false);
15
-
16
- const toggleOriginal = () => {
17
- setShowOriginal(!showOriginal);
18
- };
19
-
20
- useEffect(() => {
21
- if ((language === 'es' || language === 'fr') && translatedReviews.length === 0 && !isTranslating) {
22
- translateReviews();
23
- }
24
- }, [language, translatedReviews.length, isTranslating]);
25
-
26
- const translateReviews = async () => {
27
- setIsTranslating(true);
28
- try {
29
- // Use Google Translate API to translate the reviews
30
- const translated = await Promise.all(
31
- REVIEWS.map(async (review) => {
32
- try {
33
- // For now, we'll use a simple approach with Google Translate
34
- // In production, you might want to use the Google Translate API
35
- const response = await fetch(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${language}&dt=t&q=${encodeURIComponent(review.review)}`);
36
- const data = await response.json();
37
- const translatedText = data[0]?.map((item: any) => item[0]).join('') || review.review;
38
-
39
- return {
40
- ...review,
41
- review: translatedText
42
- };
43
- } catch (error) {
44
- console.error('Translation error for review:', error);
45
- return review; // Fallback to original
46
- }
47
- })
48
- );
49
- setTranslatedReviews(translated);
50
- } catch (error) {
51
- console.error('Error translating reviews:', error);
52
- setTranslatedReviews(REVIEWS); // Fallback to original
53
- } finally {
54
- setIsTranslating(false);
55
- }
56
- };
57
-
58
- // Return original reviews for English or when showing original
59
- if (language === 'en' || showOriginal) {
60
- return <>{children(REVIEWS, showOriginal, toggleOriginal)}</>;
61
- }
62
-
63
- // Return translated reviews for Spanish or French
64
- if (translatedReviews.length > 0) {
65
- return <>{children(translatedReviews, showOriginal, toggleOriginal)}</>;
66
- }
67
-
68
- // Show loading state while translating
69
- if (isTranslating) {
70
- return <>{children(REVIEWS, showOriginal, toggleOriginal)}</>;
71
- }
72
-
73
- // Fallback to original
74
- return <>{children(REVIEWS, showOriginal, toggleOriginal)}</>;
75
- }
@@ -1,185 +0,0 @@
1
- .value-props-container {
2
- padding: var(--spacing-medium);
3
- background-color: var(--light-orange-background);
4
- }
5
-
6
- .value-props-inner {
7
- max-width: 1200px;
8
- margin: 0 auto;
9
- }
10
-
11
- .title-subtitle-container {
12
- padding: var(--spacing-small);
13
- }
14
-
15
- .value-props-grid {
16
- display: grid;
17
- grid-template-columns: repeat(2, 1fr);
18
- gap: 16px;
19
- max-width: 1200px;
20
- margin: 0 auto;
21
- }
22
-
23
- .value-prop-card:last-child:nth-child(odd) {
24
- grid-column: 1 / -1;
25
- max-width: 350px;
26
- margin: 0 auto;
27
- }
28
-
29
- @media (min-width: 768px) {
30
- .value-props-grid {
31
- gap: 24px;
32
- }
33
-
34
- .value-prop-card {
35
- padding: 24px;
36
- }
37
-
38
- .value-prop-icon-wrapper {
39
- width: 56px;
40
- height: 56px;
41
- margin: 0 auto 20px;
42
- }
43
-
44
- .value-prop-heading {
45
- font-size: 20px;
46
- margin-bottom: 12px;
47
- }
48
- }
49
-
50
- @media (min-width: 1024px) {
51
- .value-props-grid {
52
- grid-template-columns: repeat(3, 1fr);
53
- gap: 32px;
54
- }
55
-
56
- .value-prop-card {
57
- padding: 32px;
58
- min-height: 280px;
59
- gap: 16px;
60
- }
61
-
62
- .value-prop-icon-wrapper {
63
- width: 64px;
64
- height: 64px;
65
- margin: 0 auto 24px;
66
- }
67
-
68
- .value-prop-heading {
69
- font-size: 28px;
70
- margin-bottom: 16px;
71
- }
72
-
73
- .value-prop-card:last-child:nth-child(odd) {
74
- grid-column: auto;
75
- max-width: none;
76
- margin: 0;
77
- }
78
-
79
- .value-prop-card:nth-last-child(2):nth-child(4),
80
- .value-prop-card:last-child:nth-child(5) {
81
- transform: translateX(50%);
82
- }
83
- }
84
-
85
- .value-prop-card {
86
- background: white;
87
- padding: 8px 16px;
88
- border-radius: 16px;
89
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
90
- min-height: 200px;
91
- display: flex;
92
- flex-direction: column;
93
- align-items: center;
94
- justify-content: center;
95
- gap: 8px;
96
- }
97
-
98
- .value-prop-icon-wrapper {
99
- width: 48px;
100
- height: 48px;
101
- margin: 0 auto 8px;
102
- text-align: center;
103
- }
104
-
105
- .value-prop-icon {
106
- width: 48px;
107
- height: 48px;
108
-
109
- @media (min-width: 768px) {
110
- width: 80px;
111
- height: 80px;
112
- }
113
- }
114
-
115
- .value-prop-icon-wrapper {
116
- @media (min-width: 768px) {
117
- width: 80px;
118
- height: 80px;
119
- }
120
- }
121
-
122
- .value-prop-heading {
123
- font-size: 18px;
124
- margin-bottom: 8px;
125
- }
126
-
127
- @media (max-width: 768px) {
128
- .value-props-grid {
129
- display: grid !important;
130
- grid-template-columns: repeat(3, 1fr) !important;
131
- gap: 8px !important;
132
- max-width: none !important;
133
- }
134
-
135
- .value-prop-card {
136
- padding: 8px 8px !important;
137
- min-height: 120px !important;
138
- gap: 4px !important;
139
- grid-column: auto !important;
140
- max-width: none !important;
141
- margin: 0 !important;
142
- transform: none !important;
143
- }
144
-
145
- .value-prop-description {
146
- display: none;
147
- }
148
-
149
- .value-prop-icon-wrapper {
150
- width: 48px;
151
- height: 48px;
152
- margin: 0 auto 6px;
153
- display: flex;
154
- align-items: center;
155
- justify-content: center;
156
- }
157
-
158
- .value-prop-heading {
159
- font-size: 14px;
160
- margin-bottom: 4px;
161
- text-align: center;
162
- word-wrap: break-word;
163
- hyphens: auto;
164
- }
165
-
166
- .value-prop-icon {
167
- margin: 0 !important;
168
- display: block !important;
169
- width: 48px !important;
170
- height: 48px !important;
171
- flex-shrink: 0 !important;
172
- }
173
-
174
- .value-prop-icon svg {
175
- margin: 0 !important;
176
- display: block !important;
177
- width: 48px !important;
178
- height: 48px !important;
179
- }
180
-
181
- .value-prop-icon div {
182
- width: 48px !important;
183
- height: 48px !important;
184
- }
185
- }
@@ -1,88 +0,0 @@
1
- "use client";
2
-
3
- import './value-props.css';
4
- import dynamic from 'next/dynamic';
5
- import TitleSubtitle from '@/components/title-subtitle';
6
- import { VALUE_PROPS_KEYS, animations } from '@/constants/value-props';
7
-
8
- // Dynamically import Lottie with no SSR
9
- const Lottie = dynamic(() => import("lottie-react"), { ssr: false });
10
-
11
- interface ValuePropsProps {
12
- title?: string;
13
- description?: string;
14
- filterKeys?: string[];
15
- className?: string;
16
- strings: any;
17
- }
18
-
19
- export default function ValueProps({ title, description, filterKeys, className, strings }: ValuePropsProps) {
20
- // Generate value props dynamically from strings
21
- const generateValueProps = () => {
22
- const valuePropsMap = {
23
- [VALUE_PROPS_KEYS.SMALL_GROUPS]: { animationKey: 'smallGroups' as const },
24
- [VALUE_PROPS_KEYS.COZY_BLANKETS]: { animationKey: 'cozyBlankets' as const },
25
- [VALUE_PROPS_KEYS.HOT_DRINKS]: { animationKey: 'hotDrinks' as const },
26
- [VALUE_PROPS_KEYS.PHOTO_TOURS]: { animationKey: 'photoTours' as const },
27
- [VALUE_PROPS_KEYS.LOCAL_GUIDES]: { animationKey: 'localGuides' as const },
28
- [VALUE_PROPS_KEYS.CONVENIENT_PICKUP]: { animationKey: 'convenientPickup' as const },
29
- [VALUE_PROPS_KEYS.DIRECT_ACCESS]: { animationKey: 'directAccess' as const },
30
- [VALUE_PROPS_KEYS.AVOID_PAID_PARKING]: { animationKey: 'avoidPaidParking' as const },
31
- [VALUE_PROPS_KEYS.FLEXIBLE_CANCELLATION]: { animationKey: 'flexibleCancellation' as const },
32
- [VALUE_PROPS_KEYS.MULTIPLE_LOCATIONS]: { animationKey: 'multipleLocations' as const },
33
- [VALUE_PROPS_KEYS.NO_PARKING_STRUGGLES]: { animationKey: 'noParkingStruggles' as const },
34
- [VALUE_PROPS_KEYS.YOUR_PRIVATE_GROUP]: { animationKey: 'threeFriends' as const },
35
- [VALUE_PROPS_KEYS.CUSTOMIZED_ITINERARY]: { animationKey: 'map' as const },
36
- [VALUE_PROPS_KEYS.DOORSTEP_PICKUP]: { animationKey: 'convenientPickup' as const },
37
- [VALUE_PROPS_KEYS.CAPTURE_THE_MOMENT]: { animationKey: 'photoTours' as const },
38
- [VALUE_PROPS_KEYS.COZY_COMFORT]: { animationKey: 'cozyBlankets' as const },
39
- [VALUE_PROPS_KEYS.PERSONAL_GUIDES]: { animationKey: 'localGuides' as const }
40
- };
41
-
42
- return Object.entries(valuePropsMap).map(([key, { animationKey }]) => ({
43
- key,
44
- animationKey,
45
- title: strings.valueProps[key as keyof typeof strings.valueProps].title,
46
- description: strings.valueProps[key as keyof typeof strings.valueProps].description
47
- }));
48
- };
49
-
50
- const allValueProps = generateValueProps();
51
- const displayedProps = filterKeys
52
- ? allValueProps.filter(prop => filterKeys.includes(prop.key))
53
- : allValueProps;
54
-
55
- return (
56
- <section className={`value-props-container ${className}`}>
57
- <div className="value-props-inner">
58
- <div className="title-subtitle-container">
59
- {title && (
60
- <TitleSubtitle
61
- title={title}
62
- description={description}
63
- />
64
- )}
65
- </div>
66
- <div className="value-props-grid">
67
- {displayedProps.map((prop) => (
68
- <div key={prop.key} className="value-prop-card">
69
- <div className="value-prop-icon-wrapper">
70
- <Lottie
71
- animationData={animations[prop.animationKey]}
72
- loop={true}
73
- className="value-prop-icon"
74
- />
75
- </div>
76
- <h3 className="value-prop-heading">
77
- {prop.title}
78
- </h3>
79
- <p className="value-prop-description">
80
- {prop.description}
81
- </p>
82
- </div>
83
- ))}
84
- </div>
85
- </div>
86
- </section>
87
- );
88
- }
@@ -1,64 +0,0 @@
1
- import { QuizQuestion } from "@/types/quiz";
2
- import { IMAGES } from "./images";
3
-
4
- export const QUIZ_QUESTIONS: QuizQuestion[] = [
5
- {
6
- id: "what_lakes",
7
- text: "What do you want to see during your visit to Banff National Park? Select all that apply.",
8
- subtitle: "It is possible to see multiple lakes in one day, we'll recommend the best way to combine them.",
9
- answers: [
10
- {
11
- id: "moraine_lake",
12
- text: "Moraine Lake",
13
- image: IMAGES.MORAINE_LAKE_SUNRISE
14
- },
15
- {
16
- id: "lake_louise",
17
- text: "Lake Louise",
18
- image: IMAGES.LAKE_LOUISE
19
- },
20
- {
21
- id: "emerald_lake",
22
- text: "Emerald Lake",
23
- image: IMAGES.EMERALD_LAKE
24
- },
25
- { id: "other_custom", text: "Other (you want a custom itinerary)" }
26
- ],
27
- isMultiSelect: true
28
- },
29
- {
30
- id: "sunrise",
31
- text: "Do you want to see the infamous Moraine Lake sunrise?",
32
- answers: [
33
- { id: "yes", text: "Yes, I want to see the sunrise", subtext: "🐦 Early bird gets the worm!" },
34
- { id: "no", text: "No, I don't want to see the sunrise", subtext: "😴 I need my beauty rest" }
35
- ]
36
- },
37
- {
38
- id: "what_activities",
39
- text: "What activities are you interested in? Select all that apply.",
40
- subtitle: "It's possible to do multiple activities in one day! We'll recommend the best way to combine them.",
41
- answers: [
42
- { id: "banff_bucket_list", text: "Banff Bucket List" },
43
- { id: "hiking", text: "Hiking" },
44
- { id: "photography", text: "Photography" },
45
- { id: "canoeing", text: "Canoeing" },
46
- { id: "relaxation", text: "Relaxation" }
47
- ],
48
- isMultiSelect: true
49
- },
50
- {
51
- id: "hiking",
52
- text: "What type of hikes are you interested in?",
53
- answers: [
54
- { id: "easy_short_hikes", text: "Easy short hikes", subtext: "<=1 hour or 2.5km (1.5mi)" },
55
- { id: "moderate_hikes", text: "Moderate hikes", subtext: "1-2 hours or 3-6km (2-4mi)" },
56
- { id: "challenging_hikes", text: "Challenging hikes", subtext: ">2 hours or >6km (4mi)" },
57
- { id: "expert_hikes", text: "Expert hikes", subtext: ">5 hours or >10km (6mi)" }
58
- ],
59
- showIf: (answers) => {
60
- const activities = answers["what_activities"];
61
- return Array.isArray(activities) ? activities.includes("hiking") : activities === "hiking";
62
- }
63
- }
64
- ];
@@ -1,2 +0,0 @@
1
- export const CONTACT_EMAIL = 'info@viaviamorainelake.com';
2
- export const CONTACT_PHONE = '+1 587 907 4560';