@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.
- package/.env.example +57 -0
- package/APPLE_PAY_QUICK_START.md +165 -0
- package/APPLE_PAY_SETUP.md +331 -0
- package/README.md +46 -0
- package/SEO_AUDIT_CHECKLIST_STATUS.md +244 -0
- package/SEO_AUDIT_REPORT.md +66 -0
- package/eslint.config.mjs +16 -0
- package/next-env.d.ts +5 -0
- package/next.config.ts +109 -0
- package/package.json +47 -0
- package/postcss.config.mjs +5 -0
- package/public/.well-known/apple-developer-merchantid-domain-association +1 -0
- package/public/Logo.png +0 -0
- package/public/brand-video.mp4 +0 -0
- package/public/favicon.ico +0 -0
- package/public/file.svg +1 -0
- package/public/footer/facebook.tsx +34 -0
- package/public/footer/instagram.tsx +27 -0
- package/public/footer/mail.tsx +5 -0
- package/public/footer/x.tsx +35 -0
- package/public/globe.svg +1 -0
- package/public/icons/Authorize.net.webp +0 -0
- package/public/icons/amex.gif +0 -0
- package/public/icons/appIcon.png +0 -0
- package/public/icons/discover.gif +0 -0
- package/public/icons/master.gif +0 -0
- package/public/icons/paypal.png +0 -0
- package/public/icons/stripe.png +0 -0
- package/public/icons/visa.gif +0 -0
- package/public/images/BackgroundNoise.png +0 -0
- package/public/images/footer-background.png +0 -0
- package/public/next.svg +1 -0
- package/public/no-image-avail-large.png +0 -0
- package/public/random-car-1.jpeg +0 -0
- package/public/random-car-2.png +0 -0
- package/public/random-car-3.jpg +0 -0
- package/public/random-car-4.jpg +0 -0
- package/public/random-car-5.jpg +0 -0
- package/public/star.svg +3 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/scripts/seo-audit/generate-checklist.mjs +156 -0
- package/src/app/(auth)/account/forgot-password/layout.tsx +16 -0
- package/src/app/(auth)/account/forgot-password/page.tsx +135 -0
- package/src/app/(auth)/account/login/layout.tsx +16 -0
- package/src/app/(auth)/account/login/page.tsx +288 -0
- package/src/app/(auth)/account/otp/layout.tsx +16 -0
- package/src/app/(auth)/account/otp/page.tsx +108 -0
- package/src/app/(auth)/account/register/layout.tsx +16 -0
- package/src/app/(auth)/account/register/page.tsx +431 -0
- package/src/app/(auth)/account/reset-password/layout.tsx +16 -0
- package/src/app/(auth)/account/reset-password/page.tsx +222 -0
- package/src/app/[slug]/page.tsx +43 -0
- package/src/app/about/loading.tsx +17 -0
- package/src/app/about/page.tsx +61 -0
- package/src/app/account/address/layout.tsx +15 -0
- package/src/app/account/address/page.tsx +166 -0
- package/src/app/account/head.tsx +4 -0
- package/src/app/account/layout.tsx +62 -0
- package/src/app/account/orders/[id]/layout.tsx +17 -0
- package/src/app/account/orders/[id]/page.tsx +115 -0
- package/src/app/account/orders/components/orderDetailsModal.tsx +410 -0
- package/src/app/account/orders/layout.tsx +15 -0
- package/src/app/account/orders/page.tsx +146 -0
- package/src/app/account/page.tsx +39 -0
- package/src/app/account/settings/components/editProfileSuccessModal.tsx +28 -0
- package/src/app/account/settings/layout.tsx +15 -0
- package/src/app/account/settings/page.tsx +260 -0
- package/src/app/api/affirm/check-status/route.ts +94 -0
- package/src/app/api/affirm/create-checkout/route.ts +109 -0
- package/src/app/api/affirm/get-config/route.ts +108 -0
- package/src/app/api/affirm/process-payment/route.ts +244 -0
- package/src/app/api/affirm/test-connection/route.ts +45 -0
- package/src/app/api/auth/clear/route.ts +16 -0
- package/src/app/api/auth/clear-cookies/route.ts +42 -0
- package/src/app/api/auth/set/route.ts +47 -0
- package/src/app/api/configuration/route.ts +18 -0
- package/src/app/api/dynamic-page/[slug]/route.ts +24 -0
- package/src/app/api/form-submission/route.ts +237 -0
- package/src/app/api/paypal/capture-order/route.ts +303 -0
- package/src/app/api/paypal/create-order/route.ts +211 -0
- package/src/app/api/paypal/get-config/route.ts +240 -0
- package/src/app/api/search-proxy/route.ts +52 -0
- package/src/app/authorize-net-success/layout.tsx +19 -0
- package/src/app/authorize-net-success/page.tsx +12 -0
- package/src/app/authorize-net-success/summary.tsx +486 -0
- package/src/app/blog/[slug]/blogContentRenderer.tsx +369 -0
- package/src/app/blog/[slug]/layout.tsx +17 -0
- package/src/app/blog/[slug]/page.tsx +151 -0
- package/src/app/blog/constant.tsx +147 -0
- package/src/app/blog/layout.tsx +31 -0
- package/src/app/blog/page.tsx +81 -0
- package/src/app/brand/[id]/BrandPageClient.tsx +188 -0
- package/src/app/brand/[id]/layout.tsx +17 -0
- package/src/app/brand/[id]/page.tsx +176 -0
- package/src/app/brands/components/brandsListingClient.tsx +97 -0
- package/src/app/brands/layout.tsx +31 -0
- package/src/app/brands/page.tsx +40 -0
- package/src/app/cancellation-policy/page.tsx +53 -0
- package/src/app/cart/layout.tsx +19 -0
- package/src/app/cart/page.tsx +752 -0
- package/src/app/category/[slug]/CategoryPageClient.tsx +377 -0
- package/src/app/category/[slug]/layout.tsx +17 -0
- package/src/app/category/[slug]/page.tsx +224 -0
- package/src/app/category/page.tsx +114 -0
- package/src/app/checkout/components/addNewAddressModal.tsx +474 -0
- package/src/app/checkout/layout.tsx +19 -0
- package/src/app/checkout/page.tsx +3312 -0
- package/src/app/components/account/AccountTabs.tsx +40 -0
- package/src/app/components/ads/GoogleAdSense.tsx +74 -0
- package/src/app/components/analytics/AnalyticsScripts.tsx +78 -0
- package/src/app/components/analytics/ConditionalGTMNoscript.tsx +24 -0
- package/src/app/components/analytics/ConditionalGoogleAnalytics.tsx +16 -0
- package/src/app/components/ancillary/AncillaryContent.tsx +7 -0
- package/src/app/components/auth/TokenExpirationHandler.tsx +8 -0
- package/src/app/components/blog/BlogList.tsx +112 -0
- package/src/app/components/checkout/AddressInformationSection.tsx +34 -0
- package/src/app/components/checkout/AddressManagement.tsx +571 -0
- package/src/app/components/checkout/CheckoutHeader.tsx +51 -0
- package/src/app/components/checkout/CheckoutQuestions.tsx +454 -0
- package/src/app/components/checkout/CheckoutTermsModal.tsx +81 -0
- package/src/app/components/checkout/ContactDetailsSection.tsx +52 -0
- package/src/app/components/checkout/DealerShippingSection.tsx +359 -0
- package/src/app/components/checkout/DeliveryMethodSection.tsx +249 -0
- package/src/app/components/checkout/OrderSummary.tsx +386 -0
- package/src/app/components/checkout/TermsContentRenderer.tsx +147 -0
- package/src/app/components/checkout/WillCallSection.tsx +133 -0
- package/src/app/components/checkout/affirmPayment.tsx +383 -0
- package/src/app/components/checkout/checkoutProcessingModal.tsx +96 -0
- package/src/app/components/checkout/googlePayButton.tsx +334 -0
- package/src/app/components/checkout/paymentStep.tsx +180 -0
- package/src/app/components/checkout/paypalPayment.tsx +1083 -0
- package/src/app/components/checkout/saleorNativePayment.tsx +1758 -0
- package/src/app/components/dynamicPage/DynamicPageRenderer.tsx +13 -0
- package/src/app/components/dynamicPage/HtmlWidgetRenderer.tsx +144 -0
- package/src/app/components/filtersCollapsible/index.tsx +365 -0
- package/src/app/components/globalSearch/index.tsx +423 -0
- package/src/app/components/layout/cartDropDown.tsx +628 -0
- package/src/app/components/layout/components/FooterNewsletter.tsx +21 -0
- package/src/app/components/layout/footer.tsx +283 -0
- package/src/app/components/layout/header/accountMenuDropdown.tsx +53 -0
- package/src/app/components/layout/header/components/CartBadge.tsx +18 -0
- package/src/app/components/layout/header/components/LoadingState.tsx +17 -0
- package/src/app/components/layout/header/components/MenuItemDropdown.tsx +124 -0
- package/src/app/components/layout/header/components/MobileNavbar.tsx +123 -0
- package/src/app/components/layout/header/components/NavbarActions.tsx +125 -0
- package/src/app/components/layout/header/components/NavbarBrand.tsx +29 -0
- package/src/app/components/layout/header/components/NavigationLinks.tsx +131 -0
- package/src/app/components/layout/header/hamMenuSlide.tsx +318 -0
- package/src/app/components/layout/header/header.tsx +44 -0
- package/src/app/components/layout/header/hooks/useDropdown.ts +45 -0
- package/src/app/components/layout/header/hooks/useNavbarData.ts +138 -0
- package/src/app/components/layout/header/hooks/useNavbarState.ts +66 -0
- package/src/app/components/layout/header/megaMenuDropdown.tsx +116 -0
- package/src/app/components/layout/header/navBar.tsx +121 -0
- package/src/app/components/layout/header/search.tsx +418 -0
- package/src/app/components/layout/header/styles/navbarStyles.ts +27 -0
- package/src/app/components/layout/header/topBar.tsx +214 -0
- package/src/app/components/layout/joinNewsletterForm/index.tsx +72 -0
- package/src/app/components/layout/mobileAccordian/index.tsx +92 -0
- package/src/app/components/layout/paymentMethods.tsx +75 -0
- package/src/app/components/layout/rootLayout.tsx +23 -0
- package/src/app/components/layout/siteInfo.tsx +103 -0
- package/src/app/components/layout/socialLinks.tsx +65 -0
- package/src/app/components/newsletterSection/emailListSection.tsx +224 -0
- package/src/app/components/newsletterSection/emailSectionServer.tsx +8 -0
- package/src/app/components/providers/ApolloWrapper.tsx +12 -0
- package/src/app/components/providers/AppConfigurationProvider.tsx +108 -0
- package/src/app/components/providers/GoogleAnalyticsProvider.tsx +149 -0
- package/src/app/components/providers/GoogleTagManagerProvider.tsx +31 -0
- package/src/app/components/providers/RecaptchaProvider.tsx +18 -0
- package/src/app/components/providers/ServerAppConfigurationProvider.tsx +133 -0
- package/src/app/components/providers/YMMStatusProvider.tsx +15 -0
- package/src/app/components/reuseableUI/AboutUs.tsx +115 -0
- package/src/app/components/reuseableUI/AddToCartClient.tsx +125 -0
- package/src/app/components/reuseableUI/EditorJsRenderer.tsx +219 -0
- package/src/app/components/reuseableUI/HeroSectionsearchByVehicle.tsx +188 -0
- package/src/app/components/reuseableUI/ImageWithFallback.tsx +41 -0
- package/src/app/components/reuseableUI/Toast.tsx +101 -0
- package/src/app/components/reuseableUI/blogCard.tsx +52 -0
- package/src/app/components/reuseableUI/brandCard.tsx +68 -0
- package/src/app/components/reuseableUI/breadcrumb.tsx +38 -0
- package/src/app/components/reuseableUI/categoryCard.tsx +37 -0
- package/src/app/components/reuseableUI/categorySkeleton.tsx +31 -0
- package/src/app/components/reuseableUI/commonButton.tsx +48 -0
- package/src/app/components/reuseableUI/defaultInputField/index.tsx +84 -0
- package/src/app/components/reuseableUI/emptyState.tsx +29 -0
- package/src/app/components/reuseableUI/errorTag.tsx +15 -0
- package/src/app/components/reuseableUI/heading/index.tsx +20 -0
- package/src/app/components/reuseableUI/input.tsx +117 -0
- package/src/app/components/reuseableUI/listCard.tsx +137 -0
- package/src/app/components/reuseableUI/loadingUI.tsx +12 -0
- package/src/app/components/reuseableUI/modalLayout.tsx +76 -0
- package/src/app/components/reuseableUI/newsletter/newsletterClient.tsx +622 -0
- package/src/app/components/reuseableUI/newsletter/newslettersHomeModal.tsx +68 -0
- package/src/app/components/reuseableUI/offerCard.tsx +42 -0
- package/src/app/components/reuseableUI/passwordRules/passwordRules.tsx +56 -0
- package/src/app/components/reuseableUI/primaryButton/index.tsx +34 -0
- package/src/app/components/reuseableUI/productCard.tsx +118 -0
- package/src/app/components/reuseableUI/productSkeleton.tsx +34 -0
- package/src/app/components/reuseableUI/searchByVehicle.tsx +187 -0
- package/src/app/components/reuseableUI/secondaryButton/index.tsx +34 -0
- package/src/app/components/reuseableUI/section.tsx +20 -0
- package/src/app/components/reuseableUI/select/index.tsx +98 -0
- package/src/app/components/reuseableUI/skeletonLoader.tsx +117 -0
- package/src/app/components/reuseableUI/statusTag.tsx +24 -0
- package/src/app/components/reuseableUI/tags/saleTag.tsx +19 -0
- package/src/app/components/reuseableUI/testimonialCard.tsx +93 -0
- package/src/app/components/richText/EditorRenderer.tsx +318 -0
- package/src/app/components/search/HierarchicalCategoryFilter.tsx +155 -0
- package/src/app/components/search/SearchFilters.tsx +155 -0
- package/src/app/components/search/YMMSearchSidebar.tsx +187 -0
- package/src/app/components/seo/ServerProductCard.tsx +91 -0
- package/src/app/components/seo/ServerProductGrid.tsx +45 -0
- package/src/app/components/shop/CategoryFilter.tsx +184 -0
- package/src/app/components/shop/ItemsPerPageSelect.tsx +69 -0
- package/src/app/components/shop/ItemsPerPageSelectClient.tsx +58 -0
- package/src/app/components/shop/MobileFilters.tsx +103 -0
- package/src/app/components/shop/ProductGridSkeleton.tsx +16 -0
- package/src/app/components/shop/ProductsGrid.tsx +230 -0
- package/src/app/components/shop/SearchFilter.tsx +218 -0
- package/src/app/components/shop/SearchFilterClient.tsx +122 -0
- package/src/app/components/shop/SearchLoadingOverlay.tsx +32 -0
- package/src/app/components/shop/ShopMobileFilters.tsx +205 -0
- package/src/app/components/showroom/VehicleSearchDropdowns.tsx +187 -0
- package/src/app/components/showroom/brandsSwiper.tsx +49 -0
- package/src/app/components/showroom/brandsSwiperClient copy.tsx +93 -0
- package/src/app/components/showroom/brandsSwiperClient.tsx +122 -0
- package/src/app/components/showroom/brandsSwiperServer.tsx +42 -0
- package/src/app/components/showroom/bundleProducts.tsx +120 -0
- package/src/app/components/showroom/categoryGrid.tsx +51 -0
- package/src/app/components/showroom/categoryGridServer.tsx +45 -0
- package/src/app/components/showroom/categorySwiper.tsx +115 -0
- package/src/app/components/showroom/featureStrip.tsx +139 -0
- package/src/app/components/showroom/offersSwiper.tsx +181 -0
- package/src/app/components/showroom/productGrid.tsx +56 -0
- package/src/app/components/showroom/productSwiper.tsx +119 -0
- package/src/app/components/showroom/promotion-slider.tsx +138 -0
- package/src/app/components/showroom/promotion.tsx +207 -0
- package/src/app/components/showroom/promotionsSwiper.tsx +174 -0
- package/src/app/components/showroom/showroomHeroCarousel.tsx +141 -0
- package/src/app/components/showroom/testimonialsGrid.tsx +106 -0
- package/src/app/components/skeletons/ContentSkeleton.tsx +14 -0
- package/src/app/components/sortDropdown/index.tsx +116 -0
- package/src/app/components/tertiaryButton/index.tsx +25 -0
- package/src/app/components/theme/theme-provider.tsx +82 -0
- package/src/app/contact/layout.tsx +32 -0
- package/src/app/contact/page.tsx +591 -0
- package/src/app/content/[slug]/layout.tsx +17 -0
- package/src/app/content/[slug]/page.tsx +159 -0
- package/src/app/content/layout.tsx +31 -0
- package/src/app/content/page.tsx +88 -0
- package/src/app/core-policies/page.tsx +55 -0
- package/src/app/discounts/page.tsx +54 -0
- package/src/app/frequently-asked-questions/page.tsx +57 -0
- package/src/app/globals.css +440 -0
- package/src/app/hooks/useDealerLocations.ts +259 -0
- package/src/app/hooks/useGTMEngagement.ts +71 -0
- package/src/app/hooks/useGoogleAnalytics.ts +145 -0
- package/src/app/layout.tsx +149 -0
- package/src/app/not-found.tsx +31 -0
- package/src/app/order-confirmation/layout.tsx +19 -0
- package/src/app/order-confirmation/page.tsx +12 -0
- package/src/app/order-confirmation/summary.tsx +1775 -0
- package/src/app/page.tsx +194 -0
- package/src/app/privacy-policy/loading.tsx +17 -0
- package/src/app/privacy-policy/page.tsx +56 -0
- package/src/app/product/[id]/ProductDetailClient.tsx +2448 -0
- package/src/app/product/[id]/components/itemInquiryModal.tsx +461 -0
- package/src/app/product/[id]/layout.tsx +116 -0
- package/src/app/product/[id]/page.tsx +200 -0
- package/src/app/product/layout.tsx +15 -0
- package/src/app/products/all/AllProductsClient.tsx +743 -0
- package/src/app/products/all/page.tsx +176 -0
- package/src/app/products/components/shopEmptyState.tsx +29 -0
- package/src/app/request-return/layout.tsx +36 -0
- package/src/app/request-return/page.tsx +597 -0
- package/src/app/robots.txt/route.ts +27 -0
- package/src/app/search/layout.tsx +16 -0
- package/src/app/search/page.tsx +736 -0
- package/src/app/shipping-returns/page.tsx +60 -0
- package/src/app/site-map/layout.tsx +33 -0
- package/src/app/site-map/page.tsx +113 -0
- package/src/app/sitemap-index.xml/route.ts +20 -0
- package/src/app/sitemap.ts +10 -0
- package/src/app/terms-and-conditions/loading.tsx +17 -0
- package/src/app/terms-and-conditions/page.tsx +56 -0
- package/src/app/utils/appConfiguration.ts +327 -0
- package/src/app/utils/branding.ts +52 -0
- package/src/app/utils/configurationService.ts +202 -0
- package/src/app/utils/constant.tsx +242 -0
- package/src/app/utils/editorJsUtils.tsx +249 -0
- package/src/app/utils/functions.ts +146 -0
- package/src/app/utils/googleAnalytics.ts +168 -0
- package/src/app/utils/googleTagManager.ts +475 -0
- package/src/app/utils/ipDetection.ts +270 -0
- package/src/app/utils/serverConfigurationService.ts +209 -0
- package/src/app/utils/svgs/GridIcon.tsx +45 -0
- package/src/app/utils/svgs/account/myAccount/listDotIcon.tsx +3 -0
- package/src/app/utils/svgs/account/myAccount/tickIcon.tsx +10 -0
- package/src/app/utils/svgs/account/orderHistory/InfoIcon.tsx +49 -0
- package/src/app/utils/svgs/arrowDownIcon.tsx +17 -0
- package/src/app/utils/svgs/arrowIcon.tsx +25 -0
- package/src/app/utils/svgs/arrowUpIcon.tsx +16 -0
- package/src/app/utils/svgs/brandsSearchIcon.tsx +25 -0
- package/src/app/utils/svgs/cart/cartIcon.tsx +31 -0
- package/src/app/utils/svgs/cart/plusIcon.tsx +13 -0
- package/src/app/utils/svgs/cart/subtractIcon.tsx +13 -0
- package/src/app/utils/svgs/cart/successTickIcon.tsx +14 -0
- package/src/app/utils/svgs/chevronDownIcon.tsx +21 -0
- package/src/app/utils/svgs/closeEyeIcon.tsx +47 -0
- package/src/app/utils/svgs/crossIcon.tsx +25 -0
- package/src/app/utils/svgs/eyeIcon.tsx +29 -0
- package/src/app/utils/svgs/featureTag.tsx +20 -0
- package/src/app/utils/svgs/filterIcon.tsx +3 -0
- package/src/app/utils/svgs/globleIcon.tsx +41 -0
- package/src/app/utils/svgs/infoIcon.tsx +34 -0
- package/src/app/utils/svgs/listIcon.tsx +50 -0
- package/src/app/utils/svgs/logOutIcon.tsx +35 -0
- package/src/app/utils/svgs/menuIcon.tsx +8 -0
- package/src/app/utils/svgs/minusIcon.tsx +18 -0
- package/src/app/utils/svgs/newsletterIcon.tsx +19 -0
- package/src/app/utils/svgs/noDataFoundIcon-.tsx +26 -0
- package/src/app/utils/svgs/noProductFoundIcon.tsx +43 -0
- package/src/app/utils/svgs/passwordIcons/errorIcon.tsx +31 -0
- package/src/app/utils/svgs/passwordIcons/successIcon.tsx +24 -0
- package/src/app/utils/svgs/paymentProcessingIcons/hourglassIcon.tsx +43 -0
- package/src/app/utils/svgs/paymentProcessingIcons/modalCrossIcon.tsx +23 -0
- package/src/app/utils/svgs/paymentProcessingIcons/paymentFailedIcon.tsx +47 -0
- package/src/app/utils/svgs/pencilIcon.tsx +11 -0
- package/src/app/utils/svgs/plusIcon.tsx +25 -0
- package/src/app/utils/svgs/productInquiryIcon.tsx +40 -0
- package/src/app/utils/svgs/searchIcon.tsx +31 -0
- package/src/app/utils/svgs/shoppingCart.tsx +32 -0
- package/src/app/utils/svgs/spinnerIcon.tsx +22 -0
- package/src/app/utils/svgs/spinnerLoadingIcon.tsx +26 -0
- package/src/app/utils/svgs/successTickIcon.tsx +40 -0
- package/src/app/utils/svgs/swiperArrowIconLeft.tsx +18 -0
- package/src/app/utils/svgs/swiperArrowIconRight.tsx +18 -0
- package/src/app/utils/svgs/userProfileIcon.tsx +31 -0
- package/src/app/utils/svgs/warningCircleIcon.tsx +15 -0
- package/src/app/warranty/constant.tsx +63 -0
- package/src/app/warranty/loading.tsx +17 -0
- package/src/app/warranty/page.tsx +56 -0
- package/src/graphql/client.ts +288 -0
- package/src/graphql/mutations/accountAddressCreate.ts +56 -0
- package/src/graphql/mutations/accountAddressDelete.ts +23 -0
- package/src/graphql/mutations/accountAddressUpdate.ts +55 -0
- package/src/graphql/mutations/accountSetDefaultAddress.ts +32 -0
- package/src/graphql/mutations/accountUpdate.ts +34 -0
- package/src/graphql/mutations/changePassword.ts +25 -0
- package/src/graphql/mutations/checkout.ts +117 -0
- package/src/graphql/mutations/checkoutAddVoucher.ts +63 -0
- package/src/graphql/mutations/checkoutComplete.ts +79 -0
- package/src/graphql/mutations/checkoutCreate.ts +131 -0
- package/src/graphql/mutations/checkoutCustomerAttach.ts +50 -0
- package/src/graphql/mutations/checkoutEmailUpdate.ts +15 -0
- package/src/graphql/mutations/checkoutLineMetadataUpdate.ts +52 -0
- package/src/graphql/mutations/checkoutPaymentCreate.ts +82 -0
- package/src/graphql/mutations/paymentGatewayInitialize.ts +58 -0
- package/src/graphql/mutations/registerAccount.ts +65 -0
- package/src/graphql/mutations/requestPasswordReset.ts +32 -0
- package/src/graphql/mutations/setPassword.ts +49 -0
- package/src/graphql/mutations/signIn.ts +50 -0
- package/src/graphql/mutations/tokenRefresh.ts +19 -0
- package/src/graphql/mutations/updateCheckoutMetadata.ts +49 -0
- package/src/graphql/mutations/updateProfile.ts +18 -0
- package/src/graphql/mutations/willCallDeliveryMethod.ts +81 -0
- package/src/graphql/queries/checkout.ts +168 -0
- package/src/graphql/queries/findProductByOldSlug.ts +58 -0
- package/src/graphql/queries/getAboutPage.ts +24 -0
- package/src/graphql/queries/getAboutPageId.ts +9 -0
- package/src/graphql/queries/getAboutUs.ts +38 -0
- package/src/graphql/queries/getAddressInformation.ts +38 -0
- package/src/graphql/queries/getAllCategories.ts +41 -0
- package/src/graphql/queries/getAllCategoriesTree.ts +67 -0
- package/src/graphql/queries/getAllCategoriesWithProducts.ts +29 -0
- package/src/graphql/queries/getAllCollectionsWithProducts.ts +16 -0
- package/src/graphql/queries/getBlogs.ts +222 -0
- package/src/graphql/queries/getBrands.ts +17 -0
- package/src/graphql/queries/getBundles.ts +43 -0
- package/src/graphql/queries/getCategories.ts +20 -0
- package/src/graphql/queries/getChannels.ts +77 -0
- package/src/graphql/queries/getCheckoutQuestions.ts +115 -0
- package/src/graphql/queries/getCheckoutTermsAndConditions.ts +37 -0
- package/src/graphql/queries/getContactPage.ts +117 -0
- package/src/graphql/queries/getContentPage.ts +191 -0
- package/src/graphql/queries/getDiscountOffers.ts +18 -0
- package/src/graphql/queries/getDynamicPageBySlug.ts +251 -0
- package/src/graphql/queries/getFeaturedProducts.ts +48 -0
- package/src/graphql/queries/getHeroMetadata.ts +23 -0
- package/src/graphql/queries/getMenuBySlug.ts +84 -0
- package/src/graphql/queries/getMyProfile.ts +23 -0
- package/src/graphql/queries/getNewsletter.ts +122 -0
- package/src/graphql/queries/getNewsletterPage.ts +111 -0
- package/src/graphql/queries/getPageBySlug.ts +52 -0
- package/src/graphql/queries/getPageTypeId.ts +27 -0
- package/src/graphql/queries/getPaymentMethods.ts +61 -0
- package/src/graphql/queries/getProducts.ts +78 -0
- package/src/graphql/queries/getPromotions.ts +24 -0
- package/src/graphql/queries/getRequestReturnPage.ts +121 -0
- package/src/graphql/queries/getSiteInfo.ts +54 -0
- package/src/graphql/queries/getSocialLinks.ts +52 -0
- package/src/graphql/queries/getTestimonials.ts +25 -0
- package/src/graphql/queries/getUserWithCheckout.ts +27 -0
- package/src/graphql/queries/getVehicleMakes.ts +21 -0
- package/src/graphql/queries/getVehicleModels.ts +21 -0
- package/src/graphql/queries/getVehicleYears.ts +21 -0
- package/src/graphql/queries/meAddresses.ts +56 -0
- package/src/graphql/queries/myOrders.ts +37 -0
- package/src/graphql/queries/orderDetail.ts +231 -0
- package/src/graphql/queries/productDetailsById.ts +197 -0
- package/src/graphql/queries/productInquiry.ts +115 -0
- package/src/graphql/queries/productsByCategoriesAndCollections.ts +39 -0
- package/src/graphql/queries/willCallCollectionPoints.ts +55 -0
- package/src/graphql/server-client.ts +54 -0
- package/src/graphql/types/categories.ts +9 -0
- package/src/graphql/types/checkout.ts +168 -0
- package/src/graphql/types/offer.ts +12 -0
- package/src/graphql/types/product.ts +44 -0
- package/src/hooks/scrollPageTop.ts +9 -0
- package/src/hooks/serverNavbarData.ts +79 -0
- package/src/hooks/useCartSync.ts +24 -0
- package/src/hooks/useRecaptcha.ts +33 -0
- package/src/hooks/useTokenExpiration.ts +81 -0
- package/src/hooks/useVehicleData.ts +346 -0
- package/src/lib/api/kount.ts +165 -0
- package/src/lib/api/shop.ts +1445 -0
- package/src/lib/saleor/getSaleorApiUrl.ts +25 -0
- package/src/lib/schema.ts +303 -0
- package/src/lib/seo/extractTextFromEditorJs.ts +58 -0
- package/src/lib/seo/site.ts +10 -0
- package/src/lib/urls/normalizeInternalUrl.ts +53 -0
- package/src/middleware.ts +134 -0
- package/src/sitemaps/README.md +105 -0
- package/src/sitemaps/dynamic-pages-sitemap.ts +247 -0
- package/src/sitemaps/sitemap-index.ts +21 -0
- package/src/sitemaps/static-pages-sitemap.ts +36 -0
- package/src/store/useGlobalStore.tsx +1656 -0
- package/src/types/global.d.ts +148 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Suspense, useState } from "react";
|
|
4
|
+
import { useSearchParams, useRouter } from "next/navigation";
|
|
5
|
+
import { useMutation } from "@apollo/client";
|
|
6
|
+
import {
|
|
7
|
+
SET_PASSWORD_MUTATION,
|
|
8
|
+
type SetPasswordData,
|
|
9
|
+
type SetPasswordVariables,
|
|
10
|
+
} from "@/graphql/mutations/setPassword";
|
|
11
|
+
import { useGlobalStore } from "@/store/useGlobalStore";
|
|
12
|
+
import Input from "@/app/components/reuseableUI/input";
|
|
13
|
+
import PrimaryButton from "@/app/components/reuseableUI/primaryButton";
|
|
14
|
+
import { SpinnerIcon } from "@/app/utils/svgs/spinnerIcon";
|
|
15
|
+
import { PasswordRules } from "@/app/components/reuseableUI/passwordRules/passwordRules";
|
|
16
|
+
import { ErrorTag } from "@/app/components/reuseableUI/errorTag";
|
|
17
|
+
|
|
18
|
+
function ResetPasswordInner() {
|
|
19
|
+
const searchParams = useSearchParams();
|
|
20
|
+
const prefilledEmail = searchParams.get("email") || "";
|
|
21
|
+
const prefilledToken = searchParams.get("token") || "";
|
|
22
|
+
|
|
23
|
+
const [formData, setFormData] = useState({
|
|
24
|
+
password: "",
|
|
25
|
+
confirmPassword: "",
|
|
26
|
+
});
|
|
27
|
+
const [apiError, setApiError] = useState<string | null>(null);
|
|
28
|
+
const [fieldErrors, setFieldErrors] = useState({
|
|
29
|
+
password: "",
|
|
30
|
+
confirmPassword: "",
|
|
31
|
+
});
|
|
32
|
+
const [message, setMessage] = useState<string | null>(null);
|
|
33
|
+
const [setPassword, { loading }] = useMutation<
|
|
34
|
+
SetPasswordData,
|
|
35
|
+
SetPasswordVariables
|
|
36
|
+
>(SET_PASSWORD_MUTATION);
|
|
37
|
+
const [email] = useState<string>(prefilledEmail);
|
|
38
|
+
const [token] = useState<string>(prefilledToken);
|
|
39
|
+
const router = useRouter();
|
|
40
|
+
const { login } = useGlobalStore();
|
|
41
|
+
|
|
42
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
43
|
+
setFormData({
|
|
44
|
+
...formData,
|
|
45
|
+
[e.target.name]: e.target.value,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
setApiError(null);
|
|
52
|
+
setMessage(null);
|
|
53
|
+
setFieldErrors({ password: "", confirmPassword: "" });
|
|
54
|
+
|
|
55
|
+
const passwordRegex = {
|
|
56
|
+
length: /^.{8,}$/,
|
|
57
|
+
uppercase: /[A-Z]/,
|
|
58
|
+
lowercase: /[a-z]/,
|
|
59
|
+
number: /[0-9]/,
|
|
60
|
+
specialChar: /[^A-Za-z0-9]/,
|
|
61
|
+
};
|
|
62
|
+
const errors = { password: "", confirmPassword: "" };
|
|
63
|
+
let hasError = false;
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
!passwordRegex.length.test(formData.password) ||
|
|
67
|
+
!passwordRegex.uppercase.test(formData.password) ||
|
|
68
|
+
!passwordRegex.lowercase.test(formData.password) ||
|
|
69
|
+
!passwordRegex.number.test(formData.password) ||
|
|
70
|
+
!passwordRegex.specialChar.test(formData.password)
|
|
71
|
+
) {
|
|
72
|
+
errors.password = "Password Validation Failed";
|
|
73
|
+
hasError = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (formData.password !== formData.confirmPassword) {
|
|
77
|
+
errors.confirmPassword = "Passwords do not match.";
|
|
78
|
+
hasError = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// if (!email || !token) {
|
|
82
|
+
// setFieldErrors({ email: 'Invalid or missing reset link. Please request a new one.', token: '' });
|
|
83
|
+
// return;
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
if (hasError) {
|
|
87
|
+
setFieldErrors(errors);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const { data } = await setPassword({
|
|
93
|
+
variables: {
|
|
94
|
+
email,
|
|
95
|
+
token,
|
|
96
|
+
password: formData.password,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const result = data?.setPassword;
|
|
101
|
+
const errs = result?.errors || [];
|
|
102
|
+
if (!result || errs.length) {
|
|
103
|
+
setApiError(errs[0]?.message || "Unable to reset password.");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Save tokens (auto-login after reset if provided)
|
|
108
|
+
if (result.token) localStorage.setItem("token", result.token);
|
|
109
|
+
if (result.refreshToken)
|
|
110
|
+
localStorage.setItem("refreshToken", result.refreshToken);
|
|
111
|
+
try {
|
|
112
|
+
await fetch("/api/auth/set", {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "Content-Type": "application/json" },
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
token: result.token,
|
|
117
|
+
refreshToken: result.refreshToken,
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
120
|
+
} catch {}
|
|
121
|
+
|
|
122
|
+
if (result.user) {
|
|
123
|
+
const { id, email: uEmail, firstName, lastName } = result.user;
|
|
124
|
+
const displayName =
|
|
125
|
+
[firstName, lastName].filter(Boolean).join(" ") || uEmail;
|
|
126
|
+
login({ id, email: uEmail, name: displayName });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
setMessage("Password has been reset successfully. Redirecting...");
|
|
130
|
+
// Redirect to account or login based on whether token exists
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
if (result.token) router.push("/account");
|
|
133
|
+
else router.push("/account/login");
|
|
134
|
+
}, 1000);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.error("Set password error", err);
|
|
137
|
+
setApiError("Unable to reset password. Please try again.");
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div className="flex items-center justify-center min-h-screen w-full px-4 md:px-6 py-12 md:py-16 lg:py-24px-4 sm:px-6">
|
|
143
|
+
<div className="flex w-full max-w-[756px] flex-col justify-center items-start gap-6">
|
|
144
|
+
<div className="flex flex-col items-start gap-1 md:gap-2 self-stretch">
|
|
145
|
+
<p
|
|
146
|
+
style={{ color: "var(--color-secondary-800)" }}
|
|
147
|
+
className="text-lg md:text-xl font-semibold tracking-[-0.05px] uppercase"
|
|
148
|
+
>
|
|
149
|
+
Reset Password
|
|
150
|
+
</p>
|
|
151
|
+
<p className="text-sm leading-5 tracking-[-0.035px]">
|
|
152
|
+
Please choose a new password for your account.
|
|
153
|
+
</p>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<form onSubmit={handleSubmit} className="w-full flex flex-col gap-6">
|
|
157
|
+
{message && (
|
|
158
|
+
<div
|
|
159
|
+
style={{ color: "var(--color-secondary-800)" }}
|
|
160
|
+
className="mb-4 text-sm"
|
|
161
|
+
role="status"
|
|
162
|
+
>
|
|
163
|
+
{message}
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
<div className="w-full">
|
|
167
|
+
<Input
|
|
168
|
+
label="NEW PASSWORD"
|
|
169
|
+
type="password"
|
|
170
|
+
name="password"
|
|
171
|
+
placeholder="Aero@1234"
|
|
172
|
+
value={formData.password}
|
|
173
|
+
hasError={!!fieldErrors.password}
|
|
174
|
+
onChange={handleChange}
|
|
175
|
+
className="mt-1.5 py-3 px-4 text-sm leading-5 tracking-[-0.035px]"
|
|
176
|
+
/>
|
|
177
|
+
<PasswordRules value={formData.password} />
|
|
178
|
+
</div>
|
|
179
|
+
<div className="w-full relative">
|
|
180
|
+
<Input
|
|
181
|
+
label="RE-ENTER NEW PASSWORD"
|
|
182
|
+
type="password"
|
|
183
|
+
name="confirmPassword"
|
|
184
|
+
placeholder="*******"
|
|
185
|
+
value={formData.confirmPassword}
|
|
186
|
+
onChange={handleChange}
|
|
187
|
+
className="mt-1.5 py-3 px-4 text-sm leading-5 tracking-[-0.035px]"
|
|
188
|
+
hasError={!!fieldErrors.confirmPassword}
|
|
189
|
+
errorMessage={fieldErrors.confirmPassword}
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
{apiError && <ErrorTag message={apiError} />}
|
|
193
|
+
|
|
194
|
+
<PrimaryButton
|
|
195
|
+
type="submit"
|
|
196
|
+
disabled={loading}
|
|
197
|
+
content={
|
|
198
|
+
loading ? (
|
|
199
|
+
<span className="flex items-center justify-center w-full">
|
|
200
|
+
{SpinnerIcon}
|
|
201
|
+
</span>
|
|
202
|
+
) : (
|
|
203
|
+
"Reset Password"
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
className="w-full text-sm lg:text-base font-semibold tracking-[-0.04px] py-2 md:py-3 px-4 "
|
|
207
|
+
/>
|
|
208
|
+
</form>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export default function ResetPasswordPage() {
|
|
215
|
+
return (
|
|
216
|
+
<Suspense
|
|
217
|
+
fallback={<div className="max-w-7xl mx-auto px-4 py-8">Loading...</div>}
|
|
218
|
+
>
|
|
219
|
+
<ResetPasswordInner />
|
|
220
|
+
</Suspense>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Metadata } from "next";
|
|
3
|
+
import { notFound } from "next/navigation";
|
|
4
|
+
import DynamicPageRenderer from "../components/dynamicPage/DynamicPageRenderer";
|
|
5
|
+
import { fetchDynamicPageBySlug } from "@/graphql/queries/getDynamicPageBySlug";
|
|
6
|
+
import { getStoreName } from "@/app/utils/branding";
|
|
7
|
+
|
|
8
|
+
export const dynamic = "force-dynamic";
|
|
9
|
+
export const dynamicParams = true;
|
|
10
|
+
export const revalidate = 300;
|
|
11
|
+
|
|
12
|
+
interface PageProps {
|
|
13
|
+
params: Promise<{ slug: string }>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function generateMetadata({
|
|
17
|
+
params,
|
|
18
|
+
}: PageProps): Promise<Metadata> {
|
|
19
|
+
const { slug } = await params;
|
|
20
|
+
const page = await fetchDynamicPageBySlug(slug);
|
|
21
|
+
|
|
22
|
+
if (!page) {
|
|
23
|
+
return {
|
|
24
|
+
title: `Page Not Found - ${getStoreName()}`,
|
|
25
|
+
robots: { index: false, follow: false },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
title: page.seoTitle || `${page.title} - ${getStoreName()}`,
|
|
31
|
+
description: page.seoDescription || page.excerpt || undefined,
|
|
32
|
+
alternates: {
|
|
33
|
+
canonical: `/${encodeURIComponent(slug)}`,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default async function DynamicPage({ params }: PageProps) {
|
|
39
|
+
const { slug } = await params;
|
|
40
|
+
const page = await fetchDynamicPageBySlug(slug);
|
|
41
|
+
if (!page) notFound();
|
|
42
|
+
return <DynamicPageRenderer pageData={page} />;
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ContentSkeleton from "@/app/components/skeletons/ContentSkeleton"
|
|
2
|
+
|
|
3
|
+
export default function Loading() {
|
|
4
|
+
return (
|
|
5
|
+
<main className="h-full w-full">
|
|
6
|
+
<div className="container mx-auto max-w-[1276px]">
|
|
7
|
+
<div className="flex flex-col items-start w-full py-24">
|
|
8
|
+
<div className="flex flex-col items-start gap-5 mb-6 w-full">
|
|
9
|
+
<div className="h-5 w-24 bg-[var(--color-secondary-800)]/30 rounded" />
|
|
10
|
+
<div className="h-9 w-64 bg-[var(--color-secondary-800)]/30 rounded" />
|
|
11
|
+
</div>
|
|
12
|
+
<ContentSkeleton />
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</main>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Suspense } from "react";
|
|
2
|
+
import type { Metadata } from "next";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import AncillaryContent from "@/app/components/ancillary/AncillaryContent";
|
|
5
|
+
import ContentSkeleton from "@/app/components/skeletons/ContentSkeleton";
|
|
6
|
+
import { getStoreName } from "@/app/utils/branding";
|
|
7
|
+
import Breadcrumb from "../components/reuseableUI/breadcrumb";
|
|
8
|
+
import Heading from "../components/reuseableUI/heading";
|
|
9
|
+
|
|
10
|
+
export const metadata: Metadata = {
|
|
11
|
+
title: `About Us - ${getStoreName()}`,
|
|
12
|
+
description:
|
|
13
|
+
"Learn about our mission, values, and commitment to providing high-quality products and exceptional customer service.",
|
|
14
|
+
alternates: {
|
|
15
|
+
canonical: "/about",
|
|
16
|
+
},
|
|
17
|
+
openGraph: {
|
|
18
|
+
title: `About Us - ${getStoreName()}`,
|
|
19
|
+
description:
|
|
20
|
+
"Learn about our mission, values, and commitment to providing high-quality products and exceptional customer service.",
|
|
21
|
+
type: "website",
|
|
22
|
+
url: "/about",
|
|
23
|
+
images: [{ url: "/Logo.png" }],
|
|
24
|
+
},
|
|
25
|
+
twitter: {
|
|
26
|
+
card: "summary_large_image",
|
|
27
|
+
title: `About Us - ${getStoreName()}`,
|
|
28
|
+
description:
|
|
29
|
+
"Learn about our mission, values, and commitment to providing high-quality products and exceptional customer service.",
|
|
30
|
+
images: ["/Logo.png"],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default function AboutUsPage() {
|
|
35
|
+
const pageTitle = "About Us";
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<main className="h-full w-full">
|
|
39
|
+
<div className="container mx-auto max-w-[1276px] ">
|
|
40
|
+
<div className="flex flex-col items-start w-full px-4 md:px-6 py-12 md:py-16 lg:py-24">
|
|
41
|
+
<div className="flex flex-col items-start gap-5 mb-6 w-full">
|
|
42
|
+
<Breadcrumb
|
|
43
|
+
items={[
|
|
44
|
+
{ text: "Home", link: "/" },
|
|
45
|
+
{ text: "About Us", link: "/about" },
|
|
46
|
+
]}
|
|
47
|
+
/>
|
|
48
|
+
<Heading as="h1" content={pageTitle} />
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<section className="w-full">
|
|
52
|
+
<Suspense fallback={<ContentSkeleton />}>
|
|
53
|
+
{/* Async content fetch and render */}
|
|
54
|
+
<AncillaryContent slug="about" />
|
|
55
|
+
</Suspense>
|
|
56
|
+
</section>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</main>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -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: `Address Book - ${getStoreName()}`,
|
|
6
|
+
description: "Manage your shipping and billing addresses. Add, edit, or remove addresses for faster checkout.",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function AddressLayout({
|
|
10
|
+
children,
|
|
11
|
+
}: {
|
|
12
|
+
children: React.ReactNode
|
|
13
|
+
}) {
|
|
14
|
+
return children
|
|
15
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ME_ADDRESSES_QUERY, type MeAddressesData } from '@/graphql/queries/meAddresses';
|
|
4
|
+
import { useMutation, useQuery } from '@apollo/client';
|
|
5
|
+
|
|
6
|
+
import AddNewAddressModal from '@/app/checkout/components/addNewAddressModal';
|
|
7
|
+
import CommonButton from '@/app/components/reuseableUI/commonButton';
|
|
8
|
+
import EmptyState from '@/app/components/reuseableUI/emptyState';
|
|
9
|
+
import LoadingUI from '@/app/components/reuseableUI/loadingUI';
|
|
10
|
+
import { PlusIcon } from '@/app/utils/svgs/plusIcon';
|
|
11
|
+
import { ACCOUNT_ADDRESS_DELETE, AccountAddressDeleteData, AccountAddressDeleteVars } from '@/graphql/mutations/accountAddressDelete';
|
|
12
|
+
import { AddressForm } from '@/graphql/types/checkout';
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
export default function AddressBookPage() {
|
|
15
|
+
const { data, loading, refetch } = useQuery<MeAddressesData>(ME_ADDRESSES_QUERY, { fetchPolicy: 'cache-and-network' });
|
|
16
|
+
const [deleteAddress] = useMutation<AccountAddressDeleteData, AccountAddressDeleteVars>(ACCOUNT_ADDRESS_DELETE);
|
|
17
|
+
const me = data?.me;
|
|
18
|
+
const defaultShippingId = me?.defaultShippingAddress?.id;
|
|
19
|
+
const defaultBillingId = me?.defaultBillingAddress?.id;
|
|
20
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
21
|
+
const [editingId, setEditingId] = useState<string | null>(null);
|
|
22
|
+
const [getMethods, setGetMethods] = useState({
|
|
23
|
+
defaultShippingId: defaultShippingId || null,
|
|
24
|
+
defaultBillingId: defaultBillingId || null
|
|
25
|
+
})
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
setGetMethods({
|
|
28
|
+
defaultShippingId: defaultShippingId || null,
|
|
29
|
+
defaultBillingId: defaultBillingId || null
|
|
30
|
+
})
|
|
31
|
+
}, [defaultShippingId, defaultBillingId])
|
|
32
|
+
const [formData, setFormData] = useState<AddressForm>({
|
|
33
|
+
firstName: '',
|
|
34
|
+
lastName: '',
|
|
35
|
+
phone: '',
|
|
36
|
+
companyName: '',
|
|
37
|
+
streetAddress1: '',
|
|
38
|
+
streetAddress2: '',
|
|
39
|
+
city: '',
|
|
40
|
+
postalCode: '',
|
|
41
|
+
country: 'US',
|
|
42
|
+
countryArea: '',
|
|
43
|
+
});
|
|
44
|
+
const handleEdit = (addr: NonNullable<MeAddressesData['me']>['addresses'][number]) => {
|
|
45
|
+
setEditingId(addr.id);
|
|
46
|
+
setFormData({
|
|
47
|
+
id: addr.id,
|
|
48
|
+
firstName: addr.firstName,
|
|
49
|
+
lastName: addr.lastName,
|
|
50
|
+
phone: addr.phone || '',
|
|
51
|
+
companyName: addr.companyName || '',
|
|
52
|
+
streetAddress1: addr.streetAddress1,
|
|
53
|
+
streetAddress2: addr.streetAddress2 || '',
|
|
54
|
+
city: addr.city,
|
|
55
|
+
postalCode: addr.postalCode,
|
|
56
|
+
country: addr.country.code,
|
|
57
|
+
countryArea: addr.countryArea || '',
|
|
58
|
+
});
|
|
59
|
+
setIsModalOpen(true);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleDelete = async (id: string) => {
|
|
63
|
+
try {
|
|
64
|
+
const { data } = await deleteAddress({ variables: { id } });
|
|
65
|
+
const errs = data?.accountAddressDelete.errors || [];
|
|
66
|
+
if (errs.length) {
|
|
67
|
+
// Avoid noisy logs in templates/production.
|
|
68
|
+
} else {
|
|
69
|
+
await refetch();
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Avoid noisy logs in templates/production.
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const handleAddNewAddress = () => {
|
|
76
|
+
setIsModalOpen(true);
|
|
77
|
+
setEditingId(null);
|
|
78
|
+
setFormData({
|
|
79
|
+
firstName: '',
|
|
80
|
+
lastName: '',
|
|
81
|
+
phone: '',
|
|
82
|
+
companyName: '',
|
|
83
|
+
streetAddress1: '',
|
|
84
|
+
streetAddress2: '',
|
|
85
|
+
city: '',
|
|
86
|
+
postalCode: '',
|
|
87
|
+
country: 'US',
|
|
88
|
+
countryArea: '',
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
<div>
|
|
94
|
+
<div className='flex items-center justify-between w-full'>
|
|
95
|
+
<h2 className="text-lg lg:text-xl text-[var(--color-secondary-800)] font-secondary font-semibold">MY ADDRESSES</h2>
|
|
96
|
+
<div className="uppercase cursor-pointer flex items-center gap-2" onClick={handleAddNewAddress}>
|
|
97
|
+
<span className="size-5 text-[var(--color-primary-600)]">{PlusIcon}</span>
|
|
98
|
+
<CommonButton variant='tertiary' content="Add New Address" className="p-0 text-sm lg:text-base " />
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="mt-4">
|
|
103
|
+
{
|
|
104
|
+
loading ? <LoadingUI /> :
|
|
105
|
+
!loading && me?.addresses?.length === 0
|
|
106
|
+
? <EmptyState text='No Address yet.' className='h-[50vh]' /> :
|
|
107
|
+
<div className='flex flex-col space-y-4 w-full'>
|
|
108
|
+
{me?.addresses?.map((address) => (
|
|
109
|
+
<div key={address.id} className=" w-full border-b border-[var(--color-secondary-200)] pb-4 flex flex-col md:flex-row gap-4 justify-between md:items-center ">
|
|
110
|
+
|
|
111
|
+
<div>
|
|
112
|
+
|
|
113
|
+
<div className="absolute top-4 right-4 space-x-2">
|
|
114
|
+
{defaultShippingId === address.id && (
|
|
115
|
+
<span className="px-2 py-1 bg-amber-100 text-amber-800 text-xs font-semibold rounded">Default Shipping</span>
|
|
116
|
+
)}
|
|
117
|
+
{defaultBillingId === address.id && (
|
|
118
|
+
<span className="px-2 py-1 bg-blue-100 text-blue-800 text-xs font-semibold rounded">Default Billing</span>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div className='space-y-1'>
|
|
123
|
+
<div className='flex items-center gap-2 text-medium text-lg lg:text-xl font-secondary text-[var(--color-secondary-800)]'>
|
|
124
|
+
{address.streetAddress1}{address.streetAddress2 ? `, ${address.streetAddress2}` : ''} {" "}
|
|
125
|
+
{address.city}{address.countryArea ? `, ${address.countryArea}` : ''} {" "}
|
|
126
|
+
{address.country.country}
|
|
127
|
+
</div>
|
|
128
|
+
{address.phone && <p className='text-medium text-lg font-secondary text-[var(--color-secondary-500)]'>{address.phone}</p>}
|
|
129
|
+
</div>
|
|
130
|
+
<div className="flex flex-wrap gap-3 pt-2">
|
|
131
|
+
{defaultShippingId === address.id && (
|
|
132
|
+
<p className="font-medium text-sm text-[var(--color-secondary-800)] font-secondary bg-[var(--color-secondary-600)]/10 px-2 py-0.5 border border-[var(--color-secondary-600)]/60 h-fit">
|
|
133
|
+
Default Shipping Address
|
|
134
|
+
</p>
|
|
135
|
+
)}
|
|
136
|
+
{defaultBillingId === address.id && (
|
|
137
|
+
<p className="font-medium text-sm text-[var(--color-secondary-800)] font-secondary bg-[var(--color-secondary-600)]/10 px-2 py-0.5 border border-[var(--color-secondary-600)]/60 h-fit">
|
|
138
|
+
Default Billing Address
|
|
139
|
+
</p>
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<div className='flex ml-auto items-center gap-5 [&>button]:p-0'>
|
|
144
|
+
<CommonButton
|
|
145
|
+
onClick={() => handleEdit(address)}
|
|
146
|
+
className='text-sm md:text-base py-3 px-4'
|
|
147
|
+
variant='tertiary'
|
|
148
|
+
content="Edit"
|
|
149
|
+
/>
|
|
150
|
+
<CommonButton
|
|
151
|
+
onClick={() => handleDelete(address.id)}
|
|
152
|
+
className='text-sm md:text-base py-3 px-4'
|
|
153
|
+
variant='tertiarySecondary'
|
|
154
|
+
content="Delete"
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
}
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
<AddNewAddressModal isModalOpen={isModalOpen} onClose={() => setIsModalOpen(false)} formData={formData} setFormData={setFormData} editingId={editingId} getMethods={getMethods} />
|
|
164
|
+
</>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { usePathname } from 'next/navigation';
|
|
5
|
+
import { useQuery } from '@apollo/client';
|
|
6
|
+
import { GET_MY_PROFILE, type GetMyProfileData } from '@/graphql/queries/getMyProfile';
|
|
7
|
+
import Breadcrumb from '../components/reuseableUI/breadcrumb';
|
|
8
|
+
const breadcrumbItems = [
|
|
9
|
+
{ text: 'HOME', link: '/' },
|
|
10
|
+
{ text: 'MY ACCOUNT' },
|
|
11
|
+
];
|
|
12
|
+
export default function AccountLayout({
|
|
13
|
+
children,
|
|
14
|
+
}: {
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}) {
|
|
17
|
+
const pathname = usePathname();
|
|
18
|
+
useQuery<GetMyProfileData>(GET_MY_PROFILE, {
|
|
19
|
+
fetchPolicy: 'no-cache',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const navigationItems = [
|
|
23
|
+
{
|
|
24
|
+
name: 'My Profile',
|
|
25
|
+
href: '/account/settings',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'Order History',
|
|
29
|
+
href: '/account/orders',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'Address Book',
|
|
33
|
+
href: '/account/address',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="max-w-7xl mx-auto py-12 px-4 md:px-6 md:py-16 lg:py-24 space-y-8 lg:space-y-16">
|
|
40
|
+
<div className='space-y-5'>
|
|
41
|
+
<Breadcrumb items={breadcrumbItems} />
|
|
42
|
+
<h1 className="text-2xl md:text-3xl lg:text-5xl font-normal font-primary text-[var(--color-secondary-800)]">MY ACCOUNT</h1>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="grid grid-cols-1 lg:grid-cols-4 gap-8 lg:gap-16">
|
|
45
|
+
<div className="lg:col-span-1 flex lg:flex-col border-r border-[var(--color-secondary-200)] gap-4 md:gap-3">
|
|
46
|
+
{navigationItems.map((item) => (
|
|
47
|
+
<Link
|
|
48
|
+
key={item.name}
|
|
49
|
+
href={item.href}
|
|
50
|
+
className={`uppercase block font-bold font-secondary text-sm md:text-lg ${pathname === item.href ? 'text-[var(--color-primary)]' : 'text-[var(--color-secondary-400)] hover:text-[var(--color-primary)]'}`}
|
|
51
|
+
>
|
|
52
|
+
{item.name}
|
|
53
|
+
</Link>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
<div className="lg:col-span-3">
|
|
57
|
+
{children}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import { getStoreName } from "@/app/utils/branding"
|
|
3
|
+
|
|
4
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
5
|
+
return {
|
|
6
|
+
title: `Order Details - ${getStoreName()}`,
|
|
7
|
+
description: `View detailed information about your order including tracking, items ordered, and shipping information.`,
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function OrderDetailLayout({
|
|
12
|
+
children,
|
|
13
|
+
}: {
|
|
14
|
+
children: React.ReactNode
|
|
15
|
+
}) {
|
|
16
|
+
return children
|
|
17
|
+
}
|