@ticketboothapp/booking 0.1.11 → 0.1.12

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 (252) hide show
  1. package/package.json +1 -1
  2. package/src/colours.css +23 -0
  3. package/src/components/BookingDetails.module.css +1591 -0
  4. package/src/components/BookingDetails.tsx +2072 -354
  5. package/src/components/BookingWidget.tsx +28 -248
  6. package/src/components/JobApplicationDialog.module.css +440 -0
  7. package/src/components/JobApplicationDialog.tsx +620 -0
  8. package/src/components/ManageBookingView.tsx +28 -36
  9. package/src/components/PhoneInputWithCountry.module.css +131 -0
  10. package/src/components/PhoneInputWithCountry.tsx +44 -0
  11. package/src/components/PickupLocationDialog.module.css +360 -0
  12. package/src/components/PickupLocationDialog.tsx +357 -0
  13. package/src/components/PickupLocationMap.tsx +110 -0
  14. package/src/components/PostBookingDependentAddOnUpsell.module.css +174 -0
  15. package/src/components/PostBookingDependentAddOnUpsell.tsx +407 -0
  16. package/src/components/accordion.css +27 -0
  17. package/src/components/accordion.tsx +29 -0
  18. package/src/components/analytics/AnalyticsConsentRestore.tsx +19 -0
  19. package/src/components/analytics/AnalyticsScripts.tsx +106 -0
  20. package/src/components/analytics/CookieConsentBanner.css +86 -0
  21. package/src/components/analytics/CookieConsentBanner.tsx +102 -0
  22. package/src/components/booking/AddOnsSection.module.css +10 -0
  23. package/src/components/booking/AddOnsSection.tsx +184 -0
  24. package/src/components/booking/AdminPaymentChoiceModal.tsx +98 -0
  25. package/src/components/booking/BookingDialog.module.css +643 -0
  26. package/src/components/booking/BookingDialog.tsx +356 -0
  27. package/src/components/booking/BookingFlow.tsx +4385 -0
  28. package/src/components/booking/BookingFlowCollage.module.css +148 -0
  29. package/src/components/booking/BookingFlowCollage.tsx +184 -0
  30. package/src/components/booking/BookingFlowPlaceholder.module.css +27 -0
  31. package/src/components/booking/BookingFlowPlaceholder.tsx +25 -0
  32. package/src/components/booking/BookingFlowPreview.tsx +51 -0
  33. package/src/components/booking/BookingProductGrid.module.css +359 -0
  34. package/src/components/booking/BookingProductGrid.tsx +497 -0
  35. package/src/components/booking/Calendar.module.css +616 -0
  36. package/src/components/{Calendar.tsx → booking/Calendar.tsx} +464 -247
  37. package/src/components/booking/CancellationPolicySelector.module.css +124 -0
  38. package/src/components/booking/CancellationPolicySelector.tsx +142 -0
  39. package/src/components/booking/ChangeBookingDialog.tsx +562 -0
  40. package/src/components/booking/CheckoutForm.module.css +244 -0
  41. package/src/components/booking/CheckoutForm.tsx +364 -0
  42. package/src/components/{CheckoutModal.tsx → booking/CheckoutModal.tsx} +176 -19
  43. package/src/components/booking/DapFlowCollage.tsx +88 -0
  44. package/src/components/booking/DapTourDescription.tsx +35 -0
  45. package/src/components/booking/DependentAddOnBookingDialog.tsx +1350 -0
  46. package/src/components/booking/DependentAddOnPaymentForm.tsx +124 -0
  47. package/src/components/booking/InfoTooltip.tsx +108 -0
  48. package/src/components/booking/ItineraryBox.module.css +258 -0
  49. package/src/components/booking/ItineraryBox.tsx +550 -0
  50. package/src/components/{ItineraryBuilder.tsx → booking/ItineraryBuilder.tsx} +1 -2
  51. package/src/components/booking/ItineraryPlaceholder.module.css +45 -0
  52. package/src/components/booking/ItineraryPlaceholder.tsx +26 -0
  53. package/src/components/{MealDrinkAddOnSelector.tsx → booking/MealDrinkAddOnSelector.tsx} +21 -13
  54. package/src/components/booking/PickupLocationSelector.module.css +124 -0
  55. package/src/components/{PickupLocationSelector.tsx → booking/PickupLocationSelector.tsx} +315 -290
  56. package/src/components/booking/PickupTimeSelector.module.css +134 -0
  57. package/src/components/booking/PickupTimeSelector.tsx +112 -0
  58. package/src/components/{PriceBreakdown.tsx → booking/PriceBreakdown.tsx} +3 -3
  59. package/src/components/{PriceSummary.tsx → booking/PriceSummary.tsx} +51 -28
  60. package/src/components/booking/PrivateShuttleBookingFlow.module.css +357 -0
  61. package/src/components/booking/PrivateShuttleBookingFlow.tsx +2662 -0
  62. package/src/components/booking/PromoCodeInput.module.css +166 -0
  63. package/src/components/booking/PromoCodeInput.tsx +99 -0
  64. package/src/components/booking/ReturnTimeSelector.module.css +173 -0
  65. package/src/components/booking/ReturnTimeSelector.tsx +145 -0
  66. package/src/components/{TermsAcceptance.tsx → booking/TermsAcceptance.tsx} +9 -8
  67. package/src/components/booking/TicketSelector.module.css +164 -0
  68. package/src/components/booking/TicketSelector.tsx +199 -0
  69. package/src/components/booking/TourDescription.module.css +304 -0
  70. package/src/components/booking/TourDescription.tsx +273 -0
  71. package/src/components/booking/booking-flow-ui.ts +15 -1
  72. package/src/components/booking/booking-flow.css +944 -0
  73. package/src/components/bottom-sheet.module.css +78 -0
  74. package/src/components/bottom-sheet.tsx +60 -0
  75. package/src/components/breadcrumb.module.css +40 -0
  76. package/src/components/breadcrumb.tsx +36 -0
  77. package/src/components/button.css +245 -0
  78. package/src/components/button.tsx +152 -0
  79. package/src/components/client-bottom-sheet.tsx +14 -0
  80. package/src/components/colorable-svg.tsx +29 -0
  81. package/src/components/conditional-footer.tsx +27 -0
  82. package/src/components/contact-us.module.css +147 -0
  83. package/src/components/contact-us.tsx +49 -0
  84. package/src/components/email-signup.css +151 -0
  85. package/src/components/email-signup.tsx +63 -0
  86. package/src/components/faq-wrapper.module.css +47 -0
  87. package/src/components/faq-wrapper.tsx +15 -0
  88. package/src/components/footer.css +187 -0
  89. package/src/components/footer.tsx +143 -0
  90. package/src/components/global-simple-modal.tsx +33 -0
  91. package/src/components/google-review-summary.module.css +77 -0
  92. package/src/components/google-review-summary.tsx +50 -0
  93. package/src/components/hero-image.css +13 -0
  94. package/src/components/hero-image.tsx +44 -0
  95. package/src/components/image.css +29 -0
  96. package/src/components/image.tsx +113 -0
  97. package/src/components/language-aware-link.tsx +72 -0
  98. package/src/components/language-switcher.module.css +124 -0
  99. package/src/components/language-switcher.tsx +75 -0
  100. package/src/components/map-section.css +59 -0
  101. package/src/components/map-section.tsx +63 -0
  102. package/src/components/navbar.module.css +152 -0
  103. package/src/components/navbar.tsx +125 -0
  104. package/src/components/parallax-provider.tsx +11 -0
  105. package/src/components/partner/PartnerBookingPage.module.css +130 -0
  106. package/src/components/partner/PartnerBookingPage.tsx +390 -0
  107. package/src/components/partner/PartnerBookingPageWithBrowserMetadata.tsx +19 -35
  108. package/src/components/product-tag.module.css +30 -0
  109. package/src/components/product-tag.tsx +34 -0
  110. package/src/components/product-theme-pages/best-option.module.css +70 -0
  111. package/src/components/product-theme-pages/best-option.tsx +35 -0
  112. package/src/components/product-theme-pages/extended-tour-options.module.css +22 -0
  113. package/src/components/product-theme-pages/extended-tour-options.tsx +11 -0
  114. package/src/components/product-theme-pages/image-modal.tsx +248 -0
  115. package/src/components/product-theme-pages/photo-gallery.module.css +200 -0
  116. package/src/components/product-theme-pages/photo-gallery.tsx +90 -0
  117. package/src/components/product-theme-pages/product-theme-page-layout.module.css +13 -0
  118. package/src/components/product-theme-pages/product-theme-page-layout.tsx +67 -0
  119. package/src/components/product-theme-pages/top-of-fold.module.css +179 -0
  120. package/src/components/product-theme-pages/top-of-fold.tsx +80 -0
  121. package/src/components/product-tile/image-only-product-tile-desktop.module.css +106 -0
  122. package/src/components/product-tile/image-only-product-tile-desktop.tsx +56 -0
  123. package/src/components/product-tile/image-only-product-tile-mobile.module.css +122 -0
  124. package/src/components/product-tile/image-only-product-tile-mobile.tsx +89 -0
  125. package/src/components/product-tile/image-only-product-tile.tsx +44 -0
  126. package/src/components/product-tile/product-tile-card.module.css +84 -0
  127. package/src/components/product-tile/product-tile-card.tsx +61 -0
  128. package/src/components/review-highlights-section.css +85 -0
  129. package/src/components/review-highlights-section.tsx +127 -0
  130. package/src/components/season-closure-overlay.module.css +99 -0
  131. package/src/components/season-closure-overlay.tsx +98 -0
  132. package/src/components/simple-modal.tsx +69 -0
  133. package/src/components/simple-top-of-fold.module.css +76 -0
  134. package/src/components/simple-top-of-fold.tsx +34 -0
  135. package/src/components/spacer.css +41 -0
  136. package/src/components/spacer.tsx +23 -0
  137. package/src/components/star-rating.module.css +74 -0
  138. package/src/components/star-rating.tsx +48 -0
  139. package/src/components/terms/TermsContent.tsx +178 -0
  140. package/src/components/title-subtitle.module.css +10 -0
  141. package/src/components/title-subtitle.tsx +30 -0
  142. package/src/components/translatable-reviews.tsx +75 -0
  143. package/src/components/value-pill.module.css +59 -0
  144. package/src/components/value-pill.tsx +46 -0
  145. package/src/components/value-props.css +185 -0
  146. package/src/components/value-props.tsx +88 -0
  147. package/src/constants/booking-guide-quiz.ts +64 -0
  148. package/src/constants/contact-info.ts +2 -0
  149. package/src/constants/faq.ts +44 -0
  150. package/src/constants/images.ts +556 -0
  151. package/src/constants/json-ld/faq-json-ld.tsx +170 -0
  152. package/src/constants/json-ld/homepage-json-ld.tsx +138 -0
  153. package/src/constants/json-ld/job-posting-json-ld.tsx +92 -0
  154. package/src/constants/json-ld/organization-json-ld.tsx +62 -0
  155. package/src/constants/json-ld/page-json-ld.tsx +6 -0
  156. package/src/constants/json-ld/product-json-ld.tsx +154 -0
  157. package/src/constants/json-ld/review-json-ld.tsx +377 -0
  158. package/src/constants/navigation-links/footer-links.ts +48 -0
  159. package/src/constants/navigation-links/nav-bar-links.ts +41 -0
  160. package/src/constants/navigation-links/navigation-link.ts +6 -0
  161. package/src/constants/pill-values.ts +210 -0
  162. package/src/constants/products.ts +155 -0
  163. package/src/constants/quiz-recommendations.ts +506 -0
  164. package/src/constants/reviews.ts +75 -0
  165. package/src/constants/staff.ts +197 -0
  166. package/src/constants/value-props.ts +58 -0
  167. package/src/data/dap-descriptions/session-couples-families-friends.en.json +61 -0
  168. package/src/data/dap-descriptions/session-elopements.en.json +60 -0
  169. package/src/data/dap-descriptions/session-proposals.en.json +60 -0
  170. package/src/data/product-descriptions/afternoon-delight.en.json +35 -0
  171. package/src/data/product-descriptions/emerald-lake-escape.en.json +68 -0
  172. package/src/data/product-descriptions/lake-louise-adventure.en.json +74 -0
  173. package/src/data/product-descriptions/moraine-lake-adventure.en.json +78 -0
  174. package/src/data/product-descriptions/moraine-lake-sunrise-lake-louise-golden-hour.en.json +65 -0
  175. package/src/data/product-descriptions/moraine-lake-sunrise.en.json +64 -0
  176. package/src/data/product-descriptions/private-tour.en.json +80 -0
  177. package/src/data/product-descriptions/two-lakes-combo.en.json +65 -0
  178. package/src/data/products-config.json +101 -0
  179. package/src/hooks/use-bottom-sheet.tsx +15 -0
  180. package/src/hooks/use-simple-modal.tsx +27 -0
  181. package/src/hooks/useBookingSourceMetadataFromLocation.ts +21 -0
  182. package/src/hooks/useEmailSubscription.tsx +103 -0
  183. package/src/hooks/useEmbeddedInIframe.ts +16 -0
  184. package/src/hooks/useIsBookingLaunchLive.ts +49 -0
  185. package/src/hooks/useQuiz.tsx +210 -0
  186. package/src/index.ts +27 -2
  187. package/src/lib/analytics.ts +197 -0
  188. package/src/lib/booking/booking-source.ts +20 -2
  189. package/src/lib/{checkout-breakdown.ts → booking/checkout-breakdown.ts} +1 -1
  190. package/src/lib/booking/correlation-id.ts +46 -0
  191. package/src/lib/{i18n → booking/i18n}/messages/en.json +48 -4
  192. package/src/lib/{i18n → booking/i18n}/messages/fr.json +48 -4
  193. package/src/lib/booking/itinerary-display.ts +36 -0
  194. package/src/lib/{itinerary-labels.ts → booking/itinerary-labels.ts} +1 -1
  195. package/src/lib/{location-calculations.ts → booking/location-calculations.ts} +4 -4
  196. package/src/lib/{location-utils.ts → booking/location-utils.ts} +26 -0
  197. package/src/lib/{map-utils.ts → booking/map-utils.ts} +3 -3
  198. package/src/lib/booking/normalize-booking-product-id.ts +7 -0
  199. package/src/lib/{pickup-location-types.ts → booking/pickup-location-types.ts} +2 -2
  200. package/src/lib/{pricing.ts → booking/pricing.ts} +2 -2
  201. package/src/lib/booking/product-option-id.ts +35 -0
  202. package/src/lib/booking/source-metadata.ts +72 -7
  203. package/src/lib/booking/sunday-week.ts +14 -0
  204. package/src/lib/booking/trace-context.ts +62 -0
  205. package/src/lib/booking-api.ts +1793 -0
  206. package/src/lib/{constants.ts → booking-constants.ts} +11 -5
  207. package/src/lib/booking-types.ts +36 -0
  208. package/src/lib/currency.ts +38 -45
  209. package/src/lib/dap-descriptions.ts +50 -0
  210. package/src/lib/dap-itinerary-preview.ts +315 -0
  211. package/src/lib/dependent-add-on-api.ts +434 -0
  212. package/src/lib/env.ts +89 -5
  213. package/src/lib/firebase.ts +20 -0
  214. package/src/lib/job-application-api.ts +83 -0
  215. package/src/lib/manage-booking-embed-print.ts +16 -0
  216. package/src/lib/manage-booking-post-checkout.ts +68 -0
  217. package/src/lib/photo-dap-config.ts +228 -0
  218. package/src/lib/pickup/map-utils.ts +56 -0
  219. package/src/lib/pickup/marker-icons.ts +19 -0
  220. package/src/lib/product-descriptions.ts +66 -0
  221. package/src/lib/products-config.ts +73 -0
  222. package/src/providers/booking-dialog-provider.tsx +107 -38
  223. package/src/providers/bottom-sheet-provider.tsx +40 -0
  224. package/src/providers/dependent-add-on-dialog-provider.tsx +105 -0
  225. package/src/radius.css +5 -0
  226. package/src/spacing.css +7 -0
  227. package/src/strings/en.json +1774 -0
  228. package/src/strings/es.json +1573 -0
  229. package/src/strings/fr.json +1573 -0
  230. package/src/strings/index.js +23 -0
  231. package/src/text-style.css +97 -0
  232. package/src/types/fareharbor.d.ts +12 -0
  233. package/src/types/quiz.ts +59 -0
  234. package/src/utils/currency-converter.ts +101 -0
  235. package/src/components/BookingFlow.tsx +0 -2952
  236. package/src/components/LanguageSwitcher.tsx +0 -30
  237. package/src/components/PrivateShuttleBookingFlow.tsx +0 -2290
  238. package/src/components/ProductList.tsx +0 -78
  239. package/src/components/WhatsAppPhoneInput.tsx +0 -224
  240. package/src/components/index.ts +0 -31
  241. package/src/lib/api.ts +0 -801
  242. package/src/lib/booking-api-auth.ts +0 -9
  243. package/src/lib/checkout-breakdown.test.ts +0 -70
  244. package/src/types/google-maps.d.ts +0 -2
  245. /package/src/components/{CurrencySwitcher.tsx → booking/CurrencySwitcher.tsx} +0 -0
  246. /package/src/components/{ErrorBoundary.tsx → booking/ErrorBoundary.tsx} +0 -0
  247. /package/src/lib/{i18n → booking/i18n}/config.ts +0 -0
  248. /package/src/lib/{i18n → booking/i18n}/index.tsx +0 -0
  249. /package/src/lib/{marker-icons.ts → booking/marker-icons.ts} +0 -0
  250. /package/src/lib/{places-api.ts → booking/places-api.ts} +0 -0
  251. /package/src/lib/{theme.ts → booking/theme.ts} +0 -0
  252. /package/src/lib/{utils.ts → booking/utils.ts} +0 -0
