@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,138 @@
1
+ "use client";
2
+ import Image from "next/image";
3
+ import { Swiper, SwiperSlide } from "swiper/react";
4
+ import { Navigation, Pagination, Autoplay } from "swiper/modules";
5
+ import { SwiperArrowIconLeft } from "@/app/utils/svgs/swiperArrowIconLeft";
6
+ import { SwiperArrowIconRight } from "@/app/utils/svgs/swiperArrowIconRight";
7
+
8
+ import "swiper/css";
9
+ import "swiper/css/navigation";
10
+ import "swiper/css/pagination";
11
+
12
+ type Promotion = {
13
+ id: string;
14
+ image: string;
15
+ subHeading: string;
16
+ headingLines: string[];
17
+ description: string;
18
+ listItems: string[];
19
+ };
20
+
21
+ export const PromotionSlider = ({
22
+ promotions,
23
+ }: {
24
+ promotions: Promotion[];
25
+ }) => {
26
+ return (
27
+ <div className="relative">
28
+ <Swiper
29
+ modules={[Navigation, Pagination, Autoplay]}
30
+ navigation={{ prevEl: ".promotion-prev", nextEl: ".promotion-next" }}
31
+ pagination={{ clickable: true }}
32
+ autoplay={{ delay: 5000, disableOnInteraction: false }}
33
+ loop={promotions.length > 1}
34
+ spaceBetween={0}
35
+ slidesPerView={1}
36
+ className="promotion-swiper
37
+ [&_.swiper-pagination-bullet]:!bg-neutral-300
38
+ [&_.swiper-pagination-bullet-active]:!bg-[var(--color-primary)]
39
+ [&_.swiper-pagination]:!bottom-4"
40
+ >
41
+ {promotions &&
42
+ promotions.map(
43
+ ({
44
+ id,
45
+ image,
46
+ subHeading,
47
+ headingLines,
48
+ description,
49
+ listItems,
50
+ }) => (
51
+ <SwiperSlide key={id} className="!h-auto">
52
+ <div className="flex flex-col lg:flex-row items-center justify-start gap-8 lg:gap-16 h-full">
53
+ {/* Featured Image */}
54
+ {image !== " " && (
55
+ <Image
56
+ width={768}
57
+ height={576}
58
+ sizes="(max-width: 768px) 100vw, 50vw"
59
+ src={image}
60
+ alt={headingLines?.join(" ") || "Promotion image"}
61
+ className="w-full lg:w-1/2 h-auto rounded-md bg-center bg-cover"
62
+ loading="lazy"
63
+ quality={75}
64
+ role="img"
65
+ aria-label={headingLines?.join(" ") || "Promotion image"}
66
+ />
67
+ )}
68
+
69
+ {/* Copy */}
70
+ <div className="w-full lg:w-1/2 flex flex-col gap-4 items-start justify-start">
71
+ {subHeading?.trim() ? (
72
+ <p className="font-secondary text-center w-full xl:text-left text-[18px] leading-[28px] tracking-[-0.045px] text-[var(--color-primary)]">
73
+ {subHeading}
74
+ </p>
75
+ ) : null}
76
+
77
+ <div className="font-primary text-neutral-800 tracking-[-0.12px] uppercase">
78
+ {headingLines.map((line, idx) => (
79
+ <h2
80
+ key={idx}
81
+ id={idx === 0 ? "promotion-heading" : undefined}
82
+ className="text-[36px] leading-[36px] text-center w-full xl:text-left sm:text-[44px] sm:leading-[44px] lg:text-[48px] lg:leading-[48px]"
83
+ >
84
+ {line}
85
+ </h2>
86
+ ))}
87
+ </div>
88
+
89
+ {description?.trim() ? (
90
+ <p className="font-secondary text-center w-full xl:text-left text-neutral-800 text-[16px] leading-[26px] sm:text-[18px] sm:leading-[28px] tracking-[-0.045px] max-w-3xl">
91
+ {description}
92
+ </p>
93
+ ) : null}
94
+
95
+ {listItems && listItems.length > 0 ? (
96
+ <ol className="font-secondary text-neutral-800 text-[16px] leading-[26px] sm:text-[18px] sm:leading-[28px] tracking-[-0.045px] max-w-3xl list-decimal list-inside space-y-2 w-full text-center xl:text-left">
97
+ {listItems.map((item, idx) => (
98
+ <li key={idx} className="pl-2">
99
+ {item}
100
+ </li>
101
+ ))}
102
+ </ol>
103
+ ) : null}
104
+ </div>
105
+ </div>
106
+ </SwiperSlide>
107
+ )
108
+ )}
109
+ </Swiper>
110
+
111
+ {/* Prev Button */}
112
+ <button
113
+ style={{
114
+ backgroundColor: "var(--color-secondary-200)",
115
+ color: "var(--color-secondary-800)",
116
+ }}
117
+ className="p-2 rounded-full hidden md:block disabled:opacity-50 absolute left-4 top-1/2 -translate-y-1/2 cursor-pointer promotion-prev z-10 hover:opacity-80 transition-opacity"
118
+ aria-label="Previous slide"
119
+ >
120
+ <span className="size-6 block">{SwiperArrowIconLeft}</span>
121
+ </button>
122
+
123
+ {/* Next Button */}
124
+ <button
125
+ style={{
126
+ backgroundColor: "var(--color-secondary-200)",
127
+ color: "var(--color-secondary-800)",
128
+ }}
129
+ className="p-2 rounded-full hidden md:block absolute right-4 top-1/2 -translate-y-1/2 z-10 disabled:opacity-50 cursor-pointer promotion-next hover:opacity-80 transition-opacity"
130
+ aria-label="Next slide"
131
+ >
132
+ <span className="size-6 flex-shrink-0 block">
133
+ {SwiperArrowIconRight}
134
+ </span>
135
+ </button>
136
+ </div>
137
+ );
138
+ };
@@ -0,0 +1,207 @@
1
+ import { GET_PROMOTION_PAGE_TYPE } from "@/graphql/queries/getPageTypeId";
2
+ import { GET_PROMOTIONS } from "@/graphql/queries/getPromotions";
3
+ import createApolloServerClient from "@/graphql/server-client";
4
+ import Heading from "../reuseableUI/heading";
5
+ import Link from "next/link";
6
+ import Image from "next/image";
7
+
8
+ function parseEditorJsContent(raw?: string | null): {
9
+ description: string;
10
+ listItems: string[];
11
+ } {
12
+ if (!raw) return { description: "", listItems: [] };
13
+
14
+ try {
15
+ const json = JSON.parse(raw);
16
+ type EditorBlock = {
17
+ id?: string;
18
+ type?: string;
19
+ data?: { text?: string; items?: string[] } | null;
20
+ };
21
+ const blocks: EditorBlock[] = Array.isArray(json?.blocks)
22
+ ? (json.blocks as EditorBlock[])
23
+ : [];
24
+ const firstParagraph = blocks.find((b) => b?.type === "paragraph");
25
+ const html: string = firstParagraph?.data?.text || "";
26
+ const description = html.replace(/<[^>]*>/g, "").trim();
27
+ const getList = blocks.find((b) => b?.type === "list");
28
+ const listItems =
29
+ getList?.data?.items?.map((item: string) => {
30
+ return item.replace(/<[^>]*>/g, "").trim();
31
+ }) || [];
32
+
33
+ return { description, listItems };
34
+ } catch {
35
+ return { description: "", listItems: [] };
36
+ }
37
+ }
38
+
39
+ const DiagonalArrow = () => (
40
+ <svg
41
+ width="20"
42
+ height="20"
43
+ viewBox="0 0 24 24"
44
+ fill="none"
45
+ xmlns="http://www.w3.org/2000/svg"
46
+ className="text-black/40"
47
+ >
48
+ <path
49
+ d="M7 17L17 7M17 7H7M17 7V17"
50
+ stroke="currentColor"
51
+ strokeWidth="1.5"
52
+ strokeLinecap="round"
53
+ strokeLinejoin="round"
54
+ />
55
+ </svg>
56
+ );
57
+
58
+ interface ResourceCardProps {
59
+ image: string;
60
+ title: string;
61
+ description: string;
62
+ buttonText: string;
63
+ href: string;
64
+ }
65
+
66
+ const ResourceCard = ({ image, title, description, buttonText, href }: ResourceCardProps) => (
67
+ <div className="bg-white border border-black/10 rounded-lg p-10 flex flex-col justify-between gap-6 relative group hover:shadow-md transition-all duration-300">
68
+ <div className="flex flex-col gap-6">
69
+ <div className="absolute top-8 right-8">
70
+ <DiagonalArrow />
71
+ </div>
72
+
73
+ <div className="w-14 h-14 bg-gray-50 rounded-lg flex items-center justify-center border border-gray-200 overflow-hidden">
74
+ {image ? (
75
+ <Image
76
+ src={image}
77
+ alt={title}
78
+ width={50}
79
+ height={50}
80
+ className="object-contain"
81
+ />
82
+ ) : (
83
+ <div className="w-8 h-8 bg-[var(--color-primary-600)]/10 rounded-full" />
84
+ )}
85
+ </div>
86
+
87
+ <div className="flex flex-col gap-3">
88
+ <h3 className="text-xl font-bold text-black font-secondary uppercase">
89
+ {title}
90
+ </h3>
91
+ <p className="text-gray-600 text-sm leading-relaxed font-secondary line-clamp-3">
92
+ {description}
93
+ </p>
94
+ </div>
95
+ </div>
96
+
97
+ <div className="mb-2">
98
+ <Link
99
+ href={href}
100
+ className="inline-block bg-[var(--color-primary-600)] hover:bg-[var(--color-primary-700)] text-white font-black py-3 px-10 rounded-md transition-colors text-xs font-secondary uppercase tracking-widest"
101
+ >
102
+ {buttonText}
103
+ </Link>
104
+ </div>
105
+ </div>
106
+ );
107
+
108
+ export const Promotions = async ({ first = 3 }: { first?: number }) => {
109
+ let promotions: Array<{
110
+ id: string;
111
+ image: string;
112
+ title: string;
113
+ description: string;
114
+ subtitleRedirect: string;
115
+ buttonText: string;
116
+ }> = [];
117
+
118
+ try {
119
+ const client = createApolloServerClient();
120
+
121
+ const pageTypeResp = await client.query<{
122
+ pageTypes?: {
123
+ edges?: Array<{ node?: { id: string; slug: string } | null }>;
124
+ };
125
+ }>({
126
+ query: GET_PROMOTION_PAGE_TYPE,
127
+ errorPolicy: "all",
128
+ });
129
+
130
+ const pageTypeId = pageTypeResp.data.pageTypes?.edges?.[0]?.node?.id;
131
+ if (!pageTypeId) return null;
132
+
133
+ const promosResp = await client.query<{
134
+ pages?: {
135
+ edges?: Array<{
136
+ node?: {
137
+ id: string;
138
+ title?: string | null;
139
+ content?: string | null;
140
+ metadata?: Array<{ key?: string | null; value?: string | null }>;
141
+ } | null;
142
+ }>;
143
+ };
144
+ }>({
145
+ query: GET_PROMOTIONS,
146
+ variables: { pageTypeId, first },
147
+ errorPolicy: "all",
148
+ fetchPolicy: "network-only",
149
+ });
150
+
151
+ promotions = (promosResp.data.pages?.edges || [])
152
+ .map((e) => e.node)
153
+ .filter(Boolean)
154
+ .map((n) => {
155
+ const metaEntries = Object.fromEntries(
156
+ (n!.metadata || [])
157
+ .filter((m) => m?.key)
158
+ .map((m) => [m!.key as string, m!.value || ""]) as [string, string][]
159
+ );
160
+ const image = metaEntries["promo-image"] || "";
161
+ const subtitleRedirect = metaEntries["subtitle-redirect"] || "#";
162
+ const buttonText = metaEntries["promo-subtitle"] || "LEARN MORE";
163
+ const { description } = parseEditorJsContent(n!.content);
164
+
165
+ return {
166
+ id: n!.id,
167
+ image,
168
+ title: n!.title || "",
169
+ description,
170
+ subtitleRedirect,
171
+ buttonText,
172
+ };
173
+ });
174
+ promotions.reverse(); // TODO: it should be sorted in backend
175
+ } catch (error) {
176
+ console.error("[Promotions] Error fetching dynamic data:", error);
177
+ promotions = [];
178
+ }
179
+
180
+ if (!promotions.length) return null;
181
+
182
+ return (
183
+ <section className="py-12 px-4 md:px-6 md:py-16 lg:py-24 bg-white">
184
+ <div className="container mx-auto">
185
+ <div className="mb-12">
186
+ <Heading
187
+ content="RESOURCES TO KEEP YOU ROLLING"
188
+ className="italic font-black text-black"
189
+ />
190
+ </div>
191
+
192
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
193
+ {promotions.map((promo) => (
194
+ <ResourceCard
195
+ key={promo.id}
196
+ image={promo.image}
197
+ title={promo.title}
198
+ description={promo.description}
199
+ buttonText={promo.buttonText}
200
+ href={promo.subtitleRedirect}
201
+ />
202
+ ))}
203
+ </div>
204
+ </div>
205
+ </section>
206
+ );
207
+ };
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ import { SwiperArrowIconLeft } from "@/app/utils/svgs/swiperArrowIconLeft";
4
+ import { SwiperArrowIconRight } from "@/app/utils/svgs/swiperArrowIconRight";
5
+ import Image from "next/image";
6
+ import { useRouter } from "next/navigation";
7
+ import { Suspense } from "react";
8
+ import { Autoplay, Navigation, Pagination } from "swiper/modules";
9
+ import { Swiper, SwiperSlide } from "swiper/react";
10
+ import CommonButton from "../reuseableUI/commonButton";
11
+ import EmptyState from "../reuseableUI/emptyState";
12
+
13
+ interface PromotionSlide {
14
+ id: string;
15
+ image: string;
16
+ alt: string;
17
+ Heading: string;
18
+ subHeading: string;
19
+ Offer: string;
20
+ }
21
+
22
+ const defaultSlides = [
23
+ {
24
+ id: "1",
25
+ image: "/no-image-avail-large.png",
26
+ alt: "Slide 3",
27
+ Heading: "Mustang GT Performance Exhaust System",
28
+ subHeading: "EXHAUST SYSTEMS & PERFORMANCE PARTS",
29
+ Offer: "$39.90",
30
+ },
31
+ {
32
+ id: "2",
33
+ image: "/no-image-avail-large.png",
34
+ alt: "Slide 3",
35
+ Heading: "Mustang GT Performance Exhaust System",
36
+ subHeading: "EXHAUST SYSTEMS & PERFORMANCE PARTS",
37
+ Offer: "$39.90",
38
+ },
39
+ {
40
+ id: "3",
41
+ image: "/no-image-avail-large.png",
42
+ alt: "Slide 3",
43
+ Heading: "Mustang GT Performance Exhaust System",
44
+ subHeading: "EXHAUST SYSTEMS & PERFORMANCE PARTS",
45
+ Offer: "$39.90",
46
+ },
47
+ ];
48
+
49
+ interface PromotionsSwiperProps {
50
+ slides?: PromotionSlide[];
51
+ }
52
+
53
+ export const PromotionsSwiper = ({ slides }: PromotionsSwiperProps) => {
54
+ const slidesToUse = slides && slides.length > 0 ? slides : defaultSlides;
55
+ const router = useRouter();
56
+
57
+ if (!slidesToUse || slidesToUse.length === 0) {
58
+ return (
59
+ <div className="relative w-full h-[704px] flex items-center justify-center">
60
+ <div
61
+ style={{ backgroundColor: "var(--color-primary-600)" }}
62
+ className="absolute h-[704px] max-w-[80px] w-full z-[5]"
63
+ />
64
+ <EmptyState
65
+ text="No promotions available"
66
+ textParagraph="Check back later for exciting promotions and deals"
67
+ className="h-full z-10"
68
+ />
69
+ </div>
70
+ );
71
+ }
72
+ return (
73
+ <div className="relative w-full h-[414px] lg:h-[704px]">
74
+ <div className="w-full h-full absolute bg-black/60 backdrop-blur-md z-[2] top-0 left-0 text-center flex items-center justify-center font-primary ">
75
+ <div className="bg-[var(--color-secondary-400)] px-2 py-1 size-fit text-[var(--color-secondary-90)] text-3xl">
76
+ Coming Soon
77
+ </div>
78
+ </div>
79
+ <div
80
+ style={{ backgroundColor: "var(--color-primary-600)" }}
81
+ className="absolute h-10 max-w-none md:h-full lg:h-[704px] md:max-w-[80px] w-full z-[5]"
82
+ />
83
+
84
+ <Swiper
85
+ modules={[Navigation, Pagination, Autoplay]}
86
+ navigation={{ prevEl: ".promotion-prev", nextEl: ".promotion-next" }}
87
+ pagination={{ clickable: true }}
88
+ autoplay={{ delay: 4000 }}
89
+ loop
90
+ slidesPerView={1}
91
+ mousewheel={{ enabled: true, forceToAxis: true, releaseOnEdges: true }}
92
+ keyboard={{ enabled: true, onlyInViewport: true }}
93
+ className="w-full h-full
94
+ [&_.swiper-pagination-bullet]:!bg-[var(--color-secondary-50)]
95
+ [&_.swiper-pagination-bullet-active]:!bg-[var(--color-secondary-500)]
96
+ [&_.swiper-pagination]:!bottom-8"
97
+ >
98
+ {slidesToUse.map((slide) => (
99
+ <SwiperSlide key={slide.id}>
100
+ <div className="relative w-full h-full">
101
+ <Suspense
102
+ fallback={
103
+ <div className="w-full h-full bg-gray-200 animate-pulse" />
104
+ }
105
+ >
106
+ <Image
107
+ src={slide.image}
108
+ alt={slide.alt}
109
+ fill
110
+ className="object-cover"
111
+ priority
112
+ />
113
+ <div className="absolute inset-0 bg-black/50" />
114
+ </Suspense>
115
+
116
+ <div className="absolute container flex items-center h-full w-full px-4 md:pl-[111px] lg:pl-28">
117
+ <div className="flex flex-col items-start w-full max-w-[645px] justify-center">
118
+ <p
119
+ style={{ color: "var(--color-secondary-300)" }}
120
+ className="font-secondary text-xs md:text-sm lg:*:text-base leading-[24px] tracking-[-0.04px]"
121
+ >
122
+ {slide.subHeading}
123
+ </p>
124
+
125
+ <div className="w-full flex flex-col flex-wrap justify-start gap-6 lg:gap-10">
126
+ <h2
127
+ style={{ color: "var(--color-secondary-50)" }}
128
+ className="font-primary text-2xl/none md:text-3xl/none lg:text-6xl/none tracking-[-0.15px] uppercase"
129
+ >
130
+ {slide.Heading}
131
+ </h2>
132
+
133
+ <p
134
+ style={{ color: "var(--color-secondary-50)" }}
135
+ className="font-secondary text-3xl md:text-5xl lg:text-7xl/none font-light tracking-[-0.18px]"
136
+ >
137
+ {slide.Offer}
138
+ </p>
139
+
140
+ <CommonButton variant="primary" className="py-2 md:py-3 w-fit" content={"Shop Now"} onClick={() => router.push("/products/all")} />
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </SwiperSlide>
146
+ ))}
147
+ </Swiper>
148
+
149
+ {/* Prev */}
150
+ <button
151
+ style={{
152
+ backgroundColor: "var(--color-secondary-50)",
153
+ color: "var(--color-secondary-800)",
154
+ }}
155
+ className="p-2 rounded-full hidden md:block disabled:opacity-50 absolute left-4 top-1/2 cursor-pointer promotion-prev z-[5]"
156
+ >
157
+ <span className="size-6 block">{SwiperArrowIconLeft}</span>
158
+ </button>
159
+
160
+ {/* Next */}
161
+ <button
162
+ style={{
163
+ backgroundColor: "var(--color-secondary-50)",
164
+ color: "var(--color-secondary-800)",
165
+ }}
166
+ className="p-2 rounded-full hidden md:block absolute right-4 top-1/2 z-[5] disabled:opacity-50 cursor-pointer promotion-next"
167
+ >
168
+ <span className="size-6 flex-shrink-0 block">
169
+ {SwiperArrowIconRight}
170
+ </span>
171
+ </button>
172
+ </div>
173
+ );
174
+ };
@@ -0,0 +1,141 @@
1
+ "use client";
2
+
3
+ import { GET_PAGE_METADATA_BY_SLUG } from "@/graphql/queries/getHeroMetadata";
4
+ import { useQuery } from "@apollo/client";
5
+ import Image from "next/image";
6
+ import { useMemo } from "react";
7
+ import "swiper/css";
8
+ import "swiper/css/effect-fade";
9
+ import "swiper/css/navigation";
10
+ import "swiper/css/pagination";
11
+ import { Autoplay, EffectFade, Navigation, Pagination } from "swiper/modules";
12
+ import { Swiper, SwiperSlide } from "swiper/react";
13
+ import { VehicleSearchDropdowns } from "./VehicleSearchDropdowns";
14
+
15
+ interface HeroSlide {
16
+ id: number;
17
+ image: string;
18
+ alt: string;
19
+ title: string;
20
+ description: string;
21
+ }
22
+
23
+ interface ShowroomHeroCarouselProps {
24
+ slides?: HeroSlide[];
25
+ }
26
+
27
+
28
+ const HeroBackground = ({ src, alt }: { src?: string | null; alt: string }) => {
29
+ const imageSrc = src?.trim() || "/random-car-1.jpeg";
30
+
31
+ return (
32
+ <div className="absolute inset-0">
33
+ <Image
34
+ src={imageSrc}
35
+ alt={alt}
36
+ width={1920}
37
+ height={753}
38
+ priority
39
+ quality={75}
40
+ sizes="(max-width: 768px) 100vw, (max-width: 1200px) 100vw, 1920px"
41
+ className="w-full h-full object-cover object-center"
42
+ />
43
+ </div>
44
+ );
45
+ };
46
+
47
+ const SearchFormSection = () => {
48
+ return (
49
+ <section
50
+ className="flex h-max flex-col w-full bg-[var(--color-secondary-900)] text-white px-6 py-8 lg:px-10 lg:py-12 lg:min-h-0 lg:justify-center"
51
+ aria-label="Find parts by vehicle"
52
+ >
53
+ {/* Desktop: only show when this is the left column. Mobile: always show heading */}
54
+ <div className="w-full max-w-md lg:max-w-none mx-auto lg:mx-0 space-y-4">
55
+ <h2 className="text-2xl md:text-3xl lg:text-4xl font-primary font-bold italic uppercase tracking-tight text-white">
56
+ FIND THE RIGHT PARTS
57
+ </h2>
58
+
59
+ <VehicleSearchDropdowns />
60
+ </div>
61
+ </section>
62
+ );
63
+ };
64
+
65
+ export const ShowroomHeroCarousel = ({}: ShowroomHeroCarouselProps) => {
66
+ const { data, loading } = useQuery(GET_PAGE_METADATA_BY_SLUG, {
67
+ variables: { slug: "hero-section" },
68
+ });
69
+
70
+ const heroSlides = useMemo(() => {
71
+ const meta = (data?.page?.metadata ?? []) as {
72
+ key: string;
73
+ value: string | null;
74
+ }[];
75
+ const getVal = (key: string) => {
76
+ const value = meta.find((m) => m.key === key)?.value;
77
+ return value?.trim() || null;
78
+ };
79
+ return [
80
+ {
81
+ id: 1,
82
+ title: "",
83
+ description: "",
84
+ image: getVal("background-image-url"),
85
+ alt: "Hero slide 1",
86
+ },
87
+ {
88
+ id: 2,
89
+ title: "",
90
+ description: "",
91
+ image: getVal("background-image-url-1"),
92
+ alt: "Hero slide 2",
93
+ },
94
+ ];
95
+ }, [data]);
96
+
97
+ return (
98
+ <div className="relative w-full">
99
+ {/* Mobile: hero on top, then form. Desktop: two columns — form left, hero right */}
100
+ <div className="flex flex-col lg:flex-row lg:min-h-[480px]">
101
+ {/* Mobile: hero first */}
102
+ <div className="relative w-full aspect-[16/10] lg:aspect-auto lg:flex-1 lg:min-h-[480px] order-1 lg:order-2">
103
+ {loading ? (
104
+ <div className="w-full h-full min-h-[280px] lg:min-h-[480px] bg-[var(--color-secondary-700)] animate-pulse" />
105
+ ) : (
106
+ <Swiper
107
+ modules={[Navigation, Pagination, Autoplay, EffectFade]}
108
+ navigation={{ prevEl: ".featured-prev", nextEl: ".featured-next" }}
109
+ pagination={{ clickable: true }}
110
+ autoplay={{ delay: 5000, disableOnInteraction: false }}
111
+ effect="fade"
112
+ loop
113
+ className="h-full w-full"
114
+ >
115
+ {heroSlides.map((slide) => (
116
+ <SwiperSlide key={slide.id}>
117
+ <div className="relative w-full h-full min-h-[280px] lg:min-h-[480px]">
118
+ <HeroBackground src={slide.image} alt={slide.alt} />
119
+ <div className="absolute inset-0 flex flex-col justify-center items-center text-center px-4 bg-black/20">
120
+ <p className="text-white text-sm md:text-base uppercase font-secondary tracking-wide">
121
+ {slide.title}
122
+ </p>
123
+ <p className="text-white text-2xl md:text-4xl lg:text-5xl font-primary font-bold uppercase tracking-tight mt-1 drop-shadow-md">
124
+ {slide.description}
125
+ </p>
126
+ </div>
127
+ </div>
128
+ </SwiperSlide>
129
+ ))}
130
+ </Swiper>
131
+ )}
132
+ </div>
133
+
134
+ {/* Left column (desktop) / below hero (mobile) */}
135
+ <div className="order-2 lg:order-1 lg:w-[min(500px,40%)] lg:flex-shrink-0">
136
+ <SearchFormSection />
137
+ </div>
138
+ </div>
139
+ </div>
140
+ );
141
+ };