@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,191 @@
1
+ import { gql } from "@apollo/client";
2
+ import createApolloServerClient from "../server-client";
3
+
4
+ // Query to get the page type ID for articles-blogs
5
+ export const GET_CONTENT_PAGE_TYPE = gql`
6
+ query GetBlogPageType {
7
+ pageTypes(first: 100, filter: { slugs: "pages" }) {
8
+ edges {
9
+ node {
10
+ id
11
+ name
12
+ slug
13
+ metadata {
14
+ key
15
+ value
16
+ }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ `;
22
+
23
+ // Query to get all blog pages by page type ID
24
+ export const GET_CONTENT_PAGES = gql`
25
+ query GetBlogPages($pageTypeId: [ID!], $first: Int = 100) {
26
+ pages(first: $first, filter: { pageTypes: $pageTypeId }) {
27
+ edges {
28
+ node {
29
+ id
30
+ title
31
+ slug
32
+ content
33
+ created
34
+ metadata {
35
+ key
36
+ value
37
+ }
38
+ pageType {
39
+ id
40
+ name
41
+ slug
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ `;
48
+
49
+ export type BlogPage = {
50
+ id: string;
51
+ title?: string | null;
52
+ slug?: string | null;
53
+ content?: string | null;
54
+ created?: string | null;
55
+ metadata?: Array<{
56
+ key?: string | null;
57
+ value?: string | null;
58
+ } | null> | null;
59
+ pageType?: {
60
+ id: string;
61
+ name?: string | null;
62
+ slug?: string | null;
63
+ } | null;
64
+ };
65
+
66
+ export type BlogPageTypeResponse = {
67
+ pageTypes?: {
68
+ edges?: Array<{
69
+ node?: {
70
+ id: string;
71
+ name?: string | null;
72
+ slug?: string | null;
73
+ metadata?: Array<{
74
+ key?: string | null;
75
+ value?: string | null;
76
+ } | null>;
77
+ } | null;
78
+ } | null>;
79
+ };
80
+ };
81
+
82
+ export type BlogPagesResponse = {
83
+ pages?: {
84
+ edges?: Array<{ node?: BlogPage | null } | null>;
85
+ };
86
+ };
87
+
88
+ // Helper function to extract first paragraph or generate excerpt from content
89
+ function getExcerpt(content?: string | null): string {
90
+ if (!content) return "";
91
+
92
+ try {
93
+ const parsed = JSON.parse(content);
94
+ const blocks = Array.isArray(parsed?.blocks) ? parsed.blocks : [];
95
+
96
+ // Find the first paragraph block
97
+ const firstParagraph = blocks.find(
98
+ (block: { type?: string; data?: { text?: string } }) =>
99
+ block?.type === "paragraph"
100
+ );
101
+ if (firstParagraph?.data?.text) {
102
+ // Strip HTML tags and limit length
103
+ const text = firstParagraph.data.text.replace(/<[^>]*>/g, "").trim();
104
+ return text.length > 150 ? text.substring(0, 150) + "..." : text;
105
+ }
106
+ } catch {
107
+ // Ignore parsing errors
108
+ }
109
+
110
+ return "";
111
+ }
112
+
113
+ // Fetch all blog pages
114
+ export async function fetchContentPages(): Promise<
115
+ Array<{
116
+ id: string;
117
+ title: string;
118
+ slug: string;
119
+ excerpt: string;
120
+ date: string;
121
+ }>
122
+ > {
123
+ if (!process.env.NEXT_PUBLIC_API_URL) {
124
+ console.warn("API URL not configured, skipping blog fetch");
125
+ return [];
126
+ }
127
+
128
+ try {
129
+ const client = createApolloServerClient();
130
+
131
+ // First, get the page type ID for articles-blogs
132
+ const pageTypeResponse = await client.query<BlogPageTypeResponse>({
133
+ query: GET_CONTENT_PAGE_TYPE,
134
+ fetchPolicy: "cache-first",
135
+ errorPolicy: "all",
136
+ context: {
137
+ fetchOptions: {
138
+ next: { revalidate: 600 }, // Cache for 10 minutes
139
+ },
140
+ },
141
+ });
142
+
143
+ const pageTypeId = pageTypeResponse.data?.pageTypes?.edges?.[0]?.node?.id;
144
+
145
+ if (!pageTypeId) {
146
+ console.warn("Blog page type 'articles-blogs' not found");
147
+ return [];
148
+ }
149
+
150
+ // Then fetch all pages with this page type
151
+ const pagesResponse = await client.query<BlogPagesResponse>({
152
+ query: GET_CONTENT_PAGES,
153
+ variables: { pageTypeId: [pageTypeId], first: 100 },
154
+ fetchPolicy: "cache-first",
155
+ errorPolicy: "all",
156
+ context: {
157
+ fetchOptions: {
158
+ next: { revalidate: 600 }, // Cache for 10 minutes
159
+ },
160
+ },
161
+ });
162
+
163
+ const pages = pagesResponse.data?.pages?.edges || [];
164
+ return pages
165
+ .map((edge) => {
166
+ const node = edge?.node;
167
+ if (!node || !node.slug || !node.title) return null;
168
+ return {
169
+ id: node.id,
170
+ title: node.title,
171
+ slug: node.slug,
172
+ excerpt: getExcerpt(node.content),
173
+ metadata: node.metadata,
174
+ date: node.created
175
+ ? new Date(node.created).toLocaleDateString("en-US", {
176
+ year: "numeric",
177
+ month: "long",
178
+ day: "numeric",
179
+ })
180
+ : "",
181
+ };
182
+ })
183
+ .filter((blog): blog is NonNullable<typeof blog> => blog !== null);
184
+ } catch (err) {
185
+ console.warn(
186
+ "Failed to fetch blog pages:",
187
+ err instanceof Error ? err.message : "Unknown error"
188
+ );
189
+ return [];
190
+ }
191
+ }
@@ -0,0 +1,18 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_DISCOUNT_OFFERS = gql`
4
+ query GetDiscountOffers($first: Int!) {
5
+ promotions(first: $first) {
6
+ edges {
7
+ node {
8
+ id
9
+ name
10
+ description
11
+ endDate
12
+ startDate
13
+ type
14
+ }
15
+ }
16
+ }
17
+ }
18
+ `;
@@ -0,0 +1,251 @@
1
+ import { gql } from "@apollo/client";
2
+ import createApolloServerClient from "../server-client";
3
+
4
+ export const GET_DYNAMIC_PAGE_BY_SLUG = gql`
5
+ query DynamicPageBySlug($slug: String!) {
6
+ page(slug: $slug) {
7
+ id
8
+ title
9
+ seoTitle
10
+ seoDescription
11
+ content
12
+ pageType {
13
+ id
14
+ name
15
+ slug
16
+ }
17
+ slug
18
+ isPublished
19
+ publicationDate
20
+ metadata {
21
+ key
22
+ value
23
+ }
24
+ }
25
+ shop {
26
+ id
27
+ metadata {
28
+ key
29
+ value
30
+ }
31
+ }
32
+ }
33
+ `;
34
+
35
+ export type DynamicPageData = {
36
+ id: string;
37
+ title: string;
38
+ seoTitle: string | null;
39
+ seoDescription: string | null;
40
+ content: string | null;
41
+ pageType: {
42
+ id: string;
43
+ name: string;
44
+ slug: string;
45
+ } | null;
46
+ slug: string;
47
+ isPublished: boolean;
48
+ publicationDate: string | null;
49
+ metadata: Array<{
50
+ key: string;
51
+ value: string;
52
+ }>;
53
+ excerpt?: string; // Computed field for preview
54
+ };
55
+
56
+ type DynamicPageResponse = {
57
+ page: DynamicPageData | null;
58
+ shop: {
59
+ id: string;
60
+ metadata: Array<{
61
+ key: string;
62
+ value: string;
63
+ }>;
64
+ } | null;
65
+ };
66
+
67
+ export async function fetchDynamicPageBySlug(slug: string): Promise<DynamicPageData | null> {
68
+ // Get API URL at runtime
69
+ const apiUrl = process.env.NEXT_PUBLIC_API_URL;
70
+
71
+ if (!apiUrl) {
72
+ console.warn("[DYNAMIC PAGES] API URL not configured, skipping dynamic page fetch");
73
+ return null;
74
+ }
75
+
76
+ try {
77
+ const client = createApolloServerClient();
78
+
79
+ const timeoutPromise = new Promise<never>((_, reject) =>
80
+ setTimeout(() => reject(new Error("Dynamic page fetch timeout")), 5000)
81
+ );
82
+
83
+ const queryPromise = client.query<DynamicPageResponse>({
84
+ query: GET_DYNAMIC_PAGE_BY_SLUG,
85
+ variables: { slug },
86
+ fetchPolicy: "network-only",
87
+ errorPolicy: "ignore",
88
+ });
89
+
90
+ const result = await Promise.race([queryPromise, timeoutPromise]);
91
+
92
+ let pageData = result?.data?.page;
93
+
94
+ // If no page found, check for HTML widgets in shop metadata
95
+ if (!pageData || !pageData.isPublished) {
96
+ const shopMetadata = result?.data?.shop?.metadata || [];
97
+
98
+ // Find widget with matching slug
99
+ let matchingWidget = null;
100
+ for (const metadataItem of shopMetadata) {
101
+ const widget = parseHtmlWidgetFromMetadata(metadataItem.key, metadataItem.value);
102
+ if (widget && widget.slug === slug && widget.isActive) {
103
+ matchingWidget = widget;
104
+ break;
105
+ }
106
+ }
107
+
108
+ if (matchingWidget) {
109
+ // Convert widget to page data format
110
+ pageData = convertWidgetToPageData(matchingWidget);
111
+ } else {
112
+ return null;
113
+ }
114
+ }
115
+
116
+ // Add computed excerpt if content exists
117
+ if (pageData.content) {
118
+ const textContent = pageData.content.replace(/<[^>]*>/g, ""); // Strip HTML
119
+ pageData.excerpt = textContent.substring(0, 160) + (textContent.length > 160 ? "..." : "");
120
+ }
121
+
122
+ return pageData;
123
+ } catch (err) {
124
+ console.error(
125
+ `[DYNAMIC PAGES] Failed to fetch dynamic page by slug "${slug}":`,
126
+ err instanceof Error ? err.message : "Unknown error"
127
+ );
128
+
129
+ // Don't throw the error - return null to handle gracefully
130
+ return null;
131
+ }
132
+ }
133
+
134
+ // Utility function to get page type from metadata or pageType
135
+ export function getPageTypeFromData(pageData: DynamicPageData): string {
136
+ // Check pageType first
137
+ if (pageData.pageType?.slug) {
138
+ return pageData.pageType.slug;
139
+ }
140
+
141
+ // Check metadata for page type
142
+ const pageTypeMetadata = pageData.metadata.find(item => item.key === "pageType");
143
+ if (pageTypeMetadata?.value) {
144
+ return pageTypeMetadata.value;
145
+ }
146
+
147
+ // Default to landing page
148
+ return "landing";
149
+ }
150
+
151
+ // Utility function to parse HTML widget from shop metadata
152
+ function parseHtmlWidgetFromMetadata(key: string, value: string) {
153
+ const HTML_WIDGET_PREFIX = "html_widget_";
154
+
155
+ if (!key.startsWith(HTML_WIDGET_PREFIX)) {
156
+ return null;
157
+ }
158
+
159
+ try {
160
+ const data = JSON.parse(value);
161
+ const id = key.replace(HTML_WIDGET_PREFIX, "");
162
+
163
+ return {
164
+ id,
165
+ name: data.name || "",
166
+ description: data.description || "",
167
+ slug: data.slug || "",
168
+ html: data.html || "",
169
+ javascript: data.javascript || "",
170
+ css: data.css || "",
171
+ type: data.type || "WIDGET",
172
+ isActive: data.isActive !== false,
173
+ createdAt: data.createdAt || new Date().toISOString(),
174
+ updatedAt: data.updatedAt || new Date().toISOString(),
175
+ };
176
+ } catch (error) {
177
+ console.error("Failed to parse HTML widget metadata:", error);
178
+ return null;
179
+ }
180
+ }
181
+
182
+ // Convert HTML widget to DynamicPageData format
183
+ function convertWidgetToPageData(widget: { html?: string; css?: string; js?: string; title?: string; id?: string; type?: string; javascript?: string; name?: string; description?: string; slug?: string; isActive?: boolean; createdAt?: string }): DynamicPageData {
184
+ // Extract content from HTML if it's a full document
185
+ let extractedContent = widget.html || '';
186
+ let extractedStyles = widget.css || '';
187
+
188
+ // If HTML contains full document structure, extract body content
189
+ if (extractedContent.includes('<!DOCTYPE html>') || extractedContent.includes('<html>')) {
190
+ // Parse the HTML to extract body content
191
+ const bodyMatch = extractedContent.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
192
+ if (bodyMatch) {
193
+ extractedContent = bodyMatch[1];
194
+ }
195
+
196
+ // Also extract any styles from head if not already in CSS field
197
+ if (!widget.css || widget.css.trim() === '') {
198
+ const styleMatches = widget.html?.match(/<style[^>]*>([\s\S]*?)<\/style>/gi);
199
+ if (styleMatches) {
200
+ const extractedStylesFromHead = styleMatches.map(match => {
201
+ const styleContent = match.match(/<style[^>]*>([\s\S]*?)<\/style>/i);
202
+ return styleContent ? styleContent[1] : '';
203
+ }).join('\n');
204
+
205
+ extractedStyles = extractedStylesFromHead;
206
+ }
207
+ }
208
+ }
209
+
210
+ // Keep original CSS with minimal modifications to preserve dashboard design
211
+ const scopedStyles = extractedStyles || '';
212
+
213
+ // Create clean content structure without interfering with original design
214
+ const content = `
215
+ ${extractedContent}
216
+
217
+ ${scopedStyles ? `<style>
218
+ ${scopedStyles}
219
+ </style>` : ''}
220
+
221
+ ${widget.javascript ? `<script>(function() { ${widget.javascript} })();</script>` : ''}
222
+ `.trim();
223
+
224
+ // Map widget type to page type
225
+ const pageTypeSlug = widget.type === 'CALCULATOR' ? 'calculator' :
226
+ widget.type === 'LANDING_PAGE' ? 'landing' :
227
+ 'widget';
228
+
229
+ return {
230
+ id: `widget_${widget.id}`,
231
+ title: widget.name || widget.title || 'Widget',
232
+ seoTitle: `${widget.name || widget.title || 'Widget'} | Your Site`,
233
+ seoDescription: widget.description || `${widget.name || widget.title || 'Widget'} - Interactive ${widget.type?.toLowerCase() || 'widget'}`,
234
+ content,
235
+ pageType: {
236
+ id: `type_${widget.type || 'widget'}`,
237
+ name: widget.type || 'widget',
238
+ slug: pageTypeSlug,
239
+ },
240
+ slug: widget.slug || `widget-${widget.id}`,
241
+ isPublished: widget.isActive ?? true,
242
+ publicationDate: widget.createdAt || null,
243
+ metadata: [
244
+ { key: 'widgetType', value: widget.type || 'widget' },
245
+ { key: 'widgetId', value: widget.id || 'unknown' },
246
+ { key: 'isHtmlWidget', value: 'true' },
247
+ { key: 'pageType', value: pageTypeSlug },
248
+ ],
249
+ excerpt: widget.description || "",
250
+ };
251
+ }
@@ -0,0 +1,48 @@
1
+ import { gql } from "@apollo/client";
2
+
3
+ export const GET_FEATURED_PRODUCTS = gql`
4
+ query GetFeaturedProducts($slug: String!, $first: Int!, $channel: String!) {
5
+ collection(slug: $slug, channel: $channel) {
6
+ products(first: $first) {
7
+ edges {
8
+ node {
9
+ id
10
+ name
11
+ slug
12
+ rating
13
+ pricing {
14
+ onSale
15
+ priceRange {
16
+ start {
17
+ gross {
18
+ amount
19
+ currency
20
+ }
21
+ }
22
+ stop {
23
+ gross {
24
+ amount
25
+ currency
26
+ }
27
+ }
28
+ }
29
+ discount {
30
+ gross {
31
+ amount
32
+ currency
33
+ }
34
+ }
35
+ }
36
+ media {
37
+ url
38
+ }
39
+ category {
40
+ id
41
+ name
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ `;
@@ -0,0 +1,23 @@
1
+ import { gql } from "@apollo/client"
2
+
3
+ export const GET_PAGE_METADATA_BY_SLUG = gql`
4
+ query PageMetadataBySlug($slug: String!) {
5
+ page(slug: $slug) {
6
+ metadata {
7
+ key
8
+ value
9
+ }
10
+ }
11
+ }
12
+ `
13
+
14
+ export type PageMetadataItem = {
15
+ key: string
16
+ value: string | null
17
+ }
18
+
19
+ export type PageMetadataResponse = {
20
+ page: {
21
+ metadata: PageMetadataItem[] | null
22
+ } | null
23
+ }
@@ -0,0 +1,84 @@
1
+ import { gql } from "@apollo/client";
2
+ import createApolloServerClient from "../server-client";
3
+
4
+ export const GET_MENU_BY_SLUG = gql`
5
+ query GetMenuBySlug($slug: String!) {
6
+ menu(slug: $slug) {
7
+ id
8
+ name
9
+ slug
10
+ items {
11
+ id
12
+ level
13
+ name
14
+ url
15
+ metadata {
16
+ key
17
+ value
18
+ }
19
+ children {
20
+ id
21
+ name
22
+ level
23
+ url
24
+ metadata {
25
+ key
26
+ value
27
+ }
28
+ children {
29
+ id
30
+ name
31
+ level
32
+ url
33
+ metadata {
34
+ key
35
+ value
36
+ }
37
+ children {
38
+ id
39
+ name
40
+ level
41
+ url
42
+ metadata {
43
+ key
44
+ value
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+ `;
53
+
54
+ export const fetchMenuBySlug = async (slug: "navbar" | "footer") => {
55
+ // Check if API URL is configured
56
+ if (!process.env.NEXT_PUBLIC_API_URL) {
57
+ console.warn(`API URL not configured, skipping menu fetch for [${slug}]`);
58
+ return null;
59
+ }
60
+
61
+ try {
62
+ const client = createApolloServerClient();
63
+
64
+ // Add timeout to prevent hanging requests
65
+ const timeoutPromise = new Promise((_, reject) => {
66
+ setTimeout(() => reject(new Error('Menu fetch timeout')), 5000);
67
+ });
68
+
69
+ const queryPromise = client.query({
70
+ query: GET_MENU_BY_SLUG,
71
+ variables: { slug },
72
+ fetchPolicy: 'network-only', // Don't use cache for menus
73
+ errorPolicy: 'ignore', // Ignore GraphQL errors and return null
74
+ });
75
+
76
+ const result = await Promise.race([queryPromise, timeoutPromise]) as { data: { menu: unknown } };
77
+ const { data } = result;
78
+ return data?.menu || null;
79
+ } catch (err) {
80
+ console.warn(`Failed to fetch menu [${slug}]:`, err instanceof Error ? err.message : 'Unknown error');
81
+ // Return null instead of undefined to prevent destructuring errors
82
+ return null;
83
+ }
84
+ };
@@ -0,0 +1,23 @@
1
+ import { gql } from '@apollo/client';
2
+
3
+ export const GET_MY_PROFILE = gql`
4
+ query GetMyProfile {
5
+ me {
6
+ id
7
+ firstName
8
+ lastName
9
+ email
10
+ isActive
11
+ }
12
+ }
13
+ `;
14
+
15
+ export type GetMyProfileData = {
16
+ me: {
17
+ id: string;
18
+ firstName: string | null;
19
+ lastName: string | null;
20
+ email: string;
21
+ isActive: boolean;
22
+ } | null;
23
+ };