storefront-layouts 1.0.3 → 1.0.4
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/dist/components/auth/LoginForm.js +2 -2
- package/dist/components/auth/LoginSheet.js +2 -2
- package/dist/components/auth/login-form-core.js +3 -3
- package/dist/components/auth/login-sheet-header.js +3 -3
- package/dist/components/auth/login-sheet-registry.js +2 -2
- package/dist/components/auth/login-sheet-themes/booking-agenda.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/booking.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/clothing-minimal.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/clothing.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/electronics-grid.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/electronics.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/food-modern.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/food.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/index.js +9 -9
- package/dist/components/auth/login-sheet-themes/motivational-speaker.theme.js +1 -1
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.d.ts +2 -2
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.d.ts.map +1 -1
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.js +2 -2
- package/dist/components/auth/login-sheets/StoreLoginSheetShell.d.ts.map +1 -1
- package/dist/components/auth/login-sheets/StoreLoginSheetShell.js +6 -6
- package/dist/components/auth/use-login-submit.js +3 -3
- package/dist/components/cart/InventoryHoldCountdown.js +2 -2
- package/dist/components/categories/category-masonry-grid.js +3 -3
- package/dist/components/checkout/CheckoutFeeLines.js +1 -1
- package/dist/components/checkout/ShippingOptionsPanel.js +3 -3
- package/dist/components/learning/CertificateTemplates.js +2 -2
- package/dist/components/learning/CertificateViewer.js +3 -3
- package/dist/components/learning/MentorshipProgress.d.ts.map +1 -1
- package/dist/components/learning/MentorshipProgress.js +4 -4
- package/dist/components/product/ProductVariationSelectors.js +1 -1
- package/dist/components/rich-text/CategoryDescription.js +2 -2
- package/dist/components/rich-text/ProductDescription.js +2 -2
- package/dist/components/rich-text/RichTextExcerpt.js +1 -1
- package/dist/components/rich-text/SafeRichHtml.d.ts +8 -11
- package/dist/components/rich-text/SafeRichHtml.d.ts.map +1 -1
- package/dist/components/rich-text/SafeRichHtml.js +3 -5
- package/dist/components/shipping/ProductDeliveryInfoSection.d.ts.map +1 -1
- package/dist/components/shipping/ProductDeliveryInfoSection.js +7 -4
- package/dist/components/shipping/ShippingQuoteAddressForm.js +3 -3
- package/dist/components/ui/alert-modal.js +2 -2
- package/dist/components/ui/avatar-image.js +1 -1
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumbs.js +1 -1
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/category-tree.js +2 -2
- package/dist/components/ui/checkout-button.d.ts.map +1 -1
- package/dist/components/ui/checkout-button.js +11 -283
- package/dist/components/ui/guest-checkout-modal.js +3 -3
- package/dist/components/ui/image-skeleton.js +2 -2
- package/dist/components/ui/image-with-fallback.d.ts +3 -1
- package/dist/components/ui/image-with-fallback.d.ts.map +1 -1
- package/dist/components/ui/image-with-fallback.js +55 -139
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/limited-time-offer-badge.js +2 -2
- package/dist/components/ui/loading-skeleton-wrapper.js +1 -1
- package/dist/components/ui/modal.js +2 -2
- package/dist/components/ui/otp-input.js +1 -1
- package/dist/components/ui/out-of-stock-overlay.js +1 -1
- package/dist/components/ui/page-animate-wrapper.js +2 -2
- package/dist/components/ui/page-content-loader.js +2 -2
- package/dist/components/ui/page-loader.js +1 -1
- package/dist/components/ui/product-card.d.ts.map +1 -1
- package/dist/components/ui/product-card.js +17 -17
- package/dist/components/ui/product-rating.js +1 -1
- package/dist/components/ui/product-stock-badge.js +2 -2
- package/dist/components/ui/review-form.js +2 -2
- package/dist/components/ui/route-skeleton-loader.js +6 -6
- package/dist/components/ui/sheet.d.ts +2 -1
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet.js +4 -4
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/skeletons/index.js +5 -5
- package/dist/components/ui/skeletons/product-grid-skeleton.js +1 -1
- package/dist/components/ui/store-logos.d.ts.map +1 -1
- package/dist/components/ui/store-logos.js +4 -4
- package/dist/components/ui/toast.js +1 -1
- package/dist/components/ui/video-player.js +2 -2
- package/dist/editor/alignment-schemas/booking.js +1 -1
- package/dist/editor/alignment-schemas/clothing-minimal.js +1 -1
- package/dist/editor/alignment-schemas/index.js +20 -20
- package/dist/editor/alignment-schemas/lazy-loader.js +1 -1
- package/dist/editor/alignment-schemas/metadata.js +1 -1
- package/dist/editor/alignment-schemas/resolve-canvas-inspector-leaf.js +3 -3
- package/dist/editor/blocks/index.js +3 -3
- package/dist/editor/blocks/migrate-clothing-minimal.js +3 -3
- package/dist/editor/blocks/nav-outline-utils.js +2 -2
- package/dist/editor/blocks/registry.js +1 -1
- package/dist/editor/document/adapter.js +4 -4
- package/dist/editor/document/block-tree.js +1 -1
- package/dist/editor/document/index.js +6 -6
- package/dist/editor/document/validate.js +1 -1
- package/dist/editor/index.js +12 -12
- package/dist/editor/layout-content-loader.js +3 -3
- package/dist/editor/payaza-form/ArrayItemManager.js +2 -2
- package/dist/editor/payaza-form/EditorCanvasPreview.js +5 -5
- package/dist/editor/payaza-form/FieldRenderer.js +17 -17
- package/dist/editor/payaza-form/IframePreviewMessageBridge.js +3 -3
- package/dist/editor/payaza-form/PayazaFormEditor.js +31 -31
- package/dist/editor/payaza-form/PayazaFormEditorFullPage.js +2 -2
- package/dist/editor/payaza-form/SliderArrayEditor.js +3 -3
- package/dist/editor/payaza-form/components/ArrayField.js +1 -1
- package/dist/editor/payaza-form/components/BlockStylesInspector.js +1 -1
- package/dist/editor/payaza-form/components/BlocksField.js +9 -9
- package/dist/editor/payaza-form/components/ButtonField.js +3 -3
- package/dist/editor/payaza-form/components/CanvasGranularInspector.js +11 -11
- package/dist/editor/payaza-form/components/IconField.js +2 -2
- package/dist/editor/payaza-form/components/ImageField.js +1 -1
- package/dist/editor/payaza-form/components/NumberField.js +1 -1
- package/dist/editor/payaza-form/components/RichTextField.js +2 -2
- package/dist/editor/payaza-form/components/SectionField.js +1 -1
- package/dist/editor/payaza-form/components/SectionSchemaInspector.js +3 -3
- package/dist/editor/payaza-form/components/StarRatingField.js +2 -2
- package/dist/editor/payaza-form/components/TextField.js +1 -1
- package/dist/editor/payaza-form/data-merger.js +6 -6
- package/dist/editor/payaza-form/data-transformer.js +3 -3
- package/dist/editor/payaza-form/engine.js +1 -1
- package/dist/editor/payaza-form/examples/custom-widgets.example.js +1 -1
- package/dist/editor/payaza-form/index.js +8 -8
- package/dist/editor/payaza-form/layout-loader.js +2 -2
- package/dist/editor/payaza-form/preview-message-handler.js +3 -3
- package/dist/editor/payaza-form/schema-bridge.js +3 -3
- package/dist/editor/payaza-form/widget-registry.js +1 -1
- package/dist/editor/shared/BlockOutlineTree.js +2 -2
- package/dist/editor/shared/EditorHeader.js +2 -2
- package/dist/editor/shared/EditorNavigator.js +2 -2
- package/dist/editor/shared/IframePreview.js +6 -6
- package/dist/editor/shared/InlineCanvasPreview.js +8 -8
- package/dist/editor/shared/LayoutRenderer.js +1 -1
- package/dist/editor/shared/ResizableSidebar.js +1 -1
- package/dist/editor/shared/index.js +7 -7
- package/dist/hooks/use-analytics.js +3 -3
- package/dist/hooks/use-api.js +1 -1
- package/dist/hooks/use-cart-api.d.ts.map +1 -1
- package/dist/hooks/use-cart-api.js +8 -3
- package/dist/hooks/use-catalog-loader.js +3 -3
- package/dist/hooks/use-catalog-price-range.d.ts +2 -5
- package/dist/hooks/use-catalog-price-range.d.ts.map +1 -1
- package/dist/hooks/use-catalog-price-range.js +20 -5
- package/dist/hooks/use-category-products.d.ts +8 -0
- package/dist/hooks/use-category-products.d.ts.map +1 -0
- package/dist/hooks/use-category-products.js +43 -0
- package/dist/hooks/use-checkout-fees.d.ts +3 -4
- package/dist/hooks/use-checkout-fees.d.ts.map +1 -1
- package/dist/hooks/use-checkout-fees.js +1 -1
- package/dist/hooks/use-content-ready.js +1 -1
- package/dist/hooks/use-featured-products.d.ts +3 -0
- package/dist/hooks/use-featured-products.d.ts.map +1 -0
- package/dist/hooks/use-featured-products.js +25 -0
- package/dist/hooks/use-multi-store-checkout-fees.d.ts +3 -4
- package/dist/hooks/use-multi-store-checkout-fees.d.ts.map +1 -1
- package/dist/hooks/use-multi-store-checkout-fees.js +1 -1
- package/dist/hooks/use-navigation-loading.js +1 -1
- package/dist/hooks/use-payaza-checkout.d.ts +1 -1
- package/dist/hooks/use-payaza-checkout.d.ts.map +1 -1
- package/dist/hooks/use-payaza-checkout.js +9 -3
- package/dist/hooks/use-product-brands.d.ts +5 -0
- package/dist/hooks/use-product-brands.d.ts.map +1 -0
- package/dist/hooks/use-product-brands.js +25 -0
- package/dist/hooks/use-product-by-slug.d.ts +7 -0
- package/dist/hooks/use-product-by-slug.d.ts.map +1 -0
- package/dist/hooks/use-product-by-slug.js +38 -0
- package/dist/hooks/use-product-reviews.d.ts +15 -0
- package/dist/hooks/use-product-reviews.d.ts.map +1 -0
- package/dist/hooks/use-product-reviews.js +75 -0
- package/dist/hooks/use-product-variation-selection.d.ts +2 -8
- package/dist/hooks/use-product-variation-selection.d.ts.map +1 -1
- package/dist/hooks/use-product-variation-selection.js +1 -1
- package/dist/hooks/use-products-api.js +3 -3
- package/dist/hooks/use-shipping-quote.js +2 -2
- package/dist/hooks/use-store-api.js +4 -4
- package/dist/hooks/usePreviewSlideSync.js +1 -1
- package/dist/index.d.ts +62 -74
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +141 -153
- package/dist/layouts/booking/components/BookingHomePage.d.ts.map +1 -1
- package/dist/layouts/booking/components/BookingHomePage.js +68 -74
- package/dist/layouts/booking/components/BookingMultilineHeading.js +1 -1
- package/dist/layouts/booking/components/BookingTestimonialCard.js +2 -2
- package/dist/layouts/booking/components/BookingTestimonialsEmptyState.js +1 -1
- package/dist/layouts/booking/components/booking-footer-defaults.js +2 -2
- package/dist/layouts/booking/index.js +8 -8
- package/dist/layouts/booking/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/booking/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/AboutPage.js +39 -60
- package/dist/layouts/booking/pages/BookPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/BookPage.js +16 -22
- package/dist/layouts/booking/pages/CategoriesPage.js +6 -6
- package/dist/layouts/booking/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/booking/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/CategoryPage.js +17 -26
- package/dist/layouts/booking/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/booking/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/ContactPage.js +5 -12
- package/dist/layouts/booking/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/booking/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/ProductDetailPage.js +203 -150
- package/dist/layouts/booking/pages/ServicesPage.d.ts +1 -1
- package/dist/layouts/booking/pages/ServicesPage.d.ts.map +1 -1
- package/dist/layouts/booking/pages/ServicesPage.js +11 -31
- package/dist/layouts/booking-agenda/components/BookingHomePageAgenda.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/components/BookingHomePageAgenda.js +21 -30
- package/dist/layouts/booking-agenda/index.js +8 -8
- package/dist/layouts/booking-agenda/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/booking-agenda/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/AboutPage.js +11 -14
- package/dist/layouts/booking-agenda/pages/BookPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/BookPage.js +15 -21
- package/dist/layouts/booking-agenda/pages/CategoriesPage.js +5 -5
- package/dist/layouts/booking-agenda/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/booking-agenda/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/CategoryPage.js +12 -18
- package/dist/layouts/booking-agenda/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/booking-agenda/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/ContactPage.js +8 -13
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.js +202 -149
- package/dist/layouts/booking-agenda/pages/ServicesPage.d.ts +1 -1
- package/dist/layouts/booking-agenda/pages/ServicesPage.d.ts.map +1 -1
- package/dist/layouts/booking-agenda/pages/ServicesPage.js +8 -23
- package/dist/layouts/clothing/components/ClothingHomePage.d.ts.map +1 -1
- package/dist/layouts/clothing/components/ClothingHomePage.js +199 -136
- package/dist/layouts/clothing/index.js +7 -7
- package/dist/layouts/clothing/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/clothing/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/clothing/pages/AboutPage.js +19 -33
- package/dist/layouts/clothing/pages/CategoriesPage.js +8 -8
- package/dist/layouts/clothing/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/clothing/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/clothing/pages/CategoryPage.js +15 -41
- package/dist/layouts/clothing/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/clothing/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/clothing/pages/ContactPage.js +5 -8
- package/dist/layouts/clothing/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/clothing/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/clothing/pages/ProductDetailPage.js +256 -167
- package/dist/layouts/clothing/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/clothing/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/clothing/pages/ProductsPage.js +125 -59
- package/dist/layouts/clothing/payaza-bindings.js +2 -2
- package/dist/layouts/clothing-minimal/components/ClothingHomePageMinimal.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/components/ClothingHomePageMinimal.js +32 -131
- package/dist/layouts/clothing-minimal/components/clothing-minimal-block-render.js +8 -8
- package/dist/layouts/clothing-minimal/index.js +7 -7
- package/dist/layouts/clothing-minimal/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/clothing-minimal/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/pages/AboutPage.js +37 -61
- package/dist/layouts/clothing-minimal/pages/CategoriesPage.js +7 -7
- package/dist/layouts/clothing-minimal/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/clothing-minimal/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/pages/CategoryPage.js +13 -18
- package/dist/layouts/clothing-minimal/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/clothing-minimal/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/pages/ContactPage.js +5 -8
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.js +202 -143
- package/dist/layouts/clothing-minimal/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/clothing-minimal/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/clothing-minimal/pages/ProductsPage.js +126 -57
- package/dist/layouts/electronics/components/ElectronicsCategoriesPage.js +7 -7
- package/dist/layouts/electronics/components/ElectronicsGridProductCard.js +10 -10
- package/dist/layouts/electronics/components/ElectronicsHomePage.d.ts.map +1 -1
- package/dist/layouts/electronics/components/ElectronicsHomePage.js +29 -31
- package/dist/layouts/electronics/components/ElectronicsPageWrapper.js +4 -4
- package/dist/layouts/electronics/components/ElectronicsProductsPage.d.ts.map +1 -1
- package/dist/layouts/electronics/components/ElectronicsProductsPage.js +81 -23
- package/dist/layouts/electronics/components/ElectronicsStoreFooter.js +2 -2
- package/dist/layouts/electronics/components/ElectronicsStoreHeader.js +6 -6
- package/dist/layouts/electronics/index.js +18 -18
- package/dist/layouts/electronics/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/electronics/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/electronics/pages/AboutPage.js +11 -14
- package/dist/layouts/electronics/pages/CategoriesPage.js +1 -1
- package/dist/layouts/electronics/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/electronics/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/electronics/pages/CategoryPage.js +14 -20
- package/dist/layouts/electronics/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/electronics/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/electronics/pages/ContactPage.js +8 -13
- package/dist/layouts/electronics/pages/HelpCenterPage.js +1 -1
- package/dist/layouts/electronics/pages/PrivacyPolicyPage.js +1 -1
- package/dist/layouts/electronics/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/electronics/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/electronics/pages/ProductDetailPage.js +201 -142
- package/dist/layouts/electronics/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/electronics/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/electronics/pages/ProductsPage.js +119 -49
- package/dist/layouts/electronics/pages/TermsPage.js +1 -1
- package/dist/layouts/electronics/pages/TrackOrderPage.js +4 -4
- package/dist/layouts/electronics-grid/components/ElectronicsGridProductCard.js +10 -10
- package/dist/layouts/electronics-grid/components/ElectronicsHomePageGrid.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/components/ElectronicsHomePageGrid.js +75 -33
- package/dist/layouts/electronics-grid/index.js +14 -14
- package/dist/layouts/electronics-grid/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/electronics-grid/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/pages/AboutPage.js +11 -14
- package/dist/layouts/electronics-grid/pages/CategoriesPage.js +1 -1
- package/dist/layouts/electronics-grid/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/electronics-grid/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/pages/CategoryPage.js +14 -20
- package/dist/layouts/electronics-grid/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/electronics-grid/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/pages/ContactPage.js +8 -13
- package/dist/layouts/electronics-grid/pages/ElectronicsGridCategoriesPage.js +6 -6
- package/dist/layouts/electronics-grid/pages/HelpCenterPage.js +1 -1
- package/dist/layouts/electronics-grid/pages/PrivacyPolicyPage.js +1 -1
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.js +201 -142
- package/dist/layouts/electronics-grid/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/electronics-grid/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/electronics-grid/pages/ProductsPage.js +121 -52
- package/dist/layouts/electronics-grid/pages/TermsPage.js +1 -1
- package/dist/layouts/electronics-grid/pages/TrackOrderPage.js +4 -4
- package/dist/layouts/food/components/FoodHomePage.d.ts.map +1 -1
- package/dist/layouts/food/components/FoodHomePage.js +42 -41
- package/dist/layouts/food/index.js +8 -8
- package/dist/layouts/food/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/food/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/AboutPage.js +44 -45
- package/dist/layouts/food/pages/CategoriesPage.js +6 -6
- package/dist/layouts/food/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/food/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/CategoryPage.js +23 -21
- package/dist/layouts/food/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/food/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/ContactPage.js +5 -7
- package/dist/layouts/food/pages/MenuPage.d.ts +1 -1
- package/dist/layouts/food/pages/MenuPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/MenuPage.js +81 -42
- package/dist/layouts/food/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/food/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/ProductDetailPage.js +209 -171
- package/dist/layouts/food/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/food/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/food/pages/ProductsPage.js +130 -45
- package/dist/layouts/food-modern/components/FoodHomePageModern.js +10 -10
- package/dist/layouts/food-modern/index.js +8 -8
- package/dist/layouts/food-modern/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/AboutPage.js +11 -14
- package/dist/layouts/food-modern/pages/CategoriesPage.js +5 -5
- package/dist/layouts/food-modern/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/CategoryPage.js +23 -20
- package/dist/layouts/food-modern/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/ContactPage.js +5 -7
- package/dist/layouts/food-modern/pages/MenuPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/MenuPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/MenuPage.js +81 -46
- package/dist/layouts/food-modern/pages/ProductDetailPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/ProductDetailPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/ProductDetailPage.js +202 -143
- package/dist/layouts/food-modern/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/food-modern/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/food-modern/pages/ProductsPage.js +117 -33
- package/dist/layouts/motivational-speaker/components/MotivationalHomePage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/components/MotivationalHomePage.js +32 -23
- package/dist/layouts/motivational-speaker/components/MotivationalSpeakerPageWrapper.js +1 -1
- package/dist/layouts/motivational-speaker/index.js +9 -9
- package/dist/layouts/motivational-speaker/pages/AboutPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/AboutPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/AboutPage.js +6 -9
- package/dist/layouts/motivational-speaker/pages/CategoryPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/CategoryPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/CategoryPage.js +18 -22
- package/dist/layouts/motivational-speaker/pages/ContactPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/ContactPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/ContactPage.js +9 -13
- package/dist/layouts/motivational-speaker/pages/ProductsPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/ProductsPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/ProductsPage.js +121 -52
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.js +15 -24
- package/dist/layouts/motivational-speaker/pages/ServicesPage.d.ts +1 -1
- package/dist/layouts/motivational-speaker/pages/ServicesPage.d.ts.map +1 -1
- package/dist/layouts/motivational-speaker/pages/ServicesPage.js +8 -23
- package/dist/layouts/motivational-speaker/pages/SubscriptionPage.js +7 -7
- package/dist/layouts/shared/components/BaseStoreLayout.js +9 -9
- package/dist/layouts/shared/components/CartLineQuantityControl.js +1 -1
- package/dist/layouts/shared/components/GenericPageWrapper.js +3 -3
- package/dist/layouts/shared/components/ProductPriceFilterSection.js +4 -4
- package/dist/layouts/shared/components/PromoBanner.d.ts +1 -4
- package/dist/layouts/shared/components/PromoBanner.d.ts.map +1 -1
- package/dist/layouts/shared/components/PromoBanner.js +12 -8
- package/dist/layouts/shared/components/StoreFooter.js +10 -10
- package/dist/layouts/shared/components/StoreHeader.js +7 -7
- package/dist/layouts/shared/components/TestimonialCard.d.ts.map +1 -1
- package/dist/layouts/shared/components/TestimonialCard.js +2 -2
- package/dist/layouts/shared/components/headers/BookingAgendaSidebar.js +2 -2
- package/dist/layouts/shared/components/headers/ClothingMinimalHeader.js +11 -11
- package/dist/layouts/shared/components/headers/FoodModernHeader.js +7 -7
- package/dist/layouts/shared/index.js +22 -22
- package/dist/layouts/shared/pages/AccountPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/AccountPage.js +101 -27
- package/dist/layouts/shared/pages/CartPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/CartPage.js +39 -90
- package/dist/layouts/shared/pages/CheckoutPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/CheckoutPage.js +349 -868
- package/dist/layouts/shared/pages/CookiePolicyPage.js +1 -1
- package/dist/layouts/shared/pages/FeatureDisabledPage.js +1 -1
- package/dist/layouts/shared/pages/HelpCenterPage.js +1 -1
- package/dist/layouts/shared/pages/MaintenancePage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/MaintenancePage.js +2 -3
- package/dist/layouts/shared/pages/PortfolioPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/PortfolioPage.js +2 -2
- package/dist/layouts/shared/pages/PrivacyPolicyPage.js +1 -1
- package/dist/layouts/shared/pages/SizeGuidePage.js +1 -1
- package/dist/layouts/shared/pages/StyleGuidePage.js +3 -3
- package/dist/layouts/shared/pages/TeamPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/TeamPage.js +1 -1
- package/dist/layouts/shared/pages/TermsPage.js +1 -1
- package/dist/layouts/shared/pages/TrackOrderPage.js +4 -4
- package/dist/layouts/shared/pages/WishlistPage.d.ts.map +1 -1
- package/dist/layouts/shared/pages/WishlistPage.js +44 -29
- package/dist/layouts/shared/wrappers/BookingAgendaLayout.d.ts.map +1 -1
- package/dist/layouts/shared/wrappers/BookingAgendaLayout.js +80 -35
- package/dist/layouts/shared/wrappers/ClothingLayout.js +8 -8
- package/dist/layouts/shared/wrappers/ClothingMinimalLayout.js +7 -7
- package/dist/layouts/shared/wrappers/ElectronicsLayout.js +5 -5
- package/dist/layouts/shared/wrappers/FoodModernLayout.js +6 -6
- package/dist/layouts/shared/wrappers/MotivationalLayout.js +9 -9
- package/dist/layouts/shared/wrappers/StandardLayout.js +8 -8
- package/dist/lib/api.d.ts +3 -4
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +69 -109
- package/dist/lib/auth-context.js +2 -2
- package/dist/lib/content-selectors.d.ts +1 -1
- package/dist/lib/content-selectors.d.ts.map +1 -1
- package/dist/lib/content-selectors.js +8 -0
- package/dist/lib/layout-config-hydration.js +2 -2
- package/dist/lib/loading-context.d.ts.map +1 -1
- package/dist/lib/loading-context.js +11 -21
- package/dist/lib/payaza-checkout.d.ts.map +1 -1
- package/dist/lib/payaza-checkout.js +2 -4
- package/dist/lib/payaza-public-key.d.ts +6 -0
- package/dist/lib/payaza-public-key.d.ts.map +1 -0
- package/dist/lib/payaza-public-key.js +10 -0
- package/dist/lib/rich-html.d.ts +31 -26
- package/dist/lib/rich-html.d.ts.map +1 -1
- package/dist/lib/rich-html.js +1 -0
- package/dist/lib/services/analytics.service.js +1 -1
- package/dist/lib/services/auth.service.js +1 -1
- package/dist/lib/services/booking.service.js +1 -1
- package/dist/lib/services/category.service.js +1 -1
- package/dist/lib/services/checkout.service.d.ts +3 -0
- package/dist/lib/services/checkout.service.d.ts.map +1 -1
- package/dist/lib/services/checkout.service.js +1 -1
- package/dist/lib/services/contact.service.js +1 -1
- package/dist/lib/services/customer.service.js +1 -1
- package/dist/lib/services/fees.service.d.ts +17 -63
- package/dist/lib/services/fees.service.d.ts.map +1 -1
- package/dist/lib/services/fees.service.js +4 -138
- package/dist/lib/services/index.js +13 -13
- package/dist/lib/services/location.service.js +1 -1
- package/dist/lib/services/order.service.js +1 -1
- package/dist/lib/services/payment.service.js +1 -1
- package/dist/lib/services/product.service.d.ts +7 -2
- package/dist/lib/services/product.service.d.ts.map +1 -1
- package/dist/lib/services/product.service.js +13 -1
- package/dist/lib/services/promo.service.js +1 -1
- package/dist/lib/services/review.service.js +1 -1
- package/dist/lib/services/service.service.js +1 -1
- package/dist/lib/services/shipping.service.js +1 -1
- package/dist/lib/services/store.service.js +1 -1
- package/dist/lib/store-config-utils.d.ts +1 -10
- package/dist/lib/store-config-utils.d.ts.map +1 -1
- package/dist/lib/store-config-utils.js +73 -261
- package/dist/lib/store-config.js +1 -1
- package/dist/lib/store-context.d.ts +1 -23
- package/dist/lib/store-context.d.ts.map +1 -1
- package/dist/lib/store-context.js +89 -111
- package/dist/lib/store-types.d.ts +9 -91
- package/dist/lib/store-types.d.ts.map +1 -1
- package/dist/lib/utils/asset-helpers.js +1 -1
- package/dist/lib/utils/catalog-price-bounds.d.ts +16 -6
- package/dist/lib/utils/catalog-price-bounds.d.ts.map +1 -1
- package/dist/lib/utils/catalog-price-bounds.js +58 -14
- package/dist/lib/utils/category-tree.d.ts +9 -0
- package/dist/lib/utils/category-tree.d.ts.map +1 -1
- package/dist/lib/utils/category-tree.js +26 -0
- package/dist/lib/utils/editor-preview.d.ts +5 -0
- package/dist/lib/utils/editor-preview.d.ts.map +1 -1
- package/dist/lib/utils/editor-preview.js +17 -3
- package/dist/lib/utils/fee-calculations.d.ts +5 -1
- package/dist/lib/utils/fee-calculations.d.ts.map +1 -1
- package/dist/lib/utils/fee-calculations.js +28 -31
- package/dist/lib/utils/index.d.ts +1 -1
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/lib/utils/index.js +4 -4
- package/dist/lib/utils/product-images.js +1 -1
- package/dist/lib/utils/product-share.js +1 -1
- package/dist/lib/utils/url-helpers.d.ts +6 -0
- package/dist/lib/utils/url-helpers.d.ts.map +1 -1
- package/dist/lib/utils/url-helpers.js +20 -4
- package/dist/preview/LayoutPreview.js +6 -6
- package/dist/preview/PreviewRouter.js +4 -4
- package/dist/preview/canvas/PreviewCanvasEnhancer.js +8 -8
- package/dist/preview/canvas/preview-flush-await.js +1 -1
- package/dist/preview/canvas/preview-isolation.js +1 -1
- package/dist/preview/canvas/preview-route.js +2 -2
- package/dist/preview/index.js +5 -5
- package/dist/styles/index.css +190 -149
- package/package.json +31 -43
|
@@ -1,40 +1,30 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { useProductBySlug } from '../../../hooks/use-product-by-slug';
|
|
4
|
+
import { useProductReviews } from '../../../hooks/use-product-reviews';
|
|
5
|
+
import { Button } from '../../../components/ui/button';
|
|
6
|
+
import { Breadcrumbs } from '../../../components/ui/breadcrumbs';
|
|
7
|
+
import { Modal } from '../../../components/ui/modal';
|
|
8
|
+
import { ShoppingCart, Heart, Star, CheckCircle, ThumbsUp, User, Minus, Plus, Ruler, Share2, Info } from 'lucide-react';
|
|
8
9
|
import { useState, useMemo, useEffect } from 'react';
|
|
9
|
-
import { useStore } from '../../../lib/store-context
|
|
10
|
-
import { useToast } from '../../../components/ui/toast
|
|
10
|
+
import { useStore } from '../../../lib/store-context';
|
|
11
|
+
import { useToast } from '../../../components/ui/toast';
|
|
11
12
|
import { useRouter } from 'next/navigation';
|
|
12
|
-
import { useAuth } from '../../../lib/auth-context
|
|
13
|
-
import { useAnalytics } from '../../../hooks/use-analytics
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { ProductCard } from '../../../components/ui/product-card.js';
|
|
13
|
+
import { useAuth } from '../../../lib/auth-context';
|
|
14
|
+
import { useAnalytics } from '../../../hooks/use-analytics';
|
|
15
|
+
import { customerService } from '../../../lib/services/customer.service';
|
|
16
|
+
import { GuestCheckoutModal } from '../../../components/ui/guest-checkout-modal';
|
|
17
|
+
import { getGuestUserInfo, saveGuestUserInfo } from '../../../lib/guest-user';
|
|
18
|
+
import { ProductCard } from '../../../components/ui/product-card';
|
|
19
19
|
import Image from 'next/image';
|
|
20
|
-
import { ImageWithFallback } from '../../../components/ui/image-with-fallback
|
|
21
|
-
import { ButtonLoader } from '../../../components/ui/page-loader
|
|
22
|
-
import { extractImageUrls } from '../../../lib/store-config-utils
|
|
23
|
-
import { OutOfStockOverlay } from '../../../components/ui/out-of-stock-overlay
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { useCatalogLoader } from '../../../hooks/use-catalog-loader.js';
|
|
29
|
-
import { useShippingQuote } from '../../../hooks/use-shipping-quote.js';
|
|
30
|
-
import { ProductDeliveryInfoSection } from '../../../components/shipping/ProductDeliveryInfoSection.js';
|
|
31
|
-
import { isAutomatedShippingEnabled } from '../../../lib/shipping-settings.util.js';
|
|
32
|
-
import { enrichShippingQuoteAddress } from '../../../lib/shipping-address.util.js';
|
|
33
|
-
import { useProductVariationSelection } from '../../../hooks/use-product-variation-selection.js';
|
|
34
|
-
import { ProductVariationSelectors } from '../../../components/product/ProductVariationSelectors.js';
|
|
35
|
-
import { findMatchingVariation, resolveVariantPrice, resolveVariantSKU, resolveVariantStockProduct, resolveVariantImageUrls, buildCartLineProduct, } from '../../../lib/product-variation-utils.js';
|
|
36
|
-
import { guardCheckoutAvailable, isCheckoutDisabled } from '../../../lib/checkout-availability.js';
|
|
37
|
-
import { formatDateSafe } from '../../../utils/date.js';
|
|
20
|
+
import { ImageWithFallback } from '../../../components/ui/image-with-fallback';
|
|
21
|
+
import { ButtonLoader } from '../../../components/ui/page-loader';
|
|
22
|
+
import { extractImageUrls } from '../../../lib/store-config-utils';
|
|
23
|
+
import { OutOfStockOverlay } from '../../../components/ui/out-of-stock-overlay';
|
|
24
|
+
import { cn, formatCurrency, filterActiveProducts, isEditorPreviewMode, resolvePdpProduct } from '../../../lib/utils';
|
|
25
|
+
import { shippingService } from '../../../lib/services/shipping.service';
|
|
26
|
+
import { ProductDeliveryInfoSection } from '../../../components/shipping/ProductDeliveryInfoSection';
|
|
27
|
+
import { formatDateSafe } from '../../../utils/date';
|
|
38
28
|
// Helper function to format date
|
|
39
29
|
const formatDate = (dateString) => {
|
|
40
30
|
return formatDateSafe(dateString, '—', { year: 'numeric', month: 'long', day: 'numeric' });
|
|
@@ -56,48 +46,50 @@ function StarRating({ rating, size = 'md', className = '' }) {
|
|
|
56
46
|
return (_jsxs("div", { className: `relative inline-block ${sizeClasses[size]}`, children: [_jsx(Star, { className: `w-full h-full absolute inset-0 text-gray-200 fill-gray-200` }), isHalf && (_jsx("div", { className: "absolute inset-0", style: { clipPath: 'inset(0 50% 0 0)' }, children: _jsx(Star, { className: `w-full h-full text-gray-900 fill-gray-900` }) })), isFull && (_jsx(Star, { className: `w-full h-full absolute inset-0 text-gray-900 fill-gray-900` }))] }, i));
|
|
57
47
|
}) }));
|
|
58
48
|
}
|
|
59
|
-
import { ProductDescription } from '../../../components/rich-text/ProductDescription.js';
|
|
60
49
|
function ReviewCard({ review }) {
|
|
61
|
-
return (_jsxs("div", { className: "border-b border-gray-100 pb-8 last:border-b-0 last:pb-0", children: [_jsx("div", { className: "flex items-start justify-between mb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "w-12 h-12 rounded-full bg-gradient-to-br from-gray-200 to-gray-300 flex items-center justify-center flex-shrink-0 ring-2 ring-white shadow-sm overflow-hidden", children: [review.userAvatar ? (_jsx(Image, { src: review.userAvatar, alt: review.userName, fill: true, className: "w-full h-full object-cover"
|
|
50
|
+
return (_jsxs("div", { className: "border-b border-gray-100 pb-8 last:border-b-0 last:pb-0", children: [_jsx("div", { className: "flex items-start justify-between mb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "w-12 h-12 rounded-full bg-gradient-to-br from-gray-200 to-gray-300 flex items-center justify-center flex-shrink-0 ring-2 ring-white shadow-sm overflow-hidden", children: [review.userAvatar ? (_jsx(Image, { src: review.userAvatar, alt: review.userName, fill: true, className: "w-full h-full object-cover" })) : null, _jsx(User, { className: "h-6 w-6 text-gray-600", style: { display: review.userAvatar ? 'none' : 'flex' } })] }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2 mb-1", children: [_jsx("span", { className: "font-semibold text-gray-900", children: review.userName }), review.verified && (_jsx("span", { className: "text-xs bg-blue-50 text-blue-700 px-2.5 py-1 rounded-full font-medium border border-blue-100", children: "Verified Purchase" }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: review.rating, size: "sm" }), _jsx("span", { className: "text-xs text-gray-500", children: formatDate(review.date) })] })] })] }) }), review.title && (_jsx("h4", { className: "font-semibold text-gray-900 mb-3 text-lg", children: review.title })), _jsx("p", { className: "text-gray-700 leading-relaxed mb-4", children: review.comment }), review.images && review.images.length > 0 && (_jsx("div", { className: "flex gap-2 mb-4", children: review.images.map((img, idx) => (_jsx("div", { className: "relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200", children: _jsx(Image, { src: img, alt: `${review.userName}'s review image ${idx + 1}`, fill: true, className: "object-cover" }) }, idx))) })), review.helpful !== undefined && (_jsx("div", { className: "flex items-center gap-4", children: _jsxs("button", { className: "flex items-center gap-1.5 text-xs text-gray-600 hover:text-gray-900 transition-colors font-medium", children: [_jsx(ThumbsUp, { className: "h-4 w-4" }), _jsxs("span", { children: ["Helpful (", review.helpful, ")"] })] }) }))] }));
|
|
62
51
|
}
|
|
63
|
-
export function
|
|
64
|
-
const {
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const {
|
|
68
|
-
fetchCategories: false,
|
|
69
|
-
fetchServices: false,
|
|
70
|
-
});
|
|
71
|
-
const products = resolveStoreProductsForDisplay(loadedProducts, isPreview);
|
|
72
|
-
const product = resolveProductBySlugForDisplay(loadedProducts, productSlug, isPreview);
|
|
73
|
-
const { optionGroups, selectedAttributes, setAttribute, selectedColor, selectedSize, matchingVariation, hasVariations, hasSelectedOptions, } = useProductVariationSelection(product?.variants);
|
|
52
|
+
export function ProductDetailPage({ storeConfig, productSlug }) {
|
|
53
|
+
const { addToCart, isCartLoading, toggleWishlist, isInWishlist, isWishlistLoading, setBuyNowItem } = useStore();
|
|
54
|
+
const products = filterActiveProducts(storeConfig.products || []);
|
|
55
|
+
const initialProduct = resolvePdpProduct(initialConfig.products, storeConfig.products, productSlug, isEditorPreviewMode(storeConfig));
|
|
56
|
+
const { product, relatedProducts: apiRelatedProducts, isLoading: isLoadingProduct } = useProductBySlug(storeConfig.id, productSlug, initialProduct);
|
|
74
57
|
const { addToast } = useToast();
|
|
75
58
|
const router = useRouter();
|
|
76
|
-
const { isAuthenticated } = useAuth();
|
|
59
|
+
const { isAuthenticated, openLogin } = useAuth();
|
|
77
60
|
const { trackEvent } = useAnalytics();
|
|
61
|
+
const { reviews, isSubmitting: isSubmittingReview, submitReview, } = useProductReviews(product?.id);
|
|
78
62
|
// Related products logic
|
|
79
|
-
const
|
|
63
|
+
const fallbackRelatedProducts = useMemo(() => {
|
|
80
64
|
if (!product)
|
|
81
65
|
return [];
|
|
82
66
|
return products
|
|
83
67
|
.filter(p => p.categoryId === product.categoryId && p.id !== product.id)
|
|
84
68
|
.slice(0, 4);
|
|
85
69
|
}, [product, products]);
|
|
70
|
+
const relatedProducts = apiRelatedProducts.length > 0 ? apiRelatedProducts : fallbackRelatedProducts;
|
|
86
71
|
const handleShare = async () => {
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
72
|
+
if (typeof navigator !== 'undefined' && navigator.share) {
|
|
73
|
+
try {
|
|
74
|
+
await navigator.share({
|
|
75
|
+
title: product?.name,
|
|
76
|
+
text: product?.description,
|
|
77
|
+
url: window.location.href,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.log('Error sharing:', error);
|
|
82
|
+
}
|
|
96
83
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
else {
|
|
85
|
+
// Fallback to copy to clipboard
|
|
86
|
+
try {
|
|
87
|
+
await navigator.clipboard.writeText(window.location.href);
|
|
88
|
+
addToast('Link copied to clipboard!', 'success');
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
addToast('Failed to copy link', 'error');
|
|
92
|
+
}
|
|
101
93
|
}
|
|
102
94
|
};
|
|
103
95
|
const handleQuickView = (p) => {
|
|
@@ -122,6 +114,9 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
122
114
|
addToast('Failed to update wishlist', 'error');
|
|
123
115
|
}
|
|
124
116
|
};
|
|
117
|
+
// Extract color and size variants
|
|
118
|
+
const colorVariants = product?.variants?.filter(v => v.name === 'Color') || [];
|
|
119
|
+
const sizeVariants = product?.variants?.filter(v => v.name === 'Size') || [];
|
|
125
120
|
// Initialize state with defaults
|
|
126
121
|
const [selectedImage, setSelectedImage] = useState(0);
|
|
127
122
|
// Ensure selectedImage is within bounds when images change
|
|
@@ -132,37 +127,68 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
132
127
|
return () => clearTimeout(timer);
|
|
133
128
|
}
|
|
134
129
|
}, [product, selectedImage]);
|
|
130
|
+
const [selectedColor, setSelectedColor] = useState(colorVariants.length > 0 ? colorVariants[0].value : null);
|
|
131
|
+
const [selectedSize, setSelectedSize] = useState(sizeVariants.length > 0 ? sizeVariants[0].value : null);
|
|
135
132
|
const [quantity, setQuantity] = useState(1);
|
|
136
133
|
const [showAllReviews, setShowAllReviews] = useState(false);
|
|
137
134
|
const [isReviewModalOpen, setIsReviewModalOpen] = useState(false);
|
|
138
135
|
const [newReview, setNewReview] = useState({ rating: 5, title: '', comment: '' });
|
|
139
136
|
const [showGuestModal, setShowGuestModal] = useState(false);
|
|
140
137
|
const [isBuyNowLoading, setIsBuyNowLoading] = useState(false);
|
|
141
|
-
// Shipping calculation
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
productPrice: resolveVariantPrice({ price: product?.price ?? 0 }, matchingVariation),
|
|
147
|
-
currency,
|
|
148
|
-
quantity,
|
|
149
|
-
enabled: Boolean(product) && isAutomatedShippingEnabled(storeConfig),
|
|
138
|
+
// Shipping calculation state
|
|
139
|
+
const [shippingAddress, setShippingAddress] = useState({
|
|
140
|
+
country: '',
|
|
141
|
+
city: '',
|
|
142
|
+
zipCode: '',
|
|
150
143
|
});
|
|
151
144
|
const [savedAddresses, setSavedAddresses] = useState([]);
|
|
152
|
-
const
|
|
145
|
+
const [isCountryDropdownOpen, setIsCountryDropdownOpen] = useState(false);
|
|
146
|
+
const [isCityDropdownOpen, setIsCityDropdownOpen] = useState(false);
|
|
147
|
+
const [shippingMethods, setShippingMethods] = useState([]);
|
|
148
|
+
const [isCalculatingShipping, setIsCalculatingShipping] = useState(false);
|
|
149
|
+
const [shippingError, setShippingError] = useState(null);
|
|
150
|
+
const [freeShippingEligible, setFreeShippingEligible] = useState(false);
|
|
151
|
+
const [freeShippingThreshold, setFreeShippingThreshold] = useState(undefined);
|
|
152
|
+
const handleSubmitReview = async (e) => {
|
|
153
153
|
e.preventDefault();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
if (!product?.id)
|
|
155
|
+
return;
|
|
156
|
+
if (!isAuthenticated) {
|
|
157
|
+
setIsReviewModalOpen(false);
|
|
158
|
+
openLogin({
|
|
159
|
+
onSuccess: () => setIsReviewModalOpen(true),
|
|
160
|
+
});
|
|
161
|
+
addToast('Sign in to submit your review', 'info');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const title = newReview.title.trim();
|
|
165
|
+
const comment = newReview.comment.trim();
|
|
166
|
+
if (!title && !comment) {
|
|
167
|
+
addToast('Please add a review title or comment', 'error');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
await submitReview({
|
|
172
|
+
rating: newReview.rating,
|
|
173
|
+
title,
|
|
174
|
+
comment,
|
|
175
|
+
});
|
|
176
|
+
addToast('Review submitted successfully!', 'success');
|
|
177
|
+
setIsReviewModalOpen(false);
|
|
178
|
+
setNewReview({ rating: 5, title: '', comment: '' });
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
addToast(error instanceof Error ? error.message : 'Failed to submit review', 'error');
|
|
182
|
+
}
|
|
158
183
|
};
|
|
184
|
+
if (isLoadingProduct) {
|
|
185
|
+
return _jsx("div", { className: "min-h-screen bg-white flex items-center justify-center p-8", children: "Loading product..." });
|
|
186
|
+
}
|
|
159
187
|
if (!product) {
|
|
160
188
|
return (_jsx("div", { className: "min-h-screen bg-white flex items-center justify-center p-8", children: _jsxs("div", { className: "text-center", children: [_jsx("h1", { className: "text-2xl font-bold mb-2", children: "Product Not Found" }), _jsx("p", { className: "text-gray-600 mb-4", children: "The product you're looking for doesn't exist." })] }) }));
|
|
161
189
|
}
|
|
162
190
|
// Use SKU for display, fallback to generated SKU from slug if not available
|
|
163
|
-
const
|
|
164
|
-
const displaySKU = resolveVariantSKU(product, matchingVariation);
|
|
165
|
-
const stockProduct = resolveVariantStockProduct(product, matchingVariation);
|
|
191
|
+
const displaySKU = product.sku || product.slug?.toUpperCase().replace(/-/g, '').substring(0, 12).padEnd(8, 'X') || 'N/A';
|
|
166
192
|
// Build category breadcrumb path with all parent categories
|
|
167
193
|
const buildCategoryPath = (categoryId) => {
|
|
168
194
|
if (!categoryId)
|
|
@@ -197,9 +223,6 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
197
223
|
// but handle edge cases where it might still be in object format
|
|
198
224
|
// Use the comprehensive extraction utility from store-config-utils for consistency
|
|
199
225
|
const productImages = (() => {
|
|
200
|
-
const variantImages = resolveVariantImageUrls(matchingVariation);
|
|
201
|
-
if (variantImages.length > 0)
|
|
202
|
-
return variantImages;
|
|
203
226
|
// Debug: Log the raw product.images to understand its format
|
|
204
227
|
if (process.env.NODE_ENV === 'development') {
|
|
205
228
|
console.log('[ProductDetailPage] Raw product.images:', {
|
|
@@ -235,10 +258,8 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
235
258
|
}
|
|
236
259
|
return extracted;
|
|
237
260
|
})();
|
|
261
|
+
// For gallery, use actual images only (don't duplicate to fill 5 slots)
|
|
238
262
|
const displayImages = productImages.slice(0, 5);
|
|
239
|
-
useEffect(() => {
|
|
240
|
-
setSelectedImage(0);
|
|
241
|
-
}, [matchingVariation?.id, productImages[0]]);
|
|
242
263
|
const hasMoreImages = productImages.length > 5;
|
|
243
264
|
// Debug logging for images (can be removed in production)
|
|
244
265
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -275,17 +296,18 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
275
296
|
'Navy': '#1E3A8A',
|
|
276
297
|
'Beige': '#F5F5DC',
|
|
277
298
|
};
|
|
278
|
-
//
|
|
279
|
-
const reviews = product.reviews || [];
|
|
299
|
+
// Reviews loaded from API (product payload does not include review rows)
|
|
280
300
|
const displayedReviews = showAllReviews ? reviews : reviews.slice(0, 3);
|
|
281
301
|
const hasMoreReviews = reviews.length > 3;
|
|
302
|
+
const reviewCount = Math.max(Number(product.reviewCount) || 0, reviews.length);
|
|
303
|
+
const averageRating = reviews.length > 0
|
|
304
|
+
? reviews.reduce((sum, review) => sum + review.rating, 0) / reviews.length
|
|
305
|
+
: Number(product.rating) || 0;
|
|
282
306
|
// Out of stock check
|
|
283
|
-
const
|
|
284
|
-
const isOutOfStock = !stockInfo.canPurchase;
|
|
285
|
-
const maxPurchasableQty = getMaxPurchasableQuantity({ ...product, ...stockProduct });
|
|
307
|
+
const isOutOfStock = !product.inStock;
|
|
286
308
|
// Calculate rating distribution
|
|
287
309
|
const ratingDistribution = [5, 4, 3, 2, 1].map(rating => {
|
|
288
|
-
const count = reviews.filter(r => r.rating === rating).length;
|
|
310
|
+
const count = reviews.filter(r => Math.round(r.rating) === rating).length;
|
|
289
311
|
return {
|
|
290
312
|
rating,
|
|
291
313
|
count,
|
|
@@ -294,44 +316,31 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
294
316
|
});
|
|
295
317
|
const handleAddToCart = () => {
|
|
296
318
|
if (isOutOfStock) {
|
|
297
|
-
addToast(
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
if (hasVariations && hasSelectedOptions && !matchingVariation) {
|
|
301
|
-
addToast('Please select all product options', 'error');
|
|
319
|
+
addToast('This product is currently out of stock', 'error');
|
|
302
320
|
return;
|
|
303
321
|
}
|
|
304
322
|
// Find the matching variation UUID based on selected attributes
|
|
305
323
|
// Note: StoreProduct uses 'variants' not 'variations'
|
|
306
|
-
let variationId
|
|
307
|
-
if (
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
324
|
+
let variationId;
|
|
325
|
+
if (product.variants && Array.isArray(product.variants) && product.variants.length > 0) {
|
|
326
|
+
const matchingVariation = product.variants.find((variation) => {
|
|
327
|
+
const attrs = variation.attributes || {};
|
|
328
|
+
const colorMatch = !selectedColor || attrs.color === selectedColor;
|
|
329
|
+
const sizeMatch = !selectedSize || attrs.size === selectedSize;
|
|
330
|
+
return colorMatch && sizeMatch;
|
|
312
331
|
});
|
|
313
|
-
variationId =
|
|
332
|
+
variationId = matchingVariation?.id;
|
|
314
333
|
}
|
|
315
334
|
// Fallback to composite string for backward compatibility if no variation found
|
|
316
335
|
const variantId = variationId || (selectedColor || selectedSize
|
|
317
336
|
? [selectedColor, selectedSize].filter(Boolean).join(' / ')
|
|
318
337
|
: undefined);
|
|
319
|
-
|
|
320
|
-
const variantName = resolvedVariation?.value || Object.values(resolvedVariation?.attributes || {}).filter(Boolean).join(' / ') || undefined;
|
|
321
|
-
const unitPrice = resolvedVariation?.price ?? product.price;
|
|
322
|
-
addToCart(product, quantity, { variantId, variantName, unitPrice });
|
|
338
|
+
addToCart(product, quantity, variantId);
|
|
323
339
|
addToast(`${product.name} added to cart`, 'success');
|
|
324
340
|
};
|
|
325
341
|
const handleBuyNow = async () => {
|
|
326
342
|
if (isOutOfStock) {
|
|
327
|
-
addToast(
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
if (hasVariations && hasSelectedOptions && !matchingVariation) {
|
|
331
|
-
addToast('Please select all product options', 'error');
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
if (!guardCheckoutAvailable(storeConfig, addToast)) {
|
|
343
|
+
addToast('This product is currently out of stock', 'error');
|
|
335
344
|
return;
|
|
336
345
|
}
|
|
337
346
|
if (isBuyNowLoading || isCartLoading) {
|
|
@@ -341,19 +350,17 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
341
350
|
try {
|
|
342
351
|
// Find the matching variation UUID based on selected attributes
|
|
343
352
|
// Note: StoreProduct uses 'variants' not 'variations'
|
|
344
|
-
let variationId
|
|
353
|
+
let variationId;
|
|
345
354
|
let variantName;
|
|
346
|
-
if (
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
355
|
+
if (product.variants && Array.isArray(product.variants) && product.variants.length > 0) {
|
|
356
|
+
const matchingVariation = product.variants.find((variation) => {
|
|
357
|
+
const attrs = variation.attributes || {};
|
|
358
|
+
const colorMatch = !selectedColor || attrs.color === selectedColor;
|
|
359
|
+
const sizeMatch = !selectedSize || attrs.size === selectedSize;
|
|
360
|
+
return colorMatch && sizeMatch;
|
|
351
361
|
});
|
|
352
|
-
variationId =
|
|
353
|
-
variantName =
|
|
354
|
-
}
|
|
355
|
-
else if (matchingVariation) {
|
|
356
|
-
variantName = matchingVariation.value || Object.values(matchingVariation.attributes || {}).filter(Boolean).join(' / ');
|
|
362
|
+
variationId = matchingVariation?.id;
|
|
363
|
+
variantName = matchingVariation?.name || matchingVariation?.value;
|
|
357
364
|
}
|
|
358
365
|
// Fallback to composite string for backward compatibility if no variation found
|
|
359
366
|
const variantId = variationId || (selectedColor || selectedSize
|
|
@@ -367,8 +374,8 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
367
374
|
quantity,
|
|
368
375
|
variantId,
|
|
369
376
|
variantName: variantName || variantId,
|
|
370
|
-
price:
|
|
371
|
-
product
|
|
377
|
+
price: product.price,
|
|
378
|
+
product
|
|
372
379
|
};
|
|
373
380
|
// Set buy now item and navigate directly to checkout
|
|
374
381
|
setBuyNowItem(buyNowItem);
|
|
@@ -390,6 +397,44 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
390
397
|
// Note: This is now only used for other flows, not buy now
|
|
391
398
|
// Buy now now redirects to checkout page
|
|
392
399
|
};
|
|
400
|
+
// Calculate shipping when address is provided
|
|
401
|
+
const calculateShipping = async () => {
|
|
402
|
+
if (!product || !shippingAddress.country || !shippingAddress.city) {
|
|
403
|
+
setShippingError('Please provide country and city to calculate shipping');
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
setIsCalculatingShipping(true);
|
|
407
|
+
setShippingError(null);
|
|
408
|
+
try {
|
|
409
|
+
const currency = product.currency || storeConfig.settings?.currency || 'USD';
|
|
410
|
+
const subtotal = product.price * quantity;
|
|
411
|
+
const result = await shippingService.calculateShipping({
|
|
412
|
+
storeId: storeConfig.id,
|
|
413
|
+
address: {
|
|
414
|
+
country: shippingAddress.country,
|
|
415
|
+
city: shippingAddress.city,
|
|
416
|
+
zipCode: shippingAddress.zipCode,
|
|
417
|
+
},
|
|
418
|
+
items: [{
|
|
419
|
+
productId: product.id,
|
|
420
|
+
quantity: quantity,
|
|
421
|
+
}],
|
|
422
|
+
subtotal: subtotal,
|
|
423
|
+
currency: currency,
|
|
424
|
+
});
|
|
425
|
+
setShippingMethods(result.methods || []);
|
|
426
|
+
setFreeShippingEligible(result.freeShippingEligible || false);
|
|
427
|
+
setFreeShippingThreshold(result.freeShippingThreshold);
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
console.error('Shipping calculation error:', error);
|
|
431
|
+
setShippingError(error.message || 'Failed to calculate shipping. Please try again.');
|
|
432
|
+
setShippingMethods([]);
|
|
433
|
+
}
|
|
434
|
+
finally {
|
|
435
|
+
setIsCalculatingShipping(false);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
393
438
|
// Load saved addresses for authenticated users and auto-populate shipping address
|
|
394
439
|
useEffect(() => {
|
|
395
440
|
const loadAddresses = async () => {
|
|
@@ -397,28 +442,39 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
397
442
|
try {
|
|
398
443
|
const addresses = await customerService.getAddresses();
|
|
399
444
|
setSavedAddresses(addresses);
|
|
445
|
+
// Auto-populate with default address or first address if available
|
|
400
446
|
if (addresses.length > 0) {
|
|
401
|
-
const defaultAddress = addresses.find(
|
|
447
|
+
const defaultAddress = addresses.find(a => a.isDefault) || addresses[0];
|
|
402
448
|
if (defaultAddress) {
|
|
403
|
-
|
|
449
|
+
setShippingAddress({
|
|
404
450
|
country: defaultAddress.country || '',
|
|
405
451
|
city: defaultAddress.city || '',
|
|
406
452
|
zipCode: defaultAddress.zipCode || '',
|
|
407
|
-
|
|
408
|
-
state: defaultAddress.state || '',
|
|
409
|
-
phone: defaultAddress.phone || '',
|
|
410
|
-
}));
|
|
453
|
+
});
|
|
411
454
|
}
|
|
412
455
|
}
|
|
413
456
|
}
|
|
414
457
|
catch (error) {
|
|
415
458
|
console.error('Failed to load addresses:', error);
|
|
459
|
+
// Don't show error toast - addresses are optional
|
|
460
|
+
// Users can still manually enter shipping address
|
|
416
461
|
}
|
|
417
462
|
}
|
|
418
463
|
};
|
|
419
464
|
loadAddresses();
|
|
420
465
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
421
466
|
}, [isAuthenticated]);
|
|
467
|
+
// Auto-calculate shipping when address fields are filled (debounced)
|
|
468
|
+
useEffect(() => {
|
|
469
|
+
if (!shippingAddress.country || !shippingAddress.city || !product) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const timer = setTimeout(() => {
|
|
473
|
+
calculateShipping();
|
|
474
|
+
}, 500); // Debounce 500ms
|
|
475
|
+
return () => clearTimeout(timer);
|
|
476
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
477
|
+
}, [shippingAddress.country, shippingAddress.city, shippingAddress.zipCode, quantity, product?.id, product?.price]);
|
|
422
478
|
// Track product view
|
|
423
479
|
useEffect(() => {
|
|
424
480
|
if (product && storeConfig?.id) {
|
|
@@ -431,26 +487,23 @@ export function BookingProductDetailPage({ storeConfig: initialConfig, productSl
|
|
|
431
487
|
price: product.price,
|
|
432
488
|
},
|
|
433
489
|
});
|
|
434
|
-
trackStorefrontEvent('Product_viewed', {
|
|
435
|
-
storeId: storeConfig.id,
|
|
436
|
-
storeSlug: storeConfig.slug,
|
|
437
|
-
productId: product.id,
|
|
438
|
-
productName: product.name,
|
|
439
|
-
categoryId: product.categoryId,
|
|
440
|
-
price: product.price,
|
|
441
|
-
});
|
|
442
490
|
}
|
|
443
491
|
}, [product?.id, storeConfig?.id, trackEvent]);
|
|
444
|
-
return (_jsxs("div", { className: "min-h-screen bg-white", children: [_jsxs("div", { "data-content-ready": true,
|
|
492
|
+
return (_jsxs("div", { className: "min-h-screen bg-white", children: [_jsxs("div", { "data-content-ready": true, className: "container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-7xl", children: [_jsx("div", { className: "mb-6", children: _jsx(Breadcrumbs, { items: breadcrumbItems }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16 mb-20", children: [_jsxs("div", { className: "relative lg:sticky lg:top-24 self-start z-0", children: [_jsxs("div", { className: "relative aspect-square bg-gray-50 rounded-xl overflow-hidden mb-4 border border-gray-100 shadow-sm group", children: [_jsx(ImageWithFallback, { "data-product-image": true, src: displayImages[selectedImage] || displayImages[0] || productImages[0], alt: product.name, className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }), isOutOfStock && (_jsx(OutOfStockOverlay, { badgePosition: "center" }))] }), displayImages.length > 0 && (_jsxs("div", { className: "grid grid-cols-5 gap-2", children: [displayImages.map((image, index) => (_jsx("button", { onClick: () => setSelectedImage(Math.min(index, displayImages.length - 1)), className: `aspect-square rounded-lg overflow-hidden border-2 transition-all ${selectedImage === index
|
|
445
493
|
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2'
|
|
446
|
-
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }),
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
494
|
+
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: product.inStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(product.price, product.currency || 'USD') }), product.compareAtPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(product.compareAtPrice, product.currency || 'USD') }))] }), product.compareAtPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((product.compareAtPrice - product.price) / product.compareAtPrice) * 100), "%"] }))] }), colorVariants.length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Color:" }), _jsx("span", { className: "text-sm text-gray-600 capitalize", children: selectedColor || colorVariants[0]?.value })] }), _jsx("div", { className: "flex gap-3", children: colorVariants.map((variant) => {
|
|
495
|
+
const colorValue = variant.value;
|
|
496
|
+
const swatchColor = colorSwatches[colorValue] || '#CCCCCC';
|
|
497
|
+
const isSelected = selectedColor === colorValue;
|
|
498
|
+
return (_jsx("button", { onClick: () => setSelectedColor(colorValue), className: `relative w-12 h-12 rounded-full border-2 transition-all ${isSelected
|
|
499
|
+
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2 scale-105'
|
|
500
|
+
: 'border-gray-200 hover:border-gray-300'}`, style: { backgroundColor: swatchColor }, title: colorValue, children: isSelected && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: _jsx(CheckCircle, { className: `h-5 w-5 ${['White', 'Beige', 'Yellow'].includes(colorValue) ? 'text-gray-900' : 'text-white'} drop-shadow-sm` }) })) }, variant.id));
|
|
501
|
+
}) })] })), sizeVariants.length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Size:" }), _jsx("span", { className: "text-sm text-gray-600", children: selectedSize || 'Select Size' })] }), _jsxs("a", { href: `/${storeConfig.slug}/size-guide`, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-1.5 text-xs font-medium text-gray-600 hover:text-gray-900 underline decoration-gray-400 underline-offset-4", children: [_jsx(Ruler, { className: "h-3.5 w-3.5" }), " Size guide"] })] }), _jsx("div", { className: "grid grid-cols-4 sm:grid-cols-5 gap-2.5", children: sizeVariants.map((variant) => {
|
|
502
|
+
const isSelected = selectedSize === variant.value;
|
|
503
|
+
return (_jsx("button", { onClick: () => setSelectedSize(variant.value), className: `px-4 py-3 rounded-lg border-2 text-sm font-semibold transition-all ${isSelected
|
|
504
|
+
? 'bg-gray-900 text-white border-gray-900 shadow-md transform -translate-y-0.5'
|
|
505
|
+
: 'bg-white text-gray-700 border-gray-200 hover:border-gray-300 hover:bg-gray-50'}`, children: variant.value }, variant.id));
|
|
506
|
+
}) })] })), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-col sm:flex-row gap-3 mt-2", children: [_jsx(Button, { "data-add-to-cart": true, size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-14 text-base font-bold shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-5 w-5 mr-2" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-14 text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-14 w-14 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
454
507
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
455
|
-
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: currency, productCurrency: product.currency, productPrice:
|
|
508
|
+
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: product.price, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx("p", { children: product.description }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), product.reviewCount && product.reviewCount > 0 && product.rating && product.rating > 0 ? (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: typeof product.rating === 'number' ? product.rating : Number(product.rating) || 0, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: Number(product.rating).toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [product.reviewCount, " ", product.reviewCount === 1 ? 'review' : 'reviews'] })] })) : (_jsx("div", { className: "text-gray-500", children: _jsx("p", { className: "text-base", children: "Be the first to review this product" }) }))] }), _jsx(Button, { onClick: () => setIsReviewModalOpen(true), className: "rounded-full shrink-0 bg-gray-900 hover:bg-gray-800 text-white", children: product.reviewCount && product.reviewCount > 0 ? 'Write a Review' : 'Be the First to Review' })] }), ratingDistribution.some(r => r.count > 0) && (_jsxs("div", { className: "mb-10 p-6 bg-gray-50 rounded-xl border border-gray-100", children: [_jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-5", children: "Rating Breakdown" }), _jsx("div", { className: "space-y-3", children: ratingDistribution.map(({ rating, count, percentage }) => (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-1.5 w-20", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: rating }), _jsx(Star, { className: "h-4 w-4 fill-gray-900 text-gray-900" })] }), _jsx("div", { className: "flex-1 h-2.5 bg-gray-200 rounded-full overflow-hidden", children: _jsx("div", { className: "h-full bg-gradient-to-r from-gray-700 to-gray-900 rounded-full transition-all duration-500", style: { width: `${percentage}%` } }) }), _jsx("span", { className: "text-sm font-medium text-gray-700 w-12 text-right", children: count })] }, rating))) })] })), reviews.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "space-y-6", children: displayedReviews.map((review) => (_jsx(ReviewCard, { review: review }, review.id))) }), hasMoreReviews && !showAllReviews && (_jsx("div", { className: "mt-8 text-center", children: _jsxs(Button, { variant: "outline", onClick: () => setShowAllReviews(true), className: "px-8 rounded-full h-12 border-gray-300", children: ["Show All ", reviews.length, " Reviews"] }) }))] })) : (_jsxs("div", { className: "text-center py-12 bg-gray-50 rounded-xl border border-dashed border-gray-300", children: [_jsx("div", { className: "inline-flex items-center justify-center w-12 h-12 rounded-full bg-white shadow-sm mb-4", children: _jsx(Star, { className: "h-6 w-6 text-gray-400" }) }), _jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2", children: "No Reviews Yet" }), _jsx("p", { className: "text-gray-500 max-w-sm mx-auto mb-6", children: "Be the first to review this product and help other customers make informed decisions." }), _jsx(Button, { onClick: () => setIsReviewModalOpen(true), className: "bg-gray-900 hover:bg-gray-800 text-white", children: "Write the First Review" })] }))] }) }), relatedProducts.length > 0 && (_jsxs("div", { className: "mt-20 pt-16 border-t border-gray-200", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-8", children: "You Might Also Like" }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6", children: relatedProducts.map((relatedProduct) => (_jsx("div", { className: "h-[400px]", children: _jsx(ProductCard, { product: relatedProduct, storeSlug: storeConfig.slug, onAddToCart: (p) => addToCart(p, 1), onQuickView: handleQuickView, className: "h-full" }) }, relatedProduct.id))) })] }))] }), _jsx(Modal, { isOpen: isReviewModalOpen, onClose: () => setIsReviewModalOpen(false), title: "Write a Review", children: _jsxs("form", { onSubmit: handleSubmitReview, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Rating" }), _jsxs("div", { className: "flex items-center gap-1", children: [[1, 2, 3, 4, 5].map((star) => (_jsxs("div", { className: "relative group", children: [_jsx("button", { type: "button", onClick: () => setNewReview({ ...newReview, rating: star - 0.5 }), className: "absolute top-0 left-0 w-1/2 h-full z-20 focus:outline-none", title: `${star - 0.5} stars` }), _jsx("button", { type: "button", onClick: () => setNewReview({ ...newReview, rating: star }), className: "absolute top-0 right-0 w-1/2 h-full z-20 focus:outline-none", title: `${star} stars` }), _jsxs("div", { className: "relative pointer-events-none transition-transform group-hover:scale-110", children: [_jsx(Star, { className: "h-8 w-8 text-gray-200 fill-gray-200" }), newReview.rating >= star - 0.5 && (_jsx("div", { className: "absolute inset-0 overflow-hidden", style: { width: newReview.rating === star - 0.5 ? '50%' : '100%' }, children: _jsx(Star, { className: "h-8 w-8 text-gray-900 fill-gray-900" }) }))] })] }, star))), _jsx("span", { className: "ml-3 text-lg font-medium text-gray-900 w-12", children: newReview.rating })] })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "title", className: "block text-sm font-medium text-gray-700 mb-1", children: "Review Title" }), _jsx("input", { type: "text", id: "title", required: true, className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-black", placeholder: "Summarize your thoughts", value: newReview.title, onChange: (e) => setNewReview({ ...newReview, title: e.target.value }) })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "comment", className: "block text-sm font-medium text-gray-700 mb-1", children: "Review" }), _jsx("textarea", { id: "comment", required: true, rows: 4, className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-black", placeholder: "What did you like or dislike?", value: newReview.comment, onChange: (e) => setNewReview({ ...newReview, comment: e.target.value }) })] }), _jsxs("div", { className: "pt-4 flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "outline", onClick: () => setIsReviewModalOpen(false), children: "Cancel" }), _jsx(Button, { type: "submit", className: "bg-black text-white hover:bg-gray-800", children: "Submit Review" })] })] }) }), _jsx(GuestCheckoutModal, { isOpen: showGuestModal, onClose: () => setShowGuestModal(false), onSubmit: handleGuestInfoSubmit, initialData: getGuestUserInfo() || undefined })] }));
|
|
456
509
|
}
|
|
@@ -4,6 +4,6 @@ interface ServicesPageProps {
|
|
|
4
4
|
initialCategory?: string;
|
|
5
5
|
titleOverride?: string;
|
|
6
6
|
}
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function ServicesPage({ storeConfig: initialConfig, initialCategory, titleOverride }: ServicesPageProps): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=ServicesPage.d.ts.map
|