@alphasquad/saleor-template-advance 0.1.0

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 (441) hide show
  1. package/.env.example +57 -0
  2. package/APPLE_PAY_QUICK_START.md +165 -0
  3. package/APPLE_PAY_SETUP.md +331 -0
  4. package/README.md +46 -0
  5. package/SEO_AUDIT_CHECKLIST_STATUS.md +244 -0
  6. package/SEO_AUDIT_REPORT.md +66 -0
  7. package/eslint.config.mjs +16 -0
  8. package/next-env.d.ts +5 -0
  9. package/next.config.ts +109 -0
  10. package/package.json +47 -0
  11. package/postcss.config.mjs +5 -0
  12. package/public/.well-known/apple-developer-merchantid-domain-association +1 -0
  13. package/public/Logo.png +0 -0
  14. package/public/brand-video.mp4 +0 -0
  15. package/public/favicon.ico +0 -0
  16. package/public/file.svg +1 -0
  17. package/public/footer/facebook.tsx +34 -0
  18. package/public/footer/instagram.tsx +27 -0
  19. package/public/footer/mail.tsx +5 -0
  20. package/public/footer/x.tsx +35 -0
  21. package/public/globe.svg +1 -0
  22. package/public/icons/Authorize.net.webp +0 -0
  23. package/public/icons/amex.gif +0 -0
  24. package/public/icons/appIcon.png +0 -0
  25. package/public/icons/discover.gif +0 -0
  26. package/public/icons/master.gif +0 -0
  27. package/public/icons/paypal.png +0 -0
  28. package/public/icons/stripe.png +0 -0
  29. package/public/icons/visa.gif +0 -0
  30. package/public/images/BackgroundNoise.png +0 -0
  31. package/public/images/footer-background.png +0 -0
  32. package/public/next.svg +1 -0
  33. package/public/no-image-avail-large.png +0 -0
  34. package/public/random-car-1.jpeg +0 -0
  35. package/public/random-car-2.png +0 -0
  36. package/public/random-car-3.jpg +0 -0
  37. package/public/random-car-4.jpg +0 -0
  38. package/public/random-car-5.jpg +0 -0
  39. package/public/star.svg +3 -0
  40. package/public/vercel.svg +1 -0
  41. package/public/window.svg +1 -0
  42. package/scripts/seo-audit/generate-checklist.mjs +156 -0
  43. package/src/app/(auth)/account/forgot-password/layout.tsx +16 -0
  44. package/src/app/(auth)/account/forgot-password/page.tsx +135 -0
  45. package/src/app/(auth)/account/login/layout.tsx +16 -0
  46. package/src/app/(auth)/account/login/page.tsx +288 -0
  47. package/src/app/(auth)/account/otp/layout.tsx +16 -0
  48. package/src/app/(auth)/account/otp/page.tsx +108 -0
  49. package/src/app/(auth)/account/register/layout.tsx +16 -0
  50. package/src/app/(auth)/account/register/page.tsx +431 -0
  51. package/src/app/(auth)/account/reset-password/layout.tsx +16 -0
  52. package/src/app/(auth)/account/reset-password/page.tsx +222 -0
  53. package/src/app/[slug]/page.tsx +43 -0
  54. package/src/app/about/loading.tsx +17 -0
  55. package/src/app/about/page.tsx +61 -0
  56. package/src/app/account/address/layout.tsx +15 -0
  57. package/src/app/account/address/page.tsx +166 -0
  58. package/src/app/account/head.tsx +4 -0
  59. package/src/app/account/layout.tsx +62 -0
  60. package/src/app/account/orders/[id]/layout.tsx +17 -0
  61. package/src/app/account/orders/[id]/page.tsx +115 -0
  62. package/src/app/account/orders/components/orderDetailsModal.tsx +410 -0
  63. package/src/app/account/orders/layout.tsx +15 -0
  64. package/src/app/account/orders/page.tsx +146 -0
  65. package/src/app/account/page.tsx +39 -0
  66. package/src/app/account/settings/components/editProfileSuccessModal.tsx +28 -0
  67. package/src/app/account/settings/layout.tsx +15 -0
  68. package/src/app/account/settings/page.tsx +260 -0
  69. package/src/app/api/affirm/check-status/route.ts +94 -0
  70. package/src/app/api/affirm/create-checkout/route.ts +109 -0
  71. package/src/app/api/affirm/get-config/route.ts +108 -0
  72. package/src/app/api/affirm/process-payment/route.ts +244 -0
  73. package/src/app/api/affirm/test-connection/route.ts +45 -0
  74. package/src/app/api/auth/clear/route.ts +16 -0
  75. package/src/app/api/auth/clear-cookies/route.ts +42 -0
  76. package/src/app/api/auth/set/route.ts +47 -0
  77. package/src/app/api/configuration/route.ts +18 -0
  78. package/src/app/api/dynamic-page/[slug]/route.ts +24 -0
  79. package/src/app/api/form-submission/route.ts +237 -0
  80. package/src/app/api/paypal/capture-order/route.ts +303 -0
  81. package/src/app/api/paypal/create-order/route.ts +211 -0
  82. package/src/app/api/paypal/get-config/route.ts +240 -0
  83. package/src/app/api/search-proxy/route.ts +52 -0
  84. package/src/app/authorize-net-success/layout.tsx +19 -0
  85. package/src/app/authorize-net-success/page.tsx +12 -0
  86. package/src/app/authorize-net-success/summary.tsx +486 -0
  87. package/src/app/blog/[slug]/blogContentRenderer.tsx +369 -0
  88. package/src/app/blog/[slug]/layout.tsx +17 -0
  89. package/src/app/blog/[slug]/page.tsx +151 -0
  90. package/src/app/blog/constant.tsx +147 -0
  91. package/src/app/blog/layout.tsx +31 -0
  92. package/src/app/blog/page.tsx +81 -0
  93. package/src/app/brand/[id]/BrandPageClient.tsx +188 -0
  94. package/src/app/brand/[id]/layout.tsx +17 -0
  95. package/src/app/brand/[id]/page.tsx +176 -0
  96. package/src/app/brands/components/brandsListingClient.tsx +97 -0
  97. package/src/app/brands/layout.tsx +31 -0
  98. package/src/app/brands/page.tsx +40 -0
  99. package/src/app/cancellation-policy/page.tsx +53 -0
  100. package/src/app/cart/layout.tsx +19 -0
  101. package/src/app/cart/page.tsx +752 -0
  102. package/src/app/category/[slug]/CategoryPageClient.tsx +377 -0
  103. package/src/app/category/[slug]/layout.tsx +17 -0
  104. package/src/app/category/[slug]/page.tsx +224 -0
  105. package/src/app/category/page.tsx +114 -0
  106. package/src/app/checkout/components/addNewAddressModal.tsx +474 -0
  107. package/src/app/checkout/layout.tsx +19 -0
  108. package/src/app/checkout/page.tsx +3312 -0
  109. package/src/app/components/account/AccountTabs.tsx +40 -0
  110. package/src/app/components/ads/GoogleAdSense.tsx +74 -0
  111. package/src/app/components/analytics/AnalyticsScripts.tsx +78 -0
  112. package/src/app/components/analytics/ConditionalGTMNoscript.tsx +24 -0
  113. package/src/app/components/analytics/ConditionalGoogleAnalytics.tsx +16 -0
  114. package/src/app/components/ancillary/AncillaryContent.tsx +7 -0
  115. package/src/app/components/auth/TokenExpirationHandler.tsx +8 -0
  116. package/src/app/components/blog/BlogList.tsx +112 -0
  117. package/src/app/components/checkout/AddressInformationSection.tsx +34 -0
  118. package/src/app/components/checkout/AddressManagement.tsx +571 -0
  119. package/src/app/components/checkout/CheckoutHeader.tsx +51 -0
  120. package/src/app/components/checkout/CheckoutQuestions.tsx +454 -0
  121. package/src/app/components/checkout/CheckoutTermsModal.tsx +81 -0
  122. package/src/app/components/checkout/ContactDetailsSection.tsx +52 -0
  123. package/src/app/components/checkout/DealerShippingSection.tsx +359 -0
  124. package/src/app/components/checkout/DeliveryMethodSection.tsx +249 -0
  125. package/src/app/components/checkout/OrderSummary.tsx +386 -0
  126. package/src/app/components/checkout/TermsContentRenderer.tsx +147 -0
  127. package/src/app/components/checkout/WillCallSection.tsx +133 -0
  128. package/src/app/components/checkout/affirmPayment.tsx +383 -0
  129. package/src/app/components/checkout/checkoutProcessingModal.tsx +96 -0
  130. package/src/app/components/checkout/googlePayButton.tsx +334 -0
  131. package/src/app/components/checkout/paymentStep.tsx +180 -0
  132. package/src/app/components/checkout/paypalPayment.tsx +1083 -0
  133. package/src/app/components/checkout/saleorNativePayment.tsx +1758 -0
  134. package/src/app/components/dynamicPage/DynamicPageRenderer.tsx +13 -0
  135. package/src/app/components/dynamicPage/HtmlWidgetRenderer.tsx +144 -0
  136. package/src/app/components/filtersCollapsible/index.tsx +365 -0
  137. package/src/app/components/globalSearch/index.tsx +423 -0
  138. package/src/app/components/layout/cartDropDown.tsx +628 -0
  139. package/src/app/components/layout/components/FooterNewsletter.tsx +21 -0
  140. package/src/app/components/layout/footer.tsx +283 -0
  141. package/src/app/components/layout/header/accountMenuDropdown.tsx +53 -0
  142. package/src/app/components/layout/header/components/CartBadge.tsx +18 -0
  143. package/src/app/components/layout/header/components/LoadingState.tsx +17 -0
  144. package/src/app/components/layout/header/components/MenuItemDropdown.tsx +124 -0
  145. package/src/app/components/layout/header/components/MobileNavbar.tsx +123 -0
  146. package/src/app/components/layout/header/components/NavbarActions.tsx +125 -0
  147. package/src/app/components/layout/header/components/NavbarBrand.tsx +29 -0
  148. package/src/app/components/layout/header/components/NavigationLinks.tsx +131 -0
  149. package/src/app/components/layout/header/hamMenuSlide.tsx +318 -0
  150. package/src/app/components/layout/header/header.tsx +44 -0
  151. package/src/app/components/layout/header/hooks/useDropdown.ts +45 -0
  152. package/src/app/components/layout/header/hooks/useNavbarData.ts +138 -0
  153. package/src/app/components/layout/header/hooks/useNavbarState.ts +66 -0
  154. package/src/app/components/layout/header/megaMenuDropdown.tsx +116 -0
  155. package/src/app/components/layout/header/navBar.tsx +121 -0
  156. package/src/app/components/layout/header/search.tsx +418 -0
  157. package/src/app/components/layout/header/styles/navbarStyles.ts +27 -0
  158. package/src/app/components/layout/header/topBar.tsx +214 -0
  159. package/src/app/components/layout/joinNewsletterForm/index.tsx +72 -0
  160. package/src/app/components/layout/mobileAccordian/index.tsx +92 -0
  161. package/src/app/components/layout/paymentMethods.tsx +75 -0
  162. package/src/app/components/layout/rootLayout.tsx +23 -0
  163. package/src/app/components/layout/siteInfo.tsx +103 -0
  164. package/src/app/components/layout/socialLinks.tsx +65 -0
  165. package/src/app/components/newsletterSection/emailListSection.tsx +224 -0
  166. package/src/app/components/newsletterSection/emailSectionServer.tsx +8 -0
  167. package/src/app/components/providers/ApolloWrapper.tsx +12 -0
  168. package/src/app/components/providers/AppConfigurationProvider.tsx +108 -0
  169. package/src/app/components/providers/GoogleAnalyticsProvider.tsx +149 -0
  170. package/src/app/components/providers/GoogleTagManagerProvider.tsx +31 -0
  171. package/src/app/components/providers/RecaptchaProvider.tsx +18 -0
  172. package/src/app/components/providers/ServerAppConfigurationProvider.tsx +133 -0
  173. package/src/app/components/providers/YMMStatusProvider.tsx +15 -0
  174. package/src/app/components/reuseableUI/AboutUs.tsx +115 -0
  175. package/src/app/components/reuseableUI/AddToCartClient.tsx +125 -0
  176. package/src/app/components/reuseableUI/EditorJsRenderer.tsx +219 -0
  177. package/src/app/components/reuseableUI/HeroSectionsearchByVehicle.tsx +188 -0
  178. package/src/app/components/reuseableUI/ImageWithFallback.tsx +41 -0
  179. package/src/app/components/reuseableUI/Toast.tsx +101 -0
  180. package/src/app/components/reuseableUI/blogCard.tsx +52 -0
  181. package/src/app/components/reuseableUI/brandCard.tsx +68 -0
  182. package/src/app/components/reuseableUI/breadcrumb.tsx +38 -0
  183. package/src/app/components/reuseableUI/categoryCard.tsx +37 -0
  184. package/src/app/components/reuseableUI/categorySkeleton.tsx +31 -0
  185. package/src/app/components/reuseableUI/commonButton.tsx +48 -0
  186. package/src/app/components/reuseableUI/defaultInputField/index.tsx +84 -0
  187. package/src/app/components/reuseableUI/emptyState.tsx +29 -0
  188. package/src/app/components/reuseableUI/errorTag.tsx +15 -0
  189. package/src/app/components/reuseableUI/heading/index.tsx +20 -0
  190. package/src/app/components/reuseableUI/input.tsx +117 -0
  191. package/src/app/components/reuseableUI/listCard.tsx +137 -0
  192. package/src/app/components/reuseableUI/loadingUI.tsx +12 -0
  193. package/src/app/components/reuseableUI/modalLayout.tsx +76 -0
  194. package/src/app/components/reuseableUI/newsletter/newsletterClient.tsx +622 -0
  195. package/src/app/components/reuseableUI/newsletter/newslettersHomeModal.tsx +68 -0
  196. package/src/app/components/reuseableUI/offerCard.tsx +42 -0
  197. package/src/app/components/reuseableUI/passwordRules/passwordRules.tsx +56 -0
  198. package/src/app/components/reuseableUI/primaryButton/index.tsx +34 -0
  199. package/src/app/components/reuseableUI/productCard.tsx +118 -0
  200. package/src/app/components/reuseableUI/productSkeleton.tsx +34 -0
  201. package/src/app/components/reuseableUI/searchByVehicle.tsx +187 -0
  202. package/src/app/components/reuseableUI/secondaryButton/index.tsx +34 -0
  203. package/src/app/components/reuseableUI/section.tsx +20 -0
  204. package/src/app/components/reuseableUI/select/index.tsx +98 -0
  205. package/src/app/components/reuseableUI/skeletonLoader.tsx +117 -0
  206. package/src/app/components/reuseableUI/statusTag.tsx +24 -0
  207. package/src/app/components/reuseableUI/tags/saleTag.tsx +19 -0
  208. package/src/app/components/reuseableUI/testimonialCard.tsx +93 -0
  209. package/src/app/components/richText/EditorRenderer.tsx +318 -0
  210. package/src/app/components/search/HierarchicalCategoryFilter.tsx +155 -0
  211. package/src/app/components/search/SearchFilters.tsx +155 -0
  212. package/src/app/components/search/YMMSearchSidebar.tsx +187 -0
  213. package/src/app/components/seo/ServerProductCard.tsx +91 -0
  214. package/src/app/components/seo/ServerProductGrid.tsx +45 -0
  215. package/src/app/components/shop/CategoryFilter.tsx +184 -0
  216. package/src/app/components/shop/ItemsPerPageSelect.tsx +69 -0
  217. package/src/app/components/shop/ItemsPerPageSelectClient.tsx +58 -0
  218. package/src/app/components/shop/MobileFilters.tsx +103 -0
  219. package/src/app/components/shop/ProductGridSkeleton.tsx +16 -0
  220. package/src/app/components/shop/ProductsGrid.tsx +230 -0
  221. package/src/app/components/shop/SearchFilter.tsx +218 -0
  222. package/src/app/components/shop/SearchFilterClient.tsx +122 -0
  223. package/src/app/components/shop/SearchLoadingOverlay.tsx +32 -0
  224. package/src/app/components/shop/ShopMobileFilters.tsx +205 -0
  225. package/src/app/components/showroom/VehicleSearchDropdowns.tsx +187 -0
  226. package/src/app/components/showroom/brandsSwiper.tsx +49 -0
  227. package/src/app/components/showroom/brandsSwiperClient copy.tsx +93 -0
  228. package/src/app/components/showroom/brandsSwiperClient.tsx +122 -0
  229. package/src/app/components/showroom/brandsSwiperServer.tsx +42 -0
  230. package/src/app/components/showroom/bundleProducts.tsx +120 -0
  231. package/src/app/components/showroom/categoryGrid.tsx +51 -0
  232. package/src/app/components/showroom/categoryGridServer.tsx +45 -0
  233. package/src/app/components/showroom/categorySwiper.tsx +115 -0
  234. package/src/app/components/showroom/featureStrip.tsx +139 -0
  235. package/src/app/components/showroom/offersSwiper.tsx +181 -0
  236. package/src/app/components/showroom/productGrid.tsx +56 -0
  237. package/src/app/components/showroom/productSwiper.tsx +119 -0
  238. package/src/app/components/showroom/promotion-slider.tsx +138 -0
  239. package/src/app/components/showroom/promotion.tsx +207 -0
  240. package/src/app/components/showroom/promotionsSwiper.tsx +174 -0
  241. package/src/app/components/showroom/showroomHeroCarousel.tsx +141 -0
  242. package/src/app/components/showroom/testimonialsGrid.tsx +106 -0
  243. package/src/app/components/skeletons/ContentSkeleton.tsx +14 -0
  244. package/src/app/components/sortDropdown/index.tsx +116 -0
  245. package/src/app/components/tertiaryButton/index.tsx +25 -0
  246. package/src/app/components/theme/theme-provider.tsx +82 -0
  247. package/src/app/contact/layout.tsx +32 -0
  248. package/src/app/contact/page.tsx +591 -0
  249. package/src/app/content/[slug]/layout.tsx +17 -0
  250. package/src/app/content/[slug]/page.tsx +159 -0
  251. package/src/app/content/layout.tsx +31 -0
  252. package/src/app/content/page.tsx +88 -0
  253. package/src/app/core-policies/page.tsx +55 -0
  254. package/src/app/discounts/page.tsx +54 -0
  255. package/src/app/frequently-asked-questions/page.tsx +57 -0
  256. package/src/app/globals.css +440 -0
  257. package/src/app/hooks/useDealerLocations.ts +259 -0
  258. package/src/app/hooks/useGTMEngagement.ts +71 -0
  259. package/src/app/hooks/useGoogleAnalytics.ts +145 -0
  260. package/src/app/layout.tsx +149 -0
  261. package/src/app/not-found.tsx +31 -0
  262. package/src/app/order-confirmation/layout.tsx +19 -0
  263. package/src/app/order-confirmation/page.tsx +12 -0
  264. package/src/app/order-confirmation/summary.tsx +1775 -0
  265. package/src/app/page.tsx +194 -0
  266. package/src/app/privacy-policy/loading.tsx +17 -0
  267. package/src/app/privacy-policy/page.tsx +56 -0
  268. package/src/app/product/[id]/ProductDetailClient.tsx +2448 -0
  269. package/src/app/product/[id]/components/itemInquiryModal.tsx +461 -0
  270. package/src/app/product/[id]/layout.tsx +116 -0
  271. package/src/app/product/[id]/page.tsx +200 -0
  272. package/src/app/product/layout.tsx +15 -0
  273. package/src/app/products/all/AllProductsClient.tsx +743 -0
  274. package/src/app/products/all/page.tsx +176 -0
  275. package/src/app/products/components/shopEmptyState.tsx +29 -0
  276. package/src/app/request-return/layout.tsx +36 -0
  277. package/src/app/request-return/page.tsx +597 -0
  278. package/src/app/robots.txt/route.ts +27 -0
  279. package/src/app/search/layout.tsx +16 -0
  280. package/src/app/search/page.tsx +736 -0
  281. package/src/app/shipping-returns/page.tsx +60 -0
  282. package/src/app/site-map/layout.tsx +33 -0
  283. package/src/app/site-map/page.tsx +113 -0
  284. package/src/app/sitemap-index.xml/route.ts +20 -0
  285. package/src/app/sitemap.ts +10 -0
  286. package/src/app/terms-and-conditions/loading.tsx +17 -0
  287. package/src/app/terms-and-conditions/page.tsx +56 -0
  288. package/src/app/utils/appConfiguration.ts +327 -0
  289. package/src/app/utils/branding.ts +52 -0
  290. package/src/app/utils/configurationService.ts +202 -0
  291. package/src/app/utils/constant.tsx +242 -0
  292. package/src/app/utils/editorJsUtils.tsx +249 -0
  293. package/src/app/utils/functions.ts +146 -0
  294. package/src/app/utils/googleAnalytics.ts +168 -0
  295. package/src/app/utils/googleTagManager.ts +475 -0
  296. package/src/app/utils/ipDetection.ts +270 -0
  297. package/src/app/utils/serverConfigurationService.ts +209 -0
  298. package/src/app/utils/svgs/GridIcon.tsx +45 -0
  299. package/src/app/utils/svgs/account/myAccount/listDotIcon.tsx +3 -0
  300. package/src/app/utils/svgs/account/myAccount/tickIcon.tsx +10 -0
  301. package/src/app/utils/svgs/account/orderHistory/InfoIcon.tsx +49 -0
  302. package/src/app/utils/svgs/arrowDownIcon.tsx +17 -0
  303. package/src/app/utils/svgs/arrowIcon.tsx +25 -0
  304. package/src/app/utils/svgs/arrowUpIcon.tsx +16 -0
  305. package/src/app/utils/svgs/brandsSearchIcon.tsx +25 -0
  306. package/src/app/utils/svgs/cart/cartIcon.tsx +31 -0
  307. package/src/app/utils/svgs/cart/plusIcon.tsx +13 -0
  308. package/src/app/utils/svgs/cart/subtractIcon.tsx +13 -0
  309. package/src/app/utils/svgs/cart/successTickIcon.tsx +14 -0
  310. package/src/app/utils/svgs/chevronDownIcon.tsx +21 -0
  311. package/src/app/utils/svgs/closeEyeIcon.tsx +47 -0
  312. package/src/app/utils/svgs/crossIcon.tsx +25 -0
  313. package/src/app/utils/svgs/eyeIcon.tsx +29 -0
  314. package/src/app/utils/svgs/featureTag.tsx +20 -0
  315. package/src/app/utils/svgs/filterIcon.tsx +3 -0
  316. package/src/app/utils/svgs/globleIcon.tsx +41 -0
  317. package/src/app/utils/svgs/infoIcon.tsx +34 -0
  318. package/src/app/utils/svgs/listIcon.tsx +50 -0
  319. package/src/app/utils/svgs/logOutIcon.tsx +35 -0
  320. package/src/app/utils/svgs/menuIcon.tsx +8 -0
  321. package/src/app/utils/svgs/minusIcon.tsx +18 -0
  322. package/src/app/utils/svgs/newsletterIcon.tsx +19 -0
  323. package/src/app/utils/svgs/noDataFoundIcon-.tsx +26 -0
  324. package/src/app/utils/svgs/noProductFoundIcon.tsx +43 -0
  325. package/src/app/utils/svgs/passwordIcons/errorIcon.tsx +31 -0
  326. package/src/app/utils/svgs/passwordIcons/successIcon.tsx +24 -0
  327. package/src/app/utils/svgs/paymentProcessingIcons/hourglassIcon.tsx +43 -0
  328. package/src/app/utils/svgs/paymentProcessingIcons/modalCrossIcon.tsx +23 -0
  329. package/src/app/utils/svgs/paymentProcessingIcons/paymentFailedIcon.tsx +47 -0
  330. package/src/app/utils/svgs/pencilIcon.tsx +11 -0
  331. package/src/app/utils/svgs/plusIcon.tsx +25 -0
  332. package/src/app/utils/svgs/productInquiryIcon.tsx +40 -0
  333. package/src/app/utils/svgs/searchIcon.tsx +31 -0
  334. package/src/app/utils/svgs/shoppingCart.tsx +32 -0
  335. package/src/app/utils/svgs/spinnerIcon.tsx +22 -0
  336. package/src/app/utils/svgs/spinnerLoadingIcon.tsx +26 -0
  337. package/src/app/utils/svgs/successTickIcon.tsx +40 -0
  338. package/src/app/utils/svgs/swiperArrowIconLeft.tsx +18 -0
  339. package/src/app/utils/svgs/swiperArrowIconRight.tsx +18 -0
  340. package/src/app/utils/svgs/userProfileIcon.tsx +31 -0
  341. package/src/app/utils/svgs/warningCircleIcon.tsx +15 -0
  342. package/src/app/warranty/constant.tsx +63 -0
  343. package/src/app/warranty/loading.tsx +17 -0
  344. package/src/app/warranty/page.tsx +56 -0
  345. package/src/graphql/client.ts +288 -0
  346. package/src/graphql/mutations/accountAddressCreate.ts +56 -0
  347. package/src/graphql/mutations/accountAddressDelete.ts +23 -0
  348. package/src/graphql/mutations/accountAddressUpdate.ts +55 -0
  349. package/src/graphql/mutations/accountSetDefaultAddress.ts +32 -0
  350. package/src/graphql/mutations/accountUpdate.ts +34 -0
  351. package/src/graphql/mutations/changePassword.ts +25 -0
  352. package/src/graphql/mutations/checkout.ts +117 -0
  353. package/src/graphql/mutations/checkoutAddVoucher.ts +63 -0
  354. package/src/graphql/mutations/checkoutComplete.ts +79 -0
  355. package/src/graphql/mutations/checkoutCreate.ts +131 -0
  356. package/src/graphql/mutations/checkoutCustomerAttach.ts +50 -0
  357. package/src/graphql/mutations/checkoutEmailUpdate.ts +15 -0
  358. package/src/graphql/mutations/checkoutLineMetadataUpdate.ts +52 -0
  359. package/src/graphql/mutations/checkoutPaymentCreate.ts +82 -0
  360. package/src/graphql/mutations/paymentGatewayInitialize.ts +58 -0
  361. package/src/graphql/mutations/registerAccount.ts +65 -0
  362. package/src/graphql/mutations/requestPasswordReset.ts +32 -0
  363. package/src/graphql/mutations/setPassword.ts +49 -0
  364. package/src/graphql/mutations/signIn.ts +50 -0
  365. package/src/graphql/mutations/tokenRefresh.ts +19 -0
  366. package/src/graphql/mutations/updateCheckoutMetadata.ts +49 -0
  367. package/src/graphql/mutations/updateProfile.ts +18 -0
  368. package/src/graphql/mutations/willCallDeliveryMethod.ts +81 -0
  369. package/src/graphql/queries/checkout.ts +168 -0
  370. package/src/graphql/queries/findProductByOldSlug.ts +58 -0
  371. package/src/graphql/queries/getAboutPage.ts +24 -0
  372. package/src/graphql/queries/getAboutPageId.ts +9 -0
  373. package/src/graphql/queries/getAboutUs.ts +38 -0
  374. package/src/graphql/queries/getAddressInformation.ts +38 -0
  375. package/src/graphql/queries/getAllCategories.ts +41 -0
  376. package/src/graphql/queries/getAllCategoriesTree.ts +67 -0
  377. package/src/graphql/queries/getAllCategoriesWithProducts.ts +29 -0
  378. package/src/graphql/queries/getAllCollectionsWithProducts.ts +16 -0
  379. package/src/graphql/queries/getBlogs.ts +222 -0
  380. package/src/graphql/queries/getBrands.ts +17 -0
  381. package/src/graphql/queries/getBundles.ts +43 -0
  382. package/src/graphql/queries/getCategories.ts +20 -0
  383. package/src/graphql/queries/getChannels.ts +77 -0
  384. package/src/graphql/queries/getCheckoutQuestions.ts +115 -0
  385. package/src/graphql/queries/getCheckoutTermsAndConditions.ts +37 -0
  386. package/src/graphql/queries/getContactPage.ts +117 -0
  387. package/src/graphql/queries/getContentPage.ts +191 -0
  388. package/src/graphql/queries/getDiscountOffers.ts +18 -0
  389. package/src/graphql/queries/getDynamicPageBySlug.ts +251 -0
  390. package/src/graphql/queries/getFeaturedProducts.ts +48 -0
  391. package/src/graphql/queries/getHeroMetadata.ts +23 -0
  392. package/src/graphql/queries/getMenuBySlug.ts +84 -0
  393. package/src/graphql/queries/getMyProfile.ts +23 -0
  394. package/src/graphql/queries/getNewsletter.ts +122 -0
  395. package/src/graphql/queries/getNewsletterPage.ts +111 -0
  396. package/src/graphql/queries/getPageBySlug.ts +52 -0
  397. package/src/graphql/queries/getPageTypeId.ts +27 -0
  398. package/src/graphql/queries/getPaymentMethods.ts +61 -0
  399. package/src/graphql/queries/getProducts.ts +78 -0
  400. package/src/graphql/queries/getPromotions.ts +24 -0
  401. package/src/graphql/queries/getRequestReturnPage.ts +121 -0
  402. package/src/graphql/queries/getSiteInfo.ts +54 -0
  403. package/src/graphql/queries/getSocialLinks.ts +52 -0
  404. package/src/graphql/queries/getTestimonials.ts +25 -0
  405. package/src/graphql/queries/getUserWithCheckout.ts +27 -0
  406. package/src/graphql/queries/getVehicleMakes.ts +21 -0
  407. package/src/graphql/queries/getVehicleModels.ts +21 -0
  408. package/src/graphql/queries/getVehicleYears.ts +21 -0
  409. package/src/graphql/queries/meAddresses.ts +56 -0
  410. package/src/graphql/queries/myOrders.ts +37 -0
  411. package/src/graphql/queries/orderDetail.ts +231 -0
  412. package/src/graphql/queries/productDetailsById.ts +197 -0
  413. package/src/graphql/queries/productInquiry.ts +115 -0
  414. package/src/graphql/queries/productsByCategoriesAndCollections.ts +39 -0
  415. package/src/graphql/queries/willCallCollectionPoints.ts +55 -0
  416. package/src/graphql/server-client.ts +54 -0
  417. package/src/graphql/types/categories.ts +9 -0
  418. package/src/graphql/types/checkout.ts +168 -0
  419. package/src/graphql/types/offer.ts +12 -0
  420. package/src/graphql/types/product.ts +44 -0
  421. package/src/hooks/scrollPageTop.ts +9 -0
  422. package/src/hooks/serverNavbarData.ts +79 -0
  423. package/src/hooks/useCartSync.ts +24 -0
  424. package/src/hooks/useRecaptcha.ts +33 -0
  425. package/src/hooks/useTokenExpiration.ts +81 -0
  426. package/src/hooks/useVehicleData.ts +346 -0
  427. package/src/lib/api/kount.ts +165 -0
  428. package/src/lib/api/shop.ts +1445 -0
  429. package/src/lib/saleor/getSaleorApiUrl.ts +25 -0
  430. package/src/lib/schema.ts +303 -0
  431. package/src/lib/seo/extractTextFromEditorJs.ts +58 -0
  432. package/src/lib/seo/site.ts +10 -0
  433. package/src/lib/urls/normalizeInternalUrl.ts +53 -0
  434. package/src/middleware.ts +134 -0
  435. package/src/sitemaps/README.md +105 -0
  436. package/src/sitemaps/dynamic-pages-sitemap.ts +247 -0
  437. package/src/sitemaps/sitemap-index.ts +21 -0
  438. package/src/sitemaps/static-pages-sitemap.ts +36 -0
  439. package/src/store/useGlobalStore.tsx +1656 -0
  440. package/src/types/global.d.ts +148 -0
  441. package/tsconfig.json +27 -0
