@faststore/core 22.42.6
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/.babelrc +4 -0
- package/.editorconfig +13 -0
- package/.eslintignore +8 -0
- package/.eslintrc +21 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/workflows/release.yml +40 -0
- package/.husky/pre-commit +4 -0
- package/.prettierignore +8 -0
- package/.prettierrc +1 -0
- package/.release-it.json +31 -0
- package/.storybook/components/BestPractices.tsx +18 -0
- package/.storybook/components/BestPracticesRule.tsx +43 -0
- package/.storybook/components/Callout.tsx +12 -0
- package/.storybook/components/SectionItem.tsx +44 -0
- package/.storybook/components/SectionList.tsx +27 -0
- package/.storybook/components/TokenDivider.tsx +12 -0
- package/.storybook/components/TokenRow.tsx +32 -0
- package/.storybook/components/TokenTable.tsx +33 -0
- package/.storybook/components/index.ts +8 -0
- package/.storybook/main.js +59 -0
- package/.storybook/manager-head.html +9 -0
- package/.storybook/manager.js +6 -0
- package/.storybook/mocks/cart-sidebar.js +40 -0
- package/.storybook/mocks/filter-slider.js +59 -0
- package/.storybook/mocks/index.ts +5 -0
- package/.storybook/mocks/product.ts +67 -0
- package/.storybook/mocks/productGridItems.ts +334 -0
- package/.storybook/mocks/searchHistory.ts +8 -0
- package/.storybook/mocks/searchTerms.ts +5 -0
- package/.storybook/preview-head.html +1 -0
- package/.storybook/preview.js +89 -0
- package/.storybook/storybook.css +550 -0
- package/.storybook/theme.js +21 -0
- package/.stylelintignore +1 -0
- package/.vscode/settings.json +7 -0
- package/@generated/graphql/index.ts +1133 -0
- package/@generated/graphql/persisted.json +12 -0
- package/CHANGELOG.md +730 -0
- package/LICENSE +21 -0
- package/README.md +437 -0
- package/bun.lockb +0 -0
- package/cms/content-types.json +52 -0
- package/cms/sections.json +350 -0
- package/cms/translation-keys.json +1 -0
- package/cms-webhook-urls.json +5 -0
- package/codegen.yml +22 -0
- package/cypress/fixtures/example.json +5 -0
- package/cypress/global.js +15 -0
- package/cypress/integration/a11y.test.js +45 -0
- package/cypress/integration/analytics.test.js +381 -0
- package/cypress/integration/cart.test.js +100 -0
- package/cypress/integration/performance.test.js +65 -0
- package/cypress/integration/plp.test.js +224 -0
- package/cypress/integration/search.test.js +38 -0
- package/cypress/integration/seo.test.js +318 -0
- package/cypress/plugins/index.js +41 -0
- package/cypress/support/commands.js +70 -0
- package/cypress/support/index.js +3 -0
- package/cypress.json +9 -0
- package/lighthouserc.js +22 -0
- package/next-env.d.ts +5 -0
- package/next.config.js +35 -0
- package/package.json +114 -0
- package/postcss.config.js +5 -0
- package/public/brandless-negative.png +0 -0
- package/public/brandless-neutral.png +0 -0
- package/public/brandless-positive.png +0 -0
- package/public/brandless-storybook.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/icons.svg +58 -0
- package/public/logo.svg +42 -0
- package/public/mockServiceWorker.js +367 -0
- package/public/robots.txt +5 -0
- package/pull_request_template.md +37 -0
- package/renovate.json +5 -0
- package/src/Layout.tsx +51 -0
- package/src/components/ThirdPartyScripts/GoogleTagManager.tsx +61 -0
- package/src/components/ThirdPartyScripts/ThirdPartyScripts.tsx +37 -0
- package/src/components/ThirdPartyScripts/index.ts +1 -0
- package/src/components/ThirdPartyScripts/vtex.tsx +23 -0
- package/src/components/cart/CartItem/CartItem.stories.mdx +134 -0
- package/src/components/cart/CartItem/CartItem.tsx +158 -0
- package/src/components/cart/CartItem/cart-item.module.scss +68 -0
- package/src/components/cart/CartItem/index.ts +1 -0
- package/src/components/cart/CartSidebar/CartSidebar.stories.mdx +119 -0
- package/src/components/cart/CartSidebar/CartSidebar.tsx +140 -0
- package/src/components/cart/CartSidebar/cart-sidebar.module.scss +69 -0
- package/src/components/cart/CartSidebar/index.ts +1 -0
- package/src/components/cart/CartToggle/CartToggle.tsx +20 -0
- package/src/components/cart/CartToggle/index.ts +1 -0
- package/src/components/cart/EmptyCart/EmptyCart.tsx +26 -0
- package/src/components/cart/EmptyCart/index.ts +1 -0
- package/src/components/cart/OrderSummary/OrderSummary.tsx +39 -0
- package/src/components/cart/OrderSummary/index.ts +1 -0
- package/src/components/cart/OrderSummary/order-summary.module.scss +22 -0
- package/src/components/cms/RenderPageSections.tsx +52 -0
- package/src/components/cms/SectionBoundary.tsx +34 -0
- package/src/components/common/Alert/Alert.tsx +53 -0
- package/src/components/common/Alert/index.ts +1 -0
- package/src/components/common/Footer/Footer.stories.mdx +158 -0
- package/src/components/common/Footer/Footer.tsx +160 -0
- package/src/components/common/Footer/FooterLinks.tsx +155 -0
- package/src/components/common/Footer/footer.module.scss +246 -0
- package/src/components/common/Footer/index.ts +2 -0
- package/src/components/common/Navbar/NavLinks.stories.mdx +122 -0
- package/src/components/common/Navbar/NavLinks.tsx +58 -0
- package/src/components/common/Navbar/Navbar.stories.mdx +179 -0
- package/src/components/common/Navbar/Navbar.tsx +97 -0
- package/src/components/common/Navbar/NavbarSlider.stories.mdx +108 -0
- package/src/components/common/Navbar/NavbarSlider.tsx +62 -0
- package/src/components/common/Navbar/index.ts +3 -0
- package/src/components/common/Navbar/navbar-slider.module.scss +60 -0
- package/src/components/common/Navbar/navbar.module.scss +204 -0
- package/src/components/common/Navbar/navlinks.module.scss +96 -0
- package/src/components/common/Toast/Toast.tsx +40 -0
- package/src/components/common/Toast/index.ts +1 -0
- package/src/components/product/OutOfStock/OutOfStock.stories.mdx +127 -0
- package/src/components/product/OutOfStock/OutOfStock.tsx +134 -0
- package/src/components/product/OutOfStock/index.ts +2 -0
- package/src/components/product/OutOfStock/out-of-stock.module.scss +55 -0
- package/src/components/product/ProductCard/ProductCard.stories.mdx +412 -0
- package/src/components/product/ProductCard/ProductCard.tsx +170 -0
- package/src/components/product/ProductCard/index.ts +2 -0
- package/src/components/product/ProductCard/product-card.module.scss +254 -0
- package/src/components/product/ProductGrid/ProductGrid.stories.mdx +97 -0
- package/src/components/product/ProductGrid/ProductGrid.tsx +37 -0
- package/src/components/product/ProductGrid/index.ts +1 -0
- package/src/components/product/ProductGrid/product-grid.module.scss +39 -0
- package/src/components/regionalization/Regionalization.stories.mdx +182 -0
- package/src/components/regionalization/RegionalizationBar/RegionalizationBar.stories.mdx +116 -0
- package/src/components/regionalization/RegionalizationBar/RegionalizationBar.tsx +40 -0
- package/src/components/regionalization/RegionalizationBar/index.ts +1 -0
- package/src/components/regionalization/RegionalizationBar/regionalization-bar.module.scss +56 -0
- package/src/components/regionalization/RegionalizationButton/RegionalizationButton.tsx +24 -0
- package/src/components/regionalization/RegionalizationButton/index.ts +1 -0
- package/src/components/regionalization/RegionalizationInput/RegionalizationInput.tsx +61 -0
- package/src/components/regionalization/RegionalizationInput/index.ts +1 -0
- package/src/components/regionalization/RegionalizationModal/RegionalizationModal.stories.mdx +161 -0
- package/src/components/regionalization/RegionalizationModal/RegionalizationModal.tsx +13 -0
- package/src/components/regionalization/RegionalizationModal/RegionalizationModalContent.tsx +48 -0
- package/src/components/regionalization/RegionalizationModal/index.ts +2 -0
- package/src/components/regionalization/RegionalizationModal/regionalization-modal-content.module.scss +79 -0
- package/src/components/search/Filter/Facets.stories.mdx +284 -0
- package/src/components/search/Filter/Facets.tsx +136 -0
- package/src/components/search/Filter/Filter.stories.mdx +209 -0
- package/src/components/search/Filter/Filter.tsx +91 -0
- package/src/components/search/Filter/FilterSlider.stories.mdx +226 -0
- package/src/components/search/Filter/FilterSlider.tsx +109 -0
- package/src/components/search/Filter/facets.module.scss +117 -0
- package/src/components/search/Filter/filter-slider.module.scss +63 -0
- package/src/components/search/Filter/index.ts +2 -0
- package/src/components/search/Filter/useFilter.ts +131 -0
- package/src/components/search/Search.stories.mdx +169 -0
- package/src/components/search/SearchDropdown/SearchDropdown.stories.mdx +62 -0
- package/src/components/search/SearchDropdown/SearchDropdown.tsx +44 -0
- package/src/components/search/SearchDropdown/index.ts +2 -0
- package/src/components/search/SearchHistory/SearchHistory.stories.mdx +59 -0
- package/src/components/search/SearchHistory/SearchHistory.tsx +51 -0
- package/src/components/search/SearchHistory/index.ts +1 -0
- package/src/components/search/SearchInput/SearchInput.stories.mdx +205 -0
- package/src/components/search/SearchInput/SearchInput.tsx +128 -0
- package/src/components/search/SearchInput/index.ts +2 -0
- package/src/components/search/SearchInput/search-input.module.scss +153 -0
- package/src/components/search/SearchProductCard/SearchProductCard.stories.mdx +96 -0
- package/src/components/search/SearchProductCard/SearchProductCard.tsx +103 -0
- package/src/components/search/SearchProductCard/index.ts +1 -0
- package/src/components/search/SearchProductCard/search-product-card.module.scss +54 -0
- package/src/components/search/SearchSharedTokenTable.mdx +98 -0
- package/src/components/search/SearchSuggestions/SearchSuggestions.stories.mdx +58 -0
- package/src/components/search/SearchSuggestions/SearchSuggestions.tsx +136 -0
- package/src/components/search/SearchSuggestions/index.ts +2 -0
- package/src/components/search/SearchTop/SearchTop.stories.mdx +58 -0
- package/src/components/search/SearchTop/SearchTop.tsx +78 -0
- package/src/components/search/SearchTop/index.ts +2 -0
- package/src/components/search/Sort/Sort.tsx +42 -0
- package/src/components/search/Sort/index.ts +1 -0
- package/src/components/search/search.module.scss +101 -0
- package/src/components/search/searchMock.ts +48 -0
- package/src/components/sections/BannerNewsletter/BannerNewsletter.tsx +28 -0
- package/src/components/sections/BannerNewsletter/banner-newsletter.module.scss +23 -0
- package/src/components/sections/BannerText/BannerText.stories.mdx +270 -0
- package/src/components/sections/BannerText/BannerText.tsx +87 -0
- package/src/components/sections/BannerText/banner-text.module.scss +127 -0
- package/src/components/sections/BannerText/index.ts +2 -0
- package/src/components/sections/Breadcrumb/Breadcrumb.tsx +24 -0
- package/src/components/sections/Breadcrumb/index.ts +1 -0
- package/src/components/sections/Hero/Hero.stories.mdx +277 -0
- package/src/components/sections/Hero/Hero.tsx +109 -0
- package/src/components/sections/Hero/hero.module.scss +180 -0
- package/src/components/sections/Hero/index.ts +2 -0
- package/src/components/sections/Incentives/Incentives.stories.mdx +159 -0
- package/src/components/sections/Incentives/Incentives.tsx +69 -0
- package/src/components/sections/Incentives/IncentivesFooter.tsx +8 -0
- package/src/components/sections/Incentives/IncentivesHeader.tsx +23 -0
- package/src/components/sections/Incentives/incentives.module.scss +122 -0
- package/src/components/sections/Incentives/incentivesMock.ts +55 -0
- package/src/components/sections/Incentives/index.ts +2 -0
- package/src/components/sections/Newsletter/Newsletter.stories.mdx +139 -0
- package/src/components/sections/Newsletter/Newsletter.tsx +151 -0
- package/src/components/sections/Newsletter/index.ts +2 -0
- package/src/components/sections/Newsletter/newsletter.module.scss +135 -0
- package/src/components/sections/ProducDetailsContent/ProductDetailsContent.stories.mdx +66 -0
- package/src/components/sections/ProducDetailsContent/ProductDetailsContent.tsx +278 -0
- package/src/components/sections/ProducDetailsContent/index.ts +1 -0
- package/src/components/sections/ProducDetailsContent/product-details-content.module.scss +50 -0
- package/src/components/sections/ProductDetails/ProductDetails.tsx +316 -0
- package/src/components/sections/ProductDetails/index.ts +1 -0
- package/src/components/sections/ProductDetails/product-details.module.scss +194 -0
- package/src/components/sections/ProductGallery/EmptyGallery.tsx +38 -0
- package/src/components/sections/ProductGallery/ProductGallery.tsx +186 -0
- package/src/components/sections/ProductGallery/ProductGalleryPage.tsx +70 -0
- package/src/components/sections/ProductGallery/index.ts +1 -0
- package/src/components/sections/ProductGallery/product-gallery.module.scss +184 -0
- package/src/components/sections/ProductGallery/useDelayedFacets.ts +18 -0
- package/src/components/sections/ProductGallery/useDelayedPagination.ts +16 -0
- package/src/components/sections/ProductGallery/useGalleryQuery.ts +58 -0
- package/src/components/sections/ProductGallery/usePageProducts.ts +48 -0
- package/src/components/sections/ProductShelf/ProductShelf.tsx +68 -0
- package/src/components/sections/ProductShelf/index.ts +1 -0
- package/src/components/sections/ProductShelf/product-shelf.module.scss +41 -0
- package/src/components/sections/ProductTiles/ProductTiles.tsx +83 -0
- package/src/components/sections/ProductTiles/index.ts +1 -0
- package/src/components/sections/ScrollToTopButton/ScrollToTopButton.tsx +45 -0
- package/src/components/sections/ScrollToTopButton/index.ts +1 -0
- package/src/components/sections/ScrollToTopButton/scroll-to-top-button.module.scss +12 -0
- package/src/components/sections/Section/Section.tsx +15 -0
- package/src/components/sections/Section/index.ts +1 -0
- package/src/components/sections/Section/section.scss +16 -0
- package/src/components/skeletons/FilterSkeleton/FilterSkeleton.stories.mdx +97 -0
- package/src/components/skeletons/FilterSkeleton/FilterSkeleton.tsx +34 -0
- package/src/components/skeletons/FilterSkeleton/filter-skeleton.module.scss +51 -0
- package/src/components/skeletons/FilterSkeleton/index.ts +1 -0
- package/src/components/skeletons/ProductCardSkeleton/ProductCardSkeleton.stories.mdx +176 -0
- package/src/components/skeletons/ProductCardSkeleton/ProductCardSkeleton.tsx +52 -0
- package/src/components/skeletons/ProductCardSkeleton/index.ts +1 -0
- package/src/components/skeletons/ProductCardSkeleton/product-card-skeleton.module.scss +97 -0
- package/src/components/skeletons/ProductGridSkeleton/ProductGridSkeleton.tsx +29 -0
- package/src/components/skeletons/ProductGridSkeleton/index.ts +1 -0
- package/src/components/skeletons/ProductShelfSkeleton/ProductShelfSkeleton.tsx +32 -0
- package/src/components/skeletons/ProductShelfSkeleton/index.ts +1 -0
- package/src/components/skeletons/ProductTilesSkeleton/ProductTileSkeleton/ProductTileSkeleton.tsx +57 -0
- package/src/components/skeletons/ProductTilesSkeleton/ProductTileSkeleton/index.ts +1 -0
- package/src/components/skeletons/ProductTilesSkeleton/ProductTileSkeleton/product-tile-skeleton.module.scss +218 -0
- package/src/components/skeletons/ProductTilesSkeleton/ProductTilesSkeleton.tsx +33 -0
- package/src/components/skeletons/ProductTilesSkeleton/index.ts +2 -0
- package/src/components/skeletons/Shimmer/Shimmer.tsx +11 -0
- package/src/components/skeletons/Shimmer/index.ts +1 -0
- package/src/components/skeletons/Shimmer/shimmer.module.scss +43 -0
- package/src/components/skeletons/Skeleton/Skeleton.tsx +49 -0
- package/src/components/skeletons/Skeleton/index.ts +1 -0
- package/src/components/skeletons/Skeleton/skeleton.module.scss +77 -0
- package/src/components/skeletons/Skeletons.stories.mdx +178 -0
- package/src/components/ui/Accordion/Accordion.stories.mdx +219 -0
- package/src/components/ui/Accordion/Accordion.tsx +39 -0
- package/src/components/ui/Accordion/AccordionItem.stories.mdx +116 -0
- package/src/components/ui/Accordion/AccordionItem.tsx +82 -0
- package/src/components/ui/Accordion/accordion.module.scss +65 -0
- package/src/components/ui/Accordion/index.ts +2 -0
- package/src/components/ui/Alert/Alert.stories.mdx +164 -0
- package/src/components/ui/Alert/Alert.tsx +78 -0
- package/src/components/ui/Alert/alert.module.scss +93 -0
- package/src/components/ui/Alert/index.ts +1 -0
- package/src/components/ui/Badge/Badge.stories.mdx +465 -0
- package/src/components/ui/Badge/Badge.tsx +76 -0
- package/src/components/ui/Badge/DiscountBadge.stories.mdx +191 -0
- package/src/components/ui/Badge/DiscountBadge.tsx +57 -0
- package/src/components/ui/Badge/badge.module.scss +252 -0
- package/src/components/ui/Badge/index.ts +4 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.stories.mdx +197 -0
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +122 -0
- package/src/components/ui/Breadcrumb/breadcrumb.module.scss +144 -0
- package/src/components/ui/Breadcrumb/index.ts +2 -0
- package/src/components/ui/Button/Button.stories.mdx +685 -0
- package/src/components/ui/Button/Button.tsx +85 -0
- package/src/components/ui/Button/ButtonBuy/ButtonBuy.tsx +24 -0
- package/src/components/ui/Button/ButtonBuy/index.ts +1 -0
- package/src/components/ui/Button/ButtonLink/ButtonLink.tsx +49 -0
- package/src/components/ui/Button/ButtonLink/ButtonSignIn/ButtonSignIn.tsx +22 -0
- package/src/components/ui/Button/ButtonLink/ButtonSignIn/ButtonSignInFallback/ButtonSignInFallback.tsx +18 -0
- package/src/components/ui/Button/ButtonLink/ButtonSignIn/ButtonSignInFallback/index.ts +1 -0
- package/src/components/ui/Button/ButtonLink/ButtonSignIn/index.ts +1 -0
- package/src/components/ui/Button/ButtonLink/index.ts +1 -0
- package/src/components/ui/Button/button.module.scss +392 -0
- package/src/components/ui/Button/index.ts +6 -0
- package/src/components/ui/Checkbox/Checkbox.stories.mdx +268 -0
- package/src/components/ui/Checkbox/Checkbox.tsx +20 -0
- package/src/components/ui/Checkbox/checkbox.module.scss +157 -0
- package/src/components/ui/Checkbox/index.ts +2 -0
- package/src/components/ui/Dropdown/Dropdown.stories.mdx +232 -0
- package/src/components/ui/Dropdown/Dropdown.tsx +12 -0
- package/src/components/ui/Dropdown/DropdownButton.tsx +20 -0
- package/src/components/ui/Dropdown/DropdownItem.stories.mdx +139 -0
- package/src/components/ui/Dropdown/DropdownItem.tsx +26 -0
- package/src/components/ui/Dropdown/DropdownMenu.stories.mdx +115 -0
- package/src/components/ui/Dropdown/DropdownMenu.tsx +34 -0
- package/src/components/ui/Dropdown/dropdown.module.scss +101 -0
- package/src/components/ui/Dropdown/index.ts +4 -0
- package/src/components/ui/EmptyState/EmptyState.stories.mdx +146 -0
- package/src/components/ui/EmptyState/EmptyState.tsx +26 -0
- package/src/components/ui/EmptyState/empty-state.module.scss +63 -0
- package/src/components/ui/EmptyState/index.ts +1 -0
- package/src/components/ui/Gift/Gift.stories.mdx +99 -0
- package/src/components/ui/Gift/Gift.tsx +76 -0
- package/src/components/ui/Gift/gift.module.scss +94 -0
- package/src/components/ui/Gift/index.ts +2 -0
- package/src/components/ui/Icon/Icon.tsx +35 -0
- package/src/components/ui/Icon/index.ts +1 -0
- package/src/components/ui/Image/Image.tsx +59 -0
- package/src/components/ui/Image/index.ts +1 -0
- package/src/components/ui/Image/thumborUrlBuilder.ts +101 -0
- package/src/components/ui/Image/useImage.ts +46 -0
- package/src/components/ui/ImageGallery/ImageGallery.stories.mdx +173 -0
- package/src/components/ui/ImageGallery/ImageGallery.tsx +51 -0
- package/src/components/ui/ImageGallery/ImageGallerySelector.tsx +116 -0
- package/src/components/ui/ImageGallery/ImageZoom.tsx +12 -0
- package/src/components/ui/ImageGallery/image-gallery-selector.module.scss +131 -0
- package/src/components/ui/ImageGallery/image-gallery.module.scss +56 -0
- package/src/components/ui/ImageGallery/index.ts +4 -0
- package/src/components/ui/InputText/InputText.stories.mdx +311 -0
- package/src/components/ui/InputText/InputText.tsx +128 -0
- package/src/components/ui/InputText/index.ts +2 -0
- package/src/components/ui/InputText/input-text.module.scss +168 -0
- package/src/components/ui/Link/Link.stories.mdx +272 -0
- package/src/components/ui/Link/Link.tsx +68 -0
- package/src/components/ui/Link/index.ts +2 -0
- package/src/components/ui/Link/link.module.scss +98 -0
- package/src/components/ui/Logo/Logo.tsx +14 -0
- package/src/components/ui/Logo/index.ts +1 -0
- package/src/components/ui/Logo/logo.module.scss +12 -0
- package/src/components/ui/Modal/Modal.stories.mdx +142 -0
- package/src/components/ui/Modal/Modal.tsx +43 -0
- package/src/components/ui/Modal/index.ts +1 -0
- package/src/components/ui/Modal/modal.module.scss +46 -0
- package/src/components/ui/Price/Price.stories.mdx +194 -0
- package/src/components/ui/Price/Price.tsx +32 -0
- package/src/components/ui/Price/index.ts +1 -0
- package/src/components/ui/Price/price.module.scss +27 -0
- package/src/components/ui/PriceRange/PriceRange.stories.mdx +192 -0
- package/src/components/ui/PriceRange/PriceRange.tsx +138 -0
- package/src/components/ui/PriceRange/index.ts +1 -0
- package/src/components/ui/PriceRange/price-range.module.scss +176 -0
- package/src/components/ui/ProductTitle/ProductTitle.stories.mdx +107 -0
- package/src/components/ui/ProductTitle/ProductTitle.tsx +11 -0
- package/src/components/ui/ProductTitle/index.ts +1 -0
- package/src/components/ui/ProductTitle/product-title.module.scss +48 -0
- package/src/components/ui/QuantitySelector/QuantitySelector.stories.mdx +246 -0
- package/src/components/ui/QuantitySelector/QuantitySelector.tsx +103 -0
- package/src/components/ui/QuantitySelector/index.ts +1 -0
- package/src/components/ui/QuantitySelector/quantity-selector.module.scss +160 -0
- package/src/components/ui/Radio/Radio.stories.mdx +237 -0
- package/src/components/ui/Radio/Radio.tsx +36 -0
- package/src/components/ui/Radio/index.ts +2 -0
- package/src/components/ui/Radio/radio.module.scss +122 -0
- package/src/components/ui/SROnly/SROnly.tsx +20 -0
- package/src/components/ui/SROnly/index.ts +1 -0
- package/src/components/ui/SROnly/sr-only.module.scss +15 -0
- package/src/components/ui/Select/Select.stories.mdx +168 -0
- package/src/components/ui/Select/Select.tsx +70 -0
- package/src/components/ui/Select/index.ts +2 -0
- package/src/components/ui/Select/select.module.scss +85 -0
- package/src/components/ui/ShippingSimulation/ShippingSimulation.stories.mdx +140 -0
- package/src/components/ui/ShippingSimulation/ShippingSimulation.tsx +109 -0
- package/src/components/ui/ShippingSimulation/index.ts +1 -0
- package/src/components/ui/ShippingSimulation/shipping-simulation.module.scss +96 -0
- package/src/components/ui/ShippingSimulation/useShippingSimulation.ts +225 -0
- package/src/components/ui/SkuSelector/Selectors.stories.mdx +82 -0
- package/src/components/ui/SkuSelector/Selectors.tsx +87 -0
- package/src/components/ui/SkuSelector/SkuSelector.stories.mdx +345 -0
- package/src/components/ui/SkuSelector/SkuSelector.tsx +46 -0
- package/src/components/ui/SkuSelector/index.ts +3 -0
- package/src/components/ui/SkuSelector/sku-selector.module.scss +172 -0
- package/src/components/ui/SkuSelector/skuVariants.ts +59 -0
- package/src/components/ui/SlideOver/SlideOver.stories.mdx +285 -0
- package/src/components/ui/SlideOver/SlideOver.tsx +58 -0
- package/src/components/ui/SlideOver/index.ts +1 -0
- package/src/components/ui/SlideOver/overlay.scss +14 -0
- package/src/components/ui/SlideOver/slide-over.module.scss +63 -0
- package/src/components/ui/Tiles/Tiles.stories.mdx +153 -0
- package/src/components/ui/Tiles/Tiles.tsx +14 -0
- package/src/components/ui/Tiles/index.ts +5 -0
- package/src/components/ui/Tiles/tiles.module.scss +60 -0
- package/src/components/ui/Toast/Toast.stories.mdx +158 -0
- package/src/components/ui/Toast/Toast.tsx +56 -0
- package/src/components/ui/Toast/index.ts +1 -0
- package/src/components/ui/Toast/toast.module.scss +112 -0
- package/src/components/ui/Toggle/Toggle.stories.mdx +604 -0
- package/src/components/ui/Toggle/Toggle.tsx +75 -0
- package/src/components/ui/Toggle/index.ts +2 -0
- package/src/components/ui/Toggle/toggle.module.scss +200 -0
- package/src/constants.ts +2 -0
- package/src/fonts/WebFonts.tsx +15 -0
- package/src/images/icon.png +0 -0
- package/src/pages/404.tsx +27 -0
- package/src/pages/500.tsx +31 -0
- package/src/pages/[...slug].tsx +186 -0
- package/src/pages/[slug]/p.tsx +209 -0
- package/src/pages/_app.tsx +38 -0
- package/src/pages/_document.tsx +22 -0
- package/src/pages/account.tsx +20 -0
- package/src/pages/api/graphql.ts +72 -0
- package/src/pages/api/preview.ts +61 -0
- package/src/pages/checkout.tsx +20 -0
- package/src/pages/index.tsx +72 -0
- package/src/pages/login.tsx +20 -0
- package/src/pages/s.tsx +83 -0
- package/src/sdk/analytics/hooks/useViewItemListEvent.ts +51 -0
- package/src/sdk/analytics/index.tsx +30 -0
- package/src/sdk/analytics/platform/vtex/index.ts +11 -0
- package/src/sdk/analytics/platform/vtex/search.ts +102 -0
- package/src/sdk/analytics/types.ts +22 -0
- package/src/sdk/cart/index.ts +187 -0
- package/src/sdk/cart/useBuyButton.ts +62 -0
- package/src/sdk/cart/useCartToggleButton.ts +23 -0
- package/src/sdk/cart/useCheckoutButton.ts +22 -0
- package/src/sdk/cart/useRemoveButton.ts +56 -0
- package/src/sdk/error/ErrorBoundary/ErrorBoundary.tsx +67 -0
- package/src/sdk/error/ErrorBoundary/index.ts +1 -0
- package/src/sdk/graphql/prefetchQuery.ts +20 -0
- package/src/sdk/graphql/request.ts +25 -0
- package/src/sdk/graphql/useLazyQuery.ts +29 -0
- package/src/sdk/graphql/useQuery.ts +40 -0
- package/src/sdk/newsletter/useNewsletter.ts +31 -0
- package/src/sdk/product/useDiscountPercent.ts +10 -0
- package/src/sdk/product/useFormattedPrice.ts +27 -0
- package/src/sdk/product/useProduct.ts +46 -0
- package/src/sdk/product/useProductLink.ts +69 -0
- package/src/sdk/product/useProductsQuery.ts +107 -0
- package/src/sdk/search/Sentinel.tsx +78 -0
- package/src/sdk/search/state.ts +11 -0
- package/src/sdk/search/useSearchHistory.ts +40 -0
- package/src/sdk/search/useSearchInput.tsx +43 -0
- package/src/sdk/search/useSuggestions.ts +49 -0
- package/src/sdk/search/useTopSearch.ts +49 -0
- package/src/sdk/session/index.ts +71 -0
- package/src/sdk/tests/mark.tsx +10 -0
- package/src/sdk/ui/Provider.tsx +151 -0
- package/src/sdk/ui/useFadeEffect.ts +21 -0
- package/src/sdk/ui/useOnClickOutside.ts +39 -0
- package/src/sdk/ui/useScrollDirection.ts +31 -0
- package/src/sdk/useStore.ts +24 -0
- package/src/server/cms.ts +66 -0
- package/src/server/index.ts +105 -0
- package/src/stories/brandless.stories.mdx +85 -0
- package/src/stories/changelog-template.stories.mdx +10 -0
- package/src/stories/colors.stories.mdx +306 -0
- package/src/stories/customizing.stories.mdx +113 -0
- package/src/stories/getting-started.stories.mdx +65 -0
- package/src/stories/grid-layout.stories.mdx +53 -0
- package/src/stories/icons.stories.mdx +237 -0
- package/src/stories/interactive-controls.stories.mdx +50 -0
- package/src/stories/midnight.stories.mdx +56 -0
- package/src/stories/refinements.stories.mdx +96 -0
- package/src/stories/soft-blue.stories.mdx +56 -0
- package/src/stories/spacing.stories.mdx +38 -0
- package/src/stories/typography.stories.mdx +224 -0
- package/src/styles/global/components.scss +5 -0
- package/src/styles/global/layout.scss +80 -0
- package/src/styles/global/resets.scss +48 -0
- package/src/styles/global/storybook-components.scss +5 -0
- package/src/styles/global/tokens.scss +276 -0
- package/src/styles/global/typography.scss +66 -0
- package/src/styles/global/utilities.scss +69 -0
- package/src/styles/scaffold.scss +7 -0
- package/src/styles/themes/custom-theme.scss +36 -0
- package/src/styles/themes/midnight.scss +123 -0
- package/src/styles/themes/soft-blue.scss +79 -0
- package/src/styles/vendors/include-media.scss +4 -0
- package/src/styles/vendors/include-media_overwrite.scss +9 -0
- package/src/styles/vendors/modern-normalize.css +270 -0
- package/src/typings/global.d.ts +6 -0
- package/src/typings/module.css.d.ts +7 -0
- package/store.config.js +69 -0
- package/stylelint.config.js +82 -0
- package/tsconfig.json +25 -0
- package/vtex.env +14 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import '../styles/global/tokens.scss'
|
|
2
|
+
import '../styles/global/resets.scss'
|
|
3
|
+
import '../styles/global/typography.scss'
|
|
4
|
+
import '../styles/global/layout.scss'
|
|
5
|
+
import '../styles/global/components.scss'
|
|
6
|
+
|
|
7
|
+
// Replace this with your theme style file
|
|
8
|
+
import '../styles/themes/custom-theme.scss'
|
|
9
|
+
|
|
10
|
+
import NextNProgress from 'nextjs-progressbar'
|
|
11
|
+
import type { AppProps } from 'next/app'
|
|
12
|
+
|
|
13
|
+
import Layout from 'src/Layout'
|
|
14
|
+
import AnalyticsHandler from 'src/sdk/analytics'
|
|
15
|
+
import ErrorBoundary from 'src/sdk/error/ErrorBoundary'
|
|
16
|
+
import UIProvider from 'src/sdk/ui/Provider'
|
|
17
|
+
|
|
18
|
+
function App({ Component, pageProps }: AppProps) {
|
|
19
|
+
return (
|
|
20
|
+
<ErrorBoundary>
|
|
21
|
+
<NextNProgress
|
|
22
|
+
color="var(--fs-color-primary-bkg);"
|
|
23
|
+
showOnShallow={false}
|
|
24
|
+
options={{ showSpinner: false }}
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
<AnalyticsHandler />
|
|
28
|
+
|
|
29
|
+
<UIProvider>
|
|
30
|
+
<Layout>
|
|
31
|
+
<Component {...pageProps} />
|
|
32
|
+
</Layout>
|
|
33
|
+
</UIProvider>
|
|
34
|
+
</ErrorBoundary>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default App
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Head, Html, Main, NextScript } from 'next/document'
|
|
2
|
+
|
|
3
|
+
import WebFonts from 'src/fonts/WebFonts'
|
|
4
|
+
import ThirdPartyScripts from 'src/components/ThirdPartyScripts'
|
|
5
|
+
import storeConfig from 'store.config'
|
|
6
|
+
|
|
7
|
+
function Document() {
|
|
8
|
+
return (
|
|
9
|
+
<Html>
|
|
10
|
+
<Head>
|
|
11
|
+
{!process.env.DISABLE_3P_SCRIPTS && <ThirdPartyScripts />}
|
|
12
|
+
<WebFonts />
|
|
13
|
+
</Head>
|
|
14
|
+
<body className={storeConfig.theme}>
|
|
15
|
+
<Main />
|
|
16
|
+
<NextScript />
|
|
17
|
+
</body>
|
|
18
|
+
</Html>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default Document
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { NextSeo } from 'next-seo'
|
|
3
|
+
|
|
4
|
+
import storeConfig from '../../store.config'
|
|
5
|
+
|
|
6
|
+
function Page() {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
window.location.href = storeConfig.accountUrl
|
|
9
|
+
}, [])
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<NextSeo noindex nofollow />
|
|
14
|
+
|
|
15
|
+
<div>loading...</div>
|
|
16
|
+
</>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Page
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { isFastStoreError, stringifyCacheControl } from '@faststore/api'
|
|
2
|
+
import type { NextApiHandler, NextApiRequest } from 'next'
|
|
3
|
+
|
|
4
|
+
import { execute } from '../../server'
|
|
5
|
+
|
|
6
|
+
const parseRequest = (request: NextApiRequest) => {
|
|
7
|
+
const { operationName, variables, query } =
|
|
8
|
+
request.method === 'POST'
|
|
9
|
+
? request.body
|
|
10
|
+
: {
|
|
11
|
+
operationName: request.query.operationName,
|
|
12
|
+
variables: JSON.parse(
|
|
13
|
+
typeof request.query.variables === 'string'
|
|
14
|
+
? request.query.variables
|
|
15
|
+
: ''
|
|
16
|
+
),
|
|
17
|
+
query: undefined,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
operationName,
|
|
22
|
+
variables,
|
|
23
|
+
// Do not allow queries in production, only for devMode so we can use graphql tools
|
|
24
|
+
// like introspection etc. In production, we only accept known queries for better
|
|
25
|
+
// security
|
|
26
|
+
query: process.env.NODE_ENV !== 'production' ? query : undefined,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const handler: NextApiHandler = async (request, response) => {
|
|
31
|
+
if (request.method !== 'POST' && request.method !== 'GET') {
|
|
32
|
+
response.status(405)
|
|
33
|
+
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { operationName, variables, query } = parseRequest(request)
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const { data, errors, extensions } = await execute(
|
|
41
|
+
{
|
|
42
|
+
operationName,
|
|
43
|
+
variables,
|
|
44
|
+
query,
|
|
45
|
+
},
|
|
46
|
+
{ headers: request.headers }
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const hasErrors = Array.isArray(errors)
|
|
50
|
+
|
|
51
|
+
if (hasErrors) {
|
|
52
|
+
const error = errors.find(isFastStoreError)
|
|
53
|
+
|
|
54
|
+
response.status(error?.extensions.status ?? 500)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const cacheControl =
|
|
58
|
+
!hasErrors && extensions.cacheControl
|
|
59
|
+
? stringifyCacheControl(extensions.cacheControl)
|
|
60
|
+
: 'no-cache, no-store'
|
|
61
|
+
|
|
62
|
+
response.setHeader('cache-control', cacheControl)
|
|
63
|
+
response.setHeader('content-type', 'application/json')
|
|
64
|
+
response.send(JSON.stringify({ data, errors }))
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.error(err)
|
|
67
|
+
|
|
68
|
+
response.status(500)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default handler
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { NextApiHandler, NextApiRequest } from 'next'
|
|
2
|
+
|
|
3
|
+
import { clientCMS } from 'src/server/cms'
|
|
4
|
+
|
|
5
|
+
class StatusError extends Error {
|
|
6
|
+
constructor(message: string, public status: number) {
|
|
7
|
+
super(message)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const pickParam = (req: NextApiRequest, parameter: string) => {
|
|
12
|
+
const maybeParam = req.query[parameter]
|
|
13
|
+
|
|
14
|
+
if (typeof maybeParam !== 'string') {
|
|
15
|
+
throw new StatusError(
|
|
16
|
+
`Parameter ${parameter} missing from querystring`,
|
|
17
|
+
400
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return maybeParam
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// TODO: Improve security by disabling CMS preview in production
|
|
25
|
+
const handler: NextApiHandler = async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const locator = {
|
|
28
|
+
contentType: pickParam(req, 'contentType'),
|
|
29
|
+
documentId: pickParam(req, 'documentId'),
|
|
30
|
+
versionId: pickParam(req, 'versionId'),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Fetch CMS to check if the provided `locator` exists
|
|
34
|
+
const page = await clientCMS.getCMSPage(locator)
|
|
35
|
+
|
|
36
|
+
// If the content doesn't exist prevent preview mode from being enabled
|
|
37
|
+
if (!page) {
|
|
38
|
+
throw new StatusError(
|
|
39
|
+
`Content NotFound for ${JSON.stringify(locator, null, 2)}`,
|
|
40
|
+
404
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Enable Preview Mode by setting the cookies
|
|
45
|
+
res.setPreviewData(locator, { maxAge: 3600 })
|
|
46
|
+
|
|
47
|
+
// Redirect to the path from the fetched locator
|
|
48
|
+
// TODO: apply redirect based on the content
|
|
49
|
+
res.redirect('/')
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error instanceof StatusError) {
|
|
52
|
+
res.status(error.status).end(error.message)
|
|
53
|
+
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
throw error
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default handler
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { NextSeo } from 'next-seo'
|
|
3
|
+
|
|
4
|
+
import storeConfig from '../../store.config'
|
|
5
|
+
|
|
6
|
+
function Page() {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
window.location.href = storeConfig.checkoutUrl
|
|
9
|
+
}, [])
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<NextSeo noindex nofollow />
|
|
14
|
+
|
|
15
|
+
<div>loading...</div>
|
|
16
|
+
</>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Page
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { NextSeo, SiteLinksSearchBoxJsonLd } from 'next-seo'
|
|
2
|
+
import type { GetStaticProps } from 'next'
|
|
3
|
+
import type { Locator } from '@vtex/client-cms'
|
|
4
|
+
|
|
5
|
+
import RenderPageSections from 'src/components/cms/RenderPageSections'
|
|
6
|
+
import type { PageContentType } from 'src/server/cms'
|
|
7
|
+
import { getPage } from 'src/server/cms'
|
|
8
|
+
import { mark } from 'src/sdk/tests/mark'
|
|
9
|
+
|
|
10
|
+
import storeConfig from '../../store.config'
|
|
11
|
+
|
|
12
|
+
type Props = PageContentType
|
|
13
|
+
|
|
14
|
+
function Page({ sections, settings }: Props) {
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{/* SEO */}
|
|
18
|
+
<NextSeo
|
|
19
|
+
title={settings.seo.title}
|
|
20
|
+
description={settings.seo.description}
|
|
21
|
+
titleTemplate={storeConfig.seo.titleTemplate}
|
|
22
|
+
canonical={settings.seo.canonical ?? storeConfig.storeUrl}
|
|
23
|
+
openGraph={{
|
|
24
|
+
type: 'website',
|
|
25
|
+
url: storeConfig.storeUrl,
|
|
26
|
+
title: settings.seo.title,
|
|
27
|
+
description: settings.seo.description,
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
<SiteLinksSearchBoxJsonLd
|
|
31
|
+
url={storeConfig.storeUrl}
|
|
32
|
+
potentialActions={[
|
|
33
|
+
{
|
|
34
|
+
target: `${storeConfig.storeUrl}/s/?q={search_term_string}`,
|
|
35
|
+
queryInput: 'required name=search_term_string',
|
|
36
|
+
},
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
{/*
|
|
41
|
+
WARNING: Do not import or render components from any
|
|
42
|
+
other folder than '../components/sections' in here.
|
|
43
|
+
|
|
44
|
+
This is necessary to keep the integration with the CMS
|
|
45
|
+
easy and consistent, enabling the change and reorder
|
|
46
|
+
of elements on this page.
|
|
47
|
+
|
|
48
|
+
If needed, wrap your component in a <Section /> component
|
|
49
|
+
(not the HTML tag) before rendering it here.
|
|
50
|
+
*/}
|
|
51
|
+
<RenderPageSections sections={sections} />
|
|
52
|
+
</>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const getStaticProps: GetStaticProps<
|
|
57
|
+
Props,
|
|
58
|
+
Record<string, string>,
|
|
59
|
+
Locator
|
|
60
|
+
> = async (context) => {
|
|
61
|
+
const page = await getPage<PageContentType>({
|
|
62
|
+
...(context.previewData ?? { filters: { 'settings.seo.slug': '/' } }),
|
|
63
|
+
contentType: 'page',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
props: page,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Page.displayName = 'Page'
|
|
72
|
+
export default mark(Page)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { NextSeo } from 'next-seo'
|
|
3
|
+
|
|
4
|
+
import storeConfig from '../../store.config'
|
|
5
|
+
|
|
6
|
+
function Page() {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
window.location.href = storeConfig.loginUrl
|
|
9
|
+
}, [])
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<NextSeo noindex nofollow />
|
|
14
|
+
|
|
15
|
+
<div>loading...</div>
|
|
16
|
+
</>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Page
|
package/src/pages/s.tsx
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { parseSearchState, SearchProvider } from '@faststore/sdk'
|
|
2
|
+
import { NextSeo } from 'next-seo'
|
|
3
|
+
import { useRouter } from 'next/router'
|
|
4
|
+
import { useEffect, useState } from 'react'
|
|
5
|
+
import type { SearchState } from '@faststore/sdk'
|
|
6
|
+
|
|
7
|
+
import Breadcrumb from 'src/components/sections/Breadcrumb'
|
|
8
|
+
import ProductGallery from 'src/components/sections/ProductGallery'
|
|
9
|
+
import SROnly from 'src/components/ui/SROnly'
|
|
10
|
+
import { ITEMS_PER_PAGE } from 'src/constants'
|
|
11
|
+
import { useApplySearchState } from 'src/sdk/search/state'
|
|
12
|
+
import { mark } from 'src/sdk/tests/mark'
|
|
13
|
+
|
|
14
|
+
import storeConfig from '../../store.config'
|
|
15
|
+
|
|
16
|
+
const useSearchParams = () => {
|
|
17
|
+
const [params, setParams] = useState<SearchState | null>(null)
|
|
18
|
+
const { asPath } = useRouter()
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const url = new URL(asPath, 'http://localhost')
|
|
22
|
+
|
|
23
|
+
setParams(parseSearchState(url))
|
|
24
|
+
}, [asPath])
|
|
25
|
+
|
|
26
|
+
return params
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function Page() {
|
|
30
|
+
const searchParams = useSearchParams()
|
|
31
|
+
const applySearchState = useApplySearchState()
|
|
32
|
+
const title = 'Search Results'
|
|
33
|
+
const { description, titleTemplate } = storeConfig.seo
|
|
34
|
+
|
|
35
|
+
if (!searchParams) {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<SearchProvider
|
|
41
|
+
onChange={applySearchState}
|
|
42
|
+
itemsPerPage={ITEMS_PER_PAGE}
|
|
43
|
+
{...searchParams}
|
|
44
|
+
>
|
|
45
|
+
{/* SEO */}
|
|
46
|
+
<NextSeo
|
|
47
|
+
noindex
|
|
48
|
+
title={title}
|
|
49
|
+
description={description}
|
|
50
|
+
titleTemplate={titleTemplate}
|
|
51
|
+
openGraph={{
|
|
52
|
+
type: 'website',
|
|
53
|
+
title,
|
|
54
|
+
description,
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
<SROnly as="h1" text={title} />
|
|
59
|
+
|
|
60
|
+
{/*
|
|
61
|
+
WARNING: Do not import or render components from any
|
|
62
|
+
other folder than '../components/sections' in here.
|
|
63
|
+
|
|
64
|
+
This is necessary to keep the integration with the CMS
|
|
65
|
+
easy and consistent, enabling the change and reorder
|
|
66
|
+
of elements on this page.
|
|
67
|
+
|
|
68
|
+
If needed, wrap your component in a <Section /> component
|
|
69
|
+
(not the HTML tag) before rendering it here.
|
|
70
|
+
*/}
|
|
71
|
+
<Breadcrumb name="All Products" />
|
|
72
|
+
|
|
73
|
+
<ProductGallery
|
|
74
|
+
title="Search Results"
|
|
75
|
+
searchTerm={searchParams.term ?? undefined}
|
|
76
|
+
/>
|
|
77
|
+
</SearchProvider>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Page.displayName = 'Page'
|
|
82
|
+
|
|
83
|
+
export default mark(Page)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { sendAnalyticsEvent } from '@faststore/sdk'
|
|
2
|
+
import { useCallback } from 'react'
|
|
3
|
+
import type { CurrencyCode, ViewItemListEvent } from '@faststore/sdk'
|
|
4
|
+
|
|
5
|
+
import { useSession } from 'src/sdk/session'
|
|
6
|
+
import type { ProductSummary_ProductFragment } from '@generated/graphql'
|
|
7
|
+
|
|
8
|
+
import type { AnalyticsItem } from '../types'
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
products: Array<{ node: ProductSummary_ProductFragment }>
|
|
12
|
+
title: string
|
|
13
|
+
page: number
|
|
14
|
+
pageSize: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useViewItemListEvent = ({
|
|
18
|
+
products,
|
|
19
|
+
title,
|
|
20
|
+
page,
|
|
21
|
+
pageSize,
|
|
22
|
+
}: Props) => {
|
|
23
|
+
const {
|
|
24
|
+
currency: { code },
|
|
25
|
+
} = useSession()
|
|
26
|
+
|
|
27
|
+
const sendViewItemListEvent = useCallback(() => {
|
|
28
|
+
sendAnalyticsEvent<ViewItemListEvent<AnalyticsItem>>({
|
|
29
|
+
name: 'view_item_list',
|
|
30
|
+
params: {
|
|
31
|
+
item_list_name: title,
|
|
32
|
+
item_list_id: title,
|
|
33
|
+
items: products.map(({ node: product }, index) => ({
|
|
34
|
+
item_id: product.isVariantOf.productGroupID,
|
|
35
|
+
item_name: product.isVariantOf.name,
|
|
36
|
+
item_brand: product.brand.name,
|
|
37
|
+
item_variant: product.sku,
|
|
38
|
+
price: product.offers.offers[0].price,
|
|
39
|
+
index: page * pageSize + index + 1,
|
|
40
|
+
discount:
|
|
41
|
+
product.offers.offers[0].listPrice - product.offers.offers[0].price,
|
|
42
|
+
currency: code as CurrencyCode,
|
|
43
|
+
item_variant_name: product.name,
|
|
44
|
+
product_reference_id: product.gtin,
|
|
45
|
+
})),
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
}, [code, products, title, page, pageSize])
|
|
49
|
+
|
|
50
|
+
return { sendViewItemListEvent }
|
|
51
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AnalyticsEvent } from '@faststore/sdk'
|
|
2
|
+
import { useAnalyticsEvent } from '@faststore/sdk'
|
|
3
|
+
|
|
4
|
+
import storeConfig from '../../../store.config'
|
|
5
|
+
|
|
6
|
+
if (typeof window !== 'undefined') {
|
|
7
|
+
window.dataLayer = window.dataLayer ?? []
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const AnalyticsHandler = () => {
|
|
11
|
+
useAnalyticsEvent((event: AnalyticsEvent) => {
|
|
12
|
+
// Cleans the ecommerce object before pushing a new one
|
|
13
|
+
// This prevents the new data from getting merged with the previous one
|
|
14
|
+
// which could lead do inaccurate and old data being sent with events
|
|
15
|
+
//
|
|
16
|
+
// source: https://developers.google.com/tag-manager/ecommerce-ga4?hl=pt-br#clearing_the_ecommerce_object
|
|
17
|
+
window.dataLayer.push({ ecommerce: null })
|
|
18
|
+
window.dataLayer.push({ event: event.name, ecommerce: event.params })
|
|
19
|
+
|
|
20
|
+
import(`./platform/${storeConfig.platform}`).then(
|
|
21
|
+
({ default: sendEvent }) => {
|
|
22
|
+
sendEvent(event)
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default AnalyticsHandler
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AnalyticsEvent } from '@faststore/sdk'
|
|
2
|
+
|
|
3
|
+
import handleSearchEvent from './search'
|
|
4
|
+
|
|
5
|
+
export default function sendEvent(event: AnalyticsEvent) {
|
|
6
|
+
// VTEX RC
|
|
7
|
+
window?.sendrc?.(event.name, event.params)
|
|
8
|
+
|
|
9
|
+
// VTEX Intelligent Search
|
|
10
|
+
handleSearchEvent(event)
|
|
11
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* More info at: https://www.notion.so/vtexhandbook/Event-API-Documentation-48eee26730cf4d7f80f8fd7262231f84
|
|
3
|
+
*/
|
|
4
|
+
import type { AnalyticsEvent } from '@faststore/sdk'
|
|
5
|
+
|
|
6
|
+
import config from '../../../../../store.config'
|
|
7
|
+
import type { SearchSelectItemEvent } from '../../types'
|
|
8
|
+
|
|
9
|
+
const THIRTY_MINUTES_S = 30 * 60
|
|
10
|
+
const ONE_YEAR_S = 365 * 24 * 3600
|
|
11
|
+
|
|
12
|
+
const randomUUID = () =>
|
|
13
|
+
typeof crypto.randomUUID === 'function'
|
|
14
|
+
? crypto.randomUUID()
|
|
15
|
+
: (Math.random() * 1e6).toFixed(0)
|
|
16
|
+
|
|
17
|
+
const createStorage = (key: string, expiresSecond: number) => {
|
|
18
|
+
const timelapsed = (past: number) => (Date.now() - past) / 1e3
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
const item = JSON.parse(localStorage.getItem(key) ?? 'null')
|
|
22
|
+
const isExpired = !item || timelapsed(item.createdAt) > expiresSecond
|
|
23
|
+
const payload: string = isExpired ? randomUUID() : item.payload
|
|
24
|
+
|
|
25
|
+
if (isExpired) {
|
|
26
|
+
const data = { payload, createdAt: Date.now() }
|
|
27
|
+
|
|
28
|
+
localStorage.setItem(key, JSON.stringify(data))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return payload
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const user = {
|
|
36
|
+
anonymous: createStorage('vtex.search.anonymous', ONE_YEAR_S),
|
|
37
|
+
session: createStorage('vtex.search.session', THIRTY_MINUTES_S),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type SearchEvent =
|
|
41
|
+
| {
|
|
42
|
+
type: 'session.ping'
|
|
43
|
+
}
|
|
44
|
+
| {
|
|
45
|
+
position: number
|
|
46
|
+
productId: string
|
|
47
|
+
text: string
|
|
48
|
+
url: string
|
|
49
|
+
type: 'search.click'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sendEvent = (options: SearchEvent & { url?: string }) =>
|
|
53
|
+
fetch(`https://sp.vtex.com/event-api/v1/${config.api.storeId}/event`, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
...options,
|
|
57
|
+
userAgent: navigator.userAgent,
|
|
58
|
+
anonymous: user.anonymous(),
|
|
59
|
+
session: user.session(),
|
|
60
|
+
}),
|
|
61
|
+
headers: {
|
|
62
|
+
'content-type': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const isFullTextSearch = (url: URL) =>
|
|
67
|
+
typeof url.searchParams.get('q') === 'string' &&
|
|
68
|
+
/^\/s(\/)?$/g.test(url.pathname)
|
|
69
|
+
|
|
70
|
+
const handleEvent = (event: AnalyticsEvent | SearchSelectItemEvent) => {
|
|
71
|
+
if (event.name !== 'search_select_item') {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const url = new URL(event.params.url)
|
|
76
|
+
|
|
77
|
+
if (!isFullTextSearch(url)) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for (const item of event.params.items ?? []) {
|
|
82
|
+
const productId = item.item_id ?? item.item_variant
|
|
83
|
+
const position = item.index
|
|
84
|
+
|
|
85
|
+
if (productId && position) {
|
|
86
|
+
sendEvent({
|
|
87
|
+
type: 'search.click',
|
|
88
|
+
productId,
|
|
89
|
+
position,
|
|
90
|
+
url: url.href,
|
|
91
|
+
text: url.searchParams.get('q') ?? '<empty>',
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setInterval(
|
|
98
|
+
() => sendEvent({ type: 'session.ping' }),
|
|
99
|
+
60 * 1e3 /* One minute */
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
export default handleEvent
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Item } from '@faststore/sdk'
|
|
2
|
+
|
|
3
|
+
type AdditionalItemProperties = {
|
|
4
|
+
product_reference_id: string | null
|
|
5
|
+
item_variant_name: string | null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type AnalyticsItem = Item & AdditionalItemProperties
|
|
9
|
+
|
|
10
|
+
export interface SearchSelectItemParams {
|
|
11
|
+
url: string
|
|
12
|
+
items: Array<{
|
|
13
|
+
item_id?: string
|
|
14
|
+
item_variant?: string
|
|
15
|
+
index: number
|
|
16
|
+
}>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SearchSelectItemEvent {
|
|
20
|
+
name: 'search_select_item'
|
|
21
|
+
params: SearchSelectItemParams
|
|
22
|
+
}
|