@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,359 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useDealerLocations } from '@/app/hooks/useDealerLocations';
5
+ import { SearchIcon } from '@/app/utils/svgs/searchIcon';
6
+ import ModalLayout from '@/app/components/reuseableUI/modalLayout';
7
+ import CommonButton from '@/app/components/reuseableUI/commonButton';
8
+
9
+ interface DealerShippingOption {
10
+ id: string;
11
+ name: string;
12
+ address: {
13
+ streetAddress1?: string;
14
+ city?: string;
15
+ postalCode?: string;
16
+ country?: { country?: string; code?: string };
17
+ };
18
+ phone?: string;
19
+ distance?: string;
20
+ hours?: string;
21
+ comments?: string;
22
+ state?: string;
23
+ }
24
+
25
+ interface DealerShippingSectionProps {
26
+ isShipToDealer: boolean;
27
+ onShippingTypeChange: (isShipToDealer: boolean) => void;
28
+ selectedDealer: DealerShippingOption | null;
29
+ onDealerSelect: (dealer: DealerShippingOption | null) => void;
30
+ }
31
+
32
+ export default function DealerShippingSection({
33
+ isShipToDealer,
34
+ onShippingTypeChange,
35
+ selectedDealer,
36
+ onDealerSelect
37
+ }: DealerShippingSectionProps) {
38
+ const {
39
+ sortedDealers,
40
+ nearestDealer,
41
+ userLocation,
42
+ loading,
43
+ locationError,
44
+ isGettingLocation,
45
+ requestUserLocation
46
+ } = useDealerLocations();
47
+ const [showDealerSelection, setShowDealerSelection] = useState(false);
48
+ const [searchTerm, setSearchTerm] = useState('');
49
+ const [hasTriedLocation, setHasTriedLocation] = useState(false);
50
+
51
+ // Filter dealers based on search term
52
+ const filteredDealers = sortedDealers.filter(dealer =>
53
+ dealer.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
54
+ dealer.address?.city?.toLowerCase().includes(searchTerm.toLowerCase()) ||
55
+ dealer.address?.streetAddress1?.toLowerCase().includes(searchTerm.toLowerCase())
56
+ );
57
+
58
+ // Handle ship to dealer toggle
59
+ const handleShipToDealerChange = async (checked: boolean) => {
60
+ onShippingTypeChange(checked);
61
+
62
+ if (checked) {
63
+ setShowDealerSelection(true);
64
+
65
+ // If we haven't tried getting location yet, attempt it
66
+ if (!hasTriedLocation && !userLocation) {
67
+ setHasTriedLocation(true);
68
+ try {
69
+ await requestUserLocation();
70
+ } catch {
71
+ // Location denied or failed, show manual selection
72
+ // Location access declined; fall back to manual selection.
73
+ }
74
+ }
75
+ } else {
76
+ setShowDealerSelection(false);
77
+ onDealerSelect(null);
78
+ }
79
+ };
80
+
81
+ // Auto-select nearest dealer when location is available
82
+ useEffect(() => {
83
+ if (isShipToDealer && nearestDealer && !selectedDealer && userLocation) {
84
+ const dealerOption: DealerShippingOption = {
85
+ id: nearestDealer.id,
86
+ name: nearestDealer.name,
87
+ address: nearestDealer.address || {},
88
+ phone: nearestDealer.phone,
89
+ distance: nearestDealer.distance,
90
+ hours: nearestDealer.hours,
91
+ comments: nearestDealer.comments,
92
+ state: nearestDealer.state
93
+ };
94
+ onDealerSelect(dealerOption);
95
+ }
96
+ }, [isShipToDealer, nearestDealer, selectedDealer, userLocation, onDealerSelect]);
97
+
98
+ const handleDealerSelect = (dealer: typeof sortedDealers[0]) => {
99
+ const dealerOption: DealerShippingOption = {
100
+ id: dealer.id,
101
+ name: dealer.name,
102
+ address: dealer.address || {},
103
+ phone: dealer.phone,
104
+ distance: dealer.distance,
105
+ hours: dealer.hours,
106
+ comments: dealer.comments,
107
+ state: dealer.state
108
+ };
109
+ onDealerSelect(dealerOption);
110
+ setShowDealerSelection(false);
111
+ };
112
+
113
+ return (
114
+ <div>
115
+ <h2 className="text-base font-semibold font-secondary text-[var(--color-secondary-800)] mb-3 uppercase">
116
+ Shipping Options
117
+ </h2>
118
+
119
+ <div className="grid-cols-2 grid gap-2">
120
+ {/* Standard Shipping Option */}
121
+ <label className={`flex items-start gap-3 ring-1 p-2 cursor-pointer ${
122
+ !isShipToDealer
123
+ ? "ring-[var(--color-primary-100)] bg-[var(--color-primary-50)] text-[var(--color-primary-700)]"
124
+ : "ring-gray-300 hover:bg-gray-50"
125
+ }`}>
126
+ <input
127
+ type="radio"
128
+ name="shippingType"
129
+ checked={!isShipToDealer}
130
+ onChange={() => handleShipToDealerChange(false)}
131
+ className="mt-1 accent-[var(--color-primary-600)]"
132
+ />
133
+ <div className="flex-1">
134
+ <div className="font-medium text-base font-secondary">
135
+ Ship to My Address
136
+ </div>
137
+ {/* <div className="text-sm text-[var(--color-secondary-600)] mt-1">
138
+ Standard shipping to your provided address
139
+ </div> */}
140
+ </div>
141
+ </label>
142
+
143
+ {/* Ship to Dealer Option */}
144
+ {/* <label className={`flex items-start gap-3 ring-1 p-2 cursor-pointer ${
145
+ isShipToDealer
146
+ ? "ring-[var(--color-primary-100)] bg-[var(--color-primary-50)] text-[var(--color-primary-700)]"
147
+ : "ring-gray-300 hover:bg-gray-50"
148
+ }`}>
149
+ <input
150
+ type="radio"
151
+ name="shippingType"
152
+ checked={isShipToDealer}
153
+ onChange={() => handleShipToDealerChange(true)}
154
+ className="mt-1 accent-[var(--color-primary-600)]"
155
+ />
156
+ <div className="flex-1">
157
+ <div className="font-medium text-base font-secondary">
158
+ Ship to Dealer
159
+ </div>
160
+ <div className="text-sm text-[var(--color-secondary-600)] mt-1">
161
+ Ship to your nearest dealer for pickup
162
+ </div>
163
+ {isShipToDealer && selectedDealer && (
164
+ <div className="mt-3 p-3 bg-white rounded border border-[var(--color-secondary-200)]">
165
+ <div className="font-medium text-sm">{selectedDealer.name}</div>
166
+ <div className="text-sm text-[var(--color-secondary-600)]">
167
+ {selectedDealer.address.streetAddress1}
168
+ <br />
169
+ {selectedDealer.address.city}, {selectedDealer.address.country?.code} {selectedDealer.address.postalCode}
170
+ </div>
171
+ {selectedDealer.distance && selectedDealer.distance !== 'N/A' && (
172
+ <div className="text-sm text-green-600 font-medium mt-1">
173
+ Distance: {selectedDealer.distance}
174
+ </div>
175
+ )}
176
+ {selectedDealer.phone && (
177
+ <div className="text-sm text-[var(--color-secondary-600)]">
178
+ Phone: {selectedDealer.phone}
179
+ </div>
180
+ )}
181
+ <button
182
+ type="button"
183
+ onClick={() => setShowDealerSelection(true)}
184
+ className="text-sm text-[var(--color-primary-600)] hover:text-[var(--color-primary-700)] mt-2 underline"
185
+ >
186
+ Change Dealer
187
+ </button>
188
+ </div>
189
+ )}
190
+ {isShipToDealer && !selectedDealer && (
191
+ <div className="mt-3 p-3 bg-white rounded border border-[var(--color-secondary-200)]">
192
+ <div className="text-sm text-[var(--color-secondary-600)] mb-2">
193
+ Please select a dealer for pickup
194
+ </div>
195
+ <button
196
+ type="button"
197
+ onClick={() => setShowDealerSelection(true)}
198
+ className="text-sm bg-[var(--color-primary-600)] text-white px-3 py-1 rounded hover:bg-[var(--color-primary-700)]"
199
+ >
200
+ Select Dealer
201
+ </button>
202
+ </div>
203
+ )}
204
+ </div>
205
+ </label> */}
206
+ </div>
207
+
208
+ {/* Dealer Selection Modal */}
209
+ <ModalLayout
210
+ isModalOpen={showDealerSelection}
211
+ onClose={() => setShowDealerSelection(false)}
212
+ heading="Select a Dealer"
213
+ className="lg:max-w-4xl"
214
+ >
215
+ <div className="mt-10 space-y-6">
216
+ {/* Location Status Cards */}
217
+ <div className="space-y-4">
218
+ {!userLocation && !locationError && (
219
+ <div className="p-2 bg-[var(--color-secondary-100)] border border-[var(--color-secondary-200)] rounded">
220
+ <div className="flex items-center justify-between">
221
+ <div>
222
+ <div className="text-sm font-medium text-[var(--color-secondary-800)] font-secondary">
223
+ Enable location for distance calculations
224
+ </div>
225
+ <div className="text-sm text-[var(--color-secondary-600)] mt-1">
226
+ We&apos;ll show dealers nearest to you first
227
+ </div>
228
+ </div>
229
+ <CommonButton
230
+ variant="primary"
231
+ content={isGettingLocation ? 'Getting...' : 'Allow Location'}
232
+ onClick={requestUserLocation}
233
+ disabled={isGettingLocation}
234
+ className="text-sm py-2 px-4"
235
+ />
236
+ </div>
237
+ </div>
238
+ )}
239
+
240
+ {locationError && (
241
+ <div className="p-2 bg-yellow-50 border border-yellow-200 rounded">
242
+ <div className="text-sm text-yellow-800 font-secondary font-medium">{locationError}</div>
243
+ <div className="text-sm text-yellow-600 mt-1">
244
+ You can still browse all dealers below
245
+ </div>
246
+ </div>
247
+ )}
248
+
249
+ {userLocation && (
250
+ <div className="p-2 bg-green-50 border border-green-200 rounded">
251
+ <div className="text-sm text-green-800 font-secondary font-medium">
252
+ ✓ Using your location - dealers are sorted by distance
253
+ </div>
254
+ </div>
255
+ )}
256
+ </div>
257
+
258
+ {/* Search */}
259
+ <div className="relative">
260
+ <label className="block text-sm font-medium text-[var(--color-secondary-800)] pb-2 uppercase font-secondary">
261
+ Search Dealers
262
+ </label>
263
+ <div className="relative">
264
+ <input
265
+ type="text"
266
+ placeholder="Search by dealer name, city, or address..."
267
+ value={searchTerm}
268
+ onChange={(e) => setSearchTerm(e.target.value)}
269
+ className="w-full h-12 pl-10 pr-4 text-sm border border-[var(--color-secondary-200)] bg-white rounded focus:outline-none focus:ring-2 focus:ring-[var(--color-primary-500)] focus:border-[var(--color-primary-600)] font-secondary"
270
+ />
271
+ <div className="absolute left-3 top-1/2 -translate-y-1/2">
272
+ <span className="w-4 h-4 block text-[var(--color-secondary-600)]">
273
+ {SearchIcon}
274
+ </span>
275
+ </div>
276
+ </div>
277
+ </div>
278
+
279
+ {/* Dealer List */}
280
+ <div className="border border-[var(--color-secondary-200)] rounded bg-white">
281
+ {loading && (
282
+ <div className="p-8 text-center">
283
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--color-primary-600)] mx-auto"></div>
284
+ <div className="mt-2 text-sm text-[var(--color-secondary-600)] font-secondary">Loading dealers...</div>
285
+ </div>
286
+ )}
287
+
288
+ {!loading && filteredDealers.length === 0 && (
289
+ <div className="p-8 text-center">
290
+ <div className="text-sm text-[var(--color-secondary-600)] font-secondary">
291
+ {searchTerm ? `No dealers found matching "${searchTerm}"` : 'No dealers available'}
292
+ </div>
293
+ </div>
294
+ )}
295
+
296
+ {!loading && filteredDealers.length > 0 && (
297
+ <div className="max-h-96 overflow-y-auto">
298
+ {filteredDealers.map((dealer, index) => (
299
+ <div
300
+ key={dealer.id}
301
+ className={`p-2 hover:bg-[var(--color-secondary-50)] cursor-pointer transition-colors ${
302
+ index !== filteredDealers.length - 1 ? 'border-b border-[var(--color-secondary-200)]' : ''
303
+ }`}
304
+ onClick={() => handleDealerSelect(dealer)}
305
+ >
306
+ <div className="flex items-start justify-between">
307
+ <div className="flex-1">
308
+ <div className="font-medium text-sm text-[var(--color-secondary-900)] font-secondary">
309
+ {dealer.name}
310
+ </div>
311
+ <div className="text-sm text-[var(--color-secondary-600)] mt-1">
312
+ {dealer.address?.streetAddress1}
313
+ <br />
314
+ {dealer.address?.city}, {dealer.state || dealer.address?.country?.code} {dealer.address?.postalCode}
315
+ </div>
316
+ {dealer.phone && (
317
+ <div className="text-sm text-[var(--color-secondary-600)] mt-1">
318
+ <span className="font-medium">Phone:</span> {dealer.phone}
319
+ </div>
320
+ )}
321
+ {dealer.hours && (
322
+ <div className="text-sm text-[var(--color-secondary-600)]">
323
+ <span className="font-medium">Hours:</span> {dealer.hours}
324
+ </div>
325
+ )}
326
+ </div>
327
+ <div className="ml-4 text-right flex flex-col items-end gap-2">
328
+ {dealer.distance && dealer.distance !== 'N/A' && (
329
+ <div className="text-sm font-medium text-green-600 font-secondary">
330
+ {dealer.distance}
331
+ </div>
332
+ )}
333
+ <CommonButton
334
+ variant="primary"
335
+ content="Select"
336
+ className="text-xs py-1 px-3"
337
+ />
338
+ </div>
339
+ </div>
340
+ </div>
341
+ ))}
342
+ </div>
343
+ )}
344
+ </div>
345
+
346
+ {/* Action Buttons */}
347
+ <div className="flex flex-col gap-2 pt-4">
348
+ <CommonButton
349
+ variant="secondary"
350
+ content="Cancel"
351
+ onClick={() => setShowDealerSelection(false)}
352
+ className="w-full text-sm md:text-base py-2.5 md:py-3"
353
+ />
354
+ </div>
355
+ </div>
356
+ </ModalLayout>
357
+ </div>
358
+ );
359
+ }
@@ -0,0 +1,249 @@
1
+ "use client";
2
+
3
+ import { InfoIcon } from "@/app/utils/svgs/infoIcon";
4
+
5
+ interface ShippingMethod {
6
+ id: string;
7
+ name: string;
8
+ price: { amount: number; currency: string };
9
+ minimumDeliveryDays?: number | null;
10
+ maximumDeliveryDays?: number | null;
11
+ }
12
+
13
+ interface DeliveryMethodSectionProps {
14
+ checkoutId: string | null | undefined;
15
+ canShowDeliveryMethods: boolean;
16
+ hasCompleteShippingInfo: boolean;
17
+ missingForDelivery: string[];
18
+ shippingLoading: boolean;
19
+ shippingMethods: ShippingMethod[];
20
+ shippingError: string | null;
21
+ selectedShippingId: string | null;
22
+ isUpdatingDelivery: boolean;
23
+ isProcessingSelection?: boolean;
24
+ isWillCallSelected?: boolean;
25
+ onShippingMethodSelect: (methodId: string) => void;
26
+ onRetryShippingMethods?: () => void;
27
+ }
28
+
29
+ export default function DeliveryMethodSection({
30
+ checkoutId,
31
+ canShowDeliveryMethods,
32
+ hasCompleteShippingInfo,
33
+ missingForDelivery,
34
+ shippingLoading,
35
+ shippingMethods,
36
+ shippingError,
37
+ selectedShippingId,
38
+ isUpdatingDelivery,
39
+ isProcessingSelection = false,
40
+ isWillCallSelected = false,
41
+ onShippingMethodSelect,
42
+ onRetryShippingMethods,
43
+ }: DeliveryMethodSectionProps) {
44
+ if (!checkoutId) {
45
+ return null;
46
+ }
47
+
48
+ // Filter shipping methods: if "Free Shipping" is available, only show that one
49
+ const filteredShippingMethods = (() => {
50
+ const freeShippingMethod = shippingMethods.find(method =>
51
+ method.name?.toLowerCase().includes('free shipping') && method.price?.amount === 0
52
+ );
53
+
54
+ if (freeShippingMethod) {
55
+ return [freeShippingMethod];
56
+ }
57
+
58
+ return shippingMethods;
59
+ })();
60
+
61
+ return (
62
+ <div>
63
+ <h2 className="text-base font-semibold font-secondary text-[var(--color-secondary-800)] mb-3 uppercase">
64
+ Delivery Method{" "}
65
+ {!isWillCallSelected && (isUpdatingDelivery || shippingLoading || isProcessingSelection) && (
66
+ <span className="ml-2 text-xs text-gray-500">(updating…)</span>
67
+ )}
68
+ </h2>
69
+
70
+ {/* Show delivery methods directly */}
71
+ {(
72
+ <>
73
+ {!canShowDeliveryMethods && (
74
+ <div className="text-xs font-secondary text-white bg-[var(--color-secondary-100)] border border-[var(--color-secondary-200)] p-2 flex items-start gap-2">
75
+ <svg className="w-5 h-5 text-white mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
76
+ <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
77
+ </svg>
78
+ <p>
79
+ Delivery methods will be available once you complete the shipping
80
+ address.{" "}
81
+ {!hasCompleteShippingInfo && missingForDelivery.length > 0 && (
82
+ <span>Missing: {missingForDelivery.join(", ")}</span>
83
+ )}
84
+ </p>
85
+ </div>
86
+ )}
87
+
88
+
89
+ {!shippingLoading && !isUpdatingDelivery && shippingError && (
90
+ <div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded p-3">
91
+ <p className="font-medium">
92
+ {shippingError.includes("postal code")
93
+ ? "Address Validation Error"
94
+ : shippingError.includes("session") || shippingError.includes("expired") || shippingError.includes("timeout")
95
+ ? "Session Issue"
96
+ : "Delivery Method Error"}
97
+ </p>
98
+ <p className="text-xs mt-1">{shippingError}</p>
99
+
100
+ {(shippingError.includes("session") ||
101
+ shippingError.includes("expired") ||
102
+ shippingError.includes("timeout") ||
103
+ shippingError.includes("network") ||
104
+ shippingError.includes("Failed to fetch")) && (
105
+ <div className="mt-3">
106
+ <p className="text-xs text-gray-600 mb-2">
107
+ This might be due to a session timeout or network issue. Please try refreshing or retrying.
108
+ </p>
109
+ {onRetryShippingMethods && (
110
+ <div className="flex gap-2">
111
+ <button
112
+ onClick={onRetryShippingMethods}
113
+ disabled={shippingLoading || isUpdatingDelivery}
114
+ className="px-3 py-1.5 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
115
+ >
116
+ {shippingLoading ? "Retrying..." : "Retry"}
117
+ </button>
118
+ <button
119
+ onClick={() => window.location.reload()}
120
+ disabled={shippingLoading || isUpdatingDelivery}
121
+ className="px-3 py-1.5 text-xs bg-gray-600 text-white rounded hover:bg-gray-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
122
+ >
123
+ Refresh Page
124
+ </button>
125
+ </div>
126
+ )}
127
+ </div>
128
+ )}
129
+
130
+ {shippingError.includes("not applicable") && (
131
+ <p className="text-xs mt-2 text-gray-600">
132
+ This can happen if the shipping method does not support your
133
+ address, product&apos;s weight/size, or geographic region.
134
+ </p>
135
+ )}
136
+
137
+ {shippingError.includes("no longer available") && (
138
+ <div className="mt-3">
139
+ <p className="text-xs text-gray-600 mb-2">
140
+ The selected shipping method is no longer available. This can happen if inventory or shipping options have changed.
141
+ </p>
142
+ {onRetryShippingMethods && (
143
+ <button
144
+ onClick={onRetryShippingMethods}
145
+ disabled={shippingLoading || isUpdatingDelivery}
146
+ className="px-3 py-1.5 text-xs bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
147
+ >
148
+ {shippingLoading ? "Refreshing..." : "Refresh Methods"}
149
+ </button>
150
+ )}
151
+ </div>
152
+ )}
153
+ </div>
154
+ )}
155
+
156
+ {((!shippingLoading &&
157
+ !isUpdatingDelivery &&
158
+ filteredShippingMethods.length > 0 &&
159
+ !shippingError &&
160
+ canShowDeliveryMethods) ||
161
+ (isWillCallSelected && filteredShippingMethods.length > 0)) && (
162
+ <div>
163
+ {/* Show message when free shipping is available */}
164
+ {shippingMethods.length > filteredShippingMethods.length && (
165
+ <div className="mb-4 text-sm text-green-700 bg-green-50 border border-green-200 rounded p-3">
166
+ <p className="font-medium">Free Shipping Available!</p>
167
+ <p className="text-xs mt-1">
168
+ Your order qualifies for free shipping.
169
+ </p>
170
+ </div>
171
+ )}
172
+
173
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
174
+ {filteredShippingMethods.map((m) => {
175
+ const daysLabel =
176
+ m.minimumDeliveryDays != null && m.maximumDeliveryDays != null
177
+ ? `${m.minimumDeliveryDays}-${m.maximumDeliveryDays} days`
178
+ : undefined;
179
+
180
+ const isDisabled = isUpdatingDelivery || shippingLoading || isProcessingSelection;
181
+
182
+ return (
183
+ <label
184
+ key={m.id}
185
+ className={`flex items-center gap-3 ring-1 p-2 transition-all duration-200 ${
186
+ isDisabled ? "cursor-not-allowed opacity-50 pointer-events-none" : "cursor-pointer"
187
+ } ${
188
+ selectedShippingId === m.id
189
+ ? "ring-[var(--color-primary-100)] bg-[var(--color-primary-50)] text-[var(--color-primary-700)] accent-[var(--color-primary-600)]"
190
+ : "ring-gray-300 hover:bg-gray-50"
191
+ } ${isDisabled ? "" : "hover:bg-gray-50"}`}
192
+ >
193
+ <input
194
+ type="radio"
195
+ name="delivery"
196
+ disabled={isDisabled}
197
+ checked={selectedShippingId === m.id}
198
+ onChange={() => !isDisabled && onShippingMethodSelect(m.id)}
199
+ />
200
+ <div className="flex-1">
201
+ <div className="font-medium text-base/none font-secondary">
202
+ {m.name}
203
+ </div>
204
+ {daysLabel && (
205
+ <div className="text-xs text-gray-500">{daysLabel}</div>
206
+ )}
207
+ </div>
208
+ <div className="font-medium text-base/none">
209
+ {new Intl.NumberFormat(undefined, {
210
+ style: "currency",
211
+ currency: m.price.currency,
212
+ }).format(m.price.amount)}
213
+ </div>
214
+ </label>
215
+ );
216
+ })}
217
+ </div>
218
+ </div>
219
+ )}
220
+
221
+ {!shippingLoading &&
222
+ !isUpdatingDelivery &&
223
+ !shippingError &&
224
+ filteredShippingMethods.length === 0 &&
225
+ canShowDeliveryMethods && (
226
+ <div className="text-sm text-gray-600 bg-yellow-50 border border-yellow-200 rounded p-3">
227
+ <p className="font-medium text-yellow-800">
228
+ No delivery methods found
229
+ </p>
230
+ <p className="text-xs mt-1">
231
+ No shipping methods are available for this address. This could be
232
+ due to:
233
+ </p>
234
+ <ul className="text-xs mt-2 list-disc list-inside text-gray-600">
235
+ <li>Invalid or incomplete address</li>
236
+ <li>No shipping zones configured for this location</li>
237
+ <li>Address verification issues</li>
238
+ </ul>
239
+ <p className="text-xs mt-2 text-gray-500">
240
+ Try updating your address or contact support if the issue
241
+ persists.
242
+ </p>
243
+ </div>
244
+ )}
245
+ </>
246
+ )}
247
+ </div>
248
+ );
249
+ }