@@ -0,0 +1,222 @@
1
+ import { gql } from "@apollo/client"
2
+ import createApolloServerClient from "../server-client"
3
+
4
+ // Query to get the page type ID for articles-blogs
5
+ export const GET_BLOG_PAGE_TYPE = gql`
6
+ query GetBlogPageType {
7
+ pageTypes(first: 100, filter: { slugs: "articles-blogs" }) {
8
+ edges {
9
+ node {
10
+ id
11
+ name
12
+ slug
13
+ }
14
+ }
15
+ }
16
+ }
17
+ `
18
+
19
+ // Query to get all blog pages by page type ID
20
+ export const GET_BLOG_PAGES = gql`
21
+ query GetBlogPages($pageTypeId: [ID!], $first: Int = 100) {
22
+ pages(first: $first, filter: { pageTypes: $pageTypeId }) {
23
+ edges {
24
+ node {
25
+ id
26
+ title
27
+ slug
28
+ content
29
+ created
30
+ metadata {
31
+ key
32
+ value
33
+ }
34
+ pageType {
35
+ id
36
+ name
37
+ slug
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ `
44
+
45
+ export type BlogPage = {
46
+ id: string
47
+ title?: string | null
48
+ slug?: string | null
49
+ content?: string | null
50
+ created?: string | null
51
+ metadata?: Array<{ key?: string | null; value?: string | null } | null> | null
52
+ pageType?: {
53
+ id: string
54
+ name?: string | null
55
+ slug?: string | null
56
+ } | null
57
+ }
58
+
59
+ export type BlogPageTypeResponse = {
60
+ pageTypes?: {
61
+ edges?: Array<{
62
+ node?: {
63
+ id: string
64
+ name?: string | null
65
+ slug?: string | null
66
+ } | null
67
+ } | null>
68
+ }
69
+ }
70
+
71
+ export type BlogPagesResponse = {
72
+ pages?: {
73
+ edges?: Array<{ node?: BlogPage | null } | null>
74
+ }
75
+ }
76
+
77
+ // Helper function to extract first paragraph or generate excerpt from content
78
+ function getExcerpt(content?: string | null): string {
79
+ if (!content) return ""
80
+
81
+ try {
82
+ const parsed = JSON.parse(content)
83
+ const blocks = Array.isArray(parsed?.blocks) ? parsed.blocks : []
84
+
85
+ // Find the first paragraph block
86
+ const firstParagraph = blocks.find((block: { type?: string; data?: { text?: string } }) => block?.type === "paragraph")
87
+ if (firstParagraph?.data?.text) {
88
+ // Strip HTML tags and limit length
89
+ const text = firstParagraph.data.text.replace(/<[^>]*>/g, "").trim()
90
+ return text.length > 150 ? text.substring(0, 150) + "..." : text
91
+ }
92
+ } catch {
93
+ // Ignore parsing errors
94
+ }
95
+
96
+ return ""
97
+ }
98
+
99
+ // Fetch all blog pages
100
+ export async function fetchBlogPages(): Promise<Array<{
101
+ id: string
102
+ title: string
103
+ slug: string
104
+ excerpt: string
105
+ date: string
106
+ }>> {
107
+ if (!process.env.NEXT_PUBLIC_API_URL) {
108
+ console.warn("API URL not configured, skipping blog fetch")
109
+ return []
110
+ }
111
+
112
+ try {
113
+ const client = createApolloServerClient()
114
+
115
+ // First, get the page type ID for articles-blogs
116
+ const pageTypeResponse = await client.query<BlogPageTypeResponse>({
117
+ query: GET_BLOG_PAGE_TYPE,
118
+ fetchPolicy: "cache-first",
119
+ errorPolicy: "all",
120
+ context: {
121
+ fetchOptions: {
122
+ next: { revalidate: 600 }, // Cache for 10 minutes
123
+ },
124
+ },
125
+ })
126
+
127
+ const pageTypeId = pageTypeResponse.data?.pageTypes?.edges?.[0]?.node?.id
128
+
129
+ if (!pageTypeId) {
130
+ console.warn("Blog page type 'articles-blogs' not found")
131
+ return []
132
+ }
133
+
134
+ // Then fetch all pages with this page type
135
+ const pagesResponse = await client.query<BlogPagesResponse>({
136
+ query: GET_BLOG_PAGES,
137
+ variables: { pageTypeId: [pageTypeId], first: 100 },
138
+ fetchPolicy: "cache-first",
139
+ errorPolicy: "all",
140
+ context: {
141
+ fetchOptions: {
142
+ next: { revalidate: 600 }, // Cache for 10 minutes
143
+ },
144
+ },
145
+ })
146
+
147
+ const pages = pagesResponse.data?.pages?.edges || []
148
+
149
+ return pages
150
+ .map((edge) => {
151
+ const node = edge?.node
152
+ if (!node || !node.slug || !node.title) return null
153
+
154
+ return {
155
+ id: node.id,
156
+ title: node.title,
157
+ slug: node.slug,
158
+ excerpt: getExcerpt(node.content),
159
+ date: node.created ? new Date(node.created).toLocaleDateString("en-US", {
160
+ year: "numeric",
161
+ month: "long",
162
+ day: "numeric"
163
+ }) : "",
164
+ }
165
+ })
166
+ .filter((blog): blog is NonNullable<typeof blog> => blog !== null)
167
+ } catch (err) {
168
+ console.warn(
169
+ "Failed to fetch blog pages:",
170
+ err instanceof Error ? err.message : "Unknown error"
171
+ )
172
+ return []
173
+ }
174
+ }
175
+
176
+ // Fetch a single blog page by slug
177
+ export async function fetchBlogBySlug(slug: string): Promise<BlogPage | null> {
178
+ if (!process.env.NEXT_PUBLIC_API_URL) {
179
+ console.warn("API URL not configured, skipping blog fetch")
180
+ return null
181
+ }
182
+
183
+ try {
184
+ const client = createApolloServerClient()
185
+
186
+ const BLOG_BY_SLUG = gql`
187
+ query GetBlogBySlug($slug: String!) {
188
+ page(slug: $slug) {
189
+ id
190
+ title
191
+ slug
192
+ content
193
+ created
194
+ metadata {
195
+ key
196
+ value
197
+ }
198
+ pageType {
199
+ id
200
+ name
201
+ slug
202
+ }
203
+ }
204
+ }
205
+ `
206
+
207
+ const response = await client.query({
208
+ query: BLOG_BY_SLUG,
209
+ variables: { slug },
210
+ fetchPolicy: "network-only",
211
+ errorPolicy: "ignore",
212
+ })
213
+
214
+ return response?.data?.page ?? null
215
+ } catch (err) {
216
+ console.warn(
217
+ "Failed to fetch blog by slug:",
218
+ err instanceof Error ? err.message : "Unknown error"
219
+ )
220
+ return null
221
+ }
222
+ }
@@ -0,0 +1,17 @@
1
+ import { gql } from "@apollo/client"
2
+
3
+ export const GET_BRANDS = gql`
4
+ query GetBrands($first: Int!, $key: String!, $value: String!) {
5
+ productTypes(
6
+ first: $first
7
+ filter: { metadata: { key: $key, value: $value } }
8
+ ) {
9
+ edges {
10
+ node {
11
+ name
12
+ metafields
13
+ }
14
+ }
15
+ }
16
+ }
17
+ `
@@ -0,0 +1,43 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_BUNDLES = gql`
4
+ query GetBundles($channel: String!, $first: Int = 10) {
5
+ collections(
6
+ first: 10
7
+ channel: $channel
8
+ filter: { metadata: [{ key: "bundle", value: "true" }] }
9
+ ) {
10
+ edges {
11
+ node {
12
+ id
13
+ name
14
+ slug
15
+ metadata {
16
+ key
17
+ value
18
+ }
19
+ products(first: $first) {
20
+ edges {
21
+ node {
22
+ id
23
+ name
24
+ slug
25
+ rating
26
+ pricing {
27
+ onSale
28
+ priceRange {
29
+ start { gross { amount currency } }
30
+ stop { gross { amount currency } }
31
+ }
32
+ discount { gross { amount currency } }
33
+ }
34
+ media { url }
35
+ category { id name }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ `;
@@ -0,0 +1,20 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_CATEGORIES = gql`
4
+ query GetCategories($first: Int!) {
5
+ categories(first: $first) {
6
+ edges {
7
+ node {
8
+ id
9
+ name
10
+ description
11
+ slug
12
+ backgroundImage {
13
+ url
14
+ }
15
+ }
16
+ }
17
+ totalCount
18
+ }
19
+ }
20
+ `;
@@ -0,0 +1,77 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_CHANNELS = gql`
4
+ query GetChannels {
5
+ channels {
6
+ id
7
+ name
8
+ slug
9
+ isActive
10
+ warehouses {
11
+ id
12
+ name
13
+ slug
14
+ email
15
+ isPrivate
16
+ address {
17
+ streetAddress1
18
+ streetAddress2
19
+ city
20
+ phone
21
+ postalCode
22
+ countryArea
23
+ country {
24
+ code
25
+ country
26
+ }
27
+ }
28
+ privateMetadata {
29
+ key
30
+ value
31
+ }
32
+ }
33
+ }
34
+ }
35
+ `;
36
+
37
+
38
+ export interface Address {
39
+ streetAddress1?: string;
40
+ streetAddress2?: string;
41
+ city?: string;
42
+ phone?: string;
43
+ postalCode?: string;
44
+ countryArea?: string;
45
+ country?: {
46
+ code: string;
47
+ country: string;
48
+ };
49
+ }
50
+
51
+ export interface PrivateMetadata {
52
+ key: string;
53
+ value: string;
54
+ }
55
+
56
+ export interface Warehouse {
57
+ id: string;
58
+ name: string;
59
+ slug: string;
60
+ email?: string;
61
+ isPrivate: boolean;
62
+ address?: Address;
63
+ privateMetadata?: PrivateMetadata[];
64
+ }
65
+
66
+
67
+ export interface Channel {
68
+ id: string;
69
+ name: string;
70
+ slug: string;
71
+ isActive: boolean;
72
+ warehouses: Warehouse[];
73
+ }
74
+
75
+ export interface GetChannelsData {
76
+ channels: Channel[];
77
+ }
@@ -0,0 +1,115 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_CHECKOUT_QUESTIONS = gql`
4
+ query GetCheckoutQuestions {
5
+ page(slug: "checkout-question") {
6
+ id
7
+ title
8
+ slug
9
+ content
10
+ seoTitle
11
+ seoDescription
12
+ isPublished
13
+ metadata {
14
+ key
15
+ value
16
+ }
17
+ }
18
+ }
19
+ `;
20
+
21
+ export interface CheckoutQuestionMetadata {
22
+ key: string;
23
+ value: string;
24
+ }
25
+
26
+ export interface CheckoutQuestionsData {
27
+ page: {
28
+ id: string;
29
+ title: string;
30
+ slug: string;
31
+ content: string | null;
32
+ seoTitle: string;
33
+ seoDescription: string;
34
+ isPublished: boolean;
35
+ metadata: CheckoutQuestionMetadata[];
36
+ } | null;
37
+ }
38
+
39
+ export interface ParsedQuestion {
40
+ id: string;
41
+ required: boolean;
42
+ question: string;
43
+ options?: string[];
44
+ type: 'text' | 'select' | 'radio' | 'checkbox';
45
+ }
46
+
47
+ export interface CheckoutQuestionsConfig {
48
+ isPublished: boolean;
49
+ guestOnly: boolean;
50
+ orderValueThreshold: number | null;
51
+ showReCAPTCHA: boolean;
52
+ questions: ParsedQuestion[];
53
+ }
54
+
55
+ export function parseCheckoutQuestions(data: CheckoutQuestionsData): CheckoutQuestionsConfig | null {
56
+ if (!data?.page) {
57
+ return null;
58
+ }
59
+
60
+ if (!data.page.isPublished) {
61
+ return null;
62
+ }
63
+
64
+ const metadata = data.page.metadata;
65
+ const questions: ParsedQuestion[] = [];
66
+
67
+ let guestOnly = false;
68
+ let orderValueThreshold: number | null = null;
69
+ let showReCAPTCHA = false;
70
+
71
+ metadata.forEach(({ key, value }) => {
72
+ if (key === 'guest_only') {
73
+ guestOnly = value === 'true';
74
+ } else if (key === 'order_value') {
75
+ const parsed = parseFloat(value);
76
+ orderValueThreshold = isNaN(parsed) ? null : parsed;
77
+ } else if (key === 'reCAPTCHA') {
78
+ showReCAPTCHA = value === 'true';
79
+ } else if (key.startsWith('question-')) {
80
+ const questionId = key;
81
+ const parts = value.split(':');
82
+
83
+ if (parts.length >= 2) {
84
+ const requiredStr = parts[0].trim();
85
+ const required = requiredStr === 'r';
86
+ const question = parts[1].trim();
87
+
88
+ // Handle options - check if parts[2] exists and is not empty
89
+ let options: string[] | undefined = undefined;
90
+ if (parts.length > 2 && parts[2].trim()) {
91
+ options = parts[2].split(',').map(opt => opt.trim()).filter(opt => opt.length > 0);
92
+ }
93
+
94
+ // Only add question if it has a question text
95
+ if (question) {
96
+ questions.push({
97
+ id: questionId,
98
+ required,
99
+ question,
100
+ options,
101
+ type: options && options.length > 0 ? (options.length <= 4 ? 'radio' : 'select') : 'text'
102
+ });
103
+ }
104
+ }
105
+ }
106
+ });
107
+
108
+ return {
109
+ isPublished: data.page.isPublished,
110
+ guestOnly,
111
+ orderValueThreshold,
112
+ showReCAPTCHA,
113
+ questions: questions.sort((a, b) => a.id.localeCompare(b.id))
114
+ };
115
+ }
@@ -0,0 +1,37 @@
1
+ import { gql } from "@apollo/client"
2
+
3
+ export const GET_CHECKOUT_TERMS_AND_CONDITIONS = gql`
4
+ query CheckoutTermsAndConditions($slug: String!) {
5
+ page(slug: $slug) {
6
+ id
7
+ title
8
+ slug
9
+ content
10
+ seoTitle
11
+ seoDescription
12
+ isPublished
13
+ metadata {
14
+ key
15
+ value
16
+ }
17
+ }
18
+ }
19
+ `
20
+
21
+ export type CheckoutTermsAndConditionsPage = {
22
+ id: string
23
+ title: string | null
24
+ slug: string | null
25
+ content: string | null
26
+ seoTitle: string | null
27
+ seoDescription: string | null
28
+ isPublished: boolean
29
+ metadata: Array<{
30
+ key: string
31
+ value: string
32
+ }> | null
33
+ }
34
+
35
+ export type CheckoutTermsAndConditionsResponse = {
36
+ page: CheckoutTermsAndConditionsPage | null
37
+ }
@@ -0,0 +1,117 @@
1
+ import { gql } from "@apollo/client";
2
+ import createApolloServerClient from "../server-client";
3
+
4
+ export const GET_CONTACT_PAGE = gql`
5
+ query Contact($first: Int = 1) {
6
+ pages(first: $first, filter: { slugs: "contact" }) {
7
+ edges {
8
+ node {
9
+ id
10
+ title
11
+ content
12
+ metadata {
13
+ key
14
+ value
15
+ }
16
+ }
17
+ }
18
+ }
19
+ }
20
+ `;
21
+
22
+ export type ContactMetadata = {
23
+ key: string;
24
+ value: string;
25
+ };
26
+
27
+ export type ContactPageNode = {
28
+ id: string;
29
+ title: string;
30
+ content: string | null;
31
+ metadata: ContactMetadata[];
32
+ };
33
+
34
+ export type ContactPageEdge = {
35
+ node: ContactPageNode;
36
+ };
37
+
38
+ export type ContactPageResponse = {
39
+ pages: {
40
+ edges: ContactPageEdge[];
41
+ };
42
+ };
43
+
44
+ export type ContactPageData = {
45
+ id: string;
46
+ title: string;
47
+ content: string | null;
48
+ contactFormEnabled: boolean;
49
+ productInquiryFormEnabled: boolean;
50
+ recaptchaEnabled: boolean;
51
+ fields: string[];
52
+ description: string | null;
53
+ emailTo: string | null;
54
+ emailCc: string | null;
55
+ emailBcc: string | null;
56
+ emailSubject: string | null;
57
+ successMessage: string | null;
58
+ };
59
+
60
+ export function parseContactPageMetadata(node: ContactPageNode): ContactPageData {
61
+ const metadata = node.metadata.reduce((acc, item) => {
62
+ acc[item.key] = item.value;
63
+ return acc;
64
+ }, {} as Record<string, string>);
65
+
66
+ return {
67
+ id: node.id,
68
+ title: node.title,
69
+ content: node.content,
70
+ contactFormEnabled: metadata.contact_form === "true",
71
+ productInquiryFormEnabled: metadata.product_inquiry_form === "true",
72
+ recaptchaEnabled: metadata.reCAPTCHA === "true",
73
+ fields: metadata.fields ? metadata.fields.split(",").map((f) => f.trim()) : [],
74
+ description: metadata.description || null,
75
+ emailTo: metadata.email_to || null,
76
+ emailCc: metadata.email_cc || null,
77
+ emailBcc: metadata.email_bcc || null,
78
+ emailSubject: metadata.email_subject || null,
79
+ successMessage: metadata.success_message || null,
80
+ };
81
+ }
82
+
83
+ export async function fetchContactPage(): Promise<ContactPageData | null> {
84
+ if (!process.env.NEXT_PUBLIC_API_URL) {
85
+ console.warn("API URL not configured, skipping contact page fetch");
86
+ return null;
87
+ }
88
+
89
+ try {
90
+ const client = createApolloServerClient();
91
+ const timeoutPromise = new Promise<never>((_, reject) =>
92
+ setTimeout(() => reject(new Error("Contact page fetch timeout")), 5000)
93
+ );
94
+
95
+ const queryPromise = client.query<ContactPageResponse>({
96
+ query: GET_CONTACT_PAGE,
97
+ variables: { first: 1 },
98
+ fetchPolicy: "network-only",
99
+ errorPolicy: "ignore",
100
+ });
101
+
102
+ const result = await Promise.race([queryPromise, timeoutPromise]);
103
+ const edges = result?.data?.pages?.edges;
104
+
105
+ if (edges && edges.length > 0) {
106
+ return parseContactPageMetadata(edges[0].node);
107
+ }
108
+
109
+ return null;
110
+ } catch (err) {
111
+ console.warn(
112
+ "Failed to fetch contact page:",
113
+ err instanceof Error ? err.message : "Unknown error"
114
+ );
115
+ return null;
116
+ }
117
+ }