@@ -0,0 +1,170 @@
1
+ import { getAllFAQSections, getFAQSectionByFAQPage, faqPages, faqSection } from "../faq";
2
+
3
+ // Generate FAQ JSON-LD for a specific page (e.g., HOME, MORAINE_LAKE, etc.)
4
+ export const generatePageFAQJsonLd = (faqPage: faqPages, pageUrl: string, pageTitle: string, strings: any) => {
5
+ const faqSection = getFAQSectionByFAQPage(faqPage, strings);
6
+
7
+ if (!faqSection || !faqSection.items || faqSection.items.length === 0) {
8
+ return null;
9
+ }
10
+
11
+ // SEO-optimized names and descriptions for each page type
12
+ const getPageFAQMetadata = (faqPage: faqPages, pageTitle: string) => {
13
+ switch (faqPage) {
14
+ case faqPages.HOME:
15
+ return {
16
+ name: "Moraine Lake Travel Questions & Answers",
17
+ description: "Get answers to common questions about visiting Moraine Lake, Lake Louise, and Banff National Park. Expert tips on shuttles, timing, weather, and planning your perfect trip."
18
+ };
19
+ case faqPages.MORAINE_LAKE:
20
+ return {
21
+ name: "Moraine Lake Visitor Guide - Common Questions Answered",
22
+ description: "Everything you need to know about visiting Moraine Lake: shuttle options, best times to visit, what to wear, photography tips, and how to plan your perfect day."
23
+ };
24
+ case faqPages.LAKE_LOUISE:
25
+ return {
26
+ name: "Lake Louise Travel FAQ - Plan Your Perfect Visit",
27
+ description: "Essential information for visiting Lake Louise: transportation, activities, hiking trails, canoe rentals, and insider tips for the best experience."
28
+ };
29
+ case faqPages.EMERALD_LAKE:
30
+ return {
31
+ name: "Emerald Lake Travel Questions - Hidden Gem of Banff",
32
+ description: "Discover Emerald Lake: transportation options, hiking trails, photography spots, and everything you need to know about this stunning hidden gem in Banff National Park."
33
+ };
34
+ case faqPages.PRIVATE_SHUTTLES:
35
+ return {
36
+ name: "Private Shuttle to Moraine Lake - Complete Guide",
37
+ description: "Everything about private shuttle services to Moraine Lake and Lake Louise: costs, benefits, booking tips, and how to plan your exclusive Banff adventure."
38
+ };
39
+ case faqPages.SUNRISE:
40
+ return {
41
+ name: "Moraine Lake Sunrise Experience - Plan Your Perfect Sunrise Visit",
42
+ description: "Everything you need to know about experiencing sunrise at Moraine Lake: timing, what to expect, what to wear, transportation options, and how to make the most of this magical moment."
43
+ };
44
+ default:
45
+ return {
46
+ name: `${pageTitle} - Travel Questions & Answers`,
47
+ description: `Get expert answers about visiting ${pageTitle.toLowerCase()} and the surrounding Banff National Park area. Transportation tips, planning advice, and insider knowledge.`
48
+ };
49
+ }
50
+ };
51
+
52
+ const metadata = getPageFAQMetadata(faqPage, pageTitle);
53
+
54
+ return {
55
+ "@context": "https://schema.org",
56
+ "@type": "FAQPage",
57
+ "@id": `${pageUrl}#faqpage`,
58
+ "url": pageUrl,
59
+ "name": metadata.name,
60
+ "description": metadata.description,
61
+ "mainEntity": faqSection.items.map((item, index) => ({
62
+ "@type": "Question",
63
+ "@id": `${pageUrl}#faq-question-${index + 1}`,
64
+ "name": item.question,
65
+ "acceptedAnswer": {
66
+ "@type": "Answer",
67
+ "@id": `${pageUrl}#faq-answer-${index + 1}`,
68
+ "text": item.answer.replace(/<[^>]*>/g, ''), // Remove HTML tags for clean text
69
+ "dateCreated": "2025-01-15T00:00:00+00:00",
70
+ "upvoteCount": 0,
71
+ "url": pageUrl
72
+ }
73
+ })),
74
+ "about": {
75
+ "@type": "Organization",
76
+ "@id": "https://viaviamorainelake.com/#business",
77
+ "name": "Via Via Moraine Lake Shuttle"
78
+ },
79
+ "publisher": {
80
+ "@type": "Organization",
81
+ "@id": "https://viaviamorainelake.com/#business",
82
+ "name": "Via Via Moraine Lake Shuttle"
83
+ },
84
+ "inLanguage": "en-US",
85
+ "datePublished": "2025-04-15T00:00:00+00:00",
86
+ "dateModified": "2025-08-28T00:00:00+00:00"
87
+ };
88
+ };
89
+
90
+ // Generate FAQ JSON-LD for a specific FAQ section
91
+ export const generateSectionFAQJsonLd = (section: faqSection, pageUrl: string, pageTitle: string) => {
92
+ if (!section || !section.items || section.items.length === 0) {
93
+ return null;
94
+ }
95
+
96
+ return {
97
+ "@context": "https://schema.org",
98
+ "@type": "FAQPage",
99
+ "@id": `${pageUrl}#faqpage`,
100
+ "url": pageUrl,
101
+ "name": `${pageTitle} - ${section.title || 'Travel Questions & Answers'}`,
102
+ "description": `Expert answers about ${section.title?.toLowerCase() || 'traveling in Banff National Park'}. Get insider tips, planning advice, and everything you need to know for your perfect adventure.`,
103
+ "mainEntity": section.items.map((item, index) => ({
104
+ "@type": "Question",
105
+ "@id": `${pageUrl}#faq-question-${index + 1}`,
106
+ "name": item.question,
107
+ "acceptedAnswer": {
108
+ "@type": "Answer",
109
+ "@id": `${pageUrl}#faq-answer-${index + 1}`,
110
+ "text": item.answer.replace(/<[^>]*>/g, ''), // Remove HTML tags for clean text
111
+ "dateCreated": "2025-04-15T00:00:00+00:00",
112
+ "upvoteCount": 0,
113
+ "url": pageUrl
114
+ }
115
+ })),
116
+ "about": {
117
+ "@type": "Organization",
118
+ "@id": "https://viaviamorainelake.com/#business",
119
+ "name": "Via Via Moraine Lake Shuttle"
120
+ },
121
+ "publisher": {
122
+ "@type": "Organization",
123
+ "@id": "https://viaviamorainelake.com/#business",
124
+ "name": "Via Via Moraine Lake Shuttle"
125
+ },
126
+ "inLanguage": "en-US",
127
+ "datePublished": "2025-04-15T00:00:00+00:00",
128
+ "dateModified": "2025-08-28T00:00:00+00:00"
129
+ };
130
+ };
131
+
132
+ // Main FAQ page JSON-LD (all FAQ sections)
133
+ export const faqJsonLd = (strings: any) => {
134
+ return {
135
+ "@context": "https://schema.org",
136
+ "@type": "FAQPage",
137
+ "@id": "https://viaviamorainelake.com/faq#faqpage",
138
+ "url": "https://viaviamorainelake.com/faq",
139
+ "name": "Moraine Lake & Banff Travel Questions - Complete Visitor Guide",
140
+ "description": "Get expert answers to all your questions about visiting Moraine Lake, Lake Louise, and Banff National Park. Transportation tips, planning advice, photography guidance, and insider knowledge for the perfect Canadian Rockies adventure.",
141
+ "mainEntity": getAllFAQSections(strings).flatMap((section, sectionIndex) =>
142
+ section.items.map((item, itemIndex) => ({
143
+ "@type": "Question",
144
+ "@id": `https://viaviamorainelake.com/faq#faq-${sectionIndex}-${itemIndex}`,
145
+ "name": item.question,
146
+ "acceptedAnswer": {
147
+ "@type": "Answer",
148
+ "@id": `https://viaviamorainelake.com/faq#faq-answer-${sectionIndex}-${itemIndex}`,
149
+ "text": item.answer.replace(/<[^>]*>/g, ''), // Remove HTML tags for clean text
150
+ "dateCreated": "2025-04-15T00:00:00+00:00",
151
+ "upvoteCount": 0,
152
+ "url": "https://viaviamorainelake.com/faq"
153
+ }
154
+ }))
155
+ ),
156
+ "about": {
157
+ "@type": "Organization",
158
+ "@id": "https://viaviamorainelake.com/#business",
159
+ "name": "Via Via Moraine Lake Shuttle"
160
+ },
161
+ "publisher": {
162
+ "@type": "Organization",
163
+ "@id": "https://viaviamorainelake.com/#business",
164
+ "name": "Via Via Moraine Lake Shuttle"
165
+ },
166
+ "inLanguage": "en-US",
167
+ "datePublished": "2025-04-15T00:00:00+00:00",
168
+ "dateModified": "2025-08-28T00:00:00+00:00"
169
+ }
170
+ };
@@ -0,0 +1,138 @@
1
+ import { IMAGES, getImageUrl } from "../images"
2
+ import { organizationJsonLd } from "./organization-json-ld"
3
+ import { getFAQSectionByFAQPage, faqPages } from "../faq"
4
+ import { aggregateRatingJsonLd } from "./review-json-ld"
5
+
6
+ const heroImage = IMAGES.MORAINE_LAKE_SUNRISE_YELLOW_JACKET
7
+
8
+ // Generate FAQ structured data for homepage
9
+ const generateFAQJsonLd = (strings: any) => {
10
+ const faqSection = getFAQSectionByFAQPage(faqPages.HOME, strings);
11
+
12
+ if (!faqSection || !faqSection.items || faqSection.items.length === 0) {
13
+ return null;
14
+ }
15
+
16
+ // Determine language from strings object
17
+ const isSpanish = strings?.navigationLinks?.faq === 'Preguntas frequentes' || false;
18
+ const isFrench = strings?.navigationLinks?.faq === 'FAQ' && strings?.common?.viaVia === 'Via Via' && strings?.home?.hero?.tagline?.includes('familles') || false;
19
+ const language = isSpanish ? 'es-ES' : isFrench ? 'fr-CA' : 'en-US';
20
+
21
+ return {
22
+ "@type": "FAQPage",
23
+ "@id": "https://viaviamorainelake.com/#faqpage",
24
+ "name": isSpanish ? "Preguntas y Respuestas sobre Viajes a Moraine Lake" :
25
+ isFrench ? "Questions et Réponses sur les Voyages au Lac Moraine" :
26
+ "Moraine Lake Travel Questions & Answers",
27
+ "description": isSpanish ?
28
+ "Obtén respuestas a preguntas comunes sobre visitar Moraine Lake, Lake Louise y el Parque Nacional Banff. Consejos expertos sobre transporte, horarios, clima y planificación de tu viaje perfecto." :
29
+ isFrench ?
30
+ "Obtenez des réponses aux questions courantes sur la visite du lac Moraine, du lac Louise et du parc national Banff. Conseils d'experts sur les navettes, les horaires, la météo et la planification de votre voyage parfait." :
31
+ "Get answers to common questions about visiting Moraine Lake, Lake Louise, and Banff National Park. Expert tips on shuttles, timing, weather, and planning your perfect trip.",
32
+ "mainEntity": faqSection.items.map((item, index) => ({
33
+ "@type": "Question",
34
+ "@id": `https://viaviamorainelake.com/#faq-question-${index + 1}`,
35
+ "name": item.question,
36
+ "acceptedAnswer": {
37
+ "@type": "Answer",
38
+ "@id": `https://viaviamorainelake.com/#faq-answer-${index + 1}`,
39
+ "text": item.answer.replace(/<[^>]*>/g, ''), // Remove HTML tags for clean text
40
+ "dateCreated": "2025-01-15T00:00:00+00:00",
41
+ "upvoteCount": 0,
42
+ "url": "https://viaviamorainelake.com/#faq"
43
+ }
44
+ })),
45
+ "about": {
46
+ "@id": "https://viaviamorainelake.com/#business"
47
+ },
48
+ "isPartOf": {
49
+ "@id": "https://viaviamorainelake.com/#webpage"
50
+ }
51
+ };
52
+ };
53
+
54
+ export const homepageJsonLd = (strings: any) => {
55
+ // Determine language from strings object
56
+ const isSpanish = strings?.navigationLinks?.faq === 'Preguntas frequentes' || false;
57
+ const isFrench = strings?.navigationLinks?.faq === 'FAQ' && strings?.common?.viaVia === 'Via Via' && strings?.home?.hero?.tagline?.includes('familles') || false;
58
+ const language = isSpanish ? 'es-ES' : isFrench ? 'fr-CA' : 'en-US';
59
+ const baseUrl = isSpanish ? 'https://viaviamorainelake.com/es' : isFrench ? 'https://viaviamorainelake.com/fr' : 'https://viaviamorainelake.com';
60
+
61
+ return {
62
+ "@context": "https://schema.org",
63
+ "@graph": [
64
+ {
65
+ "@type":"Place",
66
+ "@id":"https://viaviamorainelake.com/#place",
67
+ "geo":{
68
+ "@type":"GeoCoordinates",
69
+ "latitude":"51.0802635",
70
+ "longitude":" -115.3304743"
71
+ },
72
+ "hasMap":"https://maps.app.goo.gl/94Ns1sfay3WZgswVA",
73
+ "address":{
74
+ "@type":"PostalAddress",
75
+ "streetAddress":"Moraine Road",
76
+ "addressLocality":"Canmore",
77
+ "addressRegion":"Alberta",
78
+ "postalCode":"T1W 1J7",
79
+ "addressCountry":"Canada"
80
+ }
81
+ },
82
+ organizationJsonLd,
83
+ aggregateRatingJsonLd,
84
+ {
85
+ "@type":"WebSite",
86
+ "@id":"https://viaviamorainelake.com/#website",
87
+ "url": baseUrl,
88
+ "name":"Via Via Moraine Lake Shuttle",
89
+ "publisher":{
90
+ "@id":"https://viaviamorainelake.com/#business"
91
+ },
92
+ "inLanguage": language,
93
+ "potentialAction":{
94
+ "@type":"BuyAction",
95
+ "object": {
96
+ "@type": "Reservation",
97
+ "name": "Moraine Lake Shuttle"
98
+ },
99
+ "seller": {
100
+ "@type": "Organization",
101
+ "name": "Via Via Moraine Lake Shuttle"
102
+ }
103
+ }
104
+ },
105
+ {
106
+ "@type":"ImageObject",
107
+ "@id":`${heroImage.id}`,
108
+ "url": getImageUrl(heroImage.id),
109
+ "width":"1200",
110
+ "height":"630",
111
+ "caption":"Sunrise at Moraine Lake in July",
112
+ "inLanguage": language
113
+ },
114
+ {
115
+ "@type":"WebPage",
116
+ "@id":"https://viaviamorainelake.com/#webpage",
117
+ "url": baseUrl + "/",
118
+ "name": isSpanish ? "Transporte a Moraine Lake - Visita Lake Louise y Moraine Lake" :
119
+ isFrench ? "Navette du Lac Moraine - Visitez le Lac Louise et le Lac Moraine" :
120
+ "Moraine Lake Shuttle - Visit Lake Louise &amp; Moraine Lake",
121
+ "datePublished":"2024-02-04T09:16:54+00:00",
122
+ "dateModified":"2025-08-28T12:00:00+00:00",
123
+ "about":{
124
+ "@id":"https://viaviamorainelake.com/#business"
125
+ },
126
+ "isPartOf":{
127
+ "@id":"https://viaviamorainelake.com/#website"
128
+ },
129
+ "primaryImageOfPage":{
130
+ "@id":`${heroImage.id}`
131
+ },
132
+ "inLanguage": language
133
+ },
134
+ // Add FAQ structured data if available
135
+ ...(generateFAQJsonLd(strings) ? [generateFAQJsonLd(strings)] : [])
136
+ ]
137
+ };
138
+ }
@@ -0,0 +1,92 @@
1
+ import { organizationJsonLd } from "./organization-json-ld";
2
+
3
+ export const jobPostingJsonLd = {
4
+ "@context": "https://schema.org",
5
+ "@graph": [
6
+ {
7
+ organizationJsonLd,
8
+ "@context": "https://schema.org/",
9
+ "@type": "JobPosting",
10
+ "title": "Adventure Experience Guide",
11
+ "description": "<p>Are you ready for the summer of a lifetime? We're on the lookout for passionate, adventure-loving individuals to join our crew as Adventure Experience Guides! If you thrive in a dynamic environment, love connecting with people from around the world, and want to spend your summer surrounded by iconic mountain landscapes from sunrise to sunset — this could be your dream job!</p>",
12
+ "identifier": {
13
+ "@type": "PropertyValue",
14
+ "name": "Via Via Moraine Lake Shuttle",
15
+ "value": "https://docs.google.com/forms/d/e/1FAIpQLSf02Vf-CCjS_vLkXxMaGP7qSNE6WuvGIU284kBm2VCVuMyyWQ/viewform"
16
+ },
17
+ "hiringOrganization" : {
18
+ "@type": "Organization",
19
+ "name": "Via Via Moraine Lake Shuttle",
20
+ "sameAs": "https://viaviamorainelake.com/careers",
21
+ "logo": "https://www.viaviamorainelake.com/icon.png"
22
+ },
23
+ "industry": "Hospitality",
24
+ "employmentType": "FULL_TIME",
25
+ "datePosted": "2025-03-05",
26
+ "validThrough": "2025-05-31",
27
+ "jobLocation": {
28
+ "@type": "Place",
29
+ "address": {
30
+ "@type": "PostalAddress",
31
+ "streetAddress": "Moraine Road, Canmore, AB T1W 1J7",
32
+ "addressLocality": "Canmore",
33
+ "addressRegion": "AB",
34
+ "postalCode": "T1W 1J7",
35
+ "addressCountry": "CA"
36
+ },
37
+ },
38
+ "baseSalary": {
39
+ "@type": "MonetaryAmount",
40
+ "currency": "CAD",
41
+ "value": {
42
+ "@type": "QuantitativeValue",
43
+ "minValue": 25,
44
+ "maxValue": 35,
45
+ "unitText": "HOUR"
46
+ }
47
+ }
48
+ },
49
+ {
50
+ "@context": "https://schema.org/",
51
+ "@type": "JobPosting",
52
+ "title": "Operations & Adventure",
53
+ "description": "<p>We're on the lookout for a detail-savvy, adventure-loving go-getter to join our crew as an Operations & Adventure Coordinator! This dynamic role is perfect for someone who loves keeping things running smoothly behind the scenes, thrives in a fast-paced environment, and enjoys connecting with both guests and teammates. If you're passionate about creating seamless experiences in the heart of the Canadian Rockies, this could be your summer of a lifetime.</p>",
54
+ "identifier": {
55
+ "@type": "PropertyValue",
56
+ "name": "Via Via Moraine Lake Shuttle",
57
+ "value": "https://docs.google.com/forms/d/e/1FAIpQLSeHe91VJRvB79Uy2SNlqs-trxBm4u38EfrB0wyIu5-mYSlBcQ/viewform"
58
+ },
59
+ "hiringOrganization" : {
60
+ "@type": "Organization",
61
+ "name": "Via Via Moraine Lake Shuttle",
62
+ "sameAs": "https://viaviamorainelake.com/careers",
63
+ "logo": "https://www.viaviamorainelake.com/icon.png"
64
+ },
65
+ "industry": "Hospitality",
66
+ "employmentType": "FULL_TIME",
67
+ "datePosted": "2025-03-05",
68
+ "validThrough": "2025-05-31",
69
+ "jobLocation": {
70
+ "@type": "Place",
71
+ "address": {
72
+ "@type": "PostalAddress",
73
+ "streetAddress": "Moraine Road, Canmore, AB T1W 1J7",
74
+ "addressLocality": "Canmore",
75
+ "addressRegion": "AB",
76
+ "postalCode": "T1W 1J7",
77
+ "addressCountry": "CA"
78
+ },
79
+ },
80
+ "baseSalary": {
81
+ "@type": "MonetaryAmount",
82
+ "currency": "CAD",
83
+ "value": {
84
+ "@type": "QuantitativeValue",
85
+ "minValue": 28,
86
+ "maxValue": 35,
87
+ "unitText": "HOUR"
88
+ }
89
+ }
90
+ },
91
+ ]
92
+ }
@@ -0,0 +1,62 @@
1
+ export const organizationJsonLd = {
2
+ "@type": "TravelAgency",
3
+ "name": "Via Via Moraine Lake Shuttle",
4
+ "image": "https://d3leofpfxe37yh.cloudfront.net/moraine-lake-sunrise-yellow-jacket.jpg",
5
+ "@id": "https://viaviamorainelake.com#business",
6
+ "url": "https://viaviamorainelake.com",
7
+ "telephone": "+15879074560",
8
+ "email":"info@viaviamorainelake.com",
9
+ "address": {
10
+ "@type": "PostalAddress",
11
+ "streetAddress": "Moraine Road, Canmore, AB T1W 1J7",
12
+ "addressLocality": "Canmore",
13
+ "addressRegion": "AB",
14
+ "postalCode": "T1W 1J7",
15
+ "addressCountry": "CA"
16
+ },
17
+ "geo": {
18
+ "@type": "GeoCoordinates",
19
+ "latitude": 51.0802635,
20
+ "longitude": -115.3304743
21
+ },
22
+ "openingHoursSpecification": {
23
+ "@type": "OpeningHoursSpecification",
24
+ "dayOfWeek": [
25
+ "Monday",
26
+ "Tuesday",
27
+ "Wednesday",
28
+ "Thursday",
29
+ "Friday",
30
+ "Saturday",
31
+ "Sunday"
32
+ ],
33
+ "opens": "09:00",
34
+ "closes": "19:00"
35
+ },
36
+ "sameAs": [
37
+ "https://instagram.com/viaviamorainelake",
38
+ "https://www.facebook.com/profile.php?id=61557238871790",
39
+ "https://viaviamorainelake.com/",
40
+ "https://www.linkedin.com/company/via-via-moraine-lake-shuttle/"
41
+ ],
42
+ "contactPoint":[
43
+ {
44
+ "@type":"ContactPoint",
45
+ "telephone":"+15879074560",
46
+ "contactType":"customer support"
47
+ }
48
+ ],
49
+ "priceRange": "$$",
50
+ "description": "Via Via Moraine Lake Shuttle is a locally owned and operated shuttle company operating in Canmore & Banff National Park. We're not just about providing transportation, we're about making a positive impact!",
51
+ "logo":{
52
+ "@type":"ImageObject",
53
+ "@id":"https:viaviamorainelake.com/#logo",
54
+ "url":"https://www.viaviamorainelake.com/icon.png",
55
+ "contentUrl":"https://www.viaviamorainelake.com/icon.png",
56
+ "caption":"Via Via Moraine Lake Shuttle Logo",
57
+ "inLanguage":"en-US"
58
+ },
59
+ "aggregateRating": {
60
+ "@id": "https://viaviamorainelake.com/#aggregateRating"
61
+ }
62
+ }
@@ -0,0 +1,6 @@
1
+ export function pageJsonLd(graph: any[]) {
2
+ return {
3
+ "@context": "https://schema.org/",
4
+ "@graph": graph
5
+ }
6
+ }
@@ -0,0 +1,154 @@
1
+ import { PRODUCTS } from "../products";
2
+ import { getImageUrl } from "../images";
3
+
4
+ type ProductJsonLd = {
5
+ "@context": "https://schema.org/",
6
+ "@type": "Product",
7
+ name: string,
8
+ image: string[],
9
+ description: string,
10
+ brand: {
11
+ "@type": "Brand",
12
+ name: string
13
+ },
14
+ offers: {
15
+ "@type": "Offer",
16
+ url: string,
17
+ priceCurrency: string,
18
+ price: number,
19
+ availability: string
20
+ }
21
+ }
22
+
23
+ export const moraineLakeSunriseJsonLd : ProductJsonLd = {
24
+ "@context": "https://schema.org/",
25
+ "@type": "Product",
26
+ "name": PRODUCTS.MORAINE_LAKE_SUNRISE.name,
27
+ "image": PRODUCTS.MORAINE_LAKE_SUNRISE.images.map(image => getImageUrl(image.id)),
28
+ "description": PRODUCTS.MORAINE_LAKE_SUNRISE.description,
29
+ "brand": {
30
+ "@type": "Brand",
31
+ "name": "Via Via Moraine Lake Shuttle"
32
+ },
33
+ "offers": {
34
+ "@type": "Offer",
35
+ "url": `https://viaviamorainelake.com${PRODUCTS.MORAINE_LAKE_SUNRISE.path}`,
36
+ "priceCurrency": "CAD",
37
+ "price": PRODUCTS.MORAINE_LAKE_SUNRISE.avgPrice,
38
+ "availability": "https://schema.org/LimitedAvailability"
39
+ }
40
+ }
41
+
42
+ export const moraineLakeSunriseLakeLouiseGoldenHourJsonLd : ProductJsonLd = {
43
+ "@context": "https://schema.org/",
44
+ "@type": "Product",
45
+ "name": PRODUCTS.MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR.name,
46
+ "image": PRODUCTS.MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR.images.map(image => getImageUrl(image.id)),
47
+ "description": PRODUCTS.MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR.description,
48
+ "brand": {
49
+ "@type": "Brand",
50
+ "name": "Via Via Moraine Lake Shuttle"
51
+ },
52
+ "offers": {
53
+ "@type": "Offer",
54
+ "url": `https://viaviamorainelake.com${PRODUCTS.MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR.path}`,
55
+ "priceCurrency": "CAD",
56
+ "price": PRODUCTS.MORAINE_LAKE_SUNRISE_LAKE_LOUISE_GOLDEN_HOUR.avgPrice,
57
+ "availability": "https://schema.org/LimitedAvailability"
58
+ }
59
+ }
60
+
61
+ export const twoLakesComboJsonLd : ProductJsonLd = {
62
+ "@context": "https://schema.org/",
63
+ "@type": "Product",
64
+ "name": PRODUCTS.TWO_LAKES_COMBO.name,
65
+ "image": PRODUCTS.TWO_LAKES_COMBO.images.map(image => getImageUrl(image.id)),
66
+ "description": PRODUCTS.TWO_LAKES_COMBO.description,
67
+ "brand": {
68
+ "@type": "Brand",
69
+ "name": "Via Via Moraine Lake Shuttle"
70
+ },
71
+ "offers": {
72
+ "@type": "Offer",
73
+ "url": `https://viaviamorainelake.com${PRODUCTS.TWO_LAKES_COMBO.path}`,
74
+ "priceCurrency": "CAD",
75
+ "price": PRODUCTS.TWO_LAKES_COMBO.avgPrice,
76
+ "availability": "https://schema.org/LimitedAvailability"
77
+ }
78
+ }
79
+
80
+ export const moraineLakeAdventureJsonLd : ProductJsonLd = {
81
+ "@context": "https://schema.org/",
82
+ "@type": "Product",
83
+ "name": PRODUCTS.MORAINE_LAKE_ADVENTURE.name,
84
+ "image": PRODUCTS.MORAINE_LAKE_ADVENTURE.images.map(image => getImageUrl(image.id)),
85
+ "description": PRODUCTS.MORAINE_LAKE_ADVENTURE.description,
86
+ "brand": {
87
+ "@type": "Brand",
88
+ "name": "Via Via Moraine Lake Shuttle"
89
+ },
90
+ "offers": {
91
+ "@type": "Offer",
92
+ "url": `https://viaviamorainelake.com${PRODUCTS.MORAINE_LAKE_ADVENTURE.path}`,
93
+ "priceCurrency": "CAD",
94
+ "price": PRODUCTS.MORAINE_LAKE_ADVENTURE.avgPrice,
95
+ "availability": "https://schema.org/LimitedAvailability"
96
+ }
97
+ }
98
+
99
+ export const lakeLouiseAdventureJsonLd : ProductJsonLd = {
100
+ "@context": "https://schema.org/",
101
+ "@type": "Product",
102
+ "name": PRODUCTS.LAKE_LOUISE_ADVENTURE.name,
103
+ "image": PRODUCTS.LAKE_LOUISE_ADVENTURE.images.map(image => getImageUrl(image.id)),
104
+ "description": PRODUCTS.LAKE_LOUISE_ADVENTURE.description,
105
+ "brand": {
106
+ "@type": "Brand",
107
+ "name": "Via Via Moraine Lake Shuttle"
108
+ },
109
+ "offers": {
110
+ "@type": "Offer",
111
+ "url": `https://viaviamorainelake.com${PRODUCTS.LAKE_LOUISE_ADVENTURE.path}`,
112
+ "priceCurrency": "CAD",
113
+ "price": PRODUCTS.LAKE_LOUISE_ADVENTURE.avgPrice,
114
+ "availability": "https://schema.org/LimitedAvailability"
115
+ }
116
+ }
117
+
118
+ export const emeraldLakeEscapeTourJsonLd : ProductJsonLd = {
119
+ "@context": "https://schema.org/",
120
+ "@type": "Product",
121
+ "name": PRODUCTS.EMERALD_LAKE_ESCAPE.name,
122
+ "image": PRODUCTS.EMERALD_LAKE_ESCAPE.images.map(image => getImageUrl(image.id)),
123
+ "description": PRODUCTS.EMERALD_LAKE_ESCAPE.description,
124
+ "brand": {
125
+ "@type": "Brand",
126
+ "name": "Via Via Moraine Lake Shuttle"
127
+ },
128
+ "offers": {
129
+ "@type": "Offer",
130
+ "url": `https://viaviamorainelake.com${PRODUCTS.EMERALD_LAKE_ESCAPE.path}`,
131
+ "priceCurrency": "CAD",
132
+ "price": PRODUCTS.EMERALD_LAKE_ESCAPE.avgPrice,
133
+ "availability": "https://schema.org/LimitedAvailability"
134
+ }
135
+ }
136
+
137
+ export const privateTourJsonLd : ProductJsonLd = {
138
+ "@context": "https://schema.org/",
139
+ "@type": "Product",
140
+ "name": PRODUCTS.PRIVATE_TOUR.name,
141
+ "image": PRODUCTS.PRIVATE_TOUR.images.map(image => getImageUrl(image.id)),
142
+ "description": PRODUCTS.PRIVATE_TOUR.description,
143
+ "brand": {
144
+ "@type": "Brand",
145
+ "name": "Via Via Moraine Lake Shuttle"
146
+ },
147
+ "offers": {
148
+ "@type": "Offer",
149
+ "url": `https://viaviamorainelake.com${PRODUCTS.PRIVATE_TOUR.path}`,
150
+ "priceCurrency": "CAD",
151
+ "price": PRODUCTS.PRIVATE_TOUR.avgPrice,
152
+ "availability": "https://schema.org/LimitedAvailability"
153
+ }
154
+ }