@fayz-ai/storefront 0.9.0 → 0.11.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/README.md +3 -3
- package/dist/app/createStorefrontApp.d.ts +65 -0
- package/dist/app/createStorefrontApp.d.ts.map +1 -0
- package/dist/{define.d.ts → app/define.d.ts} +3 -3
- package/dist/app/define.d.ts.map +1 -0
- package/dist/app/hydration.d.ts +37 -0
- package/dist/app/hydration.d.ts.map +1 -0
- package/dist/app/prerender.d.ts +57 -0
- package/dist/app/prerender.d.ts.map +1 -0
- package/dist/{router.d.ts → app/router.d.ts} +140 -113
- package/dist/app/router.d.ts.map +1 -0
- package/dist/{scaffold.d.ts → app/scaffold.d.ts} +2 -2
- package/dist/app/scaffold.d.ts.map +1 -0
- package/dist/app/serving.d.ts +70 -0
- package/dist/app/serving.d.ts.map +1 -0
- package/dist/app/static-render.d.ts +46 -0
- package/dist/app/static-render.d.ts.map +1 -0
- package/dist/blocks/block-at-path.d.ts +59 -0
- package/dist/blocks/block-at-path.d.ts.map +1 -0
- package/dist/blocks/page-blocks.d.ts +163 -0
- package/dist/blocks/page-blocks.d.ts.map +1 -0
- package/dist/blocks/page-data.d.ts +105 -0
- package/dist/blocks/page-data.d.ts.map +1 -0
- package/dist/{blocks.d.ts → blocks/registry.d.ts} +1 -1
- package/dist/blocks/registry.d.ts.map +1 -0
- package/dist/{sections.d.ts → blocks/sections.d.ts} +40 -2
- package/dist/blocks/sections.d.ts.map +1 -0
- package/dist/chunk-6IXTENLB.js +162 -0
- package/dist/chunk-6IXTENLB.js.map +1 -0
- package/dist/chunk-SX3J3QIT.js +11046 -0
- package/dist/chunk-SX3J3QIT.js.map +1 -0
- package/dist/components/PaymentTerms.d.ts +34 -0
- package/dist/components/PaymentTerms.d.ts.map +1 -0
- package/dist/components/Skeleton.d.ts +17 -0
- package/dist/components/Skeleton.d.ts.map +1 -0
- package/dist/components/SmoothImage.d.ts +1 -1
- package/dist/components/SmoothImage.d.ts.map +1 -1
- package/dist/components/account/CustomerAccountShell.d.ts +17 -0
- package/dist/components/account/CustomerAccountShell.d.ts.map +1 -0
- package/dist/components/account/SignInModal.d.ts.map +1 -0
- package/dist/components/account/section.d.ts +15 -0
- package/dist/components/account/section.d.ts.map +1 -0
- package/dist/components/cart/CartDrawer.d.ts.map +1 -0
- package/dist/components/cart/QuantityInput.d.ts.map +1 -0
- package/dist/components/checkout/CheckoutPayment.d.ts +17 -0
- package/dist/components/checkout/CheckoutPayment.d.ts.map +1 -0
- package/dist/components/checkout/CheckoutSteps.d.ts +9 -0
- package/dist/components/checkout/CheckoutSteps.d.ts.map +1 -0
- package/dist/components/checkout/DeliveryEstimator.d.ts.map +1 -0
- package/dist/components/collection/CategoryShowcase.d.ts +44 -0
- package/dist/components/collection/CategoryShowcase.d.ts.map +1 -0
- package/dist/components/collection/FiltersPanel.d.ts +19 -0
- package/dist/components/collection/FiltersPanel.d.ts.map +1 -0
- package/dist/components/collection/ProductGrid.d.ts.map +1 -0
- package/dist/components/layout/PageBodyBlocks.d.ts +40 -0
- package/dist/components/layout/PageBodyBlocks.d.ts.map +1 -0
- package/dist/components/layout/SearchOverlay.d.ts +13 -0
- package/dist/components/layout/SearchOverlay.d.ts.map +1 -0
- package/dist/components/layout/StorefrontErrorBoundary.d.ts.map +1 -0
- package/dist/components/layout/StorefrontFooter.d.ts.map +1 -0
- package/dist/components/layout/StorefrontHeader.d.ts.map +1 -0
- package/dist/components/layout/Toaster.d.ts.map +1 -0
- package/dist/components/marketing/CollectionSections.d.ts +463 -0
- package/dist/components/marketing/CollectionSections.d.ts.map +1 -0
- package/dist/components/marketing/ConversionSections.d.ts +221 -0
- package/dist/components/marketing/ConversionSections.d.ts.map +1 -0
- package/dist/components/marketing/EditorialSections.d.ts +248 -0
- package/dist/components/marketing/EditorialSections.d.ts.map +1 -0
- package/dist/components/marketing/EntityList.d.ts +97 -0
- package/dist/components/marketing/EntityList.d.ts.map +1 -0
- package/dist/components/marketing/FormBlock.d.ts +167 -0
- package/dist/components/marketing/FormBlock.d.ts.map +1 -0
- package/dist/components/marketing/HeroSection.d.ts +125 -0
- package/dist/components/marketing/HeroSection.d.ts.map +1 -0
- package/dist/components/marketing/MediaCarousel.d.ts +135 -0
- package/dist/components/marketing/MediaCarousel.d.ts.map +1 -0
- package/dist/components/marketing/MiscSections.d.ts +252 -0
- package/dist/components/marketing/MiscSections.d.ts.map +1 -0
- package/dist/components/order/OrderTrackingTimeline.d.ts.map +1 -0
- package/dist/components/order/SuccessMark.d.ts +10 -0
- package/dist/components/order/SuccessMark.d.ts.map +1 -0
- package/dist/components/product/ProductCard.d.ts +14 -0
- package/dist/components/product/ProductCard.d.ts.map +1 -0
- package/dist/components/product/ProductEnquiryForm.d.ts.map +1 -0
- package/dist/components/product/ProductGallery.d.ts +36 -0
- package/dist/components/product/ProductGallery.d.ts.map +1 -0
- package/dist/components/{ProductOptionSelector.d.ts → product/ProductOptionSelector.d.ts} +1 -1
- package/dist/components/product/ProductOptionSelector.d.ts.map +1 -0
- package/dist/components/product/ProductRail.d.ts +93 -0
- package/dist/components/product/ProductRail.d.ts.map +1 -0
- package/dist/components/product/ProductReviews.d.ts +39 -0
- package/dist/components/product/ProductReviews.d.ts.map +1 -0
- package/dist/components/product/ProductSlider.d.ts +169 -0
- package/dist/components/product/ProductSlider.d.ts.map +1 -0
- package/dist/components/product/ProductSpecs.d.ts.map +1 -0
- package/dist/components/product/RelatedProducts.d.ts.map +1 -0
- package/dist/{auth.d.ts → data/auth.d.ts} +9 -0
- package/dist/data/auth.d.ts.map +1 -0
- package/dist/data/facets.d.ts +39 -0
- package/dist/data/facets.d.ts.map +1 -0
- package/dist/data/loaders.d.ts +52 -0
- package/dist/data/loaders.d.ts.map +1 -0
- package/dist/data/local-orders.d.ts +5 -0
- package/dist/data/local-orders.d.ts.map +1 -0
- package/dist/data/order-status.d.ts.map +1 -0
- package/dist/data/product-options.d.ts +36 -0
- package/dist/data/product-options.d.ts.map +1 -0
- package/dist/data/shipping-items.d.ts +20 -0
- package/dist/data/shipping-items.d.ts.map +1 -0
- package/dist/diagnostics/seo-audit.d.ts +54 -0
- package/dist/diagnostics/seo-audit.d.ts.map +1 -0
- package/dist/diagnostics/seo-audit.js +3 -0
- package/dist/diagnostics/seo-audit.js.map +1 -0
- package/dist/document/change.d.ts +100 -0
- package/dist/document/change.d.ts.map +1 -0
- package/dist/document/config.d.ts +311 -0
- package/dist/document/config.d.ts.map +1 -0
- package/dist/document/describe.d.ts +135 -0
- package/dist/document/describe.d.ts.map +1 -0
- package/dist/document/overlay.d.ts +58 -0
- package/dist/document/overlay.d.ts.map +1 -0
- package/dist/{presets.d.ts → document/presets.d.ts} +2 -2
- package/dist/document/presets.d.ts.map +1 -0
- package/dist/document/render.d.ts +171 -0
- package/dist/document/render.d.ts.map +1 -0
- package/dist/document/round-trip.d.ts +46 -0
- package/dist/document/round-trip.d.ts.map +1 -0
- package/dist/document/sections.d.ts +194 -0
- package/dist/document/sections.d.ts.map +1 -0
- package/dist/document/store-policy.d.ts +29 -0
- package/dist/document/store-policy.d.ts.map +1 -0
- package/dist/document/upgrade.d.ts +112 -0
- package/dist/document/upgrade.d.ts.map +1 -0
- package/dist/document/validate.d.ts +24 -0
- package/dist/document/validate.d.ts.map +1 -0
- package/dist/{component-contracts.d.ts → extend/component-contracts.d.ts} +74 -22
- package/dist/extend/component-contracts.d.ts.map +1 -0
- package/dist/extend/component-override.d.ts +38 -0
- package/dist/extend/component-override.d.ts.map +1 -0
- package/dist/extend/component-selectors.d.ts.map +1 -0
- package/dist/extend/editor-bridge.d.ts +59 -0
- package/dist/extend/editor-bridge.d.ts.map +1 -0
- package/dist/extend/extension-points.d.ts +103 -0
- package/dist/extend/extension-points.d.ts.map +1 -0
- package/dist/extend/slots.d.ts +216 -0
- package/dist/extend/slots.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +25 -6
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/use-address.d.ts +26 -0
- package/dist/hooks/use-address.d.ts.map +1 -0
- package/dist/hooks/use-cart.d.ts +3 -0
- package/dist/hooks/use-cart.d.ts.map +1 -0
- package/dist/hooks/use-catalog.d.ts +24 -0
- package/dist/hooks/use-catalog.d.ts.map +1 -0
- package/dist/hooks/use-categories.d.ts +19 -0
- package/dist/hooks/use-categories.d.ts.map +1 -0
- package/dist/hooks/use-checkout.d.ts +41 -0
- package/dist/hooks/use-checkout.d.ts.map +1 -0
- package/dist/hooks/use-discount-validator.d.ts +20 -0
- package/dist/hooks/use-discount-validator.d.ts.map +1 -0
- package/dist/hooks/use-enquiry.d.ts +7 -0
- package/dist/hooks/use-enquiry.d.ts.map +1 -0
- package/dist/hooks/{useMyOrders.d.ts → use-my-orders.d.ts} +1 -1
- package/dist/hooks/use-my-orders.d.ts.map +1 -0
- package/dist/hooks/use-order.d.ts +17 -0
- package/dist/hooks/use-order.d.ts.map +1 -0
- package/dist/hooks/use-payment-methods.d.ts +19 -0
- package/dist/hooks/use-payment-methods.d.ts.map +1 -0
- package/dist/hooks/use-policies.d.ts +25 -0
- package/dist/hooks/use-policies.d.ts.map +1 -0
- package/dist/hooks/use-product.d.ts +15 -0
- package/dist/hooks/use-product.d.ts.map +1 -0
- package/dist/hooks/{useProducts.d.ts → use-products.d.ts} +1 -1
- package/dist/hooks/use-products.d.ts.map +1 -0
- package/dist/hooks/use-region.d.ts +15 -0
- package/dist/hooks/use-region.d.ts.map +1 -0
- package/dist/hooks/use-shipping.d.ts +32 -0
- package/dist/hooks/use-shipping.d.ts.map +1 -0
- package/dist/hooks/use-storefront-actions.d.ts +12 -0
- package/dist/hooks/use-storefront-actions.d.ts.map +1 -0
- package/dist/hooks/use-storefront-head.d.ts +19 -0
- package/dist/hooks/use-storefront-head.d.ts.map +1 -0
- package/dist/hooks/use-storefront.d.ts +3 -0
- package/dist/hooks/use-storefront.d.ts.map +1 -0
- package/dist/index.d.ts +124 -54
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1310 -5010
- package/dist/index.js.map +1 -1
- package/dist/lib/errors.d.ts +9 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/motion.d.ts.map +1 -0
- package/dist/lib/seo.d.ts +26 -0
- package/dist/lib/seo.d.ts.map +1 -0
- package/dist/{testids.d.ts → lib/testids.d.ts} +33 -0
- package/dist/lib/testids.d.ts.map +1 -0
- package/dist/{theme.d.ts → lib/theme.d.ts} +41 -3
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +359 -0
- package/dist/render.js.map +1 -0
- package/dist/stores/cart.store.d.ts +34 -2
- package/dist/stores/cart.store.d.ts.map +1 -1
- package/dist/stores/catalog.store.d.ts +11 -0
- package/dist/stores/catalog.store.d.ts.map +1 -1
- package/dist/stores/delivery.store.d.ts +9 -0
- package/dist/stores/delivery.store.d.ts.map +1 -1
- package/dist/views/CatalogPage.d.ts.map +1 -0
- package/dist/views/CheckoutPage.d.ts.map +1 -0
- package/dist/views/ContentPage.d.ts +11 -0
- package/dist/views/ContentPage.d.ts.map +1 -0
- package/dist/views/HomePage.d.ts +9 -0
- package/dist/views/HomePage.d.ts.map +1 -0
- package/dist/views/MyPurchasesPage.d.ts.map +1 -0
- package/dist/views/NotFoundPage.d.ts.map +1 -0
- package/dist/views/OrderConfirmationPage.d.ts.map +1 -0
- package/dist/{pages → views}/PolicyPage.d.ts.map +1 -1
- package/dist/views/ProductDetailPage.d.ts.map +1 -0
- package/dist/views/StorefrontPage.d.ts +35 -0
- package/dist/views/StorefrontPage.d.ts.map +1 -0
- package/dist/workflows/checkout.d.ts +1 -1
- package/dist/workflows/checkout.d.ts.map +1 -1
- package/package.json +21 -14
- package/dist/auth.d.ts.map +0 -1
- package/dist/blocks.d.ts.map +0 -1
- package/dist/component-contracts.d.ts.map +0 -1
- package/dist/component-selectors.d.ts.map +0 -1
- package/dist/components/CartDrawer.d.ts.map +0 -1
- package/dist/components/CustomerAccountShell.d.ts +0 -13
- package/dist/components/CustomerAccountShell.d.ts.map +0 -1
- package/dist/components/DeliveryEstimator.d.ts.map +0 -1
- package/dist/components/FiltersPanel.d.ts +0 -3
- package/dist/components/FiltersPanel.d.ts.map +0 -1
- package/dist/components/OrderTrackingTimeline.d.ts.map +0 -1
- package/dist/components/ProductCard.d.ts +0 -4
- package/dist/components/ProductCard.d.ts.map +0 -1
- package/dist/components/ProductEnquiryForm.d.ts.map +0 -1
- package/dist/components/ProductGallery.d.ts +0 -22
- package/dist/components/ProductGallery.d.ts.map +0 -1
- package/dist/components/ProductGrid.d.ts.map +0 -1
- package/dist/components/ProductOptionSelector.d.ts.map +0 -1
- package/dist/components/ProductSpecs.d.ts.map +0 -1
- package/dist/components/QuantityInput.d.ts.map +0 -1
- package/dist/components/RelatedProducts.d.ts.map +0 -1
- package/dist/components/SignInModal.d.ts.map +0 -1
- package/dist/components/StorefrontErrorBoundary.d.ts.map +0 -1
- package/dist/components/StorefrontFooter.d.ts.map +0 -1
- package/dist/components/StorefrontHeader.d.ts.map +0 -1
- package/dist/components/Toaster.d.ts.map +0 -1
- package/dist/components/sections/CategoryShowcase.d.ts +0 -6
- package/dist/components/sections/CategoryShowcase.d.ts.map +0 -1
- package/dist/components/sections/HeroSection.d.ts +0 -9
- package/dist/components/sections/HeroSection.d.ts.map +0 -1
- package/dist/components/sections/MediaCarousel.d.ts +0 -11
- package/dist/components/sections/MediaCarousel.d.ts.map +0 -1
- package/dist/components/sections/MiscSections.d.ts +0 -33
- package/dist/components/sections/MiscSections.d.ts.map +0 -1
- package/dist/components/sections/ProductRail.d.ts +0 -9
- package/dist/components/sections/ProductRail.d.ts.map +0 -1
- package/dist/components/sections/ProductSlider.d.ts +0 -15
- package/dist/components/sections/ProductSlider.d.ts.map +0 -1
- package/dist/config.d.ts +0 -174
- package/dist/config.d.ts.map +0 -1
- package/dist/createStorefrontApp.d.ts +0 -28
- package/dist/createStorefrontApp.d.ts.map +0 -1
- package/dist/define.d.ts.map +0 -1
- package/dist/format.d.ts.map +0 -1
- package/dist/hooks/useCategories.d.ts +0 -6
- package/dist/hooks/useCategories.d.ts.map +0 -1
- package/dist/hooks/useDiscountValidator.d.ts +0 -14
- package/dist/hooks/useDiscountValidator.d.ts.map +0 -1
- package/dist/hooks/useMyOrders.d.ts.map +0 -1
- package/dist/hooks/useProduct.d.ts +0 -7
- package/dist/hooks/useProduct.d.ts.map +0 -1
- package/dist/hooks/useProducts.d.ts.map +0 -1
- package/dist/hooks/useStorefront.d.ts +0 -35
- package/dist/hooks/useStorefront.d.ts.map +0 -1
- package/dist/hooks/useStorefrontHead.d.ts +0 -11
- package/dist/hooks/useStorefrontHead.d.ts.map +0 -1
- package/dist/motion.d.ts.map +0 -1
- package/dist/order-status.d.ts.map +0 -1
- package/dist/pages/CatalogPage.d.ts.map +0 -1
- package/dist/pages/CheckoutPage.d.ts.map +0 -1
- package/dist/pages/HomePage.d.ts +0 -9
- package/dist/pages/HomePage.d.ts.map +0 -1
- package/dist/pages/MyPurchasesPage.d.ts.map +0 -1
- package/dist/pages/NotFoundPage.d.ts.map +0 -1
- package/dist/pages/OrderConfirmationPage.d.ts.map +0 -1
- package/dist/pages/ProductDetailPage.d.ts.map +0 -1
- package/dist/presets.d.ts.map +0 -1
- package/dist/product-options.d.ts +0 -12
- package/dist/product-options.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/sections.d.ts.map +0 -1
- package/dist/testids.d.ts.map +0 -1
- package/dist/theme.d.ts.map +0 -1
- package/src/auth.ts +0 -227
- package/src/blocks.tsx +0 -51
- package/src/catalog.ts +0 -3
- package/src/component-contracts.ts +0 -154
- package/src/component-selectors.ts +0 -31
- package/src/components/CartDrawer.tsx +0 -279
- package/src/components/CustomerAccountShell.tsx +0 -102
- package/src/components/DeliveryEstimator.tsx +0 -157
- package/src/components/FiltersPanel.tsx +0 -109
- package/src/components/OrderTrackingTimeline.tsx +0 -135
- package/src/components/Price.tsx +0 -32
- package/src/components/ProductCard.tsx +0 -120
- package/src/components/ProductEnquiryForm.tsx +0 -175
- package/src/components/ProductGallery.tsx +0 -174
- package/src/components/ProductGrid.tsx +0 -43
- package/src/components/ProductOptionSelector.tsx +0 -50
- package/src/components/ProductSpecs.tsx +0 -75
- package/src/components/QuantityInput.tsx +0 -52
- package/src/components/RelatedProducts.tsx +0 -40
- package/src/components/SignInModal.tsx +0 -120
- package/src/components/SmoothImage.tsx +0 -59
- package/src/components/StorefrontErrorBoundary.tsx +0 -51
- package/src/components/StorefrontFooter.tsx +0 -110
- package/src/components/StorefrontHeader.tsx +0 -477
- package/src/components/Toaster.tsx +0 -60
- package/src/components/sections/CategoryShowcase.tsx +0 -80
- package/src/components/sections/HeroSection.tsx +0 -193
- package/src/components/sections/MediaCarousel.tsx +0 -141
- package/src/components/sections/MiscSections.tsx +0 -158
- package/src/components/sections/ProductRail.tsx +0 -81
- package/src/components/sections/ProductSlider.tsx +0 -119
- package/src/config.ts +0 -229
- package/src/createStorefrontApp.tsx +0 -247
- package/src/define.ts +0 -34
- package/src/format.ts +0 -7
- package/src/hooks/index.ts +0 -6
- package/src/hooks/useCategories.ts +0 -26
- package/src/hooks/useDiscountValidator.ts +0 -43
- package/src/hooks/useMyOrders.ts +0 -41
- package/src/hooks/useProduct.ts +0 -36
- package/src/hooks/useProducts.ts +0 -39
- package/src/hooks/useStorefront.ts +0 -58
- package/src/hooks/useStorefrontHead.ts +0 -25
- package/src/index.ts +0 -202
- package/src/motion.tsx +0 -94
- package/src/order-status.ts +0 -33
- package/src/pages/CatalogPage.tsx +0 -118
- package/src/pages/CheckoutPage.tsx +0 -689
- package/src/pages/HomePage.tsx +0 -16
- package/src/pages/MyPurchasesPage.tsx +0 -311
- package/src/pages/NotFoundPage.tsx +0 -25
- package/src/pages/OrderConfirmationPage.tsx +0 -190
- package/src/pages/PolicyPage.tsx +0 -47
- package/src/pages/ProductDetailPage.tsx +0 -264
- package/src/presets.ts +0 -324
- package/src/product-options.ts +0 -63
- package/src/router.ts +0 -49
- package/src/scaffold.tsx +0 -115
- package/src/sections.ts +0 -116
- package/src/shop.ts +0 -4
- package/src/stores/cart.store.ts +0 -185
- package/src/stores/catalog.store.ts +0 -39
- package/src/stores/delivery.store.ts +0 -152
- package/src/stores/session.store.ts +0 -28
- package/src/stores/toast.store.ts +0 -43
- package/src/testids.ts +0 -136
- package/src/theme.ts +0 -194
- package/src/ui.ts +0 -5
- package/src/workflows/checkout.ts +0 -119
- /package/dist/components/{SignInModal.d.ts → account/SignInModal.d.ts} +0 -0
- /package/dist/components/{CartDrawer.d.ts → cart/CartDrawer.d.ts} +0 -0
- /package/dist/components/{QuantityInput.d.ts → cart/QuantityInput.d.ts} +0 -0
- /package/dist/components/{DeliveryEstimator.d.ts → checkout/DeliveryEstimator.d.ts} +0 -0
- /package/dist/components/{ProductGrid.d.ts → collection/ProductGrid.d.ts} +0 -0
- /package/dist/components/{StorefrontErrorBoundary.d.ts → layout/StorefrontErrorBoundary.d.ts} +0 -0
- /package/dist/components/{StorefrontFooter.d.ts → layout/StorefrontFooter.d.ts} +0 -0
- /package/dist/components/{StorefrontHeader.d.ts → layout/StorefrontHeader.d.ts} +0 -0
- /package/dist/components/{Toaster.d.ts → layout/Toaster.d.ts} +0 -0
- /package/dist/components/{OrderTrackingTimeline.d.ts → order/OrderTrackingTimeline.d.ts} +0 -0
- /package/dist/components/{ProductEnquiryForm.d.ts → product/ProductEnquiryForm.d.ts} +0 -0
- /package/dist/components/{ProductSpecs.d.ts → product/ProductSpecs.d.ts} +0 -0
- /package/dist/components/{RelatedProducts.d.ts → product/RelatedProducts.d.ts} +0 -0
- /package/dist/{order-status.d.ts → data/order-status.d.ts} +0 -0
- /package/dist/{component-selectors.d.ts → extend/component-selectors.d.ts} +0 -0
- /package/dist/{format.d.ts → lib/format.d.ts} +0 -0
- /package/dist/{motion.d.ts → lib/motion.d.ts} +0 -0
- /package/dist/{pages → views}/CatalogPage.d.ts +0 -0
- /package/dist/{pages → views}/CheckoutPage.d.ts +0 -0
- /package/dist/{pages → views}/MyPurchasesPage.d.ts +0 -0
- /package/dist/{pages → views}/NotFoundPage.d.ts +0 -0
- /package/dist/{pages → views}/OrderConfirmationPage.d.ts +0 -0
- /package/dist/{pages → views}/PolicyPage.d.ts +0 -0
- /package/dist/{pages → views}/ProductDetailPage.d.ts +0 -0
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
2
|
-
import { X, Trash2 } from 'lucide-react'
|
|
3
|
-
import {
|
|
4
|
-
useCartStore,
|
|
5
|
-
selectSubtotal,
|
|
6
|
-
selectDiscountTotal,
|
|
7
|
-
selectShipping,
|
|
8
|
-
selectTotal,
|
|
9
|
-
} from '../stores/cart.store'
|
|
10
|
-
import { useDiscountValidator } from '../hooks/useDiscountValidator'
|
|
11
|
-
import { toast } from '../stores/toast.store'
|
|
12
|
-
import { getStorefrontComponents, useStorefrontConfig } from '../config'
|
|
13
|
-
import { navigateTo } from '../router'
|
|
14
|
-
import { formatMoney } from '../format'
|
|
15
|
-
import { QuantityInput } from './QuantityInput'
|
|
16
|
-
import { formatPostalCode } from '@fayz-ai/core'
|
|
17
|
-
import { useDeliveryStore } from '../stores/delivery.store'
|
|
18
|
-
import { DeliveryEstimator } from './DeliveryEstimator'
|
|
19
|
-
import { TID } from '../testids'
|
|
20
|
-
import { SmoothImage } from './SmoothImage'
|
|
21
|
-
|
|
22
|
-
export function CartDrawer() {
|
|
23
|
-
const config = useStorefrontConfig()
|
|
24
|
-
const cart = useCartStore()
|
|
25
|
-
const components = getStorefrontComponents(config)
|
|
26
|
-
const FooterExtra = components.CartDrawerFooterExtra
|
|
27
|
-
const validate = useDiscountValidator()
|
|
28
|
-
const [code, setCode] = useState('')
|
|
29
|
-
const [discountError, setDiscountError] = useState<string | null>(null)
|
|
30
|
-
const [applying, setApplying] = useState(false)
|
|
31
|
-
|
|
32
|
-
// a11y: close on Escape while the drawer is open.
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
if (!cart.isOpen) return
|
|
35
|
-
const onKey = (e: KeyboardEvent) => {
|
|
36
|
-
if (e.key === 'Escape') cart.closeDrawer()
|
|
37
|
-
}
|
|
38
|
-
document.addEventListener('keydown', onKey)
|
|
39
|
-
return () => document.removeEventListener('keydown', onKey)
|
|
40
|
-
}, [cart.isOpen, cart.closeDrawer])
|
|
41
|
-
|
|
42
|
-
// Subscribed, not just read: selectShipping consults this store through
|
|
43
|
-
// getState(), which does not subscribe, so without this hook a fresh quote
|
|
44
|
-
// would change the price and leave the drawer showing the old one.
|
|
45
|
-
const delivery = useDeliveryStore()
|
|
46
|
-
|
|
47
|
-
const subtotal = selectSubtotal(cart)
|
|
48
|
-
const discountTotal = selectDiscountTotal(cart)
|
|
49
|
-
const shipping = selectShipping(cart, config)
|
|
50
|
-
|
|
51
|
-
const total = selectTotal(cart, config)
|
|
52
|
-
const money = (v: number) => formatMoney(v, config.currency, config.locale)
|
|
53
|
-
|
|
54
|
-
async function applyCode() {
|
|
55
|
-
setApplying(true)
|
|
56
|
-
setDiscountError(null)
|
|
57
|
-
try {
|
|
58
|
-
const result = await validate(code)
|
|
59
|
-
if (result.valid) {
|
|
60
|
-
const applied = code.trim().toUpperCase()
|
|
61
|
-
cart.applyDiscount(applied, result.percent)
|
|
62
|
-
setCode('')
|
|
63
|
-
toast.success('Cupom aplicado!', `${applied} • ${result.percent}% de desconto`)
|
|
64
|
-
} else {
|
|
65
|
-
setDiscountError(result.message ?? 'Cupom inválido.')
|
|
66
|
-
toast.error('Cupom inválido', result.message ?? 'Verifique o código e tente novamente.')
|
|
67
|
-
}
|
|
68
|
-
} finally {
|
|
69
|
-
setApplying(false)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!cart.isOpen) return null
|
|
74
|
-
|
|
75
|
-
// Free-shipping nudge: how far from the threshold this cart is
|
|
76
|
-
const freeAbove = config.shipping.freeAbove
|
|
77
|
-
const missingForFree = freeAbove != null && subtotal < freeAbove ? freeAbove - subtotal : 0
|
|
78
|
-
const progress = freeAbove != null ? Math.min(100, (subtotal / freeAbove) * 100) : 0
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<div className="fixed inset-0 z-50">
|
|
82
|
-
<div
|
|
83
|
-
className="absolute inset-0 animate-fade-in bg-black/40"
|
|
84
|
-
aria-hidden
|
|
85
|
-
onClick={cart.closeDrawer}
|
|
86
|
-
/>
|
|
87
|
-
<div
|
|
88
|
-
data-testid={TID.cartDrawer}
|
|
89
|
-
role="dialog"
|
|
90
|
-
aria-label="Carrinho"
|
|
91
|
-
className="absolute right-0 top-0 flex h-full w-full max-w-md animate-slide-in-from-right flex-col bg-background shadow-2xl"
|
|
92
|
-
>
|
|
93
|
-
<div className="flex items-center justify-between border-b px-5 py-4">
|
|
94
|
-
<h2 className="text-lg font-semibold">Carrinho</h2>
|
|
95
|
-
<button
|
|
96
|
-
type="button"
|
|
97
|
-
aria-label="Fechar carrinho"
|
|
98
|
-
onClick={cart.closeDrawer}
|
|
99
|
-
className="rounded-full p-1.5 hover:bg-muted"
|
|
100
|
-
>
|
|
101
|
-
<X className="h-5 w-5" />
|
|
102
|
-
</button>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
{cart.lines.length === 0 ? (
|
|
106
|
-
<div data-testid={TID.cartEmpty} className="flex flex-1 items-center justify-center p-8 text-center text-muted-foreground">
|
|
107
|
-
Seu carrinho está vazio.
|
|
108
|
-
</div>
|
|
109
|
-
) : (
|
|
110
|
-
<>
|
|
111
|
-
{freeAbove != null && (
|
|
112
|
-
<div data-testid={TID.shippingProgress} className="border-b bg-muted/40 px-5 py-3">
|
|
113
|
-
<p className="text-xs font-medium">
|
|
114
|
-
{missingForFree > 0 ? (
|
|
115
|
-
<>Faltam <strong>{money(missingForFree)}</strong> para frete grátis 🚚</>
|
|
116
|
-
) : (
|
|
117
|
-
<>🎉 Você ganhou <strong>frete grátis</strong>!</>
|
|
118
|
-
)}
|
|
119
|
-
</p>
|
|
120
|
-
<div className="mt-2 h-1.5 overflow-hidden rounded-full bg-border">
|
|
121
|
-
<div
|
|
122
|
-
className="h-full rounded-full bg-primary transition-all duration-500 ease-out"
|
|
123
|
-
style={{ width: `${progress}%` }}
|
|
124
|
-
/>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
<div className="flex-1 space-y-4 overflow-y-auto px-5 py-4">
|
|
129
|
-
{cart.lines.map((line) => (
|
|
130
|
-
<div
|
|
131
|
-
key={line.lineId ?? line.productId}
|
|
132
|
-
data-testid={TID.cartLine}
|
|
133
|
-
data-product-id={line.productId}
|
|
134
|
-
data-line-id={line.lineId ?? line.productId}
|
|
135
|
-
className={`flex animate-fade-up gap-3 rounded-lg p-1.5 transition-all hover:bg-muted/40 ${
|
|
136
|
-
(line.lineId ?? line.productId) === cart.justAddedLineId
|
|
137
|
-
? 'bg-primary/5 ring-1 ring-primary/30'
|
|
138
|
-
: ''
|
|
139
|
-
}`}
|
|
140
|
-
>
|
|
141
|
-
{line.imageUrl && (
|
|
142
|
-
<SmoothImage src={line.imageUrl} alt={line.name} className="h-20 w-20 shrink-0 rounded-lg border object-cover" />
|
|
143
|
-
)}
|
|
144
|
-
<div className="flex flex-1 flex-col">
|
|
145
|
-
<div className="flex items-start justify-between gap-2">
|
|
146
|
-
<span className="text-sm font-medium leading-snug">{line.name}</span>
|
|
147
|
-
<button
|
|
148
|
-
type="button"
|
|
149
|
-
data-testid={TID.lineRemove}
|
|
150
|
-
aria-label={`Remover ${line.name}`}
|
|
151
|
-
onClick={() => cart.removeItem(line.lineId ?? line.productId)}
|
|
152
|
-
className="text-muted-foreground hover:text-destructive"
|
|
153
|
-
>
|
|
154
|
-
<Trash2 className="h-4 w-4" />
|
|
155
|
-
</button>
|
|
156
|
-
</div>
|
|
157
|
-
<span className="text-xs text-muted-foreground">{line.sku}</span>
|
|
158
|
-
{line.optionsLabel && (
|
|
159
|
-
<span className="text-xs text-muted-foreground">{line.optionsLabel}</span>
|
|
160
|
-
)}
|
|
161
|
-
<div className="mt-auto flex items-center justify-between pt-2">
|
|
162
|
-
<QuantityInput
|
|
163
|
-
value={line.quantity}
|
|
164
|
-
max={line.maxQuantity || undefined}
|
|
165
|
-
onChange={(n) => cart.setQuantity(line.lineId ?? line.productId, n)}
|
|
166
|
-
testId={TID.lineQty}
|
|
167
|
-
incTestId={TID.lineInc}
|
|
168
|
-
decTestId={TID.lineDec}
|
|
169
|
-
/>
|
|
170
|
-
<span
|
|
171
|
-
className="text-sm font-semibold"
|
|
172
|
-
data-price={(line.unitPrice * line.quantity).toFixed(2)}
|
|
173
|
-
>
|
|
174
|
-
{money(line.unitPrice * line.quantity)}
|
|
175
|
-
</span>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
))}
|
|
180
|
-
</div>
|
|
181
|
-
|
|
182
|
-
<div className="space-y-3 border-t px-5 py-4">
|
|
183
|
-
{config.features.discounts && (
|
|
184
|
-
<div className="space-y-1">
|
|
185
|
-
<div className="flex gap-2">
|
|
186
|
-
<input
|
|
187
|
-
data-testid={TID.discountInput}
|
|
188
|
-
type="text"
|
|
189
|
-
placeholder="Cupom de desconto"
|
|
190
|
-
value={code}
|
|
191
|
-
onChange={(e) => setCode(e.target.value)}
|
|
192
|
-
className="flex-1 rounded-lg border bg-background px-3 py-2 text-sm uppercase"
|
|
193
|
-
/>
|
|
194
|
-
<button
|
|
195
|
-
type="button"
|
|
196
|
-
data-testid={TID.discountApply}
|
|
197
|
-
onClick={applyCode}
|
|
198
|
-
disabled={applying || !code.trim()}
|
|
199
|
-
className="rounded-lg border px-3 py-2 text-sm font-medium hover:bg-muted disabled:opacity-50"
|
|
200
|
-
>
|
|
201
|
-
Aplicar
|
|
202
|
-
</button>
|
|
203
|
-
</div>
|
|
204
|
-
{discountError && (
|
|
205
|
-
<p data-testid={TID.discountError} className="text-xs text-destructive">
|
|
206
|
-
{discountError}
|
|
207
|
-
</p>
|
|
208
|
-
)}
|
|
209
|
-
</div>
|
|
210
|
-
)}
|
|
211
|
-
|
|
212
|
-
{/* Second chance to give a CEP for anyone who added to cart from
|
|
213
|
-
the catalogue and never opened a product page. */}
|
|
214
|
-
<div className="mb-3">
|
|
215
|
-
<DeliveryEstimator compact />
|
|
216
|
-
</div>
|
|
217
|
-
|
|
218
|
-
<dl className="space-y-1.5 text-sm">
|
|
219
|
-
<div className="flex justify-between">
|
|
220
|
-
<dt className="text-muted-foreground">Subtotal</dt>
|
|
221
|
-
<dd data-testid={TID.cartSubtotal} data-price={subtotal.toFixed(2)}>{money(subtotal)}</dd>
|
|
222
|
-
</div>
|
|
223
|
-
{discountTotal > 0 && (
|
|
224
|
-
<div className="flex justify-between text-emerald-700" data-testid={TID.discountRow}>
|
|
225
|
-
<dt>
|
|
226
|
-
Desconto{' '}
|
|
227
|
-
<button
|
|
228
|
-
type="button"
|
|
229
|
-
onClick={cart.clearDiscount}
|
|
230
|
-
className="text-xs text-muted-foreground underline"
|
|
231
|
-
>
|
|
232
|
-
({cart.discountCode} ✕)
|
|
233
|
-
</button>
|
|
234
|
-
</dt>
|
|
235
|
-
<dd data-price={discountTotal.toFixed(2)}>−{money(discountTotal)}</dd>
|
|
236
|
-
</div>
|
|
237
|
-
)}
|
|
238
|
-
<div className="flex justify-between">
|
|
239
|
-
<dt className="text-muted-foreground">
|
|
240
|
-
Frete
|
|
241
|
-
{delivery.status === 'served' && delivery.postalCode && (
|
|
242
|
-
<span className="ml-1 text-xs">
|
|
243
|
-
· {formatPostalCode(delivery.postalCode)}
|
|
244
|
-
</span>
|
|
245
|
-
)}
|
|
246
|
-
</dt>
|
|
247
|
-
<dd data-testid={TID.cartShipping} data-price={shipping.toFixed(2)}>
|
|
248
|
-
{shipping === 0 ? 'Grátis' : money(shipping)}
|
|
249
|
-
</dd>
|
|
250
|
-
</div>
|
|
251
|
-
<div className="flex justify-between border-t pt-2 text-base font-semibold">
|
|
252
|
-
<dt>Total</dt>
|
|
253
|
-
<dd data-testid={TID.cartTotal} data-price={total.toFixed(2)}>{money(total)}</dd>
|
|
254
|
-
</div>
|
|
255
|
-
</dl>
|
|
256
|
-
|
|
257
|
-
<button
|
|
258
|
-
type="button"
|
|
259
|
-
data-testid={TID.goCheckout}
|
|
260
|
-
onClick={() => {
|
|
261
|
-
cart.closeDrawer()
|
|
262
|
-
navigateTo('/checkout')
|
|
263
|
-
}}
|
|
264
|
-
className="sf-cta w-full bg-primary py-3.5 font-semibold text-primary-foreground shadow-md transition-all hover:-translate-y-0.5 hover:shadow-lg"
|
|
265
|
-
style={{ borderRadius: 'var(--sf-radius-button)' }}
|
|
266
|
-
>
|
|
267
|
-
Finalizar compra
|
|
268
|
-
</button>
|
|
269
|
-
|
|
270
|
-
{FooterExtra && (
|
|
271
|
-
<FooterExtra cart={cart} config={config} commerceMode={config.commerceMode} />
|
|
272
|
-
)}
|
|
273
|
-
</div>
|
|
274
|
-
</>
|
|
275
|
-
)}
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
)
|
|
279
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { CreditCard, LogOut, MapPin, Package, ShieldCheck, User } from 'lucide-react'
|
|
3
|
-
import { signOutCustomer } from '../auth'
|
|
4
|
-
import { useStorefrontConfig } from '../config'
|
|
5
|
-
import { Link } from '../router'
|
|
6
|
-
import { useSessionStore } from '../stores/session.store'
|
|
7
|
-
import { TID } from '../testids'
|
|
8
|
-
|
|
9
|
-
export type AccountSection = 'profile' | 'orders' | 'addresses' | 'payments'
|
|
10
|
-
|
|
11
|
-
interface CustomerAccountShellProps {
|
|
12
|
-
title: string
|
|
13
|
-
subtitle?: string
|
|
14
|
-
active: AccountSection
|
|
15
|
-
/** Switch the active section in-place. */
|
|
16
|
-
onSelect?: (section: AccountSection) => void
|
|
17
|
-
children: React.ReactNode
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const menuItems = [
|
|
21
|
-
{ id: 'profile', label: 'Perfil', icon: User },
|
|
22
|
-
{ id: 'orders', label: 'Meus pedidos', icon: Package },
|
|
23
|
-
{ id: 'addresses', label: 'Endereços', icon: MapPin },
|
|
24
|
-
{ id: 'payments', label: 'Pagamentos', icon: CreditCard },
|
|
25
|
-
] as const
|
|
26
|
-
|
|
27
|
-
export function CustomerAccountShell({ title, subtitle, active, onSelect, children }: CustomerAccountShellProps) {
|
|
28
|
-
const config = useStorefrontConfig()
|
|
29
|
-
const session = useSessionStore()
|
|
30
|
-
const displayName = session.name || session.email?.split('@')[0] || 'Cliente'
|
|
31
|
-
const displayEmail = session.email || 'Conta criada no checkout'
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<main data-testid={TID.customerAccountShell} className="mx-auto max-w-6xl px-4 py-8 sm:px-6">
|
|
35
|
-
<div className="mb-6 flex flex-wrap items-center justify-between gap-4">
|
|
36
|
-
<div>
|
|
37
|
-
<p className="text-sm font-medium text-muted-foreground">{config.name}</p>
|
|
38
|
-
<h1 className="sf-heading text-3xl font-bold tracking-tight">{title}</h1>
|
|
39
|
-
{subtitle && <p className="mt-1 text-sm text-muted-foreground">{subtitle}</p>}
|
|
40
|
-
</div>
|
|
41
|
-
<Link to={config.catalogPath} className="rounded-lg border px-4 py-2 text-sm font-semibold hover:bg-muted">
|
|
42
|
-
Voltar à loja
|
|
43
|
-
</Link>
|
|
44
|
-
</div>
|
|
45
|
-
|
|
46
|
-
<div className="grid gap-6 lg:grid-cols-[260px_minmax(0,1fr)]">
|
|
47
|
-
<aside className="h-fit rounded-xl border bg-card p-4">
|
|
48
|
-
<div className="flex items-center gap-3 border-b pb-4">
|
|
49
|
-
<div className="flex h-11 w-11 items-center justify-center rounded-full bg-primary/10 font-bold text-primary">
|
|
50
|
-
{displayName.slice(0, 1).toUpperCase()}
|
|
51
|
-
</div>
|
|
52
|
-
<div className="min-w-0">
|
|
53
|
-
<p className="truncate font-semibold">{displayName}</p>
|
|
54
|
-
<p className="truncate text-xs text-muted-foreground">{displayEmail}</p>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<nav data-testid={TID.customerAccountMenu} className="mt-4 space-y-1" aria-label="Área do cliente">
|
|
59
|
-
{menuItems.map((item) => {
|
|
60
|
-
const Icon = item.icon
|
|
61
|
-
const selected = item.id === active
|
|
62
|
-
return (
|
|
63
|
-
<button
|
|
64
|
-
key={item.id}
|
|
65
|
-
type="button"
|
|
66
|
-
aria-current={selected ? 'page' : undefined}
|
|
67
|
-
onClick={() => onSelect?.(item.id)}
|
|
68
|
-
className={`flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-semibold transition ${
|
|
69
|
-
selected ? 'bg-primary/10 text-primary' : 'text-muted-foreground hover:bg-muted hover:text-foreground'
|
|
70
|
-
}`}
|
|
71
|
-
>
|
|
72
|
-
<Icon className="h-4 w-4" />
|
|
73
|
-
{item.label}
|
|
74
|
-
</button>
|
|
75
|
-
)
|
|
76
|
-
})}
|
|
77
|
-
</nav>
|
|
78
|
-
|
|
79
|
-
<div className="mt-4 rounded-lg bg-muted/40 p-3 text-xs text-muted-foreground">
|
|
80
|
-
<div className="flex items-center gap-2 font-semibold text-foreground">
|
|
81
|
-
<ShieldCheck className="h-4 w-4 text-primary" />
|
|
82
|
-
Conta protegida
|
|
83
|
-
</div>
|
|
84
|
-
<p className="mt-1">Pedidos, pagamentos e endereços ficam organizados para próximas compras.</p>
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
<button
|
|
88
|
-
type="button"
|
|
89
|
-
data-testid={TID.signout}
|
|
90
|
-
onClick={() => void signOutCustomer()}
|
|
91
|
-
className="mt-4 flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-semibold text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
92
|
-
>
|
|
93
|
-
<LogOut className="h-4 w-4" />
|
|
94
|
-
Sair
|
|
95
|
-
</button>
|
|
96
|
-
</aside>
|
|
97
|
-
|
|
98
|
-
<section className="min-w-0">{children}</section>
|
|
99
|
-
</div>
|
|
100
|
-
</main>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
2
|
-
import { MapPin, Truck } from 'lucide-react'
|
|
3
|
-
import { formatPostalCode } from '@fayz-ai/core'
|
|
4
|
-
import { useDeliveryStore, resolveOptionRate } from '../stores/delivery.store'
|
|
5
|
-
import { useCartStore, selectSubtotal } from '../stores/cart.store'
|
|
6
|
-
import { useStorefrontConfig } from '../config'
|
|
7
|
-
import { formatMoney } from '../format'
|
|
8
|
-
import { TID } from '../testids'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* "Do you deliver to me, for how much, and when" — asked on the product page,
|
|
12
|
-
* before the shopper has invested anything in a cart.
|
|
13
|
-
*
|
|
14
|
-
* The CEP is kept in the delivery store, so the answer follows them to the cart
|
|
15
|
-
* and lands at checkout with street/district/city/UF already filled. That is
|
|
16
|
-
* the actual payoff: the buyer types a house number instead of an address.
|
|
17
|
-
*
|
|
18
|
-
* `subtotal` is the PRE-discount cart subtotal, the same number shop_place_order
|
|
19
|
-
* uses to resolve free-above thresholds. Quoting against anything else is how
|
|
20
|
-
* the cart and the order end up disagreeing (see migration 0017).
|
|
21
|
-
*/
|
|
22
|
-
export function DeliveryEstimator({ compact = false }: { compact?: boolean }) {
|
|
23
|
-
const config = useStorefrontConfig()
|
|
24
|
-
const cart = useCartStore()
|
|
25
|
-
const delivery = useDeliveryStore()
|
|
26
|
-
const [draft, setDraft] = useState(() => formatPostalCode(delivery.postalCode))
|
|
27
|
-
|
|
28
|
-
const subtotal = selectSubtotal(cart)
|
|
29
|
-
const money = (value: number) => formatMoney(value, config.currency, config.locale)
|
|
30
|
-
const loading = delivery.status === 'loading'
|
|
31
|
-
|
|
32
|
-
async function submit(event: React.FormEvent) {
|
|
33
|
-
event.preventDefault()
|
|
34
|
-
await delivery.resolve(draft, subtotal)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function eta(option: { etaMinDays?: number; etaMaxDays?: number }): string | null {
|
|
38
|
-
const { etaMinDays: min, etaMaxDays: max } = option
|
|
39
|
-
if (min == null && max == null) return null
|
|
40
|
-
if (min === 0 && (max === 0 || max === 1)) return 'hoje ou amanhã'
|
|
41
|
-
if (min != null && max != null && min !== max) return `${min} a ${max} dias úteis`
|
|
42
|
-
return `${max ?? min} dia(s) útil(eis)`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<section
|
|
47
|
-
data-testid={TID.deliveryEstimator}
|
|
48
|
-
className={compact ? 'rounded-lg border p-3' : 'mt-6 rounded-lg border p-4'}
|
|
49
|
-
>
|
|
50
|
-
<div className="flex items-center gap-2 text-sm font-semibold">
|
|
51
|
-
<Truck className="h-4 w-4 text-primary" />
|
|
52
|
-
Calcular entrega
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<form onSubmit={submit} className="mt-3 flex gap-2">
|
|
56
|
-
<input
|
|
57
|
-
data-testid={TID.deliveryCepInput}
|
|
58
|
-
aria-label="CEP"
|
|
59
|
-
inputMode="numeric"
|
|
60
|
-
autoComplete="postal-code"
|
|
61
|
-
placeholder="00000-000"
|
|
62
|
-
value={draft}
|
|
63
|
-
onChange={(event) => setDraft(formatPostalCode(event.target.value))}
|
|
64
|
-
className="min-w-0 flex-1 rounded-lg border bg-background px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
|
|
65
|
-
/>
|
|
66
|
-
<button
|
|
67
|
-
type="submit"
|
|
68
|
-
data-testid={TID.deliveryCepSubmit}
|
|
69
|
-
disabled={loading}
|
|
70
|
-
className="shrink-0 rounded-lg bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground transition hover:opacity-90 disabled:opacity-50"
|
|
71
|
-
>
|
|
72
|
-
{loading ? '...' : 'Calcular'}
|
|
73
|
-
</button>
|
|
74
|
-
</form>
|
|
75
|
-
|
|
76
|
-
{/* Shown whenever there is one, including alongside a price: the range
|
|
77
|
-
may be covered even though the CEP itself was mistyped. */}
|
|
78
|
-
{delivery.error && (
|
|
79
|
-
<p data-testid={TID.deliveryError} className="mt-3 text-sm text-destructive">
|
|
80
|
-
{delivery.error}
|
|
81
|
-
</p>
|
|
82
|
-
)}
|
|
83
|
-
|
|
84
|
-
{delivery.address && (
|
|
85
|
-
<p data-testid={TID.deliveryAddress} className="mt-3 flex items-start gap-1.5 text-xs text-muted-foreground">
|
|
86
|
-
<MapPin className="mt-0.5 h-3.5 w-3.5 shrink-0" />
|
|
87
|
-
<span>
|
|
88
|
-
{[delivery.address.street, delivery.address.district].filter(Boolean).join(', ')}
|
|
89
|
-
{delivery.address.street || delivery.address.district ? ' — ' : ''}
|
|
90
|
-
{delivery.address.city}/{delivery.address.state}
|
|
91
|
-
</span>
|
|
92
|
-
</p>
|
|
93
|
-
)}
|
|
94
|
-
|
|
95
|
-
{delivery.status === 'served' && (
|
|
96
|
-
<ul className="mt-3 space-y-2">
|
|
97
|
-
{delivery.options.map((option) => {
|
|
98
|
-
const selected = delivery.selectedZoneId === option.zoneId
|
|
99
|
-
const label = eta(option)
|
|
100
|
-
// Resolved for the cart as it stands right now, not for whatever it
|
|
101
|
-
// held when the CEP was typed — the same rule the server applies.
|
|
102
|
-
const rate = resolveOptionRate(option, subtotal)
|
|
103
|
-
return (
|
|
104
|
-
<li key={option.zoneId}>
|
|
105
|
-
<button
|
|
106
|
-
type="button"
|
|
107
|
-
data-testid={TID.deliveryOption}
|
|
108
|
-
data-zone={option.zoneId}
|
|
109
|
-
data-rate={rate.toFixed(2)}
|
|
110
|
-
aria-pressed={selected}
|
|
111
|
-
onClick={() => delivery.selectZone(option.zoneId)}
|
|
112
|
-
className={`flex w-full items-center justify-between gap-3 rounded-lg border px-3 py-2 text-left text-sm transition ${
|
|
113
|
-
selected ? 'border-primary bg-primary/5' : 'border-border hover:bg-muted/40'
|
|
114
|
-
}`}
|
|
115
|
-
>
|
|
116
|
-
<span className="min-w-0">
|
|
117
|
-
<span className="block truncate font-medium">
|
|
118
|
-
{option.carrier ? `${option.carrier} · ${option.name}` : option.name}
|
|
119
|
-
</span>
|
|
120
|
-
{label && <span className="block text-xs text-muted-foreground">{label}</span>}
|
|
121
|
-
</span>
|
|
122
|
-
<span className="shrink-0 font-semibold">
|
|
123
|
-
{rate === 0 ? 'Grátis' : money(rate)}
|
|
124
|
-
</span>
|
|
125
|
-
</button>
|
|
126
|
-
</li>
|
|
127
|
-
)
|
|
128
|
-
})}
|
|
129
|
-
</ul>
|
|
130
|
-
)}
|
|
131
|
-
|
|
132
|
-
{/*
|
|
133
|
-
No options for a valid address. For a store that configured zones this
|
|
134
|
-
means "outside our delivery area" and checkout will refuse the order, so
|
|
135
|
-
it is said plainly here rather than at the end of the funnel. A store
|
|
136
|
-
with no zones at all never reaches this state — it quotes nothing and
|
|
137
|
-
keeps its flat rate.
|
|
138
|
-
*/}
|
|
139
|
-
{delivery.status === 'unserved' && (
|
|
140
|
-
<p data-testid={TID.deliveryUnserved} className="mt-3 text-sm text-destructive">
|
|
141
|
-
Ainda não entregamos nesse CEP.
|
|
142
|
-
</p>
|
|
143
|
-
)}
|
|
144
|
-
|
|
145
|
-
{delivery.postalCode && (
|
|
146
|
-
<button
|
|
147
|
-
type="button"
|
|
148
|
-
data-testid={TID.deliveryClear}
|
|
149
|
-
onClick={() => { delivery.clear(); setDraft('') }}
|
|
150
|
-
className="mt-3 text-xs text-muted-foreground underline-offset-2 hover:underline"
|
|
151
|
-
>
|
|
152
|
-
Trocar CEP
|
|
153
|
-
</button>
|
|
154
|
-
)}
|
|
155
|
-
</section>
|
|
156
|
-
)
|
|
157
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { useCatalogStore } from '../stores/catalog.store'
|
|
3
|
-
import type { CatalogSort } from '../stores/catalog.store'
|
|
4
|
-
import { useCategories } from '../hooks/useCategories'
|
|
5
|
-
import { TID } from '../testids'
|
|
6
|
-
|
|
7
|
-
export function FiltersPanel() {
|
|
8
|
-
const { categories } = useCategories()
|
|
9
|
-
const catalog = useCatalogStore()
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<aside className="w-full shrink-0 space-y-6 lg:w-56">
|
|
13
|
-
{/* Sort */}
|
|
14
|
-
<div className="space-y-2">
|
|
15
|
-
<h3 className="text-sm font-semibold">Ordenar por</h3>
|
|
16
|
-
<select
|
|
17
|
-
data-testid={TID.sortSelect}
|
|
18
|
-
value={catalog.sort}
|
|
19
|
-
onChange={(e) => catalog.setSort(e.target.value as CatalogSort)}
|
|
20
|
-
className="w-full rounded-lg border bg-background px-3 py-2 text-sm"
|
|
21
|
-
>
|
|
22
|
-
<option value="newest">Mais recentes</option>
|
|
23
|
-
<option value="price-asc">Menor preço</option>
|
|
24
|
-
<option value="price-desc">Maior preço</option>
|
|
25
|
-
<option value="name">Nome (A–Z)</option>
|
|
26
|
-
</select>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
{/* Categories */}
|
|
30
|
-
<div className="space-y-2">
|
|
31
|
-
<h3 className="text-sm font-semibold">Categorias</h3>
|
|
32
|
-
<ul className="space-y-1">
|
|
33
|
-
<li>
|
|
34
|
-
<button
|
|
35
|
-
type="button"
|
|
36
|
-
onClick={() => catalog.setCategoryId(null)}
|
|
37
|
-
className={`w-full rounded-md px-2 py-1.5 text-left text-sm transition-colors ${
|
|
38
|
-
catalog.categoryId === null ? 'bg-primary/10 font-medium text-primary' : 'hover:bg-muted'
|
|
39
|
-
}`}
|
|
40
|
-
>
|
|
41
|
-
Todas
|
|
42
|
-
</button>
|
|
43
|
-
</li>
|
|
44
|
-
{categories.map((c) => (
|
|
45
|
-
<li key={c.id}>
|
|
46
|
-
<button
|
|
47
|
-
type="button"
|
|
48
|
-
data-testid={TID.filterCategory(c.slug)}
|
|
49
|
-
onClick={() => catalog.setCategoryId(catalog.categoryId === c.id ? null : c.id)}
|
|
50
|
-
className={`w-full rounded-md px-2 py-1.5 text-left text-sm transition-colors ${
|
|
51
|
-
catalog.categoryId === c.id ? 'bg-primary/10 font-medium text-primary' : 'hover:bg-muted'
|
|
52
|
-
}`}
|
|
53
|
-
>
|
|
54
|
-
{c.name}
|
|
55
|
-
</button>
|
|
56
|
-
</li>
|
|
57
|
-
))}
|
|
58
|
-
</ul>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
{/* Price range */}
|
|
62
|
-
<div className="space-y-2">
|
|
63
|
-
<h3 className="text-sm font-semibold">Preço</h3>
|
|
64
|
-
<div className="flex items-center gap-2">
|
|
65
|
-
<input
|
|
66
|
-
data-testid={TID.filterPriceMin}
|
|
67
|
-
type="number"
|
|
68
|
-
placeholder="Mín"
|
|
69
|
-
min={0}
|
|
70
|
-
value={catalog.priceMin ?? ''}
|
|
71
|
-
onChange={(e) => catalog.setPriceMin(e.target.value === '' ? null : Number(e.target.value))}
|
|
72
|
-
className="w-full rounded-lg border bg-background px-2.5 py-1.5 text-sm"
|
|
73
|
-
/>
|
|
74
|
-
<span className="text-muted-foreground">–</span>
|
|
75
|
-
<input
|
|
76
|
-
data-testid={TID.filterPriceMax}
|
|
77
|
-
type="number"
|
|
78
|
-
placeholder="Máx"
|
|
79
|
-
min={0}
|
|
80
|
-
value={catalog.priceMax ?? ''}
|
|
81
|
-
onChange={(e) => catalog.setPriceMax(e.target.value === '' ? null : Number(e.target.value))}
|
|
82
|
-
className="w-full rounded-lg border bg-background px-2.5 py-1.5 text-sm"
|
|
83
|
-
/>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
{/* Availability */}
|
|
88
|
-
<label className="flex cursor-pointer items-center gap-2 text-sm">
|
|
89
|
-
<input
|
|
90
|
-
data-testid={TID.filterInstock}
|
|
91
|
-
type="checkbox"
|
|
92
|
-
checked={catalog.inStockOnly}
|
|
93
|
-
onChange={(e) => catalog.setInStockOnly(e.target.checked)}
|
|
94
|
-
className="h-4 w-4 rounded border"
|
|
95
|
-
/>
|
|
96
|
-
Somente em estoque
|
|
97
|
-
</label>
|
|
98
|
-
|
|
99
|
-
<button
|
|
100
|
-
type="button"
|
|
101
|
-
data-testid={TID.filtersClear}
|
|
102
|
-
onClick={() => catalog.reset()}
|
|
103
|
-
className="text-sm text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
|
|
104
|
-
>
|
|
105
|
-
Limpar filtros
|
|
106
|
-
</button>
|
|
107
|
-
</aside>
|
|
108
|
-
)
|
|
109
|
-
}
|