@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,39 @@
1
+ import type { Metadata } from "next";
2
+ import { getStoreName } from "@/app/utils/branding";
3
+ import Link from "next/link";
4
+
5
+ export const metadata: Metadata = {
6
+ title: `My Account - ${getStoreName()}`,
7
+ description: "Manage your account, view order history, update addresses, and track shipments. Your shopping dashboard.",
8
+ robots: { index: false, follow: false },
9
+ }
10
+
11
+ export default function AccountIndexPage() {
12
+ return (
13
+ <main className="container mx-auto px-4 md:px-6 py-12">
14
+ <h1 className="text-2xl md:text-3xl font-primary text-[var(--color-secondary-800)]">
15
+ My Account
16
+ </h1>
17
+ <p className="mt-2 text-[var(--color-secondary-600)]">
18
+ Choose a section:
19
+ </p>
20
+ <ul className="mt-6 space-y-2">
21
+ <li>
22
+ <Link className="underline" href="/account/settings">
23
+ Profile Settings
24
+ </Link>
25
+ </li>
26
+ <li>
27
+ <Link className="underline" href="/account/orders">
28
+ Order History
29
+ </Link>
30
+ </li>
31
+ <li>
32
+ <Link className="underline" href="/account/address">
33
+ Address Book
34
+ </Link>
35
+ </li>
36
+ </ul>
37
+ </main>
38
+ );
39
+ }
@@ -0,0 +1,28 @@
1
+ import CommonButton from '@/app/components/reuseableUI/commonButton';
2
+ import ModalLayout from '@/app/components/reuseableUI/modalLayout'
3
+ import React from 'react'
4
+
5
+ const EditProfileSuccessModal = ({ isModalOpen, onClose }: { isModalOpen: boolean; onClose: () => void }) => {
6
+ return (
7
+ <ModalLayout isModalOpen={isModalOpen} onClose={onClose} className='max-w-[758px] space-y-5' removeCrossIcon>
8
+ <div className="w-full text-center space-y-1">
9
+ <p className='text-xl font-semibold font-secondary text-[var(--color-secondary-800)]'>
10
+ PROFILE UPDATED
11
+ </p>
12
+ <p className='text-sm font-secondary text-[var(--color-secondary-600)]'>
13
+ Your profile has been updated successfully.
14
+ </p>
15
+ </div>
16
+ <CommonButton
17
+ type='button'
18
+ variant='secondary'
19
+ onClick={onClose}
20
+ className='w-full'
21
+ >
22
+ Close
23
+ </CommonButton>
24
+ </ModalLayout>
25
+ )
26
+ }
27
+
28
+ export default EditProfileSuccessModal
@@ -0,0 +1,15 @@
1
+ import type { Metadata } from "next"
2
+ import { getStoreName } from "@/app/utils/branding"
3
+
4
+ export const metadata: Metadata = {
5
+ title: `Account Settings - ${getStoreName()}`,
6
+ description: "Update your profile information, change password, and manage account preferences. Keep your account secure and up to date.",
7
+ }
8
+
9
+ export default function AccountSettingsLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode
13
+ }) {
14
+ return children
15
+ }
@@ -0,0 +1,260 @@
1
+ 'use client';
2
+
3
+ import CommonButton from '@/app/components/reuseableUI/commonButton';
4
+ import EmptyState from '@/app/components/reuseableUI/emptyState';
5
+ import Input from '@/app/components/reuseableUI/input';
6
+ import LoadingUI from '@/app/components/reuseableUI/loadingUI';
7
+ import { PasswordRules } from '@/app/components/reuseableUI/passwordRules/passwordRules';
8
+ import { PencilIcon } from '@/app/utils/svgs/pencilIcon';
9
+ import { CHANGE_PASSWORD, type ChangePasswordData, type ChangePasswordVars } from '@/graphql/mutations/changePassword';
10
+ import { UPDATE_PROFILE, type UpdateProfileData, type UpdateProfileVars } from '@/graphql/mutations/updateProfile';
11
+ import { GET_MY_PROFILE, type GetMyProfileData } from '@/graphql/queries/getMyProfile';
12
+ import { useMutation, useQuery } from '@apollo/client';
13
+ import { useEffect, useState } from 'react';
14
+ import EditProfileSuccessModal from './components/editProfileSuccessModal';
15
+
16
+ interface ProfileData {
17
+ firstName: string;
18
+ lastName: string;
19
+ email: string;
20
+ }
21
+
22
+ interface PasswordData {
23
+ currentPassword: string;
24
+ newPassword: string;
25
+ confirmPassword: string;
26
+ }
27
+
28
+ export default function AccountSettingsPage() {
29
+ // Load profile
30
+ const { data, loading, error, refetch } = useQuery<GetMyProfileData>(GET_MY_PROFILE, {
31
+ fetchPolicy: 'no-cache',
32
+ });
33
+ const [isEditing, setIsEditing] = useState(false);
34
+ const [isModalOpen, setIsModalOpen] = useState(false);
35
+ const [errorMessage, setErrorMessage] = useState('');
36
+ // Form data states
37
+ const [profileData, setProfileData] = useState<ProfileData>({
38
+ firstName: '',
39
+ lastName: '',
40
+ email: '',
41
+ });
42
+
43
+ useEffect(() => {
44
+ if (data?.me) {
45
+ setProfileData({
46
+ firstName: data.me.firstName || '',
47
+ lastName: data.me.lastName || '',
48
+ email: data.me.email,
49
+ });
50
+ }
51
+ }, [data]);
52
+
53
+ const [passwordData, setPasswordData] = useState<PasswordData>({
54
+ currentPassword: '',
55
+ newPassword: '',
56
+ confirmPassword: '',
57
+ });
58
+
59
+ const [updateProfile, { loading: updatingProfile }] = useMutation<UpdateProfileData, UpdateProfileVars>(UPDATE_PROFILE);
60
+ const [changePassword, { loading: changingPassword }] = useMutation<ChangePasswordData, ChangePasswordVars>(CHANGE_PASSWORD);
61
+
62
+ const handleProfileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
63
+ const { name, value } = e.target;
64
+ let filteredValue = value;
65
+ if (name === "firstName" || name === "lastName") {
66
+ filteredValue = value.replace(/[^A-Za-z ]/g, "");
67
+ }
68
+ setProfileData({
69
+ ...profileData,
70
+ [name]: filteredValue,
71
+ });
72
+ };
73
+
74
+ const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
75
+ const { name, value } = e.target;
76
+ setPasswordData({
77
+ ...passwordData,
78
+ [name]: value,
79
+ });
80
+ };
81
+
82
+ const editProfileSubmitHandler = async (e: React.FormEvent) => {
83
+ e.preventDefault();
84
+ try {
85
+ const res = await updateProfile({ variables: { firstName: profileData.firstName, lastName: profileData.lastName } });
86
+ const errs = res.data?.accountUpdate?.errors || [];
87
+ if (errs.length) {
88
+ setErrorMessage(errs.map(e => e.message).filter(Boolean).join('\n'));
89
+ setTimeout(() => setErrorMessage(''), 3000);
90
+ return;
91
+ }
92
+ } catch (err) {
93
+ console.error('UpdateProfile error', err);
94
+ setErrorMessage('Failed to update profile.');
95
+ setTimeout(() => setErrorMessage(''), 3000);
96
+ return;
97
+ }
98
+ if (passwordData.currentPassword || passwordData.newPassword || passwordData.confirmPassword) {
99
+ if (passwordData.newPassword !== passwordData.confirmPassword) {
100
+ setErrorMessage('New passwords do not match!');
101
+ setTimeout(() => setErrorMessage(''), 3000);
102
+ return;
103
+ }
104
+ try {
105
+ const res2 = await changePassword({ variables: { oldPassword: passwordData.currentPassword, newPassword: passwordData.newPassword } });
106
+ const payload = res2.data?.passwordChange;
107
+ const errs2 = payload?.errors || [];
108
+ if (errs2.length) {
109
+ setErrorMessage(errs2.map(e => e.message).filter(Boolean).join('\n'));
110
+ setTimeout(() => setErrorMessage(''), 3000);
111
+ return;
112
+ }
113
+ // Password changed successfully
114
+ setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' });
115
+ } catch (err) {
116
+ console.error('ChangePassword error', err);
117
+ setErrorMessage('Failed to change password.');
118
+ setTimeout(() => setErrorMessage(''), 3000);
119
+ return;
120
+ }
121
+ }
122
+
123
+ await refetch();
124
+ setIsModalOpen(true);
125
+ setIsEditing(false);
126
+ setTimeout(() => setIsModalOpen(false), 3000);
127
+ }
128
+ return (
129
+ <>
130
+ <div>
131
+ {loading ? (
132
+ <LoadingUI />
133
+ ) : error ? (
134
+ <EmptyState className="h-[50vh]" text="Failed to load profile." />
135
+ ) : (
136
+ <form
137
+ onSubmit={editProfileSubmitHandler}
138
+ className="max-w-4xl space-y-6 lg:space-y-10"
139
+ >
140
+ <div>
141
+ <div className='flex items-center justify-between w-full mb-4 lg:mb-0'>
142
+ <h3 className="text-lg lg:text-xl text-[var(--color-secondary-800)] font-semibold lg:mb-4 uppercase">Personal Information</h3>
143
+ {
144
+ !isEditing &&
145
+ <CommonButton type='button' variant='tertiary' className="p-0 text-sm flex items-center gap-2" onClick={() => setIsEditing(true)}>
146
+ <span className='[&>svg]:size-5 text-[var(--color-primary-600)]'>
147
+ {PencilIcon}
148
+ </span>
149
+ EDIT PROFILE
150
+ </CommonButton>
151
+ }
152
+ </div>
153
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
154
+ <Input
155
+ label="First Name"
156
+ type="text"
157
+ name="firstName"
158
+ value={profileData.firstName}
159
+ onChange={handleProfileChange}
160
+ disabled={!isEditing}
161
+ />
162
+ <Input
163
+ label="Last Name"
164
+ type="text"
165
+ name="lastName"
166
+ value={profileData.lastName}
167
+ onChange={handleProfileChange}
168
+ disabled={!isEditing}
169
+ />
170
+ </div>
171
+ <div className="mb-2">
172
+ <Input
173
+ label="Email"
174
+ type="email"
175
+ name="email"
176
+ value={profileData.email}
177
+ readOnly
178
+ disabled
179
+ />
180
+ </div>
181
+ </div>
182
+
183
+ <div className='space-y-5'>
184
+ <h3 className="text-lg lg:text-xl text-[var(--color-secondary-800)] font-semibold mb-4">Password</h3>
185
+ <Input
186
+ label="Current Password"
187
+ placeholder='********'
188
+ type="password"
189
+ name="currentPassword"
190
+ value={passwordData.currentPassword}
191
+ onChange={handlePasswordChange}
192
+ disabled={!isEditing}
193
+ />
194
+ {
195
+ isEditing &&
196
+ <>
197
+ <div className="mb-4 w-full">
198
+ <Input
199
+ label="New Password"
200
+ placeholder='********'
201
+ type="password"
202
+ name="newPassword"
203
+ value={passwordData.newPassword}
204
+ onChange={handlePasswordChange}
205
+ />
206
+
207
+ <div className="mt-2 text-xs space-y-1 [&>div]:flex [&>div]:items-center [&>div]:gap-1">
208
+ <PasswordRules value={passwordData.newPassword} />
209
+ </div>
210
+ </div>
211
+ <Input
212
+ label="Re-enter New Password"
213
+ type="password"
214
+ name="confirmPassword"
215
+ placeholder='********'
216
+ value={passwordData.confirmPassword}
217
+ onChange={handlePasswordChange}
218
+ />
219
+ </>
220
+ }
221
+ {errorMessage && <p className="text-red-600 text-sm font-secondary">{errorMessage}</p>}
222
+ </div>
223
+ {
224
+ isEditing &&
225
+ <div className="flex gap-3">
226
+ <CommonButton
227
+ type='button'
228
+ className='min-w-24 text-sm lg:text-base px-4 py-3'
229
+ variant='secondary'
230
+ onClick={() => {
231
+ setIsEditing(false);
232
+ if (data?.me) {
233
+ setProfileData({
234
+ firstName: data.me.firstName || '',
235
+ lastName: data.me.lastName || '',
236
+ email: data.me.email,
237
+ });
238
+ }
239
+ setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' });
240
+ }}
241
+ >
242
+ Cancel
243
+ </CommonButton>
244
+ <CommonButton
245
+ className='min-w-24 text-sm lg:text-base px-4 py-3'
246
+ variant='primary'
247
+ type="submit"
248
+ disabled={updatingProfile || changingPassword}
249
+ >
250
+ {(updatingProfile || changingPassword) ? 'Updating...' : 'Save'}
251
+ </CommonButton>
252
+ </div>
253
+ }
254
+ </form>
255
+ )}
256
+ </div>
257
+ <EditProfileSuccessModal isModalOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
258
+ </>
259
+ );
260
+ }
@@ -0,0 +1,94 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+
3
+ const GET_TRANSACTION = `
4
+ query GetTransaction($id: ID!) {
5
+ transaction(id: $id) {
6
+ id
7
+ order {
8
+ id
9
+ number
10
+ total {
11
+ gross {
12
+ amount
13
+ currency
14
+ }
15
+ }
16
+ }
17
+ events {
18
+ type
19
+ createdAt
20
+ }
21
+ }
22
+ }
23
+ `;
24
+
25
+ export async function POST(request: NextRequest) {
26
+ try {
27
+ const body = await request.json();
28
+ const { checkoutId, transactionId } = body;
29
+
30
+ if (!checkoutId) {
31
+ return NextResponse.json(
32
+ { error: "Missing checkoutId" },
33
+ { status: 400 }
34
+ );
35
+ }
36
+
37
+ // Get Saleor API URL
38
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL;
39
+ if (!apiUrl) {
40
+ throw new Error("NEXT_PUBLIC_API_URL is not configured");
41
+ }
42
+
43
+ // Get auth token from request cookies
44
+ const token = request.cookies.get("token")?.value;
45
+
46
+ const headers: Record<string, string> = {
47
+ "Content-Type": "application/json",
48
+ };
49
+
50
+ if (token) {
51
+ headers["Authorization"] = `Bearer ${token}`;
52
+ }
53
+
54
+ // Check transaction status in Saleor
55
+ const response = await fetch(apiUrl, {
56
+ method: "POST",
57
+ headers,
58
+ body: JSON.stringify({
59
+ query: GET_TRANSACTION,
60
+ variables: {
61
+ id: transactionId || checkoutId,
62
+ },
63
+ }),
64
+ });
65
+
66
+ if (!response.ok) {
67
+ return NextResponse.json({ completed: false });
68
+ }
69
+
70
+ const result = await response.json();
71
+ const transaction = result.data?.transaction;
72
+ const order = transaction?.order;
73
+
74
+ // Check if order exists (payment completed)
75
+ if (order) {
76
+ return NextResponse.json({
77
+ completed: true,
78
+ order: {
79
+ id: order.id,
80
+ number: order.number,
81
+ total: order.total.gross.amount,
82
+ currency: order.total.gross.currency,
83
+ },
84
+ });
85
+ }
86
+
87
+ // Payment not completed yet
88
+ return NextResponse.json({ completed: false });
89
+
90
+ } catch (error) {
91
+ console.error("❌ Error in check-status API:", error);
92
+ return NextResponse.json({ completed: false });
93
+ }
94
+ }
@@ -0,0 +1,109 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+
3
+ export async function POST(request: NextRequest) {
4
+ try {
5
+ const body = await request.json();
6
+ const { checkoutId, amount, currency } = body;
7
+
8
+ if (!checkoutId || !amount || !currency) {
9
+ return NextResponse.json({ error: "Missing required parameters" }, { status: 400 });
10
+ }
11
+
12
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL;
13
+ if (!apiUrl) {
14
+ return NextResponse.json({ error: "Saleor API URL not configured" }, { status: 500 });
15
+ }
16
+
17
+ const token = request.cookies.get("token")?.value;
18
+
19
+ const TRANSACTION_INITIALIZE = `
20
+ mutation TransactionInitialize(
21
+ $id: ID!
22
+ $amount: PositiveDecimal!
23
+ $paymentGateway: PaymentGatewayToInitialize!
24
+ ) {
25
+ transactionInitialize(
26
+ id: $id
27
+ amount: $amount
28
+ paymentGateway: $paymentGateway
29
+ ) {
30
+ transaction {
31
+ id
32
+ actions
33
+ }
34
+ transactionEvent {
35
+ pspReference
36
+ amount {
37
+ amount
38
+ currency
39
+ }
40
+ type
41
+ }
42
+ data
43
+ errors {
44
+ field
45
+ message
46
+ code
47
+ }
48
+ }
49
+ }
50
+ `;
51
+
52
+ const headers: HeadersInit = { "Content-Type": "application/json" };
53
+ if (token) headers["Authorization"] = `Bearer ${token}`;
54
+
55
+ const response = await fetch(apiUrl, {
56
+ method: "POST",
57
+ headers,
58
+ body: JSON.stringify({
59
+ query: TRANSACTION_INITIALIZE,
60
+ variables: {
61
+ id: checkoutId,
62
+ amount: amount.toString(),
63
+ paymentGateway: {
64
+ id: "saleor.app.affirm",
65
+ data: null,
66
+ },
67
+ },
68
+ }),
69
+ });
70
+
71
+ const data = await response.json();
72
+
73
+ if (!response.ok) {
74
+ console.error("Saleor API request failed:", response.status, data);
75
+ return NextResponse.json({ error: "Failed to initialize transaction" }, { status: response.status });
76
+ }
77
+
78
+ if (data.errors) {
79
+ console.error("GraphQL errors:", data.errors);
80
+ return NextResponse.json({ error: "GraphQL error", details: data.errors }, { status: 400 });
81
+ }
82
+
83
+ const result = data.data?.transactionInitialize;
84
+
85
+ if (result?.errors && result.errors.length > 0) {
86
+ console.error("Transaction initialization errors:", result.errors);
87
+ return NextResponse.json({ error: "Transaction initialization failed", details: result.errors }, { status: 400 });
88
+ }
89
+
90
+ const transactionData = result?.data;
91
+
92
+ if (!transactionData?.checkout_token) {
93
+ console.error("No checkout token in response:", transactionData);
94
+ return NextResponse.json({ error: "No checkout token received" }, { status: 500 });
95
+ }
96
+
97
+ return NextResponse.json({
98
+ checkoutToken: transactionData.checkout_token,
99
+ checkoutUrl: transactionData.checkout_url,
100
+ transactionId: result.transaction?.id,
101
+ publicApiKey: transactionData.public_api_key,
102
+ scriptUrl: transactionData.script_url,
103
+ environment: transactionData.environment,
104
+ });
105
+ } catch (error) {
106
+ console.error("Error creating Affirm checkout:", error);
107
+ return NextResponse.json({ error: "Internal server error" }, { status: 500 });
108
+ }
109
+ }
@@ -0,0 +1,108 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+
3
+ interface AffirmData {
4
+ publicApiKey: string;
5
+ environment: string;
6
+ scriptUrl: string;
7
+ }
8
+
9
+ interface GatewayConfig {
10
+ id: string;
11
+ data: AffirmData | null;
12
+ errors: Array<{ field: string | null; message: string; code: string }>;
13
+ }
14
+
15
+ export async function POST(request: NextRequest) {
16
+ try {
17
+ const body = await request.json();
18
+ const { checkoutId, amount } = body;
19
+
20
+ if (!checkoutId) {
21
+ return NextResponse.json({ error: "Missing checkoutId parameter" }, { status: 400 });
22
+ }
23
+
24
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL;
25
+ if (!apiUrl) {
26
+ return NextResponse.json({ error: "Saleor API URL not configured" }, { status: 500 });
27
+ }
28
+
29
+ const token = request.cookies.get("token")?.value;
30
+
31
+ const PAYMENT_GATEWAY_INITIALIZE = `
32
+ mutation PaymentGatewayInitialize(
33
+ $checkoutId: ID!
34
+ $amount: PositiveDecimal!
35
+ $paymentGateways: [PaymentGatewayToInitialize!]!
36
+ ) {
37
+ paymentGatewayInitialize(
38
+ id: $checkoutId
39
+ amount: $amount
40
+ paymentGateways: $paymentGateways
41
+ ) {
42
+ gatewayConfigs {
43
+ id
44
+ data
45
+ errors {
46
+ field
47
+ message
48
+ code
49
+ }
50
+ }
51
+ errors {
52
+ field
53
+ message
54
+ code
55
+ }
56
+ }
57
+ }
58
+ `;
59
+
60
+ const headers: HeadersInit = { "Content-Type": "application/json" };
61
+ if (token) headers["Authorization"] = `Bearer ${token}`;
62
+
63
+ const response = await fetch(apiUrl, {
64
+ method: "POST",
65
+ headers,
66
+ body: JSON.stringify({
67
+ query: PAYMENT_GATEWAY_INITIALIZE,
68
+ variables: {
69
+ checkoutId,
70
+ amount: amount.toString(),
71
+ paymentGateways: [{ id: "saleor.app.affirm" }],
72
+ },
73
+ }),
74
+ });
75
+
76
+ if (!response.ok) {
77
+ return NextResponse.json({ error: "Failed to fetch payment gateway configuration" }, { status: response.status });
78
+ }
79
+
80
+ const data = await response.json();
81
+
82
+ if (data.errors) {
83
+ return NextResponse.json({ error: "GraphQL error", details: data.errors }, { status: 400 });
84
+ }
85
+
86
+ const gatewayConfigs = data.data?.paymentGatewayInitialize?.gatewayConfigs;
87
+ const affirmConfig = gatewayConfigs?.find((config: GatewayConfig) => config.id === "saleor.app.affirm");
88
+
89
+ if (!affirmConfig || !affirmConfig.data) {
90
+ return NextResponse.json({ error: "Affirm payment gateway not available" }, { status: 404 });
91
+ }
92
+
93
+ if (affirmConfig.errors && affirmConfig.errors.length > 0) {
94
+ return NextResponse.json({ error: "Affirm configuration error", details: affirmConfig.errors }, { status: 400 });
95
+ }
96
+
97
+ const affirmData = affirmConfig.data;
98
+
99
+ return NextResponse.json({
100
+ publicApiKey: affirmData.publicApiKey,
101
+ environment: affirmData.environment,
102
+ scriptUrl: affirmData.scriptUrl,
103
+ });
104
+ } catch (error) {
105
+ console.error("Error fetching Affirm config:", error);
106
+ return NextResponse.json({ error: "Internal server error" }, { status: 500 });
107
+ }
108
+ }