@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,454 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback, useEffect, useMemo, useRef } from "react";
4
+ import { useQuery } from "@apollo/client";
5
+ import { useRecaptcha } from "@/hooks/useRecaptcha";
6
+ import ReCAPTCHA from "react-google-recaptcha";
7
+ import { useAppConfiguration } from "@/app/components/providers/ServerAppConfigurationProvider";
8
+ import {
9
+ GET_CHECKOUT_QUESTIONS,
10
+ type CheckoutQuestionsData,
11
+ parseCheckoutQuestions,
12
+ type ParsedQuestion
13
+ } from "@/graphql/queries/getCheckoutQuestions";
14
+ import {
15
+ UPDATE_CHECKOUT_METADATA,
16
+ type UpdateCheckoutMetadataData,
17
+ type UpdateCheckoutMetadataVariables
18
+ } from "@/graphql/mutations/updateCheckoutMetadata";
19
+ import { useMutation } from "@apollo/client";
20
+
21
+ interface CheckoutQuestionsProps {
22
+ isLoggedIn: boolean;
23
+ grandTotal: number;
24
+ checkoutId?: string;
25
+ onQuestionsChange?: (answers: Record<string, string>) => void;
26
+ onValidationChange?: (isValid: boolean) => void;
27
+ onSaveQuestions?: (saveFunction: () => Promise<void>) => void;
28
+ }
29
+
30
+ interface QuestionFieldProps {
31
+ question: ParsedQuestion;
32
+ value: string;
33
+ onChange: (value: string) => void;
34
+ error?: string;
35
+ }
36
+
37
+ function QuestionField({ question, value, onChange, error }: QuestionFieldProps) {
38
+ const fieldId = `question-${question.id}`;
39
+
40
+ const baseInputClasses = `w-full px-3 py-2 border rounded-md focus:ring-2 focus:ring-[var(--color-primary-500)] focus:border-[var(--color-primary-500)] transition-colors ${
41
+ error
42
+ ? 'border-red-300 focus:ring-red-500 focus:border-red-500'
43
+ : 'border-gray-300 hover:border-gray-400'
44
+ }`;
45
+
46
+ if (question.type === 'text') {
47
+ return (
48
+ <div className="space-y-2">
49
+ <label htmlFor={fieldId} className="block text-sm font-medium text-gray-700">
50
+ {question.question}
51
+ {question.required && <span className="text-red-500 ml-1">*</span>}
52
+ </label>
53
+ <textarea
54
+ id={fieldId}
55
+ value={value}
56
+ onChange={(e) => onChange(e.target.value)}
57
+ className={`${baseInputClasses} min-h-[80px] outline-none resize-vertical`}
58
+ placeholder={`Enter your answer${question.required ? ' (required)' : ''}`}
59
+ required={question.required}
60
+ />
61
+ {error && <p className="text-sm text-red-600">{error}</p>}
62
+ </div>
63
+ );
64
+ }
65
+
66
+ if (question.type === 'select' && question.options) {
67
+ return (
68
+ <div className="space-y-2">
69
+ <label htmlFor={fieldId} className="block text-sm font-medium text-gray-700">
70
+ {question.question}
71
+ {question.required && <span className="text-red-500 ml-1">*</span>}
72
+ </label>
73
+ <select
74
+ id={fieldId}
75
+ value={value}
76
+ onChange={(e) => onChange(e.target.value)}
77
+ className={baseInputClasses}
78
+ required={question.required}
79
+ >
80
+ <option value="">Please select an option{question.required ? ' (required)' : ''}</option>
81
+ {question.options.map((option, index) => (
82
+ <option key={index} value={option}>
83
+ {option}
84
+ </option>
85
+ ))}
86
+ </select>
87
+ {error && <p className="text-sm text-red-600">{error}</p>}
88
+ </div>
89
+ );
90
+ }
91
+
92
+ if (question.type === 'radio' && question.options) {
93
+ return (
94
+ <div className="space-y-3">
95
+ <fieldset>
96
+ <legend className="block text-sm font-medium text-gray-700">
97
+ {question.question}
98
+ {question.required && <span className="text-red-500 ml-1">*</span>}
99
+ </legend>
100
+ <div className="mt-2 space-y-2">
101
+ {question.options.map((option, index) => (
102
+ <label
103
+ key={index}
104
+ className={`flex items-center gap-3 ring-1 p-3 cursor-pointer rounded transition-colors ${
105
+ value === option
106
+ ? "ring-[var(--color-primary-100)] bg-[var(--color-primary-50)] text-[var(--color-primary-700)]"
107
+ : "ring-gray-300 hover:bg-gray-50"
108
+ }`}
109
+ >
110
+ <input
111
+ type="radio"
112
+ name={fieldId}
113
+ value={option}
114
+ checked={value === option}
115
+ onChange={(e) => onChange(e.target.value)}
116
+ className="h-4 w-4 text-[var(--color-primary-600)] border-gray-300 focus:ring-[var(--color-primary-500)] accent-[var(--color-primary-600)]"
117
+ required={question.required}
118
+ />
119
+ <span className="text-sm flex-1">{option}</span>
120
+ </label>
121
+ ))}
122
+ </div>
123
+ </fieldset>
124
+ {error && <p className="text-sm text-red-600 mt-2">{error}</p>}
125
+ </div>
126
+ );
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ export default function CheckoutQuestions({
133
+ isLoggedIn,
134
+ grandTotal,
135
+ checkoutId,
136
+ onQuestionsChange,
137
+ onValidationChange,
138
+ onSaveQuestions
139
+ }: CheckoutQuestionsProps) {
140
+ const { data, loading, error } = useQuery<CheckoutQuestionsData>(GET_CHECKOUT_QUESTIONS, {
141
+ fetchPolicy: "cache-first"
142
+ });
143
+
144
+ const [answers, setAnswers] = useState<Record<string, string>>({});
145
+ const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
146
+ const [_isSubmitting, setIsSubmitting] = useState(false);
147
+ const [recaptchaValue, setRecaptchaValue] = useState<string | null>(null);
148
+ const { recaptchaRef, getRecaptchaToken, resetRecaptcha } = useRecaptcha();
149
+ const config = useAppConfiguration();
150
+ const onValidationChangeRef = useRef(onValidationChange);
151
+
152
+ // Mutation for saving checkout questions as metadata
153
+ const [updateCheckoutMetadata] = useMutation<UpdateCheckoutMetadataData, UpdateCheckoutMetadataVariables>(
154
+ UPDATE_CHECKOUT_METADATA
155
+ );
156
+
157
+ // Update ref when callback changes
158
+ useEffect(() => {
159
+ onValidationChangeRef.current = onValidationChange;
160
+ });
161
+
162
+ const questionsConfig = useMemo(() => {
163
+ return data ? parseCheckoutQuestions(data) : null;
164
+ }, [data]);
165
+
166
+ // Save questions as metadata when payment is initiated
167
+ const saveQuestionsAsMetadata = useCallback(async () => {
168
+ if (!checkoutId || !questionsConfig?.questions.length) {
169
+ // No checkout ID or questions to save.
170
+ return;
171
+ }
172
+
173
+ // Convert answers to metadata format: question-1, answer-1, question-2, answer-2, etc.
174
+ const metadataInput: { key: string; value: string }[] = [];
175
+ questionsConfig.questions.forEach((question, index) => {
176
+ const questionNumber = index + 1;
177
+ const answer = answers[question.id]?.trim() || '';
178
+
179
+ metadataInput.push(
180
+ { key: `question-${questionNumber}`, value: question.question },
181
+ { key: `answer-${questionNumber}`, value: answer }
182
+ );
183
+ });
184
+
185
+ if (metadataInput.length === 0) {
186
+ // No answers to save.
187
+ return;
188
+ }
189
+
190
+ try {
191
+ const result = await updateCheckoutMetadata({
192
+ variables: {
193
+ id: checkoutId,
194
+ input: metadataInput
195
+ }
196
+ });
197
+
198
+ if (result.data?.updateMetadata?.errors?.length) {
199
+ const errorMessage = result.data.updateMetadata.errors[0].message;
200
+ console.error('[CheckoutQuestions] Error saving questions:', errorMessage);
201
+ throw new Error(`Failed to save questions: ${errorMessage}`);
202
+ }
203
+
204
+ // Saved successfully.
205
+ } catch (error) {
206
+ console.error('[CheckoutQuestions] Error saving questions:', error);
207
+ throw error;
208
+ }
209
+ }, [checkoutId, questionsConfig, answers, updateCheckoutMetadata]);
210
+
211
+ // Expose save function to parent component
212
+ useEffect(() => {
213
+ if (onSaveQuestions) {
214
+ onSaveQuestions(saveQuestionsAsMetadata);
215
+ }
216
+ }, [onSaveQuestions, saveQuestionsAsMetadata]);
217
+
218
+ const shouldShowQuestions = useCallback(() => {
219
+ if (!questionsConfig?.isPublished) return false;
220
+
221
+ // Check guest-only restriction
222
+ if (questionsConfig.guestOnly && isLoggedIn) return false;
223
+
224
+ // Check order value threshold
225
+ if (questionsConfig.orderValueThreshold && grandTotal < questionsConfig.orderValueThreshold) return false;
226
+
227
+ return true;
228
+ }, [questionsConfig, isLoggedIn, grandTotal]);
229
+
230
+ const validateAnswers = useCallback(() => {
231
+ if (!questionsConfig) return true;
232
+
233
+ const errors: Record<string, string> = {};
234
+ let hasErrors = false;
235
+
236
+ questionsConfig.questions.forEach(question => {
237
+ const answer = answers[question.id]?.trim() || '';
238
+
239
+ if (question.required && !answer) {
240
+ errors[question.id] = 'This field is required';
241
+ hasErrors = true;
242
+ }
243
+ });
244
+
245
+ // Check reCAPTCHA validation if enabled
246
+ if (questionsConfig.showReCAPTCHA && !recaptchaValue) {
247
+ errors.recaptcha = 'Please complete the reCAPTCHA verification';
248
+ hasErrors = true;
249
+ }
250
+
251
+ return !hasErrors;
252
+ }, [questionsConfig, answers, recaptchaValue]);
253
+
254
+ const handleAnswerChange = useCallback((questionId: string, value: string) => {
255
+ setAnswers(prev => {
256
+ const updated = { ...prev, [questionId]: value };
257
+ return updated;
258
+ });
259
+
260
+ // Clear validation error when user starts typing
261
+ setValidationErrors(prev => {
262
+ if (prev[questionId]) {
263
+ const updated = { ...prev };
264
+ delete updated[questionId];
265
+ return updated;
266
+ }
267
+ return prev;
268
+ });
269
+ }, []);
270
+
271
+ // Call onQuestionsChange in useEffect to avoid state update during render
272
+ useEffect(() => {
273
+ if (onQuestionsChange) {
274
+ onQuestionsChange(answers);
275
+ }
276
+ }, [answers, onQuestionsChange]);
277
+
278
+ const handleSubmit = async (e: React.FormEvent) => {
279
+ e.preventDefault();
280
+
281
+ const isValid = validateAnswers();
282
+ if (!isValid) {
283
+ return;
284
+ }
285
+
286
+ setIsSubmitting(true);
287
+
288
+ try {
289
+ // Execute reCAPTCHA if enabled
290
+ if (questionsConfig?.showReCAPTCHA) {
291
+ const recaptchaToken = await getRecaptchaToken();
292
+ if (!recaptchaToken) {
293
+ resetRecaptcha();
294
+ throw new Error('reCAPTCHA verification failed. Please try again.');
295
+ }
296
+ }
297
+
298
+ // Here you would typically submit the answers to your backend
299
+ // Avoid logging potentially sensitive checkout answers.
300
+
301
+ // Reset reCAPTCHA after successful submission
302
+ if (questionsConfig?.showReCAPTCHA) {
303
+ resetRecaptcha();
304
+ }
305
+
306
+ } catch (error) {
307
+ console.error('Failed to submit checkout questions:', error);
308
+ if (questionsConfig?.showReCAPTCHA) {
309
+ resetRecaptcha();
310
+ }
311
+ // Handle submission error
312
+ } finally {
313
+ setIsSubmitting(false);
314
+ }
315
+ };
316
+
317
+ // Update validation state when answers or questions change
318
+ useEffect(() => {
319
+ if (!questionsConfig || questionsConfig.questions.length === 0) {
320
+ onValidationChangeRef.current?.(true);
321
+ return;
322
+ }
323
+
324
+ const errors: Record<string, string> = {};
325
+ let hasErrors = false;
326
+
327
+ questionsConfig.questions.forEach(question => {
328
+ const answer = answers[question.id]?.trim() || '';
329
+
330
+ if (question.required && !answer) {
331
+ errors[question.id] = 'This field is required';
332
+ hasErrors = true;
333
+ }
334
+ });
335
+
336
+ // Check reCAPTCHA validation if enabled
337
+ if (questionsConfig.showReCAPTCHA && !recaptchaValue) {
338
+ errors.recaptcha = 'Please complete the reCAPTCHA verification';
339
+ hasErrors = true;
340
+ }
341
+
342
+ // Only update errors if they've actually changed
343
+ setValidationErrors(prevErrors => {
344
+ const errorsChanged = JSON.stringify(prevErrors) !== JSON.stringify(errors);
345
+ return errorsChanged ? errors : prevErrors;
346
+ });
347
+
348
+ const isValid = !hasErrors;
349
+ onValidationChangeRef.current?.(isValid);
350
+ }, [answers, questionsConfig, recaptchaValue]);
351
+
352
+ // Handle validation when questions are not shown due to conditions
353
+ useEffect(() => {
354
+ if (!shouldShowQuestions() || !questionsConfig) {
355
+ // When questions are not shown, consider validation as passed
356
+ onValidationChangeRef.current?.(true);
357
+ }
358
+ }, [questionsConfig, shouldShowQuestions]);
359
+
360
+ // Show loading state
361
+ if (loading) {
362
+ return (
363
+ <div className="space-y-6">
364
+ <div>
365
+ <h2 className="text-base font-semibold font-secondary text-[var(--color-secondary-800)] mb-3 uppercase">
366
+ Questions
367
+ </h2>
368
+ <p className="text-sm text-[var(--color-secondary-600)]">Loading questions...</p>
369
+ </div>
370
+ </div>
371
+ );
372
+ }
373
+
374
+ // Check if questions should be shown based on configuration
375
+ if (!shouldShowQuestions() || !questionsConfig) {
376
+ return null;
377
+ }
378
+
379
+ if (error) {
380
+ console.warn('Failed to load checkout questions:', error);
381
+ return (
382
+ <div className="space-y-6">
383
+ <div>
384
+ <h2 className="text-base font-semibold font-secondary text-[var(--color-secondary-800)] mb-3 uppercase">
385
+ Questions
386
+ </h2>
387
+ <div className="text-sm text-red-600 bg-red-50 border border-red-200 rounded p-3">
388
+ <p>Error loading questions: {error.message}</p>
389
+ </div>
390
+ </div>
391
+ </div>
392
+ );
393
+ }
394
+
395
+ return (
396
+ <div className="space-y-6">
397
+ <div>
398
+ <h2 className="text-base font-semibold font-secondary text-gray-800 mb-3 md:mb-5 uppercase">
399
+ Questions
400
+ </h2>
401
+ <p className="text-sm text-gray-600 mb-4">
402
+ Please answer the following questions to help us improve your experience.
403
+ </p>
404
+ </div>
405
+
406
+ <form onSubmit={handleSubmit} className="space-y-6">
407
+ {questionsConfig.questions.map(question => (
408
+ <QuestionField
409
+ key={question.id}
410
+ question={question}
411
+ value={answers[question.id] || ''}
412
+ onChange={(value) => handleAnswerChange(question.id, value)}
413
+ error={validationErrors[question.id]}
414
+ />
415
+ ))}
416
+
417
+ {questionsConfig.showReCAPTCHA && (
418
+ <div className="flex flex-col items-start py-4">
419
+ <ReCAPTCHA
420
+ ref={recaptchaRef}
421
+ sitekey={config.getGoogleRecaptchaConfig()?.site_key || ''}
422
+ theme="light"
423
+ size="normal"
424
+ onChange={(value) => {
425
+ setRecaptchaValue(value);
426
+ // Clear recaptcha error when user completes it
427
+ if (value && validationErrors.recaptcha) {
428
+ setValidationErrors(prev => {
429
+ const newErrors = { ...prev };
430
+ delete newErrors.recaptcha;
431
+ return newErrors;
432
+ });
433
+ }
434
+ }}
435
+ onExpired={() => {
436
+ setRecaptchaValue(null);
437
+ resetRecaptcha();
438
+ }}
439
+ onError={() => {
440
+ setRecaptchaValue(null);
441
+ resetRecaptcha();
442
+ }}
443
+ />
444
+ {validationErrors.recaptcha && (
445
+ <p className="text-red-500 text-xs mt-2 text-center">
446
+ {validationErrors.recaptcha}
447
+ </p>
448
+ )}
449
+ </div>
450
+ )}
451
+ </form>
452
+ </div>
453
+ );
454
+ }
@@ -0,0 +1,81 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { useQuery } from "@apollo/client";
5
+ import ModalLayout from "@/app/components/reuseableUI/modalLayout";
6
+ import TermsContentRenderer from "./TermsContentRenderer";
7
+ import { SpinnerIcon } from "@/app/utils/svgs/spinnerIcon";
8
+ import {
9
+ GET_CHECKOUT_TERMS_AND_CONDITIONS,
10
+ type CheckoutTermsAndConditionsResponse
11
+ } from "@/graphql/queries/getCheckoutTermsAndConditions";
12
+
13
+ interface CheckoutTermsModalProps {
14
+ isModalOpen: boolean;
15
+ onClose: () => void;
16
+ }
17
+
18
+ const CheckoutTermsModal: React.FC<CheckoutTermsModalProps> = ({
19
+ isModalOpen,
20
+ onClose,
21
+ }) => {
22
+ const { data, loading, error } = useQuery<CheckoutTermsAndConditionsResponse>(
23
+ GET_CHECKOUT_TERMS_AND_CONDITIONS,
24
+ {
25
+ variables: { slug: "checkout-terms-and-conditions" },
26
+ skip: !isModalOpen,
27
+ fetchPolicy: "cache-first",
28
+ }
29
+ );
30
+
31
+ const page = data?.page;
32
+
33
+ // Don't render modal if page is not published
34
+ if (page && !page.isPublished) {
35
+ return null;
36
+ }
37
+
38
+ return (
39
+ <ModalLayout
40
+ isModalOpen={isModalOpen}
41
+ onClose={onClose}
42
+ heading={page?.title || "Terms and Conditions"}
43
+ className="lg:max-w-4xl max-h-[80vh] overflow-y-auto"
44
+ >
45
+ <div className="mt-6 lg:mt-8 px-2 pb-4">
46
+ {loading && (
47
+ <div className="flex items-center justify-center py-12">
48
+ <div className="flex items-center gap-3 text-[var(--color-secondary-600)]">
49
+ <div className="size-5">
50
+ {SpinnerIcon}
51
+ </div>
52
+ <span className="text-sm">Loading terms and conditions...</span>
53
+ </div>
54
+ </div>
55
+ )}
56
+
57
+ {error && (
58
+ <div className="text-center py-12">
59
+ <p className="text-[var(--color-primary-600)] text-sm">
60
+ Failed to load terms and conditions. Please try again.
61
+ </p>
62
+ </div>
63
+ )}
64
+
65
+ {page && !loading && !error && (
66
+ <TermsContentRenderer content={page.content ?? null} />
67
+ )}
68
+
69
+ {!page && !loading && !error && (
70
+ <div className="text-center py-12">
71
+ <p className="text-[var(--color-secondary-600)] text-sm">
72
+ Terms and conditions not available.
73
+ </p>
74
+ </div>
75
+ )}
76
+ </div>
77
+ </ModalLayout>
78
+ );
79
+ };
80
+
81
+ export default CheckoutTermsModal;
@@ -0,0 +1,52 @@
1
+ "use client";
2
+
3
+ import Input from "../reuseableUI/input";
4
+
5
+ interface ContactDetailsSectionProps {
6
+ isLoggedIn: boolean;
7
+ userEmail?: string;
8
+ guestEmail: string;
9
+ onEmailChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
10
+ emailError?: string | null;
11
+ }
12
+
13
+ export default function ContactDetailsSection({
14
+ isLoggedIn,
15
+ userEmail,
16
+ guestEmail,
17
+ onEmailChange,
18
+ emailError,
19
+ }: ContactDetailsSectionProps) {
20
+ if (isLoggedIn) {
21
+ return (
22
+ <div className="space-y-5">
23
+
24
+ <Input
25
+ disabled
26
+ readOnly
27
+ label="EMAIL"
28
+ name="email"
29
+ type="email"
30
+ value={userEmail || ""}
31
+ className="py-1"
32
+ />
33
+ </div>
34
+ );
35
+ }
36
+
37
+ return (
38
+ <div>
39
+ <Input
40
+ label="EMAIL"
41
+ name="email"
42
+ type="email"
43
+ value={guestEmail}
44
+ onChange={onEmailChange}
45
+ required
46
+ hasError={!!emailError}
47
+ errorMessage={emailError || undefined}
48
+ className="py-1"
49
+ />
50
+ </div>
51
+ );
52
+ }