storefront-layouts-staging 1.0.0-staging.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 +539 -0
- package/dist/components/auth/LoginForm.d.ts +9 -0
- package/dist/components/auth/LoginForm.d.ts.map +1 -0
- package/dist/components/auth/LoginForm.js +21 -0
- package/dist/components/auth/LoginSheet.d.ts +7 -0
- package/dist/components/auth/LoginSheet.d.ts.map +1 -0
- package/dist/components/auth/LoginSheet.js +8 -0
- package/dist/components/auth/login-form-core.d.ts +11 -0
- package/dist/components/auth/login-form-core.d.ts.map +1 -0
- package/dist/components/auth/login-form-core.js +19 -0
- package/dist/components/auth/login-sheet-header.d.ts +10 -0
- package/dist/components/auth/login-sheet-header.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-header.js +10 -0
- package/dist/components/auth/login-sheet-registry.d.ts +11 -0
- package/dist/components/auth/login-sheet-registry.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-registry.js +9 -0
- package/dist/components/auth/login-sheet-theme.types.d.ts +29 -0
- package/dist/components/auth/login-sheet-theme.types.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-theme.types.js +1 -0
- package/dist/components/auth/login-sheet-themes/booking-agenda.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/booking-agenda.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/booking-agenda.theme.js +21 -0
- package/dist/components/auth/login-sheet-themes/booking.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/booking.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/booking.theme.js +20 -0
- package/dist/components/auth/login-sheet-themes/clothing-minimal.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/clothing-minimal.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/clothing-minimal.theme.js +20 -0
- package/dist/components/auth/login-sheet-themes/clothing.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/clothing.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/clothing.theme.js +21 -0
- package/dist/components/auth/login-sheet-themes/electronics-grid.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/electronics-grid.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/electronics-grid.theme.js +20 -0
- package/dist/components/auth/login-sheet-themes/electronics.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/electronics.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/electronics.theme.js +20 -0
- package/dist/components/auth/login-sheet-themes/food-modern.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/food-modern.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/food-modern.theme.js +22 -0
- package/dist/components/auth/login-sheet-themes/food.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/food.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/food.theme.js +22 -0
- package/dist/components/auth/login-sheet-themes/index.d.ts +14 -0
- package/dist/components/auth/login-sheet-themes/index.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/index.js +29 -0
- package/dist/components/auth/login-sheet-themes/motivational-speaker.theme.d.ts +3 -0
- package/dist/components/auth/login-sheet-themes/motivational-speaker.theme.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/motivational-speaker.theme.js +20 -0
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.d.ts +24 -0
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.d.ts.map +1 -0
- package/dist/components/auth/login-sheet-themes/theme-input-baselines.js +23 -0
- package/dist/components/auth/login-sheets/StoreLoginSheetShell.d.ts +13 -0
- package/dist/components/auth/login-sheets/StoreLoginSheetShell.d.ts.map +1 -0
- package/dist/components/auth/login-sheets/StoreLoginSheetShell.js +14 -0
- package/dist/components/auth/use-login-submit.d.ts +22 -0
- package/dist/components/auth/use-login-submit.d.ts.map +1 -0
- package/dist/components/auth/use-login-submit.js +99 -0
- package/dist/components/cart/InventoryHoldCountdown.d.ts +8 -0
- package/dist/components/cart/InventoryHoldCountdown.d.ts.map +1 -0
- package/dist/components/cart/InventoryHoldCountdown.js +73 -0
- package/dist/components/categories/category-masonry-grid.d.ts +18 -0
- package/dist/components/categories/category-masonry-grid.d.ts.map +1 -0
- package/dist/components/categories/category-masonry-grid.js +50 -0
- package/dist/components/categories/category-masonry-utils.d.ts +9 -0
- package/dist/components/categories/category-masonry-utils.d.ts.map +1 -0
- package/dist/components/categories/category-masonry-utils.js +67 -0
- package/dist/components/checkout/CheckoutFeeLines.d.ts +12 -0
- package/dist/components/checkout/CheckoutFeeLines.d.ts.map +1 -0
- package/dist/components/checkout/CheckoutFeeLines.js +9 -0
- package/dist/components/checkout/ShippingOptionsPanel.d.ts +54 -0
- package/dist/components/checkout/ShippingOptionsPanel.d.ts.map +1 -0
- package/dist/components/checkout/ShippingOptionsPanel.js +115 -0
- package/dist/components/learning/CertificateTemplates.d.ts +25 -0
- package/dist/components/learning/CertificateTemplates.d.ts.map +1 -0
- package/dist/components/learning/CertificateTemplates.js +31 -0
- package/dist/components/learning/CertificateViewer.d.ts +11 -0
- package/dist/components/learning/CertificateViewer.d.ts.map +1 -0
- package/dist/components/learning/CertificateViewer.js +114 -0
- package/dist/components/learning/MentorshipProgress.d.ts +18 -0
- package/dist/components/learning/MentorshipProgress.d.ts.map +1 -0
- package/dist/components/learning/MentorshipProgress.js +20 -0
- package/dist/components/product/ProductVariationSelectors.d.ts +10 -0
- package/dist/components/product/ProductVariationSelectors.d.ts.map +1 -0
- package/dist/components/product/ProductVariationSelectors.js +27 -0
- package/dist/components/rich-text/CategoryDescription.d.ts +7 -0
- package/dist/components/rich-text/CategoryDescription.d.ts.map +1 -0
- package/dist/components/rich-text/CategoryDescription.js +11 -0
- package/dist/components/rich-text/ProductDescription.d.ts +9 -0
- package/dist/components/rich-text/ProductDescription.d.ts.map +1 -0
- package/dist/components/rich-text/ProductDescription.js +10 -0
- package/dist/components/rich-text/RichTextExcerpt.d.ts +10 -0
- package/dist/components/rich-text/RichTextExcerpt.d.ts.map +1 -0
- package/dist/components/rich-text/RichTextExcerpt.js +12 -0
- package/dist/components/rich-text/SafeRichHtml.d.ts +14 -0
- package/dist/components/rich-text/SafeRichHtml.d.ts.map +1 -0
- package/dist/components/rich-text/SafeRichHtml.js +15 -0
- package/dist/components/shipping/MerchantHandledDeliveryNotice.d.ts +7 -0
- package/dist/components/shipping/MerchantHandledDeliveryNotice.d.ts.map +1 -0
- package/dist/components/shipping/MerchantHandledDeliveryNotice.js +7 -0
- package/dist/components/shipping/ProductDeliveryInfoSection.d.ts +21 -0
- package/dist/components/shipping/ProductDeliveryInfoSection.d.ts.map +1 -0
- package/dist/components/shipping/ProductDeliveryInfoSection.js +22 -0
- package/dist/components/shipping/ShippingQuoteAddressForm.d.ts +11 -0
- package/dist/components/shipping/ShippingQuoteAddressForm.d.ts.map +1 -0
- package/dist/components/shipping/ShippingQuoteAddressForm.js +66 -0
- package/dist/components/ui/address-selector.d.ts +11 -0
- package/dist/components/ui/address-selector.d.ts.map +1 -0
- package/dist/components/ui/address-selector.js +21 -0
- package/dist/components/ui/alert-modal.d.ts +21 -0
- package/dist/components/ui/alert-modal.d.ts.map +1 -0
- package/dist/components/ui/alert-modal.js +59 -0
- package/dist/components/ui/avatar-image.d.ts +11 -0
- package/dist/components/ui/avatar-image.d.ts.map +1 -0
- package/dist/components/ui/avatar-image.js +39 -0
- package/dist/components/ui/background-patterns.d.ts +27 -0
- package/dist/components/ui/background-patterns.d.ts.map +1 -0
- package/dist/components/ui/background-patterns.js +5 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +20 -0
- package/dist/components/ui/breadcrumbs.d.ts +12 -0
- package/dist/components/ui/breadcrumbs.d.ts.map +1 -0
- package/dist/components/ui/breadcrumbs.js +12 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +34 -0
- package/dist/components/ui/card.d.ts +10 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +24 -0
- package/dist/components/ui/category-tree.d.ts +16 -0
- package/dist/components/ui/category-tree.d.ts.map +1 -0
- package/dist/components/ui/category-tree.js +74 -0
- package/dist/components/ui/checkout-button.d.ts +11 -0
- package/dist/components/ui/checkout-button.d.ts.map +1 -0
- package/dist/components/ui/checkout-button.js +298 -0
- package/dist/components/ui/dynamic-icon.d.ts +11 -0
- package/dist/components/ui/dynamic-icon.d.ts.map +1 -0
- package/dist/components/ui/dynamic-icon.js +77 -0
- package/dist/components/ui/guest-checkout-modal.d.ts +19 -0
- package/dist/components/ui/guest-checkout-modal.d.ts.map +1 -0
- package/dist/components/ui/guest-checkout-modal.js +95 -0
- package/dist/components/ui/image-skeleton.d.ts +7 -0
- package/dist/components/ui/image-skeleton.d.ts.map +1 -0
- package/dist/components/ui/image-skeleton.js +15 -0
- package/dist/components/ui/image-with-fallback.d.ts +10 -0
- package/dist/components/ui/image-with-fallback.d.ts.map +1 -0
- package/dist/components/ui/image-with-fallback.js +165 -0
- package/dist/components/ui/input.d.ts +6 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/limited-time-offer-badge.d.ts +12 -0
- package/dist/components/ui/limited-time-offer-badge.d.ts.map +1 -0
- package/dist/components/ui/limited-time-offer-badge.js +13 -0
- package/dist/components/ui/loading-skeleton-wrapper.d.ts +6 -0
- package/dist/components/ui/loading-skeleton-wrapper.d.ts.map +1 -0
- package/dist/components/ui/loading-skeleton-wrapper.js +10 -0
- package/dist/components/ui/modal.d.ts +11 -0
- package/dist/components/ui/modal.d.ts.map +1 -0
- package/dist/components/ui/modal.js +26 -0
- package/dist/components/ui/otp-input.d.ts +10 -0
- package/dist/components/ui/otp-input.d.ts.map +1 -0
- package/dist/components/ui/otp-input.js +57 -0
- package/dist/components/ui/out-of-stock-overlay.d.ts +8 -0
- package/dist/components/ui/out-of-stock-overlay.d.ts.map +1 -0
- package/dist/components/ui/out-of-stock-overlay.js +12 -0
- package/dist/components/ui/page-animate-wrapper.d.ts +7 -0
- package/dist/components/ui/page-animate-wrapper.d.ts.map +1 -0
- package/dist/components/ui/page-animate-wrapper.js +13 -0
- package/dist/components/ui/page-content-loader.d.ts +13 -0
- package/dist/components/ui/page-content-loader.d.ts.map +1 -0
- package/dist/components/ui/page-content-loader.js +12 -0
- package/dist/components/ui/page-loader.d.ts +20 -0
- package/dist/components/ui/page-loader.d.ts.map +1 -0
- package/dist/components/ui/page-loader.js +31 -0
- package/dist/components/ui/product-card.d.ts +11 -0
- package/dist/components/ui/product-card.d.ts.map +1 -0
- package/dist/components/ui/product-card.js +124 -0
- package/dist/components/ui/product-rating.d.ts +17 -0
- package/dist/components/ui/product-rating.d.ts.map +1 -0
- package/dist/components/ui/product-rating.js +54 -0
- package/dist/components/ui/product-stock-badge.d.ts +9 -0
- package/dist/components/ui/product-stock-badge.d.ts.map +1 -0
- package/dist/components/ui/product-stock-badge.js +20 -0
- package/dist/components/ui/review-form.d.ts +9 -0
- package/dist/components/ui/review-form.d.ts.map +1 -0
- package/dist/components/ui/review-form.js +28 -0
- package/dist/components/ui/route-skeleton-loader.d.ts +7 -0
- package/dist/components/ui/route-skeleton-loader.d.ts.map +1 -0
- package/dist/components/ui/route-skeleton-loader.js +75 -0
- package/dist/components/ui/sheet.d.ts +29 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sheet.js +45 -0
- package/dist/components/ui/skeleton.d.ts +3 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeleton.js +6 -0
- package/dist/components/ui/skeletons/category-grid-skeleton.d.ts +6 -0
- package/dist/components/ui/skeletons/category-grid-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/category-grid-skeleton.js +9 -0
- package/dist/components/ui/skeletons/checkout-skeleton.d.ts +2 -0
- package/dist/components/ui/skeletons/checkout-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/checkout-skeleton.js +4 -0
- package/dist/components/ui/skeletons/index.d.ts +6 -0
- package/dist/components/ui/skeletons/index.d.ts.map +1 -0
- package/dist/components/ui/skeletons/index.js +5 -0
- package/dist/components/ui/skeletons/page-skeleton.d.ts +2 -0
- package/dist/components/ui/skeletons/page-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/page-skeleton.js +4 -0
- package/dist/components/ui/skeletons/product-card-skeleton.d.ts +2 -0
- package/dist/components/ui/skeletons/product-card-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/product-card-skeleton.js +4 -0
- package/dist/components/ui/skeletons/product-detail-skeleton.d.ts +2 -0
- package/dist/components/ui/skeletons/product-detail-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/product-detail-skeleton.js +4 -0
- package/dist/components/ui/skeletons/product-grid-skeleton.d.ts +7 -0
- package/dist/components/ui/skeletons/product-grid-skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeletons/product-grid-skeleton.js +12 -0
- package/dist/components/ui/store-logos.d.ts +43 -0
- package/dist/components/ui/store-logos.d.ts.map +1 -0
- package/dist/components/ui/store-logos.js +83 -0
- package/dist/components/ui/toast.d.ts +20 -0
- package/dist/components/ui/toast.d.ts.map +1 -0
- package/dist/components/ui/toast.js +33 -0
- package/dist/components/ui/video-player.d.ts +48 -0
- package/dist/components/ui/video-player.d.ts.map +1 -0
- package/dist/components/ui/video-player.js +101 -0
- package/dist/editor/alignment-schemas/booking-agenda.d.ts +3 -0
- package/dist/editor/alignment-schemas/booking-agenda.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/booking-agenda.js +145 -0
- package/dist/editor/alignment-schemas/booking-footer-section.d.ts +4 -0
- package/dist/editor/alignment-schemas/booking-footer-section.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/booking-footer-section.js +69 -0
- package/dist/editor/alignment-schemas/booking.d.ts +3 -0
- package/dist/editor/alignment-schemas/booking.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/booking.js +476 -0
- package/dist/editor/alignment-schemas/clothing-minimal.d.ts +3 -0
- package/dist/editor/alignment-schemas/clothing-minimal.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/clothing-minimal.js +363 -0
- package/dist/editor/alignment-schemas/clothing.d.ts +3 -0
- package/dist/editor/alignment-schemas/clothing.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/clothing.js +477 -0
- package/dist/editor/alignment-schemas/electronics-grid.d.ts +3 -0
- package/dist/editor/alignment-schemas/electronics-grid.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/electronics-grid.js +97 -0
- package/dist/editor/alignment-schemas/electronics.d.ts +3 -0
- package/dist/editor/alignment-schemas/electronics.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/electronics.js +145 -0
- package/dist/editor/alignment-schemas/food-modern.d.ts +3 -0
- package/dist/editor/alignment-schemas/food-modern.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/food-modern.js +237 -0
- package/dist/editor/alignment-schemas/food.d.ts +3 -0
- package/dist/editor/alignment-schemas/food.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/food.js +494 -0
- package/dist/editor/alignment-schemas/index.d.ts +15 -0
- package/dist/editor/alignment-schemas/index.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/index.js +50 -0
- package/dist/editor/alignment-schemas/lazy-loader.d.ts +14 -0
- package/dist/editor/alignment-schemas/lazy-loader.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/lazy-loader.js +80 -0
- package/dist/editor/alignment-schemas/metadata.d.ts +25 -0
- package/dist/editor/alignment-schemas/metadata.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/metadata.js +225 -0
- package/dist/editor/alignment-schemas/motivational-speaker.d.ts +3 -0
- package/dist/editor/alignment-schemas/motivational-speaker.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/motivational-speaker.js +185 -0
- package/dist/editor/alignment-schemas/resolve-canvas-inspector-leaf.d.ts +18 -0
- package/dist/editor/alignment-schemas/resolve-canvas-inspector-leaf.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/resolve-canvas-inspector-leaf.js +166 -0
- package/dist/editor/alignment-schemas/resolve-field.d.ts +9 -0
- package/dist/editor/alignment-schemas/resolve-field.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/resolve-field.js +56 -0
- package/dist/editor/alignment-schemas/types.d.ts +53 -0
- package/dist/editor/alignment-schemas/types.d.ts.map +1 -0
- package/dist/editor/alignment-schemas/types.js +1 -0
- package/dist/editor/blocks/defaults/clothing-minimal-home.d.ts +9 -0
- package/dist/editor/blocks/defaults/clothing-minimal-home.d.ts.map +1 -0
- package/dist/editor/blocks/defaults/clothing-minimal-home.js +207 -0
- package/dist/editor/blocks/index.d.ts +4 -0
- package/dist/editor/blocks/index.d.ts.map +1 -0
- package/dist/editor/blocks/index.js +3 -0
- package/dist/editor/blocks/migrate-clothing-minimal.d.ts +5 -0
- package/dist/editor/blocks/migrate-clothing-minimal.d.ts.map +1 -0
- package/dist/editor/blocks/migrate-clothing-minimal.js +140 -0
- package/dist/editor/blocks/nav-outline-utils.d.ts +47 -0
- package/dist/editor/blocks/nav-outline-utils.d.ts.map +1 -0
- package/dist/editor/blocks/nav-outline-utils.js +201 -0
- package/dist/editor/blocks/registry.d.ts +19 -0
- package/dist/editor/blocks/registry.d.ts.map +1 -0
- package/dist/editor/blocks/registry.js +118 -0
- package/dist/editor/blocks/types.d.ts +14 -0
- package/dist/editor/blocks/types.d.ts.map +1 -0
- package/dist/editor/blocks/types.js +14 -0
- package/dist/editor/document/adapter.d.ts +44 -0
- package/dist/editor/document/adapter.d.ts.map +1 -0
- package/dist/editor/document/adapter.js +159 -0
- package/dist/editor/document/block-tree.d.ts +46 -0
- package/dist/editor/document/block-tree.d.ts.map +1 -0
- package/dist/editor/document/block-tree.js +345 -0
- package/dist/editor/document/constants.d.ts +6 -0
- package/dist/editor/document/constants.d.ts.map +1 -0
- package/dist/editor/document/constants.js +14 -0
- package/dist/editor/document/index.d.ts +7 -0
- package/dist/editor/document/index.d.ts.map +1 -0
- package/dist/editor/document/index.js +6 -0
- package/dist/editor/document/layout-id.d.ts +3 -0
- package/dist/editor/document/layout-id.d.ts.map +1 -0
- package/dist/editor/document/layout-id.js +17 -0
- package/dist/editor/document/types.d.ts +91 -0
- package/dist/editor/document/types.d.ts.map +1 -0
- package/dist/editor/document/types.js +1 -0
- package/dist/editor/document/validate.d.ts +11 -0
- package/dist/editor/document/validate.d.ts.map +1 -0
- package/dist/editor/document/validate.js +92 -0
- package/dist/editor/feature-flags.d.ts +11 -0
- package/dist/editor/feature-flags.d.ts.map +1 -0
- package/dist/editor/feature-flags.js +19 -0
- package/dist/editor/index.d.ts +28 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +72 -0
- package/dist/editor/layout-content-loader.d.ts +13 -0
- package/dist/editor/layout-content-loader.d.ts.map +1 -0
- package/dist/editor/layout-content-loader.js +222 -0
- package/dist/editor/payaza-form/ActiveArrayFocusContext.d.ts +20 -0
- package/dist/editor/payaza-form/ActiveArrayFocusContext.d.ts.map +1 -0
- package/dist/editor/payaza-form/ActiveArrayFocusContext.js +31 -0
- package/dist/editor/payaza-form/ArrayItemManager.d.ts +19 -0
- package/dist/editor/payaza-form/ArrayItemManager.d.ts.map +1 -0
- package/dist/editor/payaza-form/ArrayItemManager.js +62 -0
- package/dist/editor/payaza-form/AssetSelectionContext.d.ts +17 -0
- package/dist/editor/payaza-form/AssetSelectionContext.d.ts.map +1 -0
- package/dist/editor/payaza-form/AssetSelectionContext.js +81 -0
- package/dist/editor/payaza-form/EditorCanvasPreview.d.ts +41 -0
- package/dist/editor/payaza-form/EditorCanvasPreview.d.ts.map +1 -0
- package/dist/editor/payaza-form/EditorCanvasPreview.js +56 -0
- package/dist/editor/payaza-form/EditorLayoutContext.d.ts +8 -0
- package/dist/editor/payaza-form/EditorLayoutContext.d.ts.map +1 -0
- package/dist/editor/payaza-form/EditorLayoutContext.js +6 -0
- package/dist/editor/payaza-form/FieldRenderer.d.ts +16 -0
- package/dist/editor/payaza-form/FieldRenderer.d.ts.map +1 -0
- package/dist/editor/payaza-form/FieldRenderer.js +192 -0
- package/dist/editor/payaza-form/IframePreviewMessageBridge.d.ts +29 -0
- package/dist/editor/payaza-form/IframePreviewMessageBridge.d.ts.map +1 -0
- package/dist/editor/payaza-form/IframePreviewMessageBridge.js +46 -0
- package/dist/editor/payaza-form/PayazaFormEditor.d.ts +12 -0
- package/dist/editor/payaza-form/PayazaFormEditor.d.ts.map +1 -0
- package/dist/editor/payaza-form/PayazaFormEditor.js +1226 -0
- package/dist/editor/payaza-form/PayazaFormEditorFullPage.d.ts +9 -0
- package/dist/editor/payaza-form/PayazaFormEditorFullPage.d.ts.map +1 -0
- package/dist/editor/payaza-form/PayazaFormEditorFullPage.js +6 -0
- package/dist/editor/payaza-form/SliderArrayEditor.d.ts +17 -0
- package/dist/editor/payaza-form/SliderArrayEditor.d.ts.map +1 -0
- package/dist/editor/payaza-form/SliderArrayEditor.js +96 -0
- package/dist/editor/payaza-form/components/ArrayField.d.ts +21 -0
- package/dist/editor/payaza-form/components/ArrayField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/ArrayField.js +18 -0
- package/dist/editor/payaza-form/components/BlockStylesInspector.d.ts +9 -0
- package/dist/editor/payaza-form/components/BlockStylesInspector.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/BlockStylesInspector.js +150 -0
- package/dist/editor/payaza-form/components/BlocksField.d.ts +17 -0
- package/dist/editor/payaza-form/components/BlocksField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/BlocksField.js +108 -0
- package/dist/editor/payaza-form/components/ButtonField.d.ts +15 -0
- package/dist/editor/payaza-form/components/ButtonField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/ButtonField.js +17 -0
- package/dist/editor/payaza-form/components/CanvasGranularInspector.d.ts +16 -0
- package/dist/editor/payaza-form/components/CanvasGranularInspector.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/CanvasGranularInspector.js +32 -0
- package/dist/editor/payaza-form/components/FieldDensityContext.d.ts +10 -0
- package/dist/editor/payaza-form/components/FieldDensityContext.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/FieldDensityContext.js +13 -0
- package/dist/editor/payaza-form/components/IconField.d.ts +12 -0
- package/dist/editor/payaza-form/components/IconField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/IconField.js +42 -0
- package/dist/editor/payaza-form/components/ImageField.d.ts +10 -0
- package/dist/editor/payaza-form/components/ImageField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/ImageField.js +30 -0
- package/dist/editor/payaza-form/components/NumberField.d.ts +14 -0
- package/dist/editor/payaza-form/components/NumberField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/NumberField.js +23 -0
- package/dist/editor/payaza-form/components/ObjectField.d.ts +11 -0
- package/dist/editor/payaza-form/components/ObjectField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/ObjectField.js +7 -0
- package/dist/editor/payaza-form/components/RichTextField.d.ts +15 -0
- package/dist/editor/payaza-form/components/RichTextField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/RichTextField.js +88 -0
- package/dist/editor/payaza-form/components/SectionField.d.ts +14 -0
- package/dist/editor/payaza-form/components/SectionField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/SectionField.js +8 -0
- package/dist/editor/payaza-form/components/SectionSchemaInspector.d.ts +18 -0
- package/dist/editor/payaza-form/components/SectionSchemaInspector.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/SectionSchemaInspector.js +64 -0
- package/dist/editor/payaza-form/components/SegmentedControlField.d.ts +13 -0
- package/dist/editor/payaza-form/components/SegmentedControlField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/SegmentedControlField.js +7 -0
- package/dist/editor/payaza-form/components/StarRatingField.d.ts +13 -0
- package/dist/editor/payaza-form/components/StarRatingField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/StarRatingField.js +16 -0
- package/dist/editor/payaza-form/components/TextField.d.ts +13 -0
- package/dist/editor/payaza-form/components/TextField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/TextField.js +12 -0
- package/dist/editor/payaza-form/components/TextareaField.d.ts +11 -0
- package/dist/editor/payaza-form/components/TextareaField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/TextareaField.js +6 -0
- package/dist/editor/payaza-form/components/ToggleField.d.ts +12 -0
- package/dist/editor/payaza-form/components/ToggleField.d.ts.map +1 -0
- package/dist/editor/payaza-form/components/ToggleField.js +15 -0
- package/dist/editor/payaza-form/data-merger.d.ts +28 -0
- package/dist/editor/payaza-form/data-merger.d.ts.map +1 -0
- package/dist/editor/payaza-form/data-merger.js +878 -0
- package/dist/editor/payaza-form/data-transformer.d.ts +28 -0
- package/dist/editor/payaza-form/data-transformer.d.ts.map +1 -0
- package/dist/editor/payaza-form/data-transformer.js +304 -0
- package/dist/editor/payaza-form/engine.d.ts +72 -0
- package/dist/editor/payaza-form/engine.d.ts.map +1 -0
- package/dist/editor/payaza-form/engine.js +140 -0
- package/dist/editor/payaza-form/examples/custom-widgets.example.d.ts +8 -0
- package/dist/editor/payaza-form/examples/custom-widgets.example.d.ts.map +1 -0
- package/dist/editor/payaza-form/examples/custom-widgets.example.js +51 -0
- package/dist/editor/payaza-form/field-renderer-ref.d.ts +4 -0
- package/dist/editor/payaza-form/field-renderer-ref.d.ts.map +1 -0
- package/dist/editor/payaza-form/field-renderer-ref.js +16 -0
- package/dist/editor/payaza-form/index.d.ts +11 -0
- package/dist/editor/payaza-form/index.d.ts.map +1 -0
- package/dist/editor/payaza-form/index.js +8 -0
- package/dist/editor/payaza-form/layout-loader.d.ts +12 -0
- package/dist/editor/payaza-form/layout-loader.d.ts.map +1 -0
- package/dist/editor/payaza-form/layout-loader.js +43 -0
- package/dist/editor/payaza-form/payaza-style-sanitize.d.ts +14 -0
- package/dist/editor/payaza-form/payaza-style-sanitize.d.ts.map +1 -0
- package/dist/editor/payaza-form/payaza-style-sanitize.js +76 -0
- package/dist/editor/payaza-form/preview-message-handler.d.ts +18 -0
- package/dist/editor/payaza-form/preview-message-handler.d.ts.map +1 -0
- package/dist/editor/payaza-form/preview-message-handler.js +89 -0
- package/dist/editor/payaza-form/schema-bridge.d.ts +12 -0
- package/dist/editor/payaza-form/schema-bridge.d.ts.map +1 -0
- package/dist/editor/payaza-form/schema-bridge.js +90 -0
- package/dist/editor/payaza-form/widget-registry.d.ts +94 -0
- package/dist/editor/payaza-form/widget-registry.d.ts.map +1 -0
- package/dist/editor/payaza-form/widget-registry.js +107 -0
- package/dist/editor/shared/AIGenerateModal.d.ts +17 -0
- package/dist/editor/shared/AIGenerateModal.d.ts.map +1 -0
- package/dist/editor/shared/AIGenerateModal.js +59 -0
- package/dist/editor/shared/BlockOutlineTree.d.ts +14 -0
- package/dist/editor/shared/BlockOutlineTree.d.ts.map +1 -0
- package/dist/editor/shared/BlockOutlineTree.js +47 -0
- package/dist/editor/shared/EditorHeader.d.ts +61 -0
- package/dist/editor/shared/EditorHeader.d.ts.map +1 -0
- package/dist/editor/shared/EditorHeader.js +181 -0
- package/dist/editor/shared/EditorNavigator.d.ts +42 -0
- package/dist/editor/shared/EditorNavigator.d.ts.map +1 -0
- package/dist/editor/shared/EditorNavigator.js +44 -0
- package/dist/editor/shared/IframePreview.d.ts +36 -0
- package/dist/editor/shared/IframePreview.d.ts.map +1 -0
- package/dist/editor/shared/IframePreview.js +217 -0
- package/dist/editor/shared/InlineCanvasPreview.d.ts +36 -0
- package/dist/editor/shared/InlineCanvasPreview.d.ts.map +1 -0
- package/dist/editor/shared/InlineCanvasPreview.js +174 -0
- package/dist/editor/shared/LayoutRenderer.d.ts +11 -0
- package/dist/editor/shared/LayoutRenderer.d.ts.map +1 -0
- package/dist/editor/shared/LayoutRenderer.js +7 -0
- package/dist/editor/shared/PageTabs.d.ts +13 -0
- package/dist/editor/shared/PageTabs.d.ts.map +1 -0
- package/dist/editor/shared/PageTabs.js +6 -0
- package/dist/editor/shared/ResizableSidebar.d.ts +14 -0
- package/dist/editor/shared/ResizableSidebar.d.ts.map +1 -0
- package/dist/editor/shared/ResizableSidebar.js +45 -0
- package/dist/editor/shared/index.d.ts +8 -0
- package/dist/editor/shared/index.d.ts.map +1 -0
- package/dist/editor/shared/index.js +7 -0
- package/dist/editor/shared/preview-viewport.d.ts +9 -0
- package/dist/editor/shared/preview-viewport.d.ts.map +1 -0
- package/dist/editor/shared/preview-viewport.js +17 -0
- package/dist/editor/shared/useEditorChromeMetrics.d.ts +15 -0
- package/dist/editor/shared/useEditorChromeMetrics.d.ts.map +1 -0
- package/dist/editor/shared/useEditorChromeMetrics.js +52 -0
- package/dist/editor/types.d.ts +162 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/types.js +1 -0
- package/dist/hooks/use-analytics.d.ts +15 -0
- package/dist/hooks/use-analytics.d.ts.map +1 -0
- package/dist/hooks/use-analytics.js +62 -0
- package/dist/hooks/use-api.d.ts +17 -0
- package/dist/hooks/use-api.d.ts.map +1 -0
- package/dist/hooks/use-api.js +53 -0
- package/dist/hooks/use-cart-api.d.ts +28 -0
- package/dist/hooks/use-cart-api.d.ts.map +1 -0
- package/dist/hooks/use-cart-api.js +116 -0
- package/dist/hooks/use-catalog-loader.d.ts +19 -0
- package/dist/hooks/use-catalog-loader.d.ts.map +1 -0
- package/dist/hooks/use-catalog-loader.js +107 -0
- package/dist/hooks/use-catalog-price-range.d.ts +17 -0
- package/dist/hooks/use-catalog-price-range.d.ts.map +1 -0
- package/dist/hooks/use-catalog-price-range.js +26 -0
- package/dist/hooks/use-checkout-fees.d.ts +16 -0
- package/dist/hooks/use-checkout-fees.d.ts.map +1 -0
- package/dist/hooks/use-checkout-fees.js +105 -0
- package/dist/hooks/use-content-ready.d.ts +17 -0
- package/dist/hooks/use-content-ready.d.ts.map +1 -0
- package/dist/hooks/use-content-ready.js +197 -0
- package/dist/hooks/use-debounce.d.ts +6 -0
- package/dist/hooks/use-debounce.d.ts.map +1 -0
- package/dist/hooks/use-debounce.js +17 -0
- package/dist/hooks/use-multi-store-checkout-fees.d.ts +25 -0
- package/dist/hooks/use-multi-store-checkout-fees.d.ts.map +1 -0
- package/dist/hooks/use-multi-store-checkout-fees.js +116 -0
- package/dist/hooks/use-navigation-loading.d.ts +4 -0
- package/dist/hooks/use-navigation-loading.d.ts.map +1 -0
- package/dist/hooks/use-navigation-loading.js +14 -0
- package/dist/hooks/use-payaza-checkout.d.ts +15 -0
- package/dist/hooks/use-payaza-checkout.d.ts.map +1 -0
- package/dist/hooks/use-payaza-checkout.js +123 -0
- package/dist/hooks/use-product-variation-selection.d.ts +26 -0
- package/dist/hooks/use-product-variation-selection.d.ts.map +1 -0
- package/dist/hooks/use-product-variation-selection.js +26 -0
- package/dist/hooks/use-products-api.d.ts +19 -0
- package/dist/hooks/use-products-api.d.ts.map +1 -0
- package/dist/hooks/use-products-api.js +84 -0
- package/dist/hooks/use-shipping-quote.d.ts +25 -0
- package/dist/hooks/use-shipping-quote.d.ts.map +1 -0
- package/dist/hooks/use-shipping-quote.js +80 -0
- package/dist/hooks/use-store-api.d.ts +12 -0
- package/dist/hooks/use-store-api.d.ts.map +1 -0
- package/dist/hooks/use-store-api.js +73 -0
- package/dist/hooks/usePreviewSlideSync.d.ts +5 -0
- package/dist/hooks/usePreviewSlideSync.d.ts.map +1 -0
- package/dist/hooks/usePreviewSlideSync.js +28 -0
- package/dist/index.d.ts +150 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +164 -0
- package/dist/json/booking-agenda.json +166 -0
- package/dist/json/booking.json +224 -0
- package/dist/json/clothing-minimal.json +203 -0
- package/dist/json/clothing.json +418 -0
- package/dist/json/electronics-grid.json +246 -0
- package/dist/json/electronics.json +303 -0
- package/dist/json/food-modern.json +191 -0
- package/dist/json/food.json +283 -0
- package/dist/json/json-map.d.ts +7 -0
- package/dist/json/json-map.d.ts.map +1 -0
- package/dist/json/json-map.js +36 -0
- package/dist/json/motivational-speaker.json +361 -0
- package/dist/layouts/booking/components/BookingHomePage.d.ts +7 -0
- package/dist/layouts/booking/components/BookingHomePage.d.ts.map +1 -0
- package/dist/layouts/booking/components/BookingHomePage.js +107 -0
- package/dist/layouts/booking/components/BookingMultilineHeading.d.ts +20 -0
- package/dist/layouts/booking/components/BookingMultilineHeading.d.ts.map +1 -0
- package/dist/layouts/booking/components/BookingMultilineHeading.js +32 -0
- package/dist/layouts/booking/components/BookingTestimonialCard.d.ts +10 -0
- package/dist/layouts/booking/components/BookingTestimonialCard.d.ts.map +1 -0
- package/dist/layouts/booking/components/BookingTestimonialCard.js +11 -0
- package/dist/layouts/booking/components/BookingTestimonialsEmptyState.d.ts +9 -0
- package/dist/layouts/booking/components/BookingTestimonialsEmptyState.d.ts.map +1 -0
- package/dist/layouts/booking/components/BookingTestimonialsEmptyState.js +19 -0
- package/dist/layouts/booking/components/booking-about-defaults.d.ts +26 -0
- package/dist/layouts/booking/components/booking-about-defaults.d.ts.map +1 -0
- package/dist/layouts/booking/components/booking-about-defaults.js +99 -0
- package/dist/layouts/booking/components/booking-footer-defaults.d.ts +19 -0
- package/dist/layouts/booking/components/booking-footer-defaults.d.ts.map +1 -0
- package/dist/layouts/booking/components/booking-footer-defaults.js +52 -0
- package/dist/layouts/booking/components/booking-testimonial-defaults.d.ts +21 -0
- package/dist/layouts/booking/components/booking-testimonial-defaults.d.ts.map +1 -0
- package/dist/layouts/booking/components/booking-testimonial-defaults.js +112 -0
- package/dist/layouts/booking/index.d.ts +9 -0
- package/dist/layouts/booking/index.d.ts.map +1 -0
- package/dist/layouts/booking/index.js +9 -0
- package/dist/layouts/booking/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/booking/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/AboutPage.js +69 -0
- package/dist/layouts/booking/pages/BookPage.d.ts +8 -0
- package/dist/layouts/booking/pages/BookPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/BookPage.js +482 -0
- package/dist/layouts/booking/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/booking/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/CategoriesPage.js +30 -0
- package/dist/layouts/booking/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/booking/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/CategoryPage.js +51 -0
- package/dist/layouts/booking/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/booking/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/ContactPage.js +59 -0
- package/dist/layouts/booking/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/booking/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/ProductDetailPage.js +433 -0
- package/dist/layouts/booking/pages/ServicesPage.d.ts +9 -0
- package/dist/layouts/booking/pages/ServicesPage.d.ts.map +1 -0
- package/dist/layouts/booking/pages/ServicesPage.js +54 -0
- package/dist/layouts/booking-agenda/components/BookingHomePageAgenda.d.ts +7 -0
- package/dist/layouts/booking-agenda/components/BookingHomePageAgenda.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/components/BookingHomePageAgenda.js +283 -0
- package/dist/layouts/booking-agenda/index.d.ts +9 -0
- package/dist/layouts/booking-agenda/index.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/index.js +9 -0
- package/dist/layouts/booking-agenda/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/booking-agenda/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/AboutPage.js +51 -0
- package/dist/layouts/booking-agenda/pages/BookPage.d.ts +8 -0
- package/dist/layouts/booking-agenda/pages/BookPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/BookPage.js +468 -0
- package/dist/layouts/booking-agenda/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/booking-agenda/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/CategoriesPage.js +23 -0
- package/dist/layouts/booking-agenda/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/booking-agenda/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/CategoryPage.js +48 -0
- package/dist/layouts/booking-agenda/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/booking-agenda/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/ContactPage.js +57 -0
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.js +433 -0
- package/dist/layouts/booking-agenda/pages/ServicesPage.d.ts +9 -0
- package/dist/layouts/booking-agenda/pages/ServicesPage.d.ts.map +1 -0
- package/dist/layouts/booking-agenda/pages/ServicesPage.js +46 -0
- package/dist/layouts/clothing/components/ClothingHomePage.d.ts +7 -0
- package/dist/layouts/clothing/components/ClothingHomePage.d.ts.map +1 -0
- package/dist/layouts/clothing/components/ClothingHomePage.js +260 -0
- package/dist/layouts/clothing/index.d.ts +8 -0
- package/dist/layouts/clothing/index.d.ts.map +1 -0
- package/dist/layouts/clothing/index.js +8 -0
- package/dist/layouts/clothing/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/clothing/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/AboutPage.js +55 -0
- package/dist/layouts/clothing/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/clothing/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/CategoriesPage.js +34 -0
- package/dist/layouts/clothing/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/clothing/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/CategoryPage.js +77 -0
- package/dist/layouts/clothing/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/clothing/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/ContactPage.js +58 -0
- package/dist/layouts/clothing/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/clothing/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/ProductDetailPage.js +393 -0
- package/dist/layouts/clothing/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/clothing/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/clothing/pages/ProductsPage.js +268 -0
- package/dist/layouts/clothing/payaza-bindings.d.ts +23 -0
- package/dist/layouts/clothing/payaza-bindings.d.ts.map +1 -0
- package/dist/layouts/clothing/payaza-bindings.js +17 -0
- package/dist/layouts/clothing/styles/clothing.css +80 -0
- package/dist/layouts/clothing-minimal/components/ClothingHomePageMinimal.d.ts +7 -0
- package/dist/layouts/clothing-minimal/components/ClothingHomePageMinimal.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/components/ClothingHomePageMinimal.js +163 -0
- package/dist/layouts/clothing-minimal/components/clothing-minimal-block-render.d.ts +40 -0
- package/dist/layouts/clothing-minimal/components/clothing-minimal-block-render.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/components/clothing-minimal-block-render.js +180 -0
- package/dist/layouts/clothing-minimal/index.d.ts +8 -0
- package/dist/layouts/clothing-minimal/index.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/index.js +8 -0
- package/dist/layouts/clothing-minimal/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/clothing-minimal/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/AboutPage.js +71 -0
- package/dist/layouts/clothing-minimal/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/clothing-minimal/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/CategoriesPage.js +35 -0
- package/dist/layouts/clothing-minimal/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/clothing-minimal/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/CategoryPage.js +56 -0
- package/dist/layouts/clothing-minimal/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/clothing-minimal/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/ContactPage.js +53 -0
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.js +432 -0
- package/dist/layouts/clothing-minimal/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/clothing-minimal/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/clothing-minimal/pages/ProductsPage.js +274 -0
- package/dist/layouts/electronics/components/ElectronicsCategoriesPage.d.ts +7 -0
- package/dist/layouts/electronics/components/ElectronicsCategoriesPage.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsCategoriesPage.js +40 -0
- package/dist/layouts/electronics/components/ElectronicsGridProductCard.d.ts +10 -0
- package/dist/layouts/electronics/components/ElectronicsGridProductCard.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsGridProductCard.js +107 -0
- package/dist/layouts/electronics/components/ElectronicsHomePage.d.ts +7 -0
- package/dist/layouts/electronics/components/ElectronicsHomePage.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsHomePage.js +96 -0
- package/dist/layouts/electronics/components/ElectronicsPageWrapper.d.ts +8 -0
- package/dist/layouts/electronics/components/ElectronicsPageWrapper.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsPageWrapper.js +10 -0
- package/dist/layouts/electronics/components/ElectronicsProductsPage.d.ts +7 -0
- package/dist/layouts/electronics/components/ElectronicsProductsPage.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsProductsPage.js +99 -0
- package/dist/layouts/electronics/components/ElectronicsStoreFooter.d.ts +7 -0
- package/dist/layouts/electronics/components/ElectronicsStoreFooter.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsStoreFooter.js +11 -0
- package/dist/layouts/electronics/components/ElectronicsStoreHeader.d.ts +7 -0
- package/dist/layouts/electronics/components/ElectronicsStoreHeader.d.ts.map +1 -0
- package/dist/layouts/electronics/components/ElectronicsStoreHeader.js +39 -0
- package/dist/layouts/electronics/index.d.ts +19 -0
- package/dist/layouts/electronics/index.d.ts.map +1 -0
- package/dist/layouts/electronics/index.js +19 -0
- package/dist/layouts/electronics/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/AboutPage.js +51 -0
- package/dist/layouts/electronics/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/CategoriesPage.js +6 -0
- package/dist/layouts/electronics/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/electronics/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/CategoryPage.js +55 -0
- package/dist/layouts/electronics/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/ContactPage.js +57 -0
- package/dist/layouts/electronics/pages/HelpCenterPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/HelpCenterPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/HelpCenterPage.js +55 -0
- package/dist/layouts/electronics/pages/PrivacyPolicyPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/PrivacyPolicyPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/PrivacyPolicyPage.js +9 -0
- package/dist/layouts/electronics/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/electronics/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/ProductDetailPage.js +430 -0
- package/dist/layouts/electronics/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/ProductsPage.js +273 -0
- package/dist/layouts/electronics/pages/ShippingReturnsPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/ShippingReturnsPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/ShippingReturnsPage.js +7 -0
- package/dist/layouts/electronics/pages/TermsPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/TermsPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/TermsPage.js +9 -0
- package/dist/layouts/electronics/pages/TrackOrderPage.d.ts +7 -0
- package/dist/layouts/electronics/pages/TrackOrderPage.d.ts.map +1 -0
- package/dist/layouts/electronics/pages/TrackOrderPage.js +376 -0
- package/dist/layouts/electronics-grid/components/ElectronicsGridProductCard.d.ts +10 -0
- package/dist/layouts/electronics-grid/components/ElectronicsGridProductCard.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/components/ElectronicsGridProductCard.js +107 -0
- package/dist/layouts/electronics-grid/components/ElectronicsHomePageGrid.d.ts +7 -0
- package/dist/layouts/electronics-grid/components/ElectronicsHomePageGrid.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/components/ElectronicsHomePageGrid.js +111 -0
- package/dist/layouts/electronics-grid/index.d.ts +15 -0
- package/dist/layouts/electronics-grid/index.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/index.js +15 -0
- package/dist/layouts/electronics-grid/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/AboutPage.js +51 -0
- package/dist/layouts/electronics-grid/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/CategoriesPage.js +6 -0
- package/dist/layouts/electronics-grid/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/electronics-grid/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/CategoryPage.js +55 -0
- package/dist/layouts/electronics-grid/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/ContactPage.js +57 -0
- package/dist/layouts/electronics-grid/pages/ElectronicsGridCategoriesPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/ElectronicsGridCategoriesPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/ElectronicsGridCategoriesPage.js +26 -0
- package/dist/layouts/electronics-grid/pages/HelpCenterPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/HelpCenterPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/HelpCenterPage.js +55 -0
- package/dist/layouts/electronics-grid/pages/PrivacyPolicyPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/PrivacyPolicyPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/PrivacyPolicyPage.js +9 -0
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.js +430 -0
- package/dist/layouts/electronics-grid/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/ProductsPage.js +273 -0
- package/dist/layouts/electronics-grid/pages/ShippingReturnsPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/ShippingReturnsPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/ShippingReturnsPage.js +7 -0
- package/dist/layouts/electronics-grid/pages/TermsPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/TermsPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/TermsPage.js +9 -0
- package/dist/layouts/electronics-grid/pages/TrackOrderPage.d.ts +7 -0
- package/dist/layouts/electronics-grid/pages/TrackOrderPage.d.ts.map +1 -0
- package/dist/layouts/electronics-grid/pages/TrackOrderPage.js +376 -0
- package/dist/layouts/food/components/FoodHomePage.d.ts +7 -0
- package/dist/layouts/food/components/FoodHomePage.d.ts.map +1 -0
- package/dist/layouts/food/components/FoodHomePage.js +387 -0
- package/dist/layouts/food/index.d.ts +9 -0
- package/dist/layouts/food/index.d.ts.map +1 -0
- package/dist/layouts/food/index.js +9 -0
- package/dist/layouts/food/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/food/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/AboutPage.js +67 -0
- package/dist/layouts/food/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/food/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/CategoriesPage.js +26 -0
- package/dist/layouts/food/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/food/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/CategoryPage.js +65 -0
- package/dist/layouts/food/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/food/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/ContactPage.js +55 -0
- package/dist/layouts/food/pages/MenuPage.d.ts +8 -0
- package/dist/layouts/food/pages/MenuPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/MenuPage.js +107 -0
- package/dist/layouts/food/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/food/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/ProductDetailPage.js +485 -0
- package/dist/layouts/food/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/food/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/food/pages/ProductsPage.js +174 -0
- package/dist/layouts/food-modern/components/FoodHomePageModern.d.ts +7 -0
- package/dist/layouts/food-modern/components/FoodHomePageModern.d.ts.map +1 -0
- package/dist/layouts/food-modern/components/FoodHomePageModern.js +101 -0
- package/dist/layouts/food-modern/index.d.ts +9 -0
- package/dist/layouts/food-modern/index.d.ts.map +1 -0
- package/dist/layouts/food-modern/index.js +9 -0
- package/dist/layouts/food-modern/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/food-modern/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/AboutPage.js +52 -0
- package/dist/layouts/food-modern/pages/CategoriesPage.d.ts +7 -0
- package/dist/layouts/food-modern/pages/CategoriesPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/CategoriesPage.js +23 -0
- package/dist/layouts/food-modern/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/food-modern/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/CategoryPage.js +64 -0
- package/dist/layouts/food-modern/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/food-modern/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/ContactPage.js +55 -0
- package/dist/layouts/food-modern/pages/MenuPage.d.ts +8 -0
- package/dist/layouts/food-modern/pages/MenuPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/MenuPage.js +110 -0
- package/dist/layouts/food-modern/pages/ProductDetailPage.d.ts +8 -0
- package/dist/layouts/food-modern/pages/ProductDetailPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/ProductDetailPage.js +427 -0
- package/dist/layouts/food-modern/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/food-modern/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/food-modern/pages/ProductsPage.js +175 -0
- package/dist/layouts/motivational-speaker/components/MotivationalHomePage.d.ts +7 -0
- package/dist/layouts/motivational-speaker/components/MotivationalHomePage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/components/MotivationalHomePage.js +131 -0
- package/dist/layouts/motivational-speaker/components/MotivationalSpeakerPageWrapper.d.ts +3 -0
- package/dist/layouts/motivational-speaker/components/MotivationalSpeakerPageWrapper.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/components/MotivationalSpeakerPageWrapper.js +7 -0
- package/dist/layouts/motivational-speaker/index.d.ts +10 -0
- package/dist/layouts/motivational-speaker/index.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/index.js +10 -0
- package/dist/layouts/motivational-speaker/pages/AboutPage.d.ts +7 -0
- package/dist/layouts/motivational-speaker/pages/AboutPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/AboutPage.js +51 -0
- package/dist/layouts/motivational-speaker/pages/CategoryPage.d.ts +8 -0
- package/dist/layouts/motivational-speaker/pages/CategoryPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/CategoryPage.js +72 -0
- package/dist/layouts/motivational-speaker/pages/ContactPage.d.ts +7 -0
- package/dist/layouts/motivational-speaker/pages/ContactPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/ContactPage.js +57 -0
- package/dist/layouts/motivational-speaker/pages/ProductsPage.d.ts +7 -0
- package/dist/layouts/motivational-speaker/pages/ProductsPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/ProductsPage.js +273 -0
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.d.ts +8 -0
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/ServiceDetailPage.js +153 -0
- package/dist/layouts/motivational-speaker/pages/ServicesPage.d.ts +9 -0
- package/dist/layouts/motivational-speaker/pages/ServicesPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/ServicesPage.js +46 -0
- package/dist/layouts/motivational-speaker/pages/SubscriptionPage.d.ts +7 -0
- package/dist/layouts/motivational-speaker/pages/SubscriptionPage.d.ts.map +1 -0
- package/dist/layouts/motivational-speaker/pages/SubscriptionPage.js +137 -0
- package/dist/layouts/shared/components/BaseStoreLayout.d.ts +8 -0
- package/dist/layouts/shared/components/BaseStoreLayout.d.ts.map +1 -0
- package/dist/layouts/shared/components/BaseStoreLayout.js +49 -0
- package/dist/layouts/shared/components/CartLineQuantityControl.d.ts +12 -0
- package/dist/layouts/shared/components/CartLineQuantityControl.d.ts.map +1 -0
- package/dist/layouts/shared/components/CartLineQuantityControl.js +99 -0
- package/dist/layouts/shared/components/GenericPageWrapper.d.ts +8 -0
- package/dist/layouts/shared/components/GenericPageWrapper.d.ts.map +1 -0
- package/dist/layouts/shared/components/GenericPageWrapper.js +24 -0
- package/dist/layouts/shared/components/PromoBanner.d.ts +12 -0
- package/dist/layouts/shared/components/PromoBanner.d.ts.map +1 -0
- package/dist/layouts/shared/components/PromoBanner.js +17 -0
- package/dist/layouts/shared/components/StoreFooter.d.ts +7 -0
- package/dist/layouts/shared/components/StoreFooter.d.ts.map +1 -0
- package/dist/layouts/shared/components/StoreFooter.js +156 -0
- package/dist/layouts/shared/components/StoreHeader.d.ts +8 -0
- package/dist/layouts/shared/components/StoreHeader.d.ts.map +1 -0
- package/dist/layouts/shared/components/StoreHeader.js +111 -0
- package/dist/layouts/shared/components/TestimonialCard.d.ts +8 -0
- package/dist/layouts/shared/components/TestimonialCard.d.ts.map +1 -0
- package/dist/layouts/shared/components/TestimonialCard.js +10 -0
- package/dist/layouts/shared/components/headers/BookingAgendaSidebar.d.ts +8 -0
- package/dist/layouts/shared/components/headers/BookingAgendaSidebar.d.ts.map +1 -0
- package/dist/layouts/shared/components/headers/BookingAgendaSidebar.js +16 -0
- package/dist/layouts/shared/components/headers/ClothingMinimalHeader.d.ts +7 -0
- package/dist/layouts/shared/components/headers/ClothingMinimalHeader.d.ts.map +1 -0
- package/dist/layouts/shared/components/headers/ClothingMinimalHeader.js +38 -0
- package/dist/layouts/shared/components/headers/FoodModernHeader.d.ts +7 -0
- package/dist/layouts/shared/components/headers/FoodModernHeader.d.ts.map +1 -0
- package/dist/layouts/shared/components/headers/FoodModernHeader.js +61 -0
- package/dist/layouts/shared/index.d.ts +23 -0
- package/dist/layouts/shared/index.d.ts.map +1 -0
- package/dist/layouts/shared/index.js +23 -0
- package/dist/layouts/shared/pages/AccountPage.d.ts +7 -0
- package/dist/layouts/shared/pages/AccountPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/AccountPage.js +549 -0
- package/dist/layouts/shared/pages/CartPage.d.ts +7 -0
- package/dist/layouts/shared/pages/CartPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/CartPage.js +121 -0
- package/dist/layouts/shared/pages/CheckoutPage.d.ts +7 -0
- package/dist/layouts/shared/pages/CheckoutPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/CheckoutPage.js +1430 -0
- package/dist/layouts/shared/pages/CookiePolicyPage.d.ts +7 -0
- package/dist/layouts/shared/pages/CookiePolicyPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/CookiePolicyPage.js +9 -0
- package/dist/layouts/shared/pages/FeatureDisabledPage.d.ts +9 -0
- package/dist/layouts/shared/pages/FeatureDisabledPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/FeatureDisabledPage.js +8 -0
- package/dist/layouts/shared/pages/HelpCenterPage.d.ts +7 -0
- package/dist/layouts/shared/pages/HelpCenterPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/HelpCenterPage.js +55 -0
- package/dist/layouts/shared/pages/MaintenancePage.d.ts +7 -0
- package/dist/layouts/shared/pages/MaintenancePage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/MaintenancePage.js +10 -0
- package/dist/layouts/shared/pages/PortfolioPage.d.ts +7 -0
- package/dist/layouts/shared/pages/PortfolioPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/PortfolioPage.js +130 -0
- package/dist/layouts/shared/pages/PrivacyPolicyPage.d.ts +7 -0
- package/dist/layouts/shared/pages/PrivacyPolicyPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/PrivacyPolicyPage.js +9 -0
- package/dist/layouts/shared/pages/ShippingReturnsPage.d.ts +7 -0
- package/dist/layouts/shared/pages/ShippingReturnsPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/ShippingReturnsPage.js +7 -0
- package/dist/layouts/shared/pages/SizeGuidePage.d.ts +7 -0
- package/dist/layouts/shared/pages/SizeGuidePage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/SizeGuidePage.js +10 -0
- package/dist/layouts/shared/pages/StyleGuidePage.d.ts +7 -0
- package/dist/layouts/shared/pages/StyleGuidePage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/StyleGuidePage.js +126 -0
- package/dist/layouts/shared/pages/TeamPage.d.ts +7 -0
- package/dist/layouts/shared/pages/TeamPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/TeamPage.js +39 -0
- package/dist/layouts/shared/pages/TermsPage.d.ts +7 -0
- package/dist/layouts/shared/pages/TermsPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/TermsPage.js +9 -0
- package/dist/layouts/shared/pages/TrackOrderPage.d.ts +7 -0
- package/dist/layouts/shared/pages/TrackOrderPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/TrackOrderPage.js +379 -0
- package/dist/layouts/shared/pages/WishlistPage.d.ts +7 -0
- package/dist/layouts/shared/pages/WishlistPage.d.ts.map +1 -0
- package/dist/layouts/shared/pages/WishlistPage.js +144 -0
- package/dist/layouts/shared/wrappers/BookingAgendaLayout.d.ts +14 -0
- package/dist/layouts/shared/wrappers/BookingAgendaLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/BookingAgendaLayout.js +152 -0
- package/dist/layouts/shared/wrappers/ClothingLayout.d.ts +10 -0
- package/dist/layouts/shared/wrappers/ClothingLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/ClothingLayout.js +44 -0
- package/dist/layouts/shared/wrappers/ClothingMinimalLayout.d.ts +8 -0
- package/dist/layouts/shared/wrappers/ClothingMinimalLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/ClothingMinimalLayout.js +48 -0
- package/dist/layouts/shared/wrappers/ElectronicsLayout.d.ts +8 -0
- package/dist/layouts/shared/wrappers/ElectronicsLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/ElectronicsLayout.js +40 -0
- package/dist/layouts/shared/wrappers/FoodModernLayout.d.ts +8 -0
- package/dist/layouts/shared/wrappers/FoodModernLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/FoodModernLayout.js +48 -0
- package/dist/layouts/shared/wrappers/MotivationalLayout.d.ts +8 -0
- package/dist/layouts/shared/wrappers/MotivationalLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/MotivationalLayout.js +51 -0
- package/dist/layouts/shared/wrappers/StandardLayout.d.ts +8 -0
- package/dist/layouts/shared/wrappers/StandardLayout.d.ts.map +1 -0
- package/dist/layouts/shared/wrappers/StandardLayout.js +45 -0
- package/dist/lib/alignment-schemas.d.ts +51 -0
- package/dist/lib/alignment-schemas.d.ts.map +1 -0
- package/dist/lib/alignment-schemas.js +637 -0
- package/dist/lib/api.d.ts +11 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +167 -0
- package/dist/lib/auth-context.d.ts +49 -0
- package/dist/lib/auth-context.d.ts.map +1 -0
- package/dist/lib/auth-context.js +296 -0
- package/dist/lib/checkout-availability.d.ts +10 -0
- package/dist/lib/checkout-availability.d.ts.map +1 -0
- package/dist/lib/checkout-availability.js +16 -0
- package/dist/lib/compact-array-items.d.ts +7 -0
- package/dist/lib/compact-array-items.d.ts.map +1 -0
- package/dist/lib/compact-array-items.js +13 -0
- package/dist/lib/content-selectors.d.ts +21 -0
- package/dist/lib/content-selectors.d.ts.map +1 -0
- package/dist/lib/content-selectors.js +75 -0
- package/dist/lib/countries.d.ts +13 -0
- package/dist/lib/countries.d.ts.map +1 -0
- package/dist/lib/countries.js +292 -0
- package/dist/lib/currency-symbols.d.ts +36 -0
- package/dist/lib/currency-symbols.d.ts.map +1 -0
- package/dist/lib/currency-symbols.js +153 -0
- package/dist/lib/guest-user.d.ts +27 -0
- package/dist/lib/guest-user.d.ts.map +1 -0
- package/dist/lib/guest-user.js +71 -0
- package/dist/lib/inventory-utils.d.ts +41 -0
- package/dist/lib/inventory-utils.d.ts.map +1 -0
- package/dist/lib/inventory-utils.js +180 -0
- package/dist/lib/layout-badges.d.ts +4 -0
- package/dist/lib/layout-badges.d.ts.map +1 -0
- package/dist/lib/layout-badges.js +5 -0
- package/dist/lib/layout-config-hydration.d.ts +25 -0
- package/dist/lib/layout-config-hydration.d.ts.map +1 -0
- package/dist/lib/layout-config-hydration.js +264 -0
- package/dist/lib/layout-field-normalize.d.ts +18 -0
- package/dist/lib/layout-field-normalize.d.ts.map +1 -0
- package/dist/lib/layout-field-normalize.js +190 -0
- package/dist/lib/layout-route-utils.d.ts +30 -0
- package/dist/lib/layout-route-utils.d.ts.map +1 -0
- package/dist/lib/layout-route-utils.js +79 -0
- package/dist/lib/limited-time-offer.d.ts +6 -0
- package/dist/lib/limited-time-offer.d.ts.map +1 -0
- package/dist/lib/limited-time-offer.js +24 -0
- package/dist/lib/loading-context.d.ts +20 -0
- package/dist/lib/loading-context.d.ts.map +1 -0
- package/dist/lib/loading-context.js +212 -0
- package/dist/lib/mock-stores.d.ts +24 -0
- package/dist/lib/mock-stores.d.ts.map +1 -0
- package/dist/lib/mock-stores.js +2106 -0
- package/dist/lib/order-success-cart.d.ts +5 -0
- package/dist/lib/order-success-cart.d.ts.map +1 -0
- package/dist/lib/order-success-cart.js +50 -0
- package/dist/lib/payaza-checkout.d.ts +147 -0
- package/dist/lib/payaza-checkout.d.ts.map +1 -0
- package/dist/lib/payaza-checkout.js +717 -0
- package/dist/lib/payaza-section-styles.d.ts +16 -0
- package/dist/lib/payaza-section-styles.d.ts.map +1 -0
- package/dist/lib/payaza-section-styles.js +93 -0
- package/dist/lib/preview-data.d.ts +58 -0
- package/dist/lib/preview-data.d.ts.map +1 -0
- package/dist/lib/preview-data.js +2576 -0
- package/dist/lib/product-variation-utils.d.ts +8 -0
- package/dist/lib/product-variation-utils.d.ts.map +1 -0
- package/dist/lib/product-variation-utils.js +101 -0
- package/dist/lib/rich-html.d.ts +38 -0
- package/dist/lib/rich-html.d.ts.map +1 -0
- package/dist/lib/rich-html.js +272 -0
- package/dist/lib/services/analytics.service.d.ts +59 -0
- package/dist/lib/services/analytics.service.d.ts.map +1 -0
- package/dist/lib/services/analytics.service.js +382 -0
- package/dist/lib/services/auth.service.d.ts +63 -0
- package/dist/lib/services/auth.service.d.ts.map +1 -0
- package/dist/lib/services/auth.service.js +101 -0
- package/dist/lib/services/booking.service.d.ts +53 -0
- package/dist/lib/services/booking.service.d.ts.map +1 -0
- package/dist/lib/services/booking.service.js +52 -0
- package/dist/lib/services/category.service.d.ts +21 -0
- package/dist/lib/services/category.service.d.ts.map +1 -0
- package/dist/lib/services/category.service.js +41 -0
- package/dist/lib/services/checkout.service.d.ts +168 -0
- package/dist/lib/services/checkout.service.d.ts.map +1 -0
- package/dist/lib/services/checkout.service.js +48 -0
- package/dist/lib/services/contact.service.d.ts +26 -0
- package/dist/lib/services/contact.service.d.ts.map +1 -0
- package/dist/lib/services/contact.service.js +23 -0
- package/dist/lib/services/customer.service.d.ts +54 -0
- package/dist/lib/services/customer.service.d.ts.map +1 -0
- package/dist/lib/services/customer.service.js +64 -0
- package/dist/lib/services/fees.service.d.ts +85 -0
- package/dist/lib/services/fees.service.d.ts.map +1 -0
- package/dist/lib/services/fees.service.js +147 -0
- package/dist/lib/services/index.d.ts +19 -0
- package/dist/lib/services/index.d.ts.map +1 -0
- package/dist/lib/services/index.js +18 -0
- package/dist/lib/services/location.service.d.ts +31 -0
- package/dist/lib/services/location.service.d.ts.map +1 -0
- package/dist/lib/services/location.service.js +25 -0
- package/dist/lib/services/order.service.d.ts +5 -0
- package/dist/lib/services/order.service.d.ts.map +1 -0
- package/dist/lib/services/order.service.js +12 -0
- package/dist/lib/services/payment.service.d.ts +56 -0
- package/dist/lib/services/payment.service.d.ts.map +1 -0
- package/dist/lib/services/payment.service.js +122 -0
- package/dist/lib/services/product.service.d.ts +92 -0
- package/dist/lib/services/product.service.d.ts.map +1 -0
- package/dist/lib/services/product.service.js +86 -0
- package/dist/lib/services/promo.service.d.ts +31 -0
- package/dist/lib/services/promo.service.d.ts.map +1 -0
- package/dist/lib/services/promo.service.js +29 -0
- package/dist/lib/services/review.service.d.ts +47 -0
- package/dist/lib/services/review.service.d.ts.map +1 -0
- package/dist/lib/services/review.service.js +54 -0
- package/dist/lib/services/service.service.d.ts +55 -0
- package/dist/lib/services/service.service.d.ts.map +1 -0
- package/dist/lib/services/service.service.js +37 -0
- package/dist/lib/services/shipping.service.d.ts +62 -0
- package/dist/lib/services/shipping.service.d.ts.map +1 -0
- package/dist/lib/services/shipping.service.js +39 -0
- package/dist/lib/services/store.service.d.ts +89 -0
- package/dist/lib/services/store.service.d.ts.map +1 -0
- package/dist/lib/services/store.service.js +41 -0
- package/dist/lib/shipping-address.util.d.ts +76 -0
- package/dist/lib/shipping-address.util.d.ts.map +1 -0
- package/dist/lib/shipping-address.util.js +149 -0
- package/dist/lib/shipping-settings.util.d.ts +4 -0
- package/dist/lib/shipping-settings.util.d.ts.map +1 -0
- package/dist/lib/shipping-settings.util.js +6 -0
- package/dist/lib/store-config-utils.d.ts +50 -0
- package/dist/lib/store-config-utils.d.ts.map +1 -0
- package/dist/lib/store-config-utils.js +1713 -0
- package/dist/lib/store-config.d.ts +4 -0
- package/dist/lib/store-config.d.ts.map +1 -0
- package/dist/lib/store-config.js +4 -0
- package/dist/lib/store-context.d.ts +69 -0
- package/dist/lib/store-context.d.ts.map +1 -0
- package/dist/lib/store-context.js +456 -0
- package/dist/lib/store-types.d.ts +921 -0
- package/dist/lib/store-types.d.ts.map +1 -0
- package/dist/lib/store-types.js +1 -0
- package/dist/lib/template-pages.d.ts +8 -0
- package/dist/lib/template-pages.d.ts.map +1 -0
- package/dist/lib/template-pages.js +62 -0
- package/dist/lib/utils/asset-helpers.d.ts +111 -0
- package/dist/lib/utils/asset-helpers.d.ts.map +1 -0
- package/dist/lib/utils/asset-helpers.js +462 -0
- package/dist/lib/utils/catalog-price-bounds.d.ts +13 -0
- package/dist/lib/utils/catalog-price-bounds.d.ts.map +1 -0
- package/dist/lib/utils/catalog-price-bounds.js +24 -0
- package/dist/lib/utils/category-tree.d.ts +25 -0
- package/dist/lib/utils/category-tree.d.ts.map +1 -0
- package/dist/lib/utils/category-tree.js +85 -0
- package/dist/lib/utils/demo-detection.d.ts +23 -0
- package/dist/lib/utils/demo-detection.d.ts.map +1 -0
- package/dist/lib/utils/demo-detection.js +36 -0
- package/dist/lib/utils/editor-preview.d.ts +42 -0
- package/dist/lib/utils/editor-preview.d.ts.map +1 -0
- package/dist/lib/utils/editor-preview.js +214 -0
- package/dist/lib/utils/fee-calculations.d.ts +35 -0
- package/dist/lib/utils/fee-calculations.d.ts.map +1 -0
- package/dist/lib/utils/fee-calculations.js +81 -0
- package/dist/lib/utils/footer-nav-defaults.d.ts +11 -0
- package/dist/lib/utils/footer-nav-defaults.d.ts.map +1 -0
- package/dist/lib/utils/footer-nav-defaults.js +67 -0
- package/dist/lib/utils/idempotency-key.d.ts +15 -0
- package/dist/lib/utils/idempotency-key.d.ts.map +1 -0
- package/dist/lib/utils/idempotency-key.js +22 -0
- package/dist/lib/utils/index.d.ts +45 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +197 -0
- package/dist/lib/utils/mobile-editor.d.ts +13 -0
- package/dist/lib/utils/mobile-editor.d.ts.map +1 -0
- package/dist/lib/utils/mobile-editor.js +34 -0
- package/dist/lib/utils/phone-format.d.ts +6 -0
- package/dist/lib/utils/phone-format.d.ts.map +1 -0
- package/dist/lib/utils/phone-format.js +17 -0
- package/dist/lib/utils/product-catalog.d.ts +11 -0
- package/dist/lib/utils/product-catalog.d.ts.map +1 -0
- package/dist/lib/utils/product-catalog.js +40 -0
- package/dist/lib/utils/product-images.d.ts +20 -0
- package/dist/lib/utils/product-images.d.ts.map +1 -0
- package/dist/lib/utils/product-images.js +31 -0
- package/dist/lib/utils/product-share.d.ts +17 -0
- package/dist/lib/utils/product-share.d.ts.map +1 -0
- package/dist/lib/utils/product-share.js +48 -0
- package/dist/lib/utils/scroll-to-top.util.d.ts +9 -0
- package/dist/lib/utils/scroll-to-top.util.d.ts.map +1 -0
- package/dist/lib/utils/scroll-to-top.util.js +18 -0
- package/dist/lib/utils/url-helpers.d.ts +30 -0
- package/dist/lib/utils/url-helpers.d.ts.map +1 -0
- package/dist/lib/utils/url-helpers.js +61 -0
- package/dist/lib/utils/video-helpers.d.ts +32 -0
- package/dist/lib/utils/video-helpers.d.ts.map +1 -0
- package/dist/lib/utils/video-helpers.js +210 -0
- package/dist/preview/LayoutPreview.d.ts +14 -0
- package/dist/preview/LayoutPreview.d.ts.map +1 -0
- package/dist/preview/LayoutPreview.js +122 -0
- package/dist/preview/PreviewRouter.d.ts +9 -0
- package/dist/preview/PreviewRouter.d.ts.map +1 -0
- package/dist/preview/PreviewRouter.js +332 -0
- package/dist/preview/ShadowDOMWrapper.d.ts +18 -0
- package/dist/preview/ShadowDOMWrapper.d.ts.map +1 -0
- package/dist/preview/ShadowDOMWrapper.js +80 -0
- package/dist/preview/canvas/PreviewBlockToolbar.d.ts +23 -0
- package/dist/preview/canvas/PreviewBlockToolbar.d.ts.map +1 -0
- package/dist/preview/canvas/PreviewBlockToolbar.js +113 -0
- package/dist/preview/canvas/PreviewCanvasEnhancer.d.ts +17 -0
- package/dist/preview/canvas/PreviewCanvasEnhancer.d.ts.map +1 -0
- package/dist/preview/canvas/PreviewCanvasEnhancer.js +741 -0
- package/dist/preview/canvas/PreviewCanvasStyles.d.ts +4 -0
- package/dist/preview/canvas/PreviewCanvasStyles.d.ts.map +1 -0
- package/dist/preview/canvas/PreviewCanvasStyles.js +51 -0
- package/dist/preview/canvas/extract-editable-plain-text.d.ts +11 -0
- package/dist/preview/canvas/extract-editable-plain-text.d.ts.map +1 -0
- package/dist/preview/canvas/extract-editable-plain-text.js +65 -0
- package/dist/preview/canvas/field-key.d.ts +34 -0
- package/dist/preview/canvas/field-key.d.ts.map +1 -0
- package/dist/preview/canvas/field-key.js +62 -0
- package/dist/preview/canvas/preview-editable-commit.util.d.ts +3 -0
- package/dist/preview/canvas/preview-editable-commit.util.d.ts.map +1 -0
- package/dist/preview/canvas/preview-editable-commit.util.js +11 -0
- package/dist/preview/canvas/preview-flush-await.d.ts +6 -0
- package/dist/preview/canvas/preview-flush-await.d.ts.map +1 -0
- package/dist/preview/canvas/preview-flush-await.js +23 -0
- package/dist/preview/canvas/preview-flush-handle.d.ts +13 -0
- package/dist/preview/canvas/preview-flush-handle.d.ts.map +1 -0
- package/dist/preview/canvas/preview-flush-handle.js +3 -0
- package/dist/preview/canvas/preview-isolation.d.ts +9 -0
- package/dist/preview/canvas/preview-isolation.d.ts.map +1 -0
- package/dist/preview/canvas/preview-isolation.js +10 -0
- package/dist/preview/canvas/preview-messages.d.ts +65 -0
- package/dist/preview/canvas/preview-messages.d.ts.map +1 -0
- package/dist/preview/canvas/preview-messages.js +17 -0
- package/dist/preview/canvas/preview-route.d.ts +4 -0
- package/dist/preview/canvas/preview-route.d.ts.map +1 -0
- package/dist/preview/canvas/preview-route.js +76 -0
- package/dist/preview/index.d.ts +13 -0
- package/dist/preview/index.d.ts.map +1 -0
- package/dist/preview/index.js +12 -0
- package/dist/preview/route-audit.d.ts +17 -0
- package/dist/preview/route-audit.d.ts.map +1 -0
- package/dist/preview/route-audit.js +54 -0
- package/dist/styles/index.css +10598 -0
- package/dist/utils/date.d.ts +20 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +47 -0
- package/package.json +192 -0
|
@@ -0,0 +1,1430 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from '../../../components/ui/button.js';
|
|
4
|
+
import { ArrowLeft, ShieldCheck, CheckCircle, MapPin, Lock, ChevronRight, Tag, Truck, ChevronDown, Loader2, AlertCircle } from 'lucide-react';
|
|
5
|
+
import Link from 'next/link';
|
|
6
|
+
import Image from 'next/image';
|
|
7
|
+
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
8
|
+
import { cn } from '../../../lib/utils/index.js';
|
|
9
|
+
import { usePayazaCheckout } from '../../../hooks/use-payaza-checkout.js';
|
|
10
|
+
import { generateCheckoutConfig } from '../../../lib/payaza-checkout.js';
|
|
11
|
+
import { useToast } from '../../../components/ui/toast.js';
|
|
12
|
+
import { useStore } from '../../../lib/store-context.js';
|
|
13
|
+
import { useRouter } from 'next/navigation';
|
|
14
|
+
import { normalizePrice, formatCurrency, getUserFriendlyErrorMessage } from '../../../lib/utils/index.js';
|
|
15
|
+
import { checkoutService } from '../../../lib/services/checkout.service.js';
|
|
16
|
+
import { orderService } from '../../../lib/services/order.service.js';
|
|
17
|
+
import { paymentService, isPaymentConfirmed } from '../../../lib/services/payment.service.js';
|
|
18
|
+
import { ApiError } from '../../../lib/api.js';
|
|
19
|
+
import { useAuth } from '../../../lib/auth-context.js';
|
|
20
|
+
import { customerService } from '../../../lib/services/customer.service.js';
|
|
21
|
+
import { AddressSelector } from '../../../components/ui/address-selector.js';
|
|
22
|
+
import { countries, getCountryByName, getCitiesByCountry, getNigerianCitiesByState } from '../../../lib/countries.js';
|
|
23
|
+
import { useCheckoutFees } from '../../../hooks/use-checkout-fees.js';
|
|
24
|
+
import { useMultiStoreCheckoutFees } from '../../../hooks/use-multi-store-checkout-fees.js';
|
|
25
|
+
import { CheckoutFeeLines } from '../../../components/checkout/CheckoutFeeLines.js';
|
|
26
|
+
import { shippingService } from '../../../lib/services/shipping.service.js';
|
|
27
|
+
import { CHECKOUT_UNAVAILABLE_MESSAGE } from '../../../lib/checkout-availability.js';
|
|
28
|
+
import { enrichShippingQuoteAddress, buildShippingCalculatePayload, canRequestShippingQuote, isNigeria, deriveNigerianStateFromCity, NIGERIAN_STATES } from '../../../lib/shipping-address.util.js';
|
|
29
|
+
import { ShippingOptionsPanel } from '../../../components/checkout/ShippingOptionsPanel.js';
|
|
30
|
+
import { CheckoutSkeleton } from '../../../components/ui/skeletons/checkout-skeleton.js';
|
|
31
|
+
const CHECKOUT_ITEM_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
32
|
+
function normalizeCheckoutPayloadItem(item) {
|
|
33
|
+
const product = item.product;
|
|
34
|
+
return {
|
|
35
|
+
productId: item.productId,
|
|
36
|
+
storeId: product?.storeId,
|
|
37
|
+
quantity: Number(item.quantity) || 1,
|
|
38
|
+
price: normalizePrice(item.price),
|
|
39
|
+
variationId: item.variantId && CHECKOUT_ITEM_UUID_REGEX.test(item.variantId)
|
|
40
|
+
? item.variantId
|
|
41
|
+
: undefined,
|
|
42
|
+
variantId: item.variantId ?? undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
import { useAnalytics } from '../../../hooks/use-analytics.js';
|
|
46
|
+
import { getOrCreateIdempotencyKey, resetIdempotencyKey } from '../../../lib/utils/idempotency-key.js';
|
|
47
|
+
import { formatPhoneInput, validatePhone, getPhonePlaceholder, normalizePhoneForPayaza } from '../../../lib/utils/phone-format.js';
|
|
48
|
+
import { saveGuestUserInfo } from '../../../lib/guest-user.js';
|
|
49
|
+
import { InventoryHoldCountdown } from '../../../components/cart/InventoryHoldCountdown.js';
|
|
50
|
+
import { formatCheckoutStockError, getCartLineStockInfo, isInventoryHoldExpired } from '../../../lib/inventory-utils.js';
|
|
51
|
+
import { MerchantHandledDeliveryNotice } from '../../../components/shipping/MerchantHandledDeliveryNotice.js';
|
|
52
|
+
import { isAutomatedShippingEnabled } from '../../../lib/shipping-settings.util.js';
|
|
53
|
+
import { setOrderSuccessJustCompleted, isOrderSuccessPending } from '../../../lib/order-success-cart.js';
|
|
54
|
+
const PROMO_CODE_ENABLED = false;
|
|
55
|
+
function isPaymentInventoryError(error) {
|
|
56
|
+
if (!error || typeof error !== 'object')
|
|
57
|
+
return false;
|
|
58
|
+
const candidate = error;
|
|
59
|
+
if (candidate.status === 409)
|
|
60
|
+
return true;
|
|
61
|
+
const message = (candidate.message || '').toLowerCase();
|
|
62
|
+
return (message.includes('insufficient stock') ||
|
|
63
|
+
message.includes('insufficient inventory') ||
|
|
64
|
+
message.includes('out of stock'));
|
|
65
|
+
}
|
|
66
|
+
function buildOrderSuccessUrl(storeSlug, params) {
|
|
67
|
+
const search = new URLSearchParams({
|
|
68
|
+
orderId: params.orderId,
|
|
69
|
+
ref: params.ref,
|
|
70
|
+
});
|
|
71
|
+
if (params.orderNumber)
|
|
72
|
+
search.set('orderNumber', params.orderNumber);
|
|
73
|
+
if (params.email)
|
|
74
|
+
search.set('email', params.email);
|
|
75
|
+
if (params.fulfillmentPending)
|
|
76
|
+
search.set('fulfillmentPending', 'true');
|
|
77
|
+
return `/${storeSlug}/order/success?${search.toString()}`;
|
|
78
|
+
}
|
|
79
|
+
function RequiredLabel({ children }) {
|
|
80
|
+
return (_jsxs("label", { className: "text-sm font-bold text-gray-700 ml-1", children: [children, " ", _jsx("span", { className: "text-red-500", children: "*" })] }));
|
|
81
|
+
}
|
|
82
|
+
export function CheckoutPage({ storeConfig }) {
|
|
83
|
+
const primaryColor = storeConfig.branding.primaryColor;
|
|
84
|
+
const checkoutDisabled = storeConfig.checkoutEnabled === false;
|
|
85
|
+
const { cart, cartTotal, buyNowItem, clearBuyNowItem, setBuyNowItem, inventoryHoldUntil, setInventoryHoldUntil, handleInventoryHoldExpired, isCartRefreshing, refreshCart, finalizeCartAfterOrder, removeOrderItemsFromCart, isCartHydrated } = useStore();
|
|
86
|
+
const { addToast } = useToast();
|
|
87
|
+
const router = useRouter();
|
|
88
|
+
const { user, isAuthenticated } = useAuth();
|
|
89
|
+
const { trackEvent } = useAnalytics();
|
|
90
|
+
const [isHoldExpired, setIsHoldExpired] = useState(false);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
setIsHoldExpired(isInventoryHoldExpired(inventoryHoldUntil));
|
|
93
|
+
}, [inventoryHoldUntil]);
|
|
94
|
+
const isHoldBlocking = !!inventoryHoldUntil && (isHoldExpired || isInventoryHoldExpired(inventoryHoldUntil));
|
|
95
|
+
// Read from sessionStorage synchronously on mount if buyNowItem is not in context
|
|
96
|
+
const [sessionBuyNowItem] = useState(() => {
|
|
97
|
+
if (typeof window === 'undefined')
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
const stored = sessionStorage.getItem('buyNowItem');
|
|
101
|
+
if (stored) {
|
|
102
|
+
return JSON.parse(stored);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error('Failed to read buyNowItem from sessionStorage:', error);
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
});
|
|
110
|
+
// State to track buy-now restoration from sessionStorage
|
|
111
|
+
const hasRestoredRef = useRef(false);
|
|
112
|
+
// Restore buyNowItem from sessionStorage to context if needed (only once on mount)
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (hasRestoredRef.current) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
hasRestoredRef.current = true;
|
|
118
|
+
if (!buyNowItem && sessionBuyNowItem) {
|
|
119
|
+
setBuyNowItem(sessionBuyNowItem);
|
|
120
|
+
}
|
|
121
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
122
|
+
}, []);
|
|
123
|
+
// Ensure cart is loaded before rendering checkout (API-backed stores)
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!isCartHydrated) {
|
|
126
|
+
void refreshCart?.();
|
|
127
|
+
}
|
|
128
|
+
}, [isCartHydrated, refreshCart]);
|
|
129
|
+
// Use buyNowItem from context or sessionStorage, otherwise use cart
|
|
130
|
+
const effectiveBuyNowItem = buyNowItem || sessionBuyNowItem;
|
|
131
|
+
const checkoutItems = effectiveBuyNowItem ? [effectiveBuyNowItem] : cart;
|
|
132
|
+
const isMarketplaceCheckout = storeConfig.layout === 'marketplace' || storeConfig.slug === 'marketplace';
|
|
133
|
+
// Group checkout items by their real storeId regardless of context (marketplace or not) — a
|
|
134
|
+
// cart can end up spanning more than one store, and fee calculation needs to be done per store
|
|
135
|
+
// group either way. For marketplace checkouts specifically, the backend also creates one Order
|
|
136
|
+
// (and settles one Payment) per store even though the customer pays once — group the summary
|
|
137
|
+
// the same way so the customer sees this before submitting, mirroring Amazon's "split into N
|
|
138
|
+
// shipments" pattern.
|
|
139
|
+
const storeBreakdown = useMemo(() => {
|
|
140
|
+
const groups = new Map();
|
|
141
|
+
for (const item of checkoutItems) {
|
|
142
|
+
const product = item.product;
|
|
143
|
+
const storeId = product?.storeId || storeConfig.id;
|
|
144
|
+
const storeName = product?.storeName || `Store ${storeId.slice(0, 8)}`;
|
|
145
|
+
const existing = groups.get(storeId) || { storeId, storeName, subtotal: 0, itemCount: 0 };
|
|
146
|
+
existing.subtotal += normalizePrice(item.price) * item.quantity;
|
|
147
|
+
existing.itemCount += item.quantity;
|
|
148
|
+
groups.set(storeId, existing);
|
|
149
|
+
}
|
|
150
|
+
return Array.from(groups.values());
|
|
151
|
+
}, [checkoutItems, storeConfig.id]);
|
|
152
|
+
// Fees must be split per store whenever the cart spans more than one — this isn't limited to
|
|
153
|
+
// the "marketplace" virtual storefront, it's whatever the item data says.
|
|
154
|
+
const isMultiStoreCheckout = storeBreakdown.length > 1;
|
|
155
|
+
const checkoutStockIssues = useMemo(() => {
|
|
156
|
+
return checkoutItems
|
|
157
|
+
.map((item) => {
|
|
158
|
+
const stockInfo = getCartLineStockInfo(item.product, item.quantity);
|
|
159
|
+
const message = stockInfo.stockError || formatCheckoutStockError(item.product, item.quantity);
|
|
160
|
+
if (!message)
|
|
161
|
+
return null;
|
|
162
|
+
return { id: item.id, name: item.product.name, message };
|
|
163
|
+
})
|
|
164
|
+
.filter((issue) => issue != null);
|
|
165
|
+
}, [checkoutItems]);
|
|
166
|
+
const hasCheckoutStockIssues = checkoutStockIssues.length > 0;
|
|
167
|
+
const checkoutTotal = effectiveBuyNowItem
|
|
168
|
+
? effectiveBuyNowItem.price * effectiveBuyNowItem.quantity
|
|
169
|
+
: cartTotal;
|
|
170
|
+
const checkoutEntireCart = !effectiveBuyNowItem;
|
|
171
|
+
const completingOrderRef = useRef(false);
|
|
172
|
+
const [isCompletingOrder, setIsCompletingOrder] = useState(false);
|
|
173
|
+
const isPostPaymentNavigationPending = () => completingOrderRef.current || isCompletingOrder || isOrderSuccessPending();
|
|
174
|
+
const beginPostPaymentNavigation = (orderId) => {
|
|
175
|
+
completingOrderRef.current = true;
|
|
176
|
+
setIsCompletingOrder(true);
|
|
177
|
+
setOrderSuccessJustCompleted(orderId);
|
|
178
|
+
};
|
|
179
|
+
const redirectToPaymentCallback = (transactionRef) => {
|
|
180
|
+
beginPostPaymentNavigation(transactionRef);
|
|
181
|
+
router.replace(buildPaymentCallbackUrl(transactionRef));
|
|
182
|
+
};
|
|
183
|
+
const redirectToPaymentError = (reason, transactionRef, detailMessage) => {
|
|
184
|
+
const params = new URLSearchParams({ reason });
|
|
185
|
+
if (transactionRef)
|
|
186
|
+
params.set('ref', transactionRef);
|
|
187
|
+
if (detailMessage)
|
|
188
|
+
params.set('message', detailMessage);
|
|
189
|
+
setLoading(false);
|
|
190
|
+
router.replace(`/${storeConfig.slug}/payment/error?${params.toString()}`);
|
|
191
|
+
};
|
|
192
|
+
const completeOrderAndRedirect = async (orderId, transactionRef, orderNumber, customerEmail, fulfillmentPending) => {
|
|
193
|
+
beginPostPaymentNavigation(orderId);
|
|
194
|
+
if (fulfillmentPending) {
|
|
195
|
+
addToast('Payment received. Your order is under review — we will contact you if any items are unavailable.', 'info');
|
|
196
|
+
}
|
|
197
|
+
router.replace(buildOrderSuccessUrl(storeConfig.slug, {
|
|
198
|
+
orderId,
|
|
199
|
+
ref: transactionRef,
|
|
200
|
+
orderNumber: orderNumber || undefined,
|
|
201
|
+
email: customerEmail || undefined,
|
|
202
|
+
fulfillmentPending,
|
|
203
|
+
}));
|
|
204
|
+
const purchasedItems = checkoutItems.map((item) => ({
|
|
205
|
+
productId: item.productId,
|
|
206
|
+
variantId: item.variantId,
|
|
207
|
+
quantity: item.quantity,
|
|
208
|
+
}));
|
|
209
|
+
try {
|
|
210
|
+
if (finalizeCartAfterOrder) {
|
|
211
|
+
await finalizeCartAfterOrder(purchasedItems, { checkoutEntireCart });
|
|
212
|
+
}
|
|
213
|
+
else if (removeOrderItemsFromCart) {
|
|
214
|
+
await removeOrderItemsFromCart(purchasedItems);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
console.error('[Checkout] Failed to clear cart after order:', error);
|
|
219
|
+
}
|
|
220
|
+
if (effectiveBuyNowItem) {
|
|
221
|
+
clearBuyNowItem();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const [step, setStep] = useState('details');
|
|
225
|
+
const [loading, setLoading] = useState(false);
|
|
226
|
+
const lastMerchantReferenceRef = useRef(null);
|
|
227
|
+
const lastTransactionReferenceRef = useRef(null);
|
|
228
|
+
const lastCheckoutOrderIdRef = useRef(null);
|
|
229
|
+
const checkoutIdempotencyKeyRef = useRef(null);
|
|
230
|
+
const checkoutCartFingerprintRef = useRef('');
|
|
231
|
+
const checkoutItemsFingerprint = useMemo(() => {
|
|
232
|
+
return JSON.stringify(checkoutItems.map((item) => ({
|
|
233
|
+
productId: item.productId,
|
|
234
|
+
variantId: item.variantId,
|
|
235
|
+
quantity: item.quantity,
|
|
236
|
+
price: item.price,
|
|
237
|
+
})));
|
|
238
|
+
}, [checkoutItems]);
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
if (checkoutCartFingerprintRef.current && checkoutCartFingerprintRef.current !== checkoutItemsFingerprint) {
|
|
241
|
+
resetIdempotencyKey(checkoutIdempotencyKeyRef);
|
|
242
|
+
}
|
|
243
|
+
checkoutCartFingerprintRef.current = checkoutItemsFingerprint;
|
|
244
|
+
}, [checkoutItemsFingerprint]);
|
|
245
|
+
const handlePaymentCancelCleanup = useCallback(async () => {
|
|
246
|
+
const orderId = lastCheckoutOrderIdRef.current;
|
|
247
|
+
if (orderId) {
|
|
248
|
+
try {
|
|
249
|
+
await orderService.abandonPaymentAttempt(orderId);
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
console.error('[Checkout] Failed to abandon payment attempt:', error);
|
|
253
|
+
}
|
|
254
|
+
lastCheckoutOrderIdRef.current = null;
|
|
255
|
+
}
|
|
256
|
+
resetIdempotencyKey(checkoutIdempotencyKeyRef);
|
|
257
|
+
lastMerchantReferenceRef.current = null;
|
|
258
|
+
lastTransactionReferenceRef.current = null;
|
|
259
|
+
setInventoryHoldUntil?.(null);
|
|
260
|
+
try {
|
|
261
|
+
await refreshCart?.();
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
console.error('[Checkout] Failed to refresh cart after payment cancel:', error);
|
|
265
|
+
}
|
|
266
|
+
}, [refreshCart, setInventoryHoldUntil]);
|
|
267
|
+
const buildPaymentCallbackUrl = (transactionRef) => {
|
|
268
|
+
const params = new URLSearchParams({
|
|
269
|
+
reference: transactionRef,
|
|
270
|
+
storeId: storeConfig.id,
|
|
271
|
+
});
|
|
272
|
+
const merchantRef = lastMerchantReferenceRef.current;
|
|
273
|
+
if (merchantRef) {
|
|
274
|
+
params.set('merchantReference', merchantRef);
|
|
275
|
+
params.set('orderNumber', merchantRef);
|
|
276
|
+
}
|
|
277
|
+
return `/${storeConfig.slug}/payment/callback?${params.toString()}`;
|
|
278
|
+
};
|
|
279
|
+
const enrichPayazaCallbackData = (callbackData) => {
|
|
280
|
+
const merchantRef = lastMerchantReferenceRef.current || undefined;
|
|
281
|
+
const internalTrx = lastTransactionReferenceRef.current || undefined;
|
|
282
|
+
return {
|
|
283
|
+
...callbackData,
|
|
284
|
+
type: 'success',
|
|
285
|
+
status: callbackData.status || 201,
|
|
286
|
+
data: {
|
|
287
|
+
...callbackData.data,
|
|
288
|
+
merchant_reference: callbackData.data?.merchant_reference || merchantRef,
|
|
289
|
+
additional_details: {
|
|
290
|
+
...(callbackData.data?.additional_details || {}),
|
|
291
|
+
storeId: storeConfig.id,
|
|
292
|
+
merchantReference: merchantRef,
|
|
293
|
+
orderNumber: merchantRef,
|
|
294
|
+
internalTransactionReference: internalTrx,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
const resolvePostPaymentRefs = (response) => {
|
|
300
|
+
const merchantRef = lastMerchantReferenceRef.current || undefined;
|
|
301
|
+
const internalTrx = lastTransactionReferenceRef.current || undefined;
|
|
302
|
+
const payazaRef = response.callbackData?.data?.payaza_reference ||
|
|
303
|
+
(response.callbackData?.data?.transaction_reference?.startsWith('P-C-')
|
|
304
|
+
? response.callbackData.data.transaction_reference
|
|
305
|
+
: undefined);
|
|
306
|
+
const callbackTrx = response.callbackData?.data?.transaction_reference;
|
|
307
|
+
const transactionRef = (callbackTrx?.startsWith('TRX-') ? callbackTrx : undefined) ||
|
|
308
|
+
(response.transactionRef?.startsWith('TRX-') ? response.transactionRef : undefined) ||
|
|
309
|
+
internalTrx ||
|
|
310
|
+
response.transactionRef ||
|
|
311
|
+
callbackTrx ||
|
|
312
|
+
payazaRef ||
|
|
313
|
+
'';
|
|
314
|
+
return { transactionRef, payazaRef, merchantRef };
|
|
315
|
+
};
|
|
316
|
+
const tryConfirmFromReference = async (transactionRef, merchantRef) => {
|
|
317
|
+
return paymentService.confirmPaymentFromReference(transactionRef, storeConfig.id, merchantRef);
|
|
318
|
+
};
|
|
319
|
+
// Address management state
|
|
320
|
+
const [savedAddresses, setSavedAddresses] = useState([]);
|
|
321
|
+
const [selectedAddressId, setSelectedAddressId] = useState(null);
|
|
322
|
+
const [saveNewAddress, setSaveNewAddress] = useState(false);
|
|
323
|
+
const [addressLabel, setAddressLabel] = useState('');
|
|
324
|
+
const [loadingAddresses, setLoadingAddresses] = useState(false);
|
|
325
|
+
// Shipping calculation state
|
|
326
|
+
const [shippingMethods, setShippingMethods] = useState([]);
|
|
327
|
+
const [selectedShippingMethod, setSelectedShippingMethod] = useState(null);
|
|
328
|
+
const [isCalculatingShipping, setIsCalculatingShipping] = useState(false);
|
|
329
|
+
const [shippingError, setShippingError] = useState(null);
|
|
330
|
+
const [freeShippingEligible, setFreeShippingEligible] = useState(false);
|
|
331
|
+
const [freeShippingThreshold, setFreeShippingThreshold] = useState(undefined);
|
|
332
|
+
const [isCourierMode, setIsCourierMode] = useState(false);
|
|
333
|
+
const [checkingDeliveryStatus, setCheckingDeliveryStatus] = useState(false);
|
|
334
|
+
const [selectedCourier, setSelectedCourier] = useState(null);
|
|
335
|
+
// Payaza Configuration
|
|
336
|
+
// Fallback key only — the authoritative key is resolved per-currency by the
|
|
337
|
+
// backend from the database-managed registry and returned by /checkout/process
|
|
338
|
+
// as `payazaPublicKey`. Priority: backend-resolved key → storeConfig → env.
|
|
339
|
+
const payazaPublicKey = storeConfig.payment?.payazaPublicKey || process.env.NEXT_PUBLIC_PAYAZA_PUBLIC_KEY || '';
|
|
340
|
+
const { checkout: initiateCheckout, isLoading: isPayazaLoading } = usePayazaCheckout({
|
|
341
|
+
publicKey: payazaPublicKey,
|
|
342
|
+
onSuccess: async (response) => {
|
|
343
|
+
try {
|
|
344
|
+
setLoading(true);
|
|
345
|
+
const { transactionRef, payazaRef, merchantRef } = resolvePostPaymentRefs(response);
|
|
346
|
+
if (!transactionRef) {
|
|
347
|
+
addToast('Payment successful but no transaction reference. Please contact support.', 'info');
|
|
348
|
+
setLoading(false);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
console.log('[Checkout] SDK callback received, verifying payment...', {
|
|
352
|
+
transactionRef,
|
|
353
|
+
payazaRef,
|
|
354
|
+
merchantRef,
|
|
355
|
+
});
|
|
356
|
+
addToast('Verifying payment...', 'info');
|
|
357
|
+
// Step 1: Immediate check if payment already completed
|
|
358
|
+
let immediateVerification;
|
|
359
|
+
try {
|
|
360
|
+
immediateVerification = await paymentService.verifyPayment(transactionRef, storeConfig.id, merchantRef);
|
|
361
|
+
if (immediateVerification.verified && isPaymentConfirmed(immediateVerification.paymentStatus)) {
|
|
362
|
+
console.log('[Checkout] Payment already completed, proceeding to success page');
|
|
363
|
+
await completeOrderAndRedirect(immediateVerification.orderId || transactionRef, transactionRef, immediateVerification.orderNumber || undefined, formData.email || undefined);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
console.log('[Checkout] Immediate verification failed, proceeding with confirmation');
|
|
369
|
+
}
|
|
370
|
+
const confirmAndRedirect = async (confirmation) => {
|
|
371
|
+
await completeOrderAndRedirect(confirmation.orderId, transactionRef, confirmation.orderNumber || undefined, formData.email || undefined, confirmation.fulfillmentBlocked);
|
|
372
|
+
};
|
|
373
|
+
let inventoryConfirmationError = null;
|
|
374
|
+
const recordConfirmationError = (error) => {
|
|
375
|
+
if (isPaymentInventoryError(error)) {
|
|
376
|
+
inventoryConfirmationError = error;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
// Step 2: Confirm from enriched Payaza callback payload
|
|
380
|
+
if (response.callbackData) {
|
|
381
|
+
console.log('[Checkout] Processing Payaza callback confirmation immediately');
|
|
382
|
+
const enrichedCallback = enrichPayazaCallbackData(response.callbackData);
|
|
383
|
+
const MAX_RETRIES = 3;
|
|
384
|
+
const RETRY_DELAY = 1000;
|
|
385
|
+
let confirmation;
|
|
386
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
387
|
+
try {
|
|
388
|
+
confirmation = await paymentService.confirmPaymentFromCallback(enrichedCallback);
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
console.error(`[Checkout] Payment confirmation attempt ${attempt} failed:`, error);
|
|
393
|
+
recordConfirmationError(error);
|
|
394
|
+
if (inventoryConfirmationError)
|
|
395
|
+
break;
|
|
396
|
+
if (attempt < MAX_RETRIES) {
|
|
397
|
+
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY * attempt));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (inventoryConfirmationError) {
|
|
402
|
+
redirectToPaymentError('insufficient_stock', transactionRef, inventoryConfirmationError instanceof ApiError
|
|
403
|
+
? inventoryConfirmationError.message
|
|
404
|
+
: undefined);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (confirmation) {
|
|
408
|
+
await confirmAndRedirect(confirmation);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Step 3: Confirm by transaction / merchant reference (covers transfer + P-C refs)
|
|
413
|
+
console.log('[Checkout] Trying confirm-from-reference fallback');
|
|
414
|
+
const refsToTry = [transactionRef, payazaRef, lastTransactionReferenceRef.current].filter((ref, index, arr) => Boolean(ref) && arr.indexOf(ref) === index);
|
|
415
|
+
for (const ref of refsToTry) {
|
|
416
|
+
try {
|
|
417
|
+
const confirmation = await tryConfirmFromReference(ref, merchantRef);
|
|
418
|
+
if (isPaymentConfirmed(confirmation.paymentStatus)) {
|
|
419
|
+
await confirmAndRedirect(confirmation);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
console.error(`[Checkout] confirm-from-reference failed for ${ref}:`, error);
|
|
425
|
+
recordConfirmationError(error);
|
|
426
|
+
if (inventoryConfirmationError) {
|
|
427
|
+
redirectToPaymentError('insufficient_stock', transactionRef, inventoryConfirmationError instanceof ApiError
|
|
428
|
+
? inventoryConfirmationError.message
|
|
429
|
+
: undefined);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Step 4: Poll for webhook / async processing
|
|
435
|
+
console.log('[Checkout] Polling payment status after SDK success...');
|
|
436
|
+
try {
|
|
437
|
+
const polledVerification = await paymentService.pollPaymentStatus(transactionRef, storeConfig.id, {
|
|
438
|
+
maxAttempts: 10,
|
|
439
|
+
intervalMs: 1500,
|
|
440
|
+
merchantReference: merchantRef,
|
|
441
|
+
onProgress: (attempt, maxAttempts) => {
|
|
442
|
+
console.log(`[Checkout] Polling payment status (${attempt}/${maxAttempts})...`);
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
if (polledVerification?.verified && isPaymentConfirmed(polledVerification.paymentStatus)) {
|
|
446
|
+
await completeOrderAndRedirect(polledVerification.orderId || transactionRef, transactionRef, polledVerification.orderNumber || undefined, formData.email || undefined);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch (pollError) {
|
|
451
|
+
console.error('[Checkout] Polling failed:', pollError);
|
|
452
|
+
}
|
|
453
|
+
// Step 5: Final fallback — callback page with merchant reference in URL
|
|
454
|
+
if (inventoryConfirmationError) {
|
|
455
|
+
redirectToPaymentError('insufficient_stock', transactionRef, inventoryConfirmationError instanceof ApiError
|
|
456
|
+
? inventoryConfirmationError.message
|
|
457
|
+
: undefined);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
console.log('[Checkout] Redirecting to callback page for verification');
|
|
461
|
+
addToast('Payment successful. Verifying transaction...', 'info');
|
|
462
|
+
redirectToPaymentCallback(transactionRef);
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
console.error('[Checkout] Error processing payment callback:', error);
|
|
466
|
+
const { transactionRef } = resolvePostPaymentRefs(response);
|
|
467
|
+
if (isPaymentInventoryError(error) && transactionRef) {
|
|
468
|
+
redirectToPaymentError('insufficient_stock', transactionRef, error instanceof ApiError ? error.message : undefined);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (transactionRef) {
|
|
472
|
+
addToast('Payment successful. Verifying transaction...', 'info');
|
|
473
|
+
redirectToPaymentCallback(transactionRef);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
addToast('Payment successful but verification failed. Please contact support with your transaction details.', 'error');
|
|
477
|
+
setLoading(false);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
onError: async (error) => {
|
|
482
|
+
const message = String(error || '');
|
|
483
|
+
const shouldResetCheckoutState = /reference already/i.test(message) ||
|
|
484
|
+
/reservation expired/i.test(message) ||
|
|
485
|
+
/already being processed/i.test(message);
|
|
486
|
+
if (shouldResetCheckoutState) {
|
|
487
|
+
await handlePaymentCancelCleanup();
|
|
488
|
+
}
|
|
489
|
+
addToast(`Checkout error: ${error}`, 'error');
|
|
490
|
+
setLoading(false);
|
|
491
|
+
},
|
|
492
|
+
onClose: async () => {
|
|
493
|
+
await handlePaymentCancelCleanup();
|
|
494
|
+
addToast('Payment canceled', 'info');
|
|
495
|
+
setLoading(false);
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
// Track checkout_start event when checkout page loads with items
|
|
499
|
+
useEffect(() => {
|
|
500
|
+
if (!isCartHydrated || !storeConfig?.id || (checkoutItems.length === 0 && !effectiveBuyNowItem)) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const totalValue = checkoutTotal;
|
|
504
|
+
const itemCount = checkoutItems.length;
|
|
505
|
+
trackEvent({
|
|
506
|
+
eventType: 'checkout_start',
|
|
507
|
+
metadata: {
|
|
508
|
+
totalValue,
|
|
509
|
+
itemCount,
|
|
510
|
+
items: checkoutItems.map(item => ({
|
|
511
|
+
productId: item.productId,
|
|
512
|
+
quantity: item.quantity,
|
|
513
|
+
price: item.price,
|
|
514
|
+
})),
|
|
515
|
+
},
|
|
516
|
+
}).catch(err => console.warn('Failed to track checkout_start:', err));
|
|
517
|
+
}, [isCartHydrated, storeConfig?.id, checkoutItems, effectiveBuyNowItem, checkoutTotal, trackEvent]);
|
|
518
|
+
// Redirect to home if checkout items are empty (with delay to allow state propagation)
|
|
519
|
+
useEffect(() => {
|
|
520
|
+
if (!isCartHydrated) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const redirectTimer = setTimeout(() => {
|
|
524
|
+
if (isPostPaymentNavigationPending()) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const hasBuyNowInStorage = typeof window !== 'undefined' && sessionStorage.getItem('buyNowItem');
|
|
528
|
+
if (hasBuyNowInStorage) {
|
|
529
|
+
if (!effectiveBuyNowItem) {
|
|
530
|
+
try {
|
|
531
|
+
const stored = sessionStorage.getItem('buyNowItem');
|
|
532
|
+
if (stored) {
|
|
533
|
+
const parsedItem = JSON.parse(stored);
|
|
534
|
+
setBuyNowItem(parsedItem);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
console.error('Failed to restore buyNowItem:', error);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (!checkoutItems || checkoutItems.length === 0) {
|
|
547
|
+
router.push(`/${storeConfig.slug}`);
|
|
548
|
+
}
|
|
549
|
+
}, 400);
|
|
550
|
+
return () => clearTimeout(redirectTimer);
|
|
551
|
+
}, [checkoutItems, isCartHydrated, router, storeConfig.slug, effectiveBuyNowItem, setBuyNowItem]);
|
|
552
|
+
// Clear buyNowItem when component unmounts or user navigates away (not during order completion)
|
|
553
|
+
useEffect(() => {
|
|
554
|
+
return () => {
|
|
555
|
+
if (effectiveBuyNowItem && !completingOrderRef.current) {
|
|
556
|
+
clearBuyNowItem();
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}, [effectiveBuyNowItem, clearBuyNowItem]);
|
|
560
|
+
// Load saved addresses for authenticated users (runs on mount and when auth state changes)
|
|
561
|
+
useEffect(() => {
|
|
562
|
+
const loadAddresses = async () => {
|
|
563
|
+
if (isAuthenticated) {
|
|
564
|
+
setLoadingAddresses(true);
|
|
565
|
+
try {
|
|
566
|
+
const addresses = await customerService.getAddresses();
|
|
567
|
+
setSavedAddresses(addresses);
|
|
568
|
+
// Priority 1: Auto-select default address if available
|
|
569
|
+
const defaultAddress = addresses.find(a => a.isDefault);
|
|
570
|
+
if (defaultAddress) {
|
|
571
|
+
handleAddressSelect(defaultAddress.id);
|
|
572
|
+
return; // Don't pre-fill from profile if we have a saved address
|
|
573
|
+
}
|
|
574
|
+
// Priority 2: If no saved addresses, pre-fill from profile data
|
|
575
|
+
if (addresses.length === 0 && user) {
|
|
576
|
+
setFormData(prev => ({
|
|
577
|
+
email: user.email || prev.email,
|
|
578
|
+
firstName: user.firstName || prev.firstName,
|
|
579
|
+
lastName: user.lastName || prev.lastName,
|
|
580
|
+
phone: user.phone || prev.phone,
|
|
581
|
+
address: user.address || prev.address,
|
|
582
|
+
city: user.city || prev.city,
|
|
583
|
+
state: deriveNigerianStateFromCity(user.city || prev.city) || prev.state || '',
|
|
584
|
+
country: user.country || prev.country || 'Nigeria',
|
|
585
|
+
postalCode: user.zipCode || prev.postalCode,
|
|
586
|
+
}));
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
catch (error) {
|
|
590
|
+
console.error('Failed to load addresses:', error);
|
|
591
|
+
// Don't show error toast - addresses are optional
|
|
592
|
+
// Guest users can still checkout without saved addresses
|
|
593
|
+
// If address loading fails but user is authenticated, still try to pre-fill from profile
|
|
594
|
+
if (user) {
|
|
595
|
+
setFormData(prev => ({
|
|
596
|
+
email: user.email || prev.email,
|
|
597
|
+
firstName: user.firstName || prev.firstName,
|
|
598
|
+
lastName: user.lastName || prev.lastName,
|
|
599
|
+
phone: user.phone || prev.phone,
|
|
600
|
+
address: user.address || prev.address,
|
|
601
|
+
city: user.city || prev.city,
|
|
602
|
+
state: deriveNigerianStateFromCity(user.city || prev.city) || prev.state || '',
|
|
603
|
+
country: user.country || prev.country || 'Nigeria',
|
|
604
|
+
postalCode: user.zipCode || prev.postalCode,
|
|
605
|
+
}));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
finally {
|
|
609
|
+
setLoadingAddresses(false);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
loadAddresses();
|
|
614
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
615
|
+
}, [isAuthenticated]);
|
|
616
|
+
// Pre-fill form data for authenticated users when no saved address is selected
|
|
617
|
+
// This runs after addresses are loaded to ensure proper priority
|
|
618
|
+
useEffect(() => {
|
|
619
|
+
if (isAuthenticated && user && !selectedAddressId && savedAddresses.length === 0 && !loadingAddresses) {
|
|
620
|
+
setFormData(prev => ({
|
|
621
|
+
email: user.email || prev.email,
|
|
622
|
+
firstName: user.firstName || prev.firstName,
|
|
623
|
+
lastName: user.lastName || prev.lastName,
|
|
624
|
+
phone: user.phone || prev.phone,
|
|
625
|
+
address: user.address || prev.address,
|
|
626
|
+
city: user.city || prev.city,
|
|
627
|
+
state: deriveNigerianStateFromCity(user.city || prev.city) || prev.state || '',
|
|
628
|
+
country: user.country || prev.country || 'Nigeria',
|
|
629
|
+
postalCode: user.zipCode || prev.postalCode,
|
|
630
|
+
}));
|
|
631
|
+
}
|
|
632
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
633
|
+
}, [isAuthenticated, user, selectedAddressId, savedAddresses.length, loadingAddresses]);
|
|
634
|
+
// Calculate legacy shipping when address is filled (flat-rate / zone methods)
|
|
635
|
+
const calculateShipping = async () => {
|
|
636
|
+
const quoteAddress = enrichShippingQuoteAddress({
|
|
637
|
+
street: formData.address,
|
|
638
|
+
address1: formData.address,
|
|
639
|
+
city: formData.city,
|
|
640
|
+
state: formData.state || formData.city,
|
|
641
|
+
zipCode: formData.postalCode,
|
|
642
|
+
country: formData.country,
|
|
643
|
+
phone: formData.phone,
|
|
644
|
+
email: formData.email,
|
|
645
|
+
});
|
|
646
|
+
if (!canRequestShippingQuote(quoteAddress) || checkoutItems.length === 0) {
|
|
647
|
+
setShippingMethods([]);
|
|
648
|
+
setSelectedShippingMethod(null);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
setIsCalculatingShipping(true);
|
|
652
|
+
setShippingError(null);
|
|
653
|
+
try {
|
|
654
|
+
const result = await shippingService.calculateShipping(buildShippingCalculatePayload({
|
|
655
|
+
storeId: storeConfig.id,
|
|
656
|
+
address: quoteAddress,
|
|
657
|
+
customerInfo: {
|
|
658
|
+
firstName: formData.firstName,
|
|
659
|
+
lastName: formData.lastName,
|
|
660
|
+
phone: formData.phone,
|
|
661
|
+
email: formData.email,
|
|
662
|
+
},
|
|
663
|
+
items: checkoutItems.map((item) => ({
|
|
664
|
+
productId: item.productId,
|
|
665
|
+
quantity: item.quantity,
|
|
666
|
+
})),
|
|
667
|
+
subtotal,
|
|
668
|
+
currency,
|
|
669
|
+
}));
|
|
670
|
+
// Filter out any methods with invalid costs before storing
|
|
671
|
+
const validMethods = (result.methods || []).filter(method => Number.isFinite(method.cost) && method.cost >= 0);
|
|
672
|
+
setShippingMethods(validMethods);
|
|
673
|
+
setFreeShippingEligible(result.freeShippingEligible || false);
|
|
674
|
+
setFreeShippingThreshold(result.freeShippingThreshold);
|
|
675
|
+
// Auto-select first method or selected method, but only if it has valid cost
|
|
676
|
+
if (validMethods.length > 0) {
|
|
677
|
+
// Find the selected method in valid methods, or use first valid method
|
|
678
|
+
const methodToSelect = result.selectedMethod &&
|
|
679
|
+
validMethods.find(m => m.code === result.selectedMethod?.code)
|
|
680
|
+
? validMethods.find(m => m.code === result.selectedMethod?.code)
|
|
681
|
+
: validMethods[0];
|
|
682
|
+
if (methodToSelect) {
|
|
683
|
+
setSelectedShippingMethod(methodToSelect);
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
setSelectedShippingMethod(null);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
setSelectedShippingMethod(null);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
console.error('Shipping calculation error:', error);
|
|
695
|
+
setShippingError(error.message || 'Failed to calculate shipping. Please try again.');
|
|
696
|
+
setShippingMethods([]);
|
|
697
|
+
setSelectedShippingMethod(null);
|
|
698
|
+
}
|
|
699
|
+
finally {
|
|
700
|
+
setIsCalculatingShipping(false);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
// Determine currency from checkout items or store config (avoid switching to USD at checkout)
|
|
704
|
+
const getCurrency = () => {
|
|
705
|
+
if (checkoutItems.length > 0) {
|
|
706
|
+
const itemCurrency = checkoutItems[0]?.currency ?? checkoutItems[0]?.product?.currency;
|
|
707
|
+
if (itemCurrency)
|
|
708
|
+
return itemCurrency;
|
|
709
|
+
}
|
|
710
|
+
return storeConfig.settings?.currency || 'USD';
|
|
711
|
+
};
|
|
712
|
+
const currency = getCurrency();
|
|
713
|
+
// Calculations
|
|
714
|
+
const subtotal = checkoutTotal;
|
|
715
|
+
// Only use shipping cost if it's a valid number and from a properly selected method
|
|
716
|
+
const shipping = (selectedShippingMethod &&
|
|
717
|
+
Number.isFinite(selectedShippingMethod.cost) &&
|
|
718
|
+
selectedShippingMethod.cost >= 0)
|
|
719
|
+
? selectedShippingMethod.cost
|
|
720
|
+
: 0;
|
|
721
|
+
// Any cart spanning more than one real store (the marketplace virtual store or otherwise) needs
|
|
722
|
+
// fees split per store rather than a single /fees/calculate call against storeConfig.id — that
|
|
723
|
+
// id may not even be a real store row (e.g. the marketplace "virtual store"). The multi-store
|
|
724
|
+
// hook fetches every store's breakdown in one batched request and sums them (mirrors how the
|
|
725
|
+
// backend computes fees per-store during process-marketplace).
|
|
726
|
+
const multiStoreSubtotals = useMemo(() => storeBreakdown.map((s) => ({ storeId: s.storeId, subtotal: s.subtotal })), [storeBreakdown]);
|
|
727
|
+
const singleStoreFees = useCheckoutFees({
|
|
728
|
+
storeId: isMultiStoreCheckout ? undefined : storeConfig.id,
|
|
729
|
+
subtotal,
|
|
730
|
+
currency,
|
|
731
|
+
shippingCost: shipping,
|
|
732
|
+
onError: (message) => addToast(message, 'error'),
|
|
733
|
+
});
|
|
734
|
+
const multiStoreFees = useMultiStoreCheckoutFees({
|
|
735
|
+
stores: isMultiStoreCheckout ? multiStoreSubtotals : [],
|
|
736
|
+
currency,
|
|
737
|
+
onError: (message) => addToast(message, 'error'),
|
|
738
|
+
});
|
|
739
|
+
const { feeBreakdown, loading: feesLoading, totalPayable, displayLines } = isMultiStoreCheckout
|
|
740
|
+
? multiStoreFees
|
|
741
|
+
: singleStoreFees;
|
|
742
|
+
const safeSubtotal = Number.isFinite(subtotal) && subtotal >= 0 ? subtotal : 0;
|
|
743
|
+
const total = feeBreakdown?.totalPayable ?? Math.max(safeSubtotal, totalPayable);
|
|
744
|
+
// Debug logging in development
|
|
745
|
+
if (process.env.NODE_ENV === 'development' && safeSubtotal > 0 && total === 0) {
|
|
746
|
+
console.warn('[CheckoutPage] Total calculation issue detected:', {
|
|
747
|
+
subtotal: safeSubtotal,
|
|
748
|
+
shipping,
|
|
749
|
+
total,
|
|
750
|
+
feeBreakdown,
|
|
751
|
+
checkoutTotal,
|
|
752
|
+
checkoutItemsCount: checkoutItems.length,
|
|
753
|
+
effectiveBuyNowItem: !!effectiveBuyNowItem,
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
// Mock Form Data
|
|
757
|
+
const [formData, setFormData] = useState({
|
|
758
|
+
email: '',
|
|
759
|
+
firstName: '',
|
|
760
|
+
lastName: '',
|
|
761
|
+
address: '',
|
|
762
|
+
city: '',
|
|
763
|
+
state: '',
|
|
764
|
+
country: 'Nigeria',
|
|
765
|
+
postalCode: '',
|
|
766
|
+
phone: ''
|
|
767
|
+
});
|
|
768
|
+
const [errors, setErrors] = useState({});
|
|
769
|
+
const [isCountryDropdownOpen, setIsCountryDropdownOpen] = useState(false);
|
|
770
|
+
const [isCityDropdownOpen, setIsCityDropdownOpen] = useState(false);
|
|
771
|
+
const [isStateDropdownOpen, setIsStateDropdownOpen] = useState(false);
|
|
772
|
+
const [countrySearch, setCountrySearch] = useState('');
|
|
773
|
+
const [citySearch, setCitySearch] = useState('');
|
|
774
|
+
const deliveryEnabled = storeConfig.features?.delivery !== false;
|
|
775
|
+
const automatedShippingEnabled = isAutomatedShippingEnabled(storeConfig);
|
|
776
|
+
const buildQuoteAddress = () => enrichShippingQuoteAddress({
|
|
777
|
+
street: formData.address,
|
|
778
|
+
address1: formData.address,
|
|
779
|
+
city: formData.city,
|
|
780
|
+
state: formData.state || formData.city,
|
|
781
|
+
zipCode: formData.postalCode,
|
|
782
|
+
country: formData.country,
|
|
783
|
+
phone: formData.phone,
|
|
784
|
+
email: formData.email,
|
|
785
|
+
});
|
|
786
|
+
const handleCourierSelect = useCallback((selection) => {
|
|
787
|
+
setSelectedCourier(selection);
|
|
788
|
+
if (!selection) {
|
|
789
|
+
setSelectedShippingMethod(null);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
setSelectedShippingMethod({
|
|
793
|
+
code: selection.serviceCode,
|
|
794
|
+
name: selection.courierName,
|
|
795
|
+
cost: selection.price,
|
|
796
|
+
estimatedDays: 0,
|
|
797
|
+
providerKey: selection.providerKey,
|
|
798
|
+
deliveryMethodId: selection.serviceCode,
|
|
799
|
+
deliveryQuoteId: selection.quoteId,
|
|
800
|
+
});
|
|
801
|
+
}, []);
|
|
802
|
+
// Hybrid shipping: courier quotes when providers enabled, else legacy calculate
|
|
803
|
+
useEffect(() => {
|
|
804
|
+
if (!deliveryEnabled || !automatedShippingEnabled || checkoutItems.length === 0) {
|
|
805
|
+
setIsCourierMode(false);
|
|
806
|
+
setShippingMethods([]);
|
|
807
|
+
setSelectedShippingMethod(null);
|
|
808
|
+
setSelectedCourier(null);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const quoteAddress = buildQuoteAddress();
|
|
812
|
+
if (!canRequestShippingQuote(quoteAddress)) {
|
|
813
|
+
setIsCourierMode(false);
|
|
814
|
+
setShippingMethods([]);
|
|
815
|
+
setSelectedShippingMethod(null);
|
|
816
|
+
setSelectedCourier(null);
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const timer = setTimeout(async () => {
|
|
820
|
+
setCheckingDeliveryStatus(true);
|
|
821
|
+
setShippingError(null);
|
|
822
|
+
try {
|
|
823
|
+
const status = await shippingService.getDeliveryStatus(storeConfig.id);
|
|
824
|
+
const anyProvider = status.enabled && Object.values(status.providers || {}).some(Boolean);
|
|
825
|
+
setIsCourierMode(anyProvider);
|
|
826
|
+
if (anyProvider) {
|
|
827
|
+
setShippingMethods([]);
|
|
828
|
+
setSelectedShippingMethod(null);
|
|
829
|
+
setSelectedCourier(null);
|
|
830
|
+
}
|
|
831
|
+
else {
|
|
832
|
+
await calculateShipping();
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
catch {
|
|
836
|
+
setIsCourierMode(false);
|
|
837
|
+
await calculateShipping();
|
|
838
|
+
}
|
|
839
|
+
finally {
|
|
840
|
+
setCheckingDeliveryStatus(false);
|
|
841
|
+
}
|
|
842
|
+
}, 500);
|
|
843
|
+
return () => clearTimeout(timer);
|
|
844
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
845
|
+
}, [deliveryEnabled, automatedShippingEnabled, formData.address, formData.city, formData.state, formData.country, formData.postalCode, formData.email, formData.phone, formData.firstName, formData.lastName, checkoutItems.length, subtotal, currency, storeConfig.id]);
|
|
846
|
+
const validateForm = () => {
|
|
847
|
+
const newErrors = {};
|
|
848
|
+
if (!formData.email)
|
|
849
|
+
newErrors.email = 'Email is required';
|
|
850
|
+
else if (!/\S+@\S+\.\S+/.test(formData.email))
|
|
851
|
+
newErrors.email = 'Invalid email address';
|
|
852
|
+
if (!formData.firstName)
|
|
853
|
+
newErrors.firstName = 'First name is required';
|
|
854
|
+
if (!formData.lastName)
|
|
855
|
+
newErrors.lastName = 'Last name is required';
|
|
856
|
+
if (!formData.address)
|
|
857
|
+
newErrors.address = 'Address is required';
|
|
858
|
+
if (!formData.country)
|
|
859
|
+
newErrors.country = 'Country is required';
|
|
860
|
+
if (!formData.city)
|
|
861
|
+
newErrors.city = 'City is required';
|
|
862
|
+
if (isNigeria(formData.country) && !formData.state) {
|
|
863
|
+
newErrors.state = 'State is required for Nigeria';
|
|
864
|
+
}
|
|
865
|
+
if (!formData.phone)
|
|
866
|
+
newErrors.phone = 'Phone is required';
|
|
867
|
+
else if (!validatePhone(formData.phone)) {
|
|
868
|
+
newErrors.phone = 'Please enter a valid phone number';
|
|
869
|
+
}
|
|
870
|
+
setErrors(newErrors);
|
|
871
|
+
return Object.keys(newErrors).length === 0;
|
|
872
|
+
};
|
|
873
|
+
const [promoCode, setPromoCode] = useState('');
|
|
874
|
+
const [isPromoApplied, setIsPromoApplied] = useState(false);
|
|
875
|
+
const handleApplyPromo = () => {
|
|
876
|
+
if (!promoCode)
|
|
877
|
+
return;
|
|
878
|
+
setIsPromoApplied(true);
|
|
879
|
+
addToast('Promo code applied successfully!', 'success');
|
|
880
|
+
};
|
|
881
|
+
const phonePlaceholder = getPhonePlaceholder();
|
|
882
|
+
const handlePhoneChange = (value) => {
|
|
883
|
+
setFormData({ ...formData, phone: formatPhoneInput(value) });
|
|
884
|
+
};
|
|
885
|
+
// Handle address selection
|
|
886
|
+
const handleAddressSelect = (addressId) => {
|
|
887
|
+
if (addressId === null) {
|
|
888
|
+
const profileAddress = user?.address && typeof user.address === 'object'
|
|
889
|
+
? user.address.address1 ||
|
|
890
|
+
user.address.street ||
|
|
891
|
+
''
|
|
892
|
+
: typeof user?.address === 'string'
|
|
893
|
+
? user.address
|
|
894
|
+
: '';
|
|
895
|
+
// "Add new address" selected - pre-fill with profile data if available, otherwise clear
|
|
896
|
+
setFormData(prev => ({
|
|
897
|
+
email: user?.email || prev.email,
|
|
898
|
+
firstName: user?.firstName || prev.firstName,
|
|
899
|
+
lastName: user?.lastName || prev.lastName,
|
|
900
|
+
phone: user?.phone || prev.phone,
|
|
901
|
+
address: profileAddress,
|
|
902
|
+
city: (user?.address && typeof user.address === 'object'
|
|
903
|
+
? user.address.city
|
|
904
|
+
: undefined) ||
|
|
905
|
+
user?.city ||
|
|
906
|
+
'',
|
|
907
|
+
state: '',
|
|
908
|
+
country: (user?.address && typeof user.address === 'object'
|
|
909
|
+
? user.address.country
|
|
910
|
+
: undefined) ||
|
|
911
|
+
user?.country ||
|
|
912
|
+
prev.country ||
|
|
913
|
+
'Nigeria',
|
|
914
|
+
postalCode: (user?.address && typeof user.address === 'object'
|
|
915
|
+
? user.address.zipCode
|
|
916
|
+
: undefined) ||
|
|
917
|
+
user?.zipCode ||
|
|
918
|
+
'',
|
|
919
|
+
}));
|
|
920
|
+
setSelectedAddressId(null);
|
|
921
|
+
setSaveNewAddress(false);
|
|
922
|
+
setAddressLabel('');
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
const address = savedAddresses.find(a => a.id === addressId);
|
|
926
|
+
if (address) {
|
|
927
|
+
setFormData(prev => ({
|
|
928
|
+
...prev,
|
|
929
|
+
firstName: address.firstName,
|
|
930
|
+
lastName: address.lastName,
|
|
931
|
+
address: address.address1,
|
|
932
|
+
city: address.city,
|
|
933
|
+
state: address.state || '',
|
|
934
|
+
country: address.country,
|
|
935
|
+
postalCode: address.zipCode,
|
|
936
|
+
phone: address.phone || prev.phone,
|
|
937
|
+
}));
|
|
938
|
+
setSelectedAddressId(addressId);
|
|
939
|
+
setSaveNewAddress(false);
|
|
940
|
+
setAddressLabel('');
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
const saveCheckoutAddressIfNeeded = async () => {
|
|
944
|
+
if (!isAuthenticated || !saveNewAddress || selectedAddressId) {
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
try {
|
|
948
|
+
const newAddress = await customerService.addAddress({
|
|
949
|
+
firstName: formData.firstName.trim(),
|
|
950
|
+
lastName: formData.lastName.trim(),
|
|
951
|
+
address1: formData.address.trim(),
|
|
952
|
+
address2: '',
|
|
953
|
+
city: formData.city.trim(),
|
|
954
|
+
state: formData.state?.trim() || undefined,
|
|
955
|
+
zipCode: formData.postalCode?.trim() || undefined,
|
|
956
|
+
country: formData.country.trim(),
|
|
957
|
+
phone: formData.phone?.trim() || undefined,
|
|
958
|
+
isDefault: savedAddresses.length === 0,
|
|
959
|
+
label: addressLabel.trim() || undefined,
|
|
960
|
+
}, { suppressToast: true });
|
|
961
|
+
const addresses = await customerService.getAddresses();
|
|
962
|
+
setSavedAddresses(addresses);
|
|
963
|
+
handleAddressSelect(newAddress.id);
|
|
964
|
+
addToast('Address saved successfully!', 'success');
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
catch (addressError) {
|
|
968
|
+
console.error('[Checkout] Failed to save address:', addressError);
|
|
969
|
+
addToast(addressError?.message || 'Unable to save address right now. You can save it later from your account.', 'error');
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
const validateCheckoutPreFlight = () => {
|
|
974
|
+
// Validate checkout items
|
|
975
|
+
if (checkoutItems.length === 0) {
|
|
976
|
+
return { isValid: false, error: 'No items to checkout' };
|
|
977
|
+
}
|
|
978
|
+
// Note: no local Payaza key check here — the backend resolves the key for
|
|
979
|
+
// the order currency from the database registry and returns it from
|
|
980
|
+
// /checkout/process. Missing keys are reported after order creation.
|
|
981
|
+
// Validate form data
|
|
982
|
+
if (!formData.email) {
|
|
983
|
+
return { isValid: false, error: 'Email is required' };
|
|
984
|
+
}
|
|
985
|
+
if (!/\S+@\S+\.\S+/.test(formData.email)) {
|
|
986
|
+
return { isValid: false, error: 'Invalid email address' };
|
|
987
|
+
}
|
|
988
|
+
if (!formData.firstName) {
|
|
989
|
+
return { isValid: false, error: 'First name is required' };
|
|
990
|
+
}
|
|
991
|
+
if (!formData.lastName) {
|
|
992
|
+
return { isValid: false, error: 'Last name is required' };
|
|
993
|
+
}
|
|
994
|
+
if (!formData.address) {
|
|
995
|
+
return { isValid: false, error: 'Address is required' };
|
|
996
|
+
}
|
|
997
|
+
if (!formData.city) {
|
|
998
|
+
return { isValid: false, error: 'City is required' };
|
|
999
|
+
}
|
|
1000
|
+
if (!formData.phone) {
|
|
1001
|
+
return { isValid: false, error: 'Phone is required' };
|
|
1002
|
+
}
|
|
1003
|
+
if (!validatePhone(formData.phone)) {
|
|
1004
|
+
return { isValid: false, error: 'Please enter a valid phone number' };
|
|
1005
|
+
}
|
|
1006
|
+
if (isNigeria(formData.country) && !formData.state) {
|
|
1007
|
+
return { isValid: false, error: 'State is required for Nigeria' };
|
|
1008
|
+
}
|
|
1009
|
+
// Validate currency availability
|
|
1010
|
+
const hasCurrency = storeConfig.settings?.currency || checkoutItems.some(item => item.product.currency);
|
|
1011
|
+
if (!hasCurrency) {
|
|
1012
|
+
console.warn('[Checkout] No currency found, will use USD fallback');
|
|
1013
|
+
}
|
|
1014
|
+
for (const item of checkoutItems) {
|
|
1015
|
+
const stockError = formatCheckoutStockError(item.product, item.quantity);
|
|
1016
|
+
if (stockError) {
|
|
1017
|
+
return {
|
|
1018
|
+
isValid: false,
|
|
1019
|
+
error: stockError,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return { isValid: true };
|
|
1024
|
+
};
|
|
1025
|
+
const handlePayazaCheckout = async () => {
|
|
1026
|
+
if (checkoutDisabled) {
|
|
1027
|
+
addToast(CHECKOUT_UNAVAILABLE_MESSAGE, 'error');
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
// Pre-flight validation
|
|
1031
|
+
const validation = validateCheckoutPreFlight();
|
|
1032
|
+
if (!validation.isValid) {
|
|
1033
|
+
addToast(validation.error || 'Please complete all required fields', 'error');
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
if (hasCheckoutStockIssues) {
|
|
1037
|
+
addToast(checkoutStockIssues[0]?.message || 'One or more items are no longer available.', 'error');
|
|
1038
|
+
refreshCart?.();
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
setLoading(true);
|
|
1042
|
+
try {
|
|
1043
|
+
await refreshCart?.();
|
|
1044
|
+
}
|
|
1045
|
+
catch (refreshError) {
|
|
1046
|
+
console.warn('[Checkout] Cart refresh before payment failed:', refreshError);
|
|
1047
|
+
}
|
|
1048
|
+
// DEMO MODE BYPASS
|
|
1049
|
+
if (storeConfig.slug.startsWith('demo/')) {
|
|
1050
|
+
setTimeout(() => {
|
|
1051
|
+
router.push(`/${storeConfig.slug}/payment/callback?status=success&reference=DEMO-${Date.now()}`);
|
|
1052
|
+
}, 1500);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
await saveCheckoutAddressIfNeeded();
|
|
1056
|
+
let checkoutResponse;
|
|
1057
|
+
let checkoutConfig;
|
|
1058
|
+
try {
|
|
1059
|
+
// Step 1: Create order via API before payment
|
|
1060
|
+
console.log('[Checkout] Step 1: Creating order via API', {
|
|
1061
|
+
storeId: storeConfig.id,
|
|
1062
|
+
itemCount: checkoutItems.length,
|
|
1063
|
+
customerEmail: formData.email,
|
|
1064
|
+
});
|
|
1065
|
+
if (!isAuthenticated && formData.email && formData.firstName && formData.lastName && formData.phone) {
|
|
1066
|
+
saveGuestUserInfo({
|
|
1067
|
+
email: formData.email,
|
|
1068
|
+
firstName: formData.firstName,
|
|
1069
|
+
lastName: formData.lastName,
|
|
1070
|
+
phone: formData.phone,
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
try {
|
|
1074
|
+
const normalizedItems = checkoutItems.map((item) => normalizeCheckoutPayloadItem(item));
|
|
1075
|
+
if (isMarketplaceCheckout) {
|
|
1076
|
+
const marketplaceItems = normalizedItems.filter((item) => item.storeId);
|
|
1077
|
+
if (marketplaceItems.length !== normalizedItems.length) {
|
|
1078
|
+
throw new Error('Some cart items are missing store information. Please refresh your cart and try again.');
|
|
1079
|
+
}
|
|
1080
|
+
// Belt-and-suspenders: the backend now hard-rejects mixed-currency marketplace
|
|
1081
|
+
// checkouts, and in the normal flow this branch is unreachable since the cart is
|
|
1082
|
+
// already pre-filtered to one currency before this page mounts. Guard here anyway for
|
|
1083
|
+
// any other consumer of this shared component that doesn't pre-filter, and to fail
|
|
1084
|
+
// fast client-side instead of round-tripping to the server first.
|
|
1085
|
+
const checkoutCurrencies = new Set(checkoutItems
|
|
1086
|
+
.map((item) => item.currency ?? item.product?.currency)
|
|
1087
|
+
.filter((value) => Boolean(value)));
|
|
1088
|
+
if (checkoutCurrencies.size > 1) {
|
|
1089
|
+
throw new Error(`Your cart has items in different currencies (${Array.from(checkoutCurrencies).join(', ')}). Please check out one currency group at a time.`);
|
|
1090
|
+
}
|
|
1091
|
+
checkoutResponse = await checkoutService.processMarketplaceCheckout({
|
|
1092
|
+
items: marketplaceItems,
|
|
1093
|
+
sessionId: typeof window !== 'undefined' ? sessionStorage.getItem('sessionId') || undefined : undefined,
|
|
1094
|
+
customerInfo: {
|
|
1095
|
+
email: formData.email,
|
|
1096
|
+
firstName: formData.firstName,
|
|
1097
|
+
lastName: formData.lastName,
|
|
1098
|
+
phone: formData.phone,
|
|
1099
|
+
},
|
|
1100
|
+
shippingAddress: {
|
|
1101
|
+
firstName: formData.firstName,
|
|
1102
|
+
lastName: formData.lastName,
|
|
1103
|
+
address1: formData.address,
|
|
1104
|
+
city: formData.city,
|
|
1105
|
+
state: formData.state || formData.city || formData.country,
|
|
1106
|
+
zipCode: formData.postalCode,
|
|
1107
|
+
country: formData.country,
|
|
1108
|
+
phone: formData.phone,
|
|
1109
|
+
},
|
|
1110
|
+
paymentMethod: 'payaza',
|
|
1111
|
+
customerId: isAuthenticated && user ? user.id : undefined,
|
|
1112
|
+
}, {
|
|
1113
|
+
idempotencyKey: getOrCreateIdempotencyKey(checkoutIdempotencyKeyRef),
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
checkoutResponse = await checkoutService.processCheckout({
|
|
1118
|
+
storeId: storeConfig.id,
|
|
1119
|
+
sessionId: typeof window !== 'undefined' ? sessionStorage.getItem('sessionId') || undefined : undefined,
|
|
1120
|
+
items: checkoutItems.map((item) => normalizeCheckoutPayloadItem(item)),
|
|
1121
|
+
customerInfo: {
|
|
1122
|
+
email: formData.email,
|
|
1123
|
+
firstName: formData.firstName,
|
|
1124
|
+
lastName: formData.lastName,
|
|
1125
|
+
phone: formData.phone,
|
|
1126
|
+
},
|
|
1127
|
+
shippingAddress: {
|
|
1128
|
+
firstName: formData.firstName,
|
|
1129
|
+
lastName: formData.lastName,
|
|
1130
|
+
address1: formData.address,
|
|
1131
|
+
city: formData.city,
|
|
1132
|
+
state: formData.state || formData.city || formData.country,
|
|
1133
|
+
zipCode: formData.postalCode,
|
|
1134
|
+
country: formData.country,
|
|
1135
|
+
phone: formData.phone,
|
|
1136
|
+
},
|
|
1137
|
+
shippingMethod: deliveryEnabled ? selectedShippingMethod?.code : undefined,
|
|
1138
|
+
shippingCost: deliveryEnabled ? shipping : 0,
|
|
1139
|
+
paymentMethod: 'payaza',
|
|
1140
|
+
deliveryProviderKey: selectedShippingMethod?.providerKey,
|
|
1141
|
+
deliveryMethodId: selectedShippingMethod?.deliveryMethodId,
|
|
1142
|
+
deliveryQuoteId: selectedShippingMethod?.deliveryQuoteId,
|
|
1143
|
+
customerId: isAuthenticated && user ? user.id : undefined, // Pass customerId for authenticated users
|
|
1144
|
+
}, {
|
|
1145
|
+
idempotencyKey: getOrCreateIdempotencyKey(checkoutIdempotencyKeyRef),
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
console.log('[Checkout] Step 1: Order created successfully', {
|
|
1149
|
+
orderId: checkoutResponse.orderId,
|
|
1150
|
+
orderNumber: checkoutResponse.orderNumber,
|
|
1151
|
+
currency: checkoutResponse.currency,
|
|
1152
|
+
transactionReference: checkoutResponse.transactionReference,
|
|
1153
|
+
});
|
|
1154
|
+
lastMerchantReferenceRef.current =
|
|
1155
|
+
checkoutResponse.merchantReference || checkoutResponse.orderNumber || null;
|
|
1156
|
+
lastTransactionReferenceRef.current = checkoutResponse.transactionReference || null;
|
|
1157
|
+
lastCheckoutOrderIdRef.current = checkoutResponse.orderId || null;
|
|
1158
|
+
if (checkoutResponse.inventoryHoldUntil) {
|
|
1159
|
+
setInventoryHoldUntil?.(checkoutResponse.inventoryHoldUntil);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
catch (apiError) {
|
|
1163
|
+
console.error('[Checkout] Step 1: API call failed', {
|
|
1164
|
+
error: apiError,
|
|
1165
|
+
message: apiError?.message,
|
|
1166
|
+
status: apiError?.status,
|
|
1167
|
+
data: apiError?.data,
|
|
1168
|
+
requestData: {
|
|
1169
|
+
storeId: storeConfig.id,
|
|
1170
|
+
itemCount: checkoutItems.length,
|
|
1171
|
+
},
|
|
1172
|
+
});
|
|
1173
|
+
const isNetworkError = !apiError?.status ||
|
|
1174
|
+
apiError?.status === 0 ||
|
|
1175
|
+
apiError?.code === 'ECONNABORTED' ||
|
|
1176
|
+
apiError?.message === 'Network Error' ||
|
|
1177
|
+
apiError?.message?.includes('timeout');
|
|
1178
|
+
if (isNetworkError) {
|
|
1179
|
+
addToast(getUserFriendlyErrorMessage(apiError, 'Unable to reach the server. Please check your connection and try again.'), 'error');
|
|
1180
|
+
}
|
|
1181
|
+
else if (apiError?.status === 500) {
|
|
1182
|
+
addToast(getUserFriendlyErrorMessage(apiError, 'A server error occurred. Please try again in a moment.'), 'error');
|
|
1183
|
+
}
|
|
1184
|
+
else if (apiError?.status === 400 || apiError?.status === 422) {
|
|
1185
|
+
addToast(getUserFriendlyErrorMessage(apiError, 'Invalid checkout data. Please review your shipping information.'), 'error');
|
|
1186
|
+
}
|
|
1187
|
+
else if (apiError?.status === 409) {
|
|
1188
|
+
addToast(getUserFriendlyErrorMessage(apiError, 'One or more items are no longer available in the requested quantity.'), 'error');
|
|
1189
|
+
refreshCart?.();
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
addToast(getUserFriendlyErrorMessage(apiError, 'Failed to create order. Please try again.'), 'error');
|
|
1193
|
+
}
|
|
1194
|
+
setLoading(false);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
// Resolve the Payaza public key. Priority order:
|
|
1198
|
+
// 1. Key resolved by the backend for the order currency from the
|
|
1199
|
+
// database-managed registry (backoffice → Payment Control)
|
|
1200
|
+
// 2. storeConfig.payment.payazaPublicKey
|
|
1201
|
+
// 3. NEXT_PUBLIC_PAYAZA_PUBLIC_KEY build-time env var
|
|
1202
|
+
const effectivePayazaPublicKey = checkoutResponse.payazaPublicKey || payazaPublicKey;
|
|
1203
|
+
if (!effectivePayazaPublicKey) {
|
|
1204
|
+
console.error('[Checkout] No Payaza public key available', {
|
|
1205
|
+
fromBackend: !!checkoutResponse.payazaPublicKey,
|
|
1206
|
+
fromStoreConfig: !!storeConfig.payment?.payazaPublicKey,
|
|
1207
|
+
fromEnv: !!process.env.NEXT_PUBLIC_PAYAZA_PUBLIC_KEY,
|
|
1208
|
+
});
|
|
1209
|
+
addToast('Payment gateway not configured. Please contact support.', 'error');
|
|
1210
|
+
setLoading(false);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
// Step 2: Convert checkout items to Payaza format
|
|
1214
|
+
console.log('[Checkout] Step 2: Converting checkout items to Payaza format');
|
|
1215
|
+
try {
|
|
1216
|
+
const payazaItems = checkoutItems.map(item => ({
|
|
1217
|
+
product: {
|
|
1218
|
+
name: item.product.name,
|
|
1219
|
+
price: item.price,
|
|
1220
|
+
currency: item.product.currency,
|
|
1221
|
+
},
|
|
1222
|
+
quantity: item.quantity,
|
|
1223
|
+
price: item.price,
|
|
1224
|
+
}));
|
|
1225
|
+
console.log('[Checkout] Step 2: Items converted', { itemCount: payazaItems.length });
|
|
1226
|
+
// Step 3: Generate Payaza checkout config with order details
|
|
1227
|
+
console.log('[Checkout] Step 3: Generating Payaza checkout config', {
|
|
1228
|
+
currency: checkoutResponse.currency || storeConfig.settings?.currency,
|
|
1229
|
+
orderId: checkoutResponse.orderId,
|
|
1230
|
+
orderNumber: checkoutResponse.orderNumber,
|
|
1231
|
+
});
|
|
1232
|
+
const orderMerchantRef = checkoutResponse.merchantReference || checkoutResponse.orderNumber || '';
|
|
1233
|
+
checkoutConfig = generateCheckoutConfig(payazaItems, formData.email, effectivePayazaPublicKey, {
|
|
1234
|
+
firstName: formData.firstName,
|
|
1235
|
+
lastName: formData.lastName,
|
|
1236
|
+
phone: normalizePhoneForPayaza(formData.phone),
|
|
1237
|
+
callbackUrl: `${typeof window !== 'undefined' ? window.location.origin : ''}/${storeConfig.slug}/payment/callback?storeId=${storeConfig.id}${orderMerchantRef ? `&merchantReference=${encodeURIComponent(orderMerchantRef)}&orderNumber=${encodeURIComponent(orderMerchantRef)}` : ''}`,
|
|
1238
|
+
currency: checkoutResponse.currency || storeConfig.settings?.currency,
|
|
1239
|
+
storeId: storeConfig.id,
|
|
1240
|
+
orderId: checkoutResponse.orderId,
|
|
1241
|
+
orderNumber: checkoutResponse.orderNumber,
|
|
1242
|
+
merchantReference: checkoutResponse.merchantReference || checkoutResponse.orderNumber,
|
|
1243
|
+
totalAmount: checkoutResponse.totalAmount ??
|
|
1244
|
+
checkoutResponse.feeBreakdown?.totalPayable ??
|
|
1245
|
+
checkoutResponse.feeBreakdown?.total ??
|
|
1246
|
+
total,
|
|
1247
|
+
connectionMode: checkoutResponse.payazaConnectionMode,
|
|
1248
|
+
shippingAddress: {
|
|
1249
|
+
firstName: formData.firstName,
|
|
1250
|
+
lastName: formData.lastName,
|
|
1251
|
+
address: formData.address,
|
|
1252
|
+
city: formData.city,
|
|
1253
|
+
state: formData.state || formData.city || formData.country,
|
|
1254
|
+
country: formData.country,
|
|
1255
|
+
zipCode: formData.postalCode,
|
|
1256
|
+
},
|
|
1257
|
+
});
|
|
1258
|
+
console.log('[Checkout] Step 3: Checkout config generated', {
|
|
1259
|
+
amount: checkoutConfig.amount,
|
|
1260
|
+
currency: checkoutConfig.currency,
|
|
1261
|
+
reference: checkoutConfig.reference,
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
catch (configError) {
|
|
1265
|
+
console.error('[Checkout] Step 2-3: Config generation failed', {
|
|
1266
|
+
error: configError,
|
|
1267
|
+
message: configError?.message,
|
|
1268
|
+
stack: configError?.stack,
|
|
1269
|
+
});
|
|
1270
|
+
addToast(configError?.message || 'Invalid checkout configuration. Please contact support.', 'error');
|
|
1271
|
+
setLoading(false);
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
// Step 4: Use transaction reference from order
|
|
1275
|
+
checkoutConfig.reference = checkoutResponse.transactionReference;
|
|
1276
|
+
console.log('[Checkout] Step 4: Transaction reference set', {
|
|
1277
|
+
reference: checkoutConfig.reference,
|
|
1278
|
+
});
|
|
1279
|
+
// Step 5: Initiate Payaza checkout
|
|
1280
|
+
console.log('[Checkout] Step 6: Initiating Payaza checkout');
|
|
1281
|
+
try {
|
|
1282
|
+
await initiateCheckout(checkoutConfig);
|
|
1283
|
+
console.log('[Checkout] Step 6: Payaza checkout initiated successfully');
|
|
1284
|
+
// Order is created; release page-level loading — Payaza SDK overlay handles payment UI.
|
|
1285
|
+
setLoading(false);
|
|
1286
|
+
// Clear buyNowItem after successful checkout initiation
|
|
1287
|
+
// The item has been processed and order created
|
|
1288
|
+
if (effectiveBuyNowItem) {
|
|
1289
|
+
clearBuyNowItem();
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
catch (sdkError) {
|
|
1293
|
+
console.error('[Checkout] Step 5: Payaza SDK initiation failed', {
|
|
1294
|
+
error: sdkError,
|
|
1295
|
+
message: sdkError?.message,
|
|
1296
|
+
config: {
|
|
1297
|
+
amount: checkoutConfig.amount,
|
|
1298
|
+
currency: checkoutConfig.currency,
|
|
1299
|
+
publicKey: checkoutConfig.publicKey?.substring(0, 20) + '...',
|
|
1300
|
+
},
|
|
1301
|
+
});
|
|
1302
|
+
if (sdkError?.message?.includes('SDK not loaded') || sdkError?.message?.includes('PayazaCheckout')) {
|
|
1303
|
+
addToast('Payment system is loading. Please wait a moment and try again.', 'error');
|
|
1304
|
+
}
|
|
1305
|
+
else if (sdkError?.message?.includes('Currency')) {
|
|
1306
|
+
addToast('Invalid currency code. Please contact support.', 'error');
|
|
1307
|
+
}
|
|
1308
|
+
else {
|
|
1309
|
+
addToast('Payment popup failed to open. Please try again.', 'error');
|
|
1310
|
+
}
|
|
1311
|
+
setLoading(false);
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
catch (error) {
|
|
1316
|
+
console.error('[Checkout] Unexpected error in checkout flow', {
|
|
1317
|
+
error,
|
|
1318
|
+
message: error?.message,
|
|
1319
|
+
stack: error?.stack,
|
|
1320
|
+
name: error?.name,
|
|
1321
|
+
});
|
|
1322
|
+
const isCollectionsDisabled = (error instanceof ApiError && error.status === 403) ||
|
|
1323
|
+
error?.response?.status === 403 ||
|
|
1324
|
+
error?.code === 'COLLECTIONS_DISABLED' ||
|
|
1325
|
+
String(error?.message || '').toLowerCase().includes('not accepting payments');
|
|
1326
|
+
addToast(isCollectionsDisabled ? CHECKOUT_UNAVAILABLE_MESSAGE : 'Failed to initiate checkout. Please try again.', 'error');
|
|
1327
|
+
setLoading(false);
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
const handleDetailsSubmit = (e) => {
|
|
1331
|
+
e.preventDefault();
|
|
1332
|
+
if (validateForm()) {
|
|
1333
|
+
setStep('payment');
|
|
1334
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
addToast('Please fix the errors in the form.', 'error');
|
|
1338
|
+
// Scroll to the first error or top of form
|
|
1339
|
+
const firstErrorField = document.querySelector('.border-red-500');
|
|
1340
|
+
if (firstErrorField) {
|
|
1341
|
+
firstErrorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1342
|
+
}
|
|
1343
|
+
else {
|
|
1344
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
};
|
|
1348
|
+
// Show skeleton while cart hydrates (buy-now flow skips cart hydration)
|
|
1349
|
+
if (!isCartHydrated && !effectiveBuyNowItem) {
|
|
1350
|
+
return _jsx(CheckoutSkeleton, {});
|
|
1351
|
+
}
|
|
1352
|
+
if (isPostPaymentNavigationPending()) {
|
|
1353
|
+
return (_jsxs("div", { className: "min-h-screen bg-gray-50/50 flex flex-col items-center justify-center p-4 font-sans", children: [_jsx(Loader2, { className: "mb-4 h-10 w-10 animate-spin text-gray-400" }), _jsx("p", { className: "font-medium text-gray-600", children: "Completing your order..." })] }));
|
|
1354
|
+
}
|
|
1355
|
+
// Show empty cart message if checkout items are empty (redirect will happen after delay)
|
|
1356
|
+
if (!checkoutItems || checkoutItems.length === 0) {
|
|
1357
|
+
return (_jsx("div", { className: "min-h-screen bg-gray-50/50 py-12 px-4 sm:px-6 lg:px-8 font-sans", children: _jsx("div", { className: "container mx-auto max-w-6xl", children: _jsx("div", { className: "bg-white rounded-3xl shadow-sm border border-gray-100 p-12 text-center", children: _jsxs("div", { className: "max-w-md mx-auto space-y-6", children: [_jsx("div", { className: "w-20 h-20 mx-auto rounded-full bg-gray-100 flex items-center justify-center", children: _jsx("svg", { className: "w-10 h-10 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" }) }) }), _jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Your cart is empty" }), _jsx("p", { className: "text-gray-600", children: "Add some items to your cart before proceeding to checkout." }), _jsx("div", { className: "pt-4", children: _jsx(Link, { href: `/${storeConfig.slug}`, children: _jsxs(Button, { size: "lg", className: "bg-black hover:bg-gray-800 text-white rounded-full px-8 py-6 h-auto font-semibold shadow-lg shadow-black/10 hover:shadow-xl transition-all hover:scale-105 flex items-center gap-2 mx-auto", children: [_jsx(ArrowLeft, { className: "w-5 h-5" }), "Continue Shopping"] }) }) })] }) }) }) }));
|
|
1358
|
+
}
|
|
1359
|
+
return (_jsx("div", { className: "min-h-screen bg-gray-50/50 py-12 px-4 sm:px-6 lg:px-8 font-sans", children: _jsxs("div", { className: "container mx-auto max-w-6xl", children: [_jsxs("div", { className: "mb-10 flex items-center justify-between", children: [_jsxs(Link, { href: `/${storeConfig.slug}/cart`, className: "group flex items-center gap-2 text-gray-500 hover:text-black transition-colors font-medium", children: [_jsx("div", { className: "p-2 rounded-full bg-white border border-gray-200 group-hover:border-black transition-colors", children: _jsx(ArrowLeft, { className: "w-4 h-4" }) }), "Back to Cart"] }), _jsx("div", { className: "flex items-center gap-2 text-sm font-bold", children: deliveryEnabled ? (_jsxs(_Fragment, { children: [_jsx("span", { className: cn("px-3 py-1.5 rounded-full transition-colors", step === 'details' ? "bg-black text-white" : "bg-green-100 text-green-700"), children: step === 'details' ? '1' : _jsx(CheckCircle, { className: "w-4 h-4" }) }), _jsx("span", { className: cn(step === 'details' ? "text-black" : "text-gray-500"), children: "Shipping" }), _jsx("div", { className: "w-8 h-0.5 bg-gray-200" }), _jsx("span", { className: cn("px-3 py-1.5 rounded-full transition-colors", step === 'payment' ? "bg-black text-white" : "bg-gray-200 text-gray-500"), children: "2" }), _jsx("span", { className: cn(step === 'payment' ? "text-black" : "text-gray-400"), children: "Payment" })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: cn("px-3 py-1.5 rounded-full transition-colors", step === 'details' ? "bg-black text-white" : "bg-green-100 text-green-700"), children: step === 'details' ? '1' : _jsx(CheckCircle, { className: "w-4 h-4" }) }), _jsx("span", { className: cn(step === 'details' ? "text-black" : "text-gray-500"), children: "Details" }), _jsx("div", { className: "w-8 h-0.5 bg-gray-200" }), _jsx("span", { className: cn("px-3 py-1.5 rounded-full transition-colors", step === 'payment' ? "bg-black text-white" : "bg-gray-200 text-gray-500"), children: "2" }), _jsx("span", { className: cn(step === 'payment' ? "text-black" : "text-gray-400"), children: "Payment" })] })) })] }), _jsxs("div", { className: "flex flex-col lg:flex-row gap-10", children: [_jsx("div", { className: "flex-1", children: step === 'details' ? (_jsxs("form", { onSubmit: handleDetailsSubmit, className: "space-y-8 animate-fade-in", children: [_jsxs("section", { className: "bg-white p-8 rounded-3xl shadow-sm border border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx("div", { className: "p-2 bg-blue-50 text-blue-600 rounded-xl", children: _jsx(ShieldCheck, { className: "w-5 h-5" }) }), _jsx("h2", { className: "text-xl font-bold text-gray-900", children: "Contact Information" })] }), _jsx("div", { className: "space-y-4", children: isAuthenticated && user ? (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "p-4 bg-gray-50 rounded-xl border border-gray-200", children: [_jsx("p", { className: "text-xs font-bold text-gray-500 uppercase tracking-wider mb-2", children: "Logged in as" }), _jsxs("p", { className: "font-bold text-gray-900", children: [user.firstName, " ", user.lastName] }), _jsx("p", { className: "text-sm text-gray-600", children: user.email })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "Email Address" }), _jsx("input", { type: "email", className: cn("w-full px-5 py-3.5 bg-white border-2 rounded-xl focus:outline-none focus:ring-0 transition-all font-medium", errors.email ? "border-red-500 focus:border-red-500" : "border-gray-100 focus:border-black"), placeholder: "john@example.com", value: formData.email, onChange: e => setFormData({ ...formData, email: e.target.value }) }), _jsx("p", { className: "text-xs text-gray-500 ml-1", children: "You can use a different email for this order" }), errors.email && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.email })] })] })) : (_jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "Email Address" }), _jsx("input", { type: "email", className: cn("w-full px-5 py-3.5 bg-white border-2 rounded-xl focus:outline-none focus:ring-0 transition-all font-medium", errors.email ? "border-red-500 focus:border-red-500" : "border-gray-100 focus:border-black"), placeholder: "john@example.com", value: formData.email, onChange: e => setFormData({ ...formData, email: e.target.value }) }), errors.email && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.email })] })) })] }), _jsxs("section", { className: "bg-white p-8 rounded-3xl shadow-sm border border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx("div", { className: "p-2 bg-orange-50 text-orange-600 rounded-xl", children: _jsx(MapPin, { className: "w-5 h-5" }) }), _jsx("h2", { className: "text-xl font-bold text-gray-900", children: storeConfig.settings?.shippingEnabled === false ? 'Billing Address' : 'Shipping Address' })] }), isAuthenticated && (_jsx(AddressSelector, { addresses: savedAddresses, selectedAddressId: selectedAddressId, onSelect: handleAddressSelect, isLoading: loadingAddresses, isAuthenticated: isAuthenticated })), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-5", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "First Name" }), _jsx("input", { type: "text", className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.firstName ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), value: formData.firstName, onChange: e => setFormData({ ...formData, firstName: e.target.value }) }), errors.firstName && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.firstName })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "Last Name" }), _jsx("input", { type: "text", className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.lastName ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), value: formData.lastName, onChange: e => setFormData({ ...formData, lastName: e.target.value }) }), errors.lastName && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.lastName })] }), _jsxs("div", { className: "space-y-1.5 md:col-span-2", children: [_jsx(RequiredLabel, { children: "Address" }), _jsx("input", { type: "text", className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.address ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), placeholder: "e.g. 12 Adeola Odeku Street, Victoria Island", value: formData.address, onChange: e => setFormData({ ...formData, address: e.target.value }) }), errors.address
|
|
1360
|
+
? _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.address })
|
|
1361
|
+
: _jsx("p", { className: "text-[11px] text-gray-500 mt-1 ml-1", children: "Enter your house/flat number and street name for accurate delivery rates." })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "Country" }), _jsxs("div", { className: "relative", children: [_jsxs("button", { type: "button", onClick: () => setIsCountryDropdownOpen(!isCountryDropdownOpen), className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-left flex items-center justify-between text-base", errors.country ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), children: [_jsx("span", { className: "flex items-center gap-2", children: (() => {
|
|
1362
|
+
const selectedCountry = getCountryByName(formData.country);
|
|
1363
|
+
return selectedCountry ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-lg", children: selectedCountry.flag }), _jsx("span", { children: selectedCountry.name })] })) : (_jsx("span", { className: "text-gray-400", children: "Select country" }));
|
|
1364
|
+
})() }), _jsx(ChevronDown, { className: cn("w-5 h-5 text-gray-400 transition-transform", isCountryDropdownOpen && "transform rotate-180") })] }), isCountryDropdownOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => { setIsCountryDropdownOpen(false); setCountrySearch(''); } }), _jsxs("div", { className: "absolute z-30 w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-xl overflow-hidden", children: [_jsx("div", { className: "p-2 border-b border-gray-100", children: _jsx("input", { autoFocus: true, type: "text", placeholder: "Search country...", value: countrySearch, onChange: (e) => setCountrySearch(e.target.value), className: "w-full px-3 py-2 text-sm border border-gray-200 rounded-lg focus:outline-none focus:border-black", onClick: (e) => e.stopPropagation() }) }), _jsxs("div", { className: "max-h-52 overflow-y-auto", children: [countries.filter(c => c.name.toLowerCase().includes(countrySearch.toLowerCase())).map((country) => (_jsxs("button", { type: "button", onClick: () => {
|
|
1365
|
+
setFormData(prev => ({
|
|
1366
|
+
...prev,
|
|
1367
|
+
country: country.name,
|
|
1368
|
+
city: '',
|
|
1369
|
+
state: '',
|
|
1370
|
+
}));
|
|
1371
|
+
setIsCountryDropdownOpen(false);
|
|
1372
|
+
setCountrySearch('');
|
|
1373
|
+
setIsCityDropdownOpen(false);
|
|
1374
|
+
setIsStateDropdownOpen(false);
|
|
1375
|
+
}, className: cn("w-full px-5 py-3 text-left flex items-center gap-3 hover:bg-gray-50 transition-colors", formData.country === country.name && "bg-gray-50 font-medium"), children: [_jsx("span", { className: "text-lg", children: country.flag }), _jsx("span", { children: country.name })] }, country.code))), countries.filter(c => c.name.toLowerCase().includes(countrySearch.toLowerCase())).length === 0 && (_jsx("div", { className: "px-5 py-3 text-gray-400 text-sm", children: "No countries found" }))] })] })] }))] }), errors.country && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.country })] }), isNigeria(formData.country) && (_jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "State" }), _jsxs("div", { className: "relative", children: [_jsxs("button", { type: "button", onClick: () => setIsStateDropdownOpen(!isStateDropdownOpen), className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-left flex items-center justify-between text-base", errors.state ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), children: [_jsx("span", { className: formData.state ? "text-gray-900" : "text-gray-400", children: formData.state || 'Select state' }), _jsx(ChevronDown, { className: cn("w-5 h-5 text-gray-400 transition-transform", isStateDropdownOpen && "transform rotate-180") })] }), isStateDropdownOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => setIsStateDropdownOpen(false) }), _jsx("div", { className: "absolute z-30 w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-xl max-h-52 overflow-y-auto", children: NIGERIAN_STATES.map((state) => (_jsx("button", { type: "button", onClick: () => {
|
|
1376
|
+
// Clear city when state changes so stale city isn't submitted
|
|
1377
|
+
setFormData({ ...formData, state, city: '' });
|
|
1378
|
+
setIsStateDropdownOpen(false);
|
|
1379
|
+
}, className: cn("w-full px-5 py-3 text-left hover:bg-gray-50 transition-colors", formData.state === state && "bg-gray-50 font-medium"), children: state }, state))) })] }))] }), errors.state && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.state })] })), _jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "City" }), _jsxs("div", { className: "relative", children: [_jsx("input", { type: "text", placeholder: isNigeria(formData.country) && !formData.state ? 'Select a state first' : 'e.g. Lagos, Lekki, Ikeja', disabled: isNigeria(formData.country) && !formData.state, value: formData.city, onChange: (e) => {
|
|
1380
|
+
setFormData({ ...formData, city: e.target.value });
|
|
1381
|
+
setCitySearch(e.target.value);
|
|
1382
|
+
setIsCityDropdownOpen(true);
|
|
1383
|
+
}, onFocus: () => {
|
|
1384
|
+
if (!formData.country) {
|
|
1385
|
+
addToast('Please select a country first', 'error');
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
setIsCityDropdownOpen(true);
|
|
1389
|
+
}, onBlur: () => setTimeout(() => setIsCityDropdownOpen(false), 150), className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.city ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black", isNigeria(formData.country) && !formData.state && "bg-gray-50 text-gray-400 cursor-not-allowed") }), isCityDropdownOpen && formData.country && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-10", onClick: () => setIsCityDropdownOpen(false) }), (() => {
|
|
1390
|
+
const nigeriaState = isNigeria(formData.country) ? formData.state : null;
|
|
1391
|
+
const suggestions = nigeriaState
|
|
1392
|
+
? getNigerianCitiesByState(nigeriaState).filter(c => c.toLowerCase().includes((formData.city || '').toLowerCase()))
|
|
1393
|
+
: getCitiesByCountry(formData.country).filter(c => c.toLowerCase().includes((formData.city || '').toLowerCase()));
|
|
1394
|
+
if (suggestions.length === 0)
|
|
1395
|
+
return null;
|
|
1396
|
+
return (_jsx("div", { className: "absolute z-30 w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-xl max-h-52 overflow-y-auto", children: suggestions.map((city) => (_jsx("button", { type: "button", onMouseDown: (e) => e.preventDefault(), onClick: () => {
|
|
1397
|
+
setFormData({ ...formData, city });
|
|
1398
|
+
setIsCityDropdownOpen(false);
|
|
1399
|
+
setCitySearch('');
|
|
1400
|
+
}, className: cn("w-full px-5 py-3 text-left hover:bg-gray-50 transition-colors text-base", formData.city === city && "bg-gray-50 font-medium"), children: city }, city))) }));
|
|
1401
|
+
})()] }))] }), errors.city
|
|
1402
|
+
? _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.city })
|
|
1403
|
+
: _jsx("p", { className: "text-[11px] text-gray-500 mt-1 ml-1", children: "Type your city or town name \u2014 you can enter any location not shown in suggestions." })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-sm font-bold text-gray-700 ml-1", children: "Postal/Zip Code" }), _jsx("input", { type: "text", className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.postalCode ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), placeholder: "Optional", value: formData.postalCode, onChange: e => setFormData({ ...formData, postalCode: e.target.value }) }), errors.postalCode && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.postalCode })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(RequiredLabel, { children: "Phone" }), _jsx("input", { type: "tel", className: cn("w-full px-4 py-3 rounded-lg border focus:ring-2 focus:ring-black focus:outline-none transition-all text-base", errors.phone ? "border-red-300 focus:border-red-500 bg-red-50" : "border-gray-200 focus:border-black"), placeholder: phonePlaceholder, value: formData.phone, onChange: e => handlePhoneChange(e.target.value) }), errors.phone && _jsx("p", { className: "text-red-500 text-xs ml-1", children: errors.phone })] })] }), isAuthenticated && !selectedAddressId && (_jsxs("div", { className: "mt-6 space-y-3", children: [_jsxs("label", { className: "flex items-center gap-3 cursor-pointer group", children: [_jsx("input", { type: "checkbox", checked: saveNewAddress, onChange: (e) => setSaveNewAddress(e.target.checked), className: "w-5 h-5 rounded border-2 border-gray-300 text-black focus:ring-2 focus:ring-black cursor-pointer" }), _jsx("span", { className: "text-sm font-medium text-gray-700 group-hover:text-black transition-colors", children: "Save this address for future use" })] }), saveNewAddress && (_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-sm font-bold text-gray-700 ml-1", children: "Address Label (optional)" }), _jsx("input", { type: "text", value: addressLabel, onChange: (e) => setAddressLabel(e.target.value), placeholder: "e.g., Home, Work, Office", className: "w-full px-5 py-3.5 bg-white border-2 border-gray-100 rounded-xl focus:outline-none focus:ring-0 focus:border-black transition-all font-medium" })] }))] }))] }), deliveryEnabled && !automatedShippingEnabled && (_jsxs("section", { className: "bg-white p-8 rounded-3xl shadow-sm border border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-3 mb-4", children: [_jsx("div", { className: "p-2 bg-amber-50 text-amber-700 rounded-xl", children: _jsx(Truck, { className: "w-5 h-5" }) }), _jsx("h2", { className: "text-xl font-bold text-gray-900", children: "Delivery" })] }), _jsx(MerchantHandledDeliveryNotice, { storeName: storeConfig.name })] })), deliveryEnabled && automatedShippingEnabled && canRequestShippingQuote(buildQuoteAddress()) && (_jsxs("section", { className: "bg-white p-8 rounded-3xl shadow-sm border border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx("div", { className: "p-2 bg-purple-50 text-purple-600 rounded-xl", children: _jsx(Truck, { className: "w-5 h-5" }) }), _jsx("h2", { className: "text-xl font-bold text-gray-900", children: "Shipping Method" })] }), !isCourierMode && freeShippingThreshold !== undefined && !freeShippingEligible && (_jsxs("div", { className: "mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg", children: [_jsxs("p", { className: "text-xs font-medium text-blue-900 mb-1", children: ["Spend ", formatCurrency(freeShippingThreshold - subtotal, currency), " more for free shipping!"] }), _jsx("div", { className: "w-full bg-blue-200 rounded-full h-2", children: _jsx("div", { className: "bg-blue-600 h-2 rounded-full transition-all", style: {
|
|
1404
|
+
width: `${Math.min(100, (subtotal / freeShippingThreshold) * 100)}%`,
|
|
1405
|
+
} }) })] })), checkingDeliveryStatus || (!isCourierMode && isCalculatingShipping) ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsxs("div", { className: "flex items-center gap-2 text-gray-600", children: [_jsx("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-gray-900" }), _jsx("span", { className: "text-sm font-medium", children: "Calculating shipping options..." })] }) })) : isCourierMode ? (_jsx(ShippingOptionsPanel, { storeId: storeConfig.id, address: buildQuoteAddress(), packages: checkoutItems.map((item) => ({
|
|
1406
|
+
weight: item.product?.weight || 0.5,
|
|
1407
|
+
value: item.price,
|
|
1408
|
+
name: item.product?.name,
|
|
1409
|
+
quantity: item.quantity,
|
|
1410
|
+
})), customerInfo: {
|
|
1411
|
+
firstName: formData.firstName,
|
|
1412
|
+
lastName: formData.lastName,
|
|
1413
|
+
phone: formData.phone,
|
|
1414
|
+
email: formData.email,
|
|
1415
|
+
}, onSelect: handleCourierSelect, selected: selectedCourier })) : shippingError ? (_jsx("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg", children: _jsx("p", { className: "text-sm text-red-600", children: shippingError }) })) : shippingMethods.length > 0 ? (_jsx("div", { className: "space-y-3", children: shippingMethods.map((method) => (_jsxs("label", { className: cn("flex items-center justify-between p-4 border-2 rounded-xl cursor-pointer transition-all", selectedShippingMethod?.code === method.code
|
|
1416
|
+
? "border-black bg-gray-50"
|
|
1417
|
+
: "border-gray-200 hover:border-gray-300 bg-white"), children: [_jsxs("div", { className: "flex items-center gap-4 flex-1", children: [_jsx("input", { type: "radio", name: "shippingMethod", value: method.code, checked: selectedShippingMethod?.code === method.code, onChange: () => setSelectedShippingMethod(method), className: "w-5 h-5 text-black focus:ring-2 focus:ring-black cursor-pointer" }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "font-bold text-gray-900", children: method.name }), freeShippingEligible && method.cost === 0 && (_jsx("span", { className: "text-xs font-normal text-green-700 bg-green-100 px-2 py-0.5 rounded-full", children: "FREE" }))] }), method.description && (_jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: method.description })), method.estimatedDays && (_jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: method.estimatedDaysMin && method.estimatedDaysMax
|
|
1418
|
+
? `Estimated delivery: ${method.estimatedDaysMin}-${method.estimatedDaysMax} business days`
|
|
1419
|
+
: `Estimated delivery: ${method.estimatedDays} business days` }))] })] }), _jsx("div", { className: "text-right", children: _jsx("p", { className: "font-bold text-gray-900", children: freeShippingEligible && method.cost === 0
|
|
1420
|
+
? 'FREE'
|
|
1421
|
+
: Number.isFinite(method.cost) && method.cost >= 0
|
|
1422
|
+
? formatCurrency(method.cost, currency)
|
|
1423
|
+
: 'Not available' }) })] }, method.code))) })) : (_jsx("div", { className: "p-4 bg-gray-50 border border-gray-200 rounded-lg text-center", children: _jsx("p", { className: "text-sm text-gray-600", children: "No shipping methods available. Please check your address." }) }))] })), _jsxs(Button, { type: "submit", size: "lg", className: "w-full h-14 text-lg font-bold rounded-2xl shadow-xl hover:shadow-2xl hover:-translate-y-0.5 transition-all text-white [&_svg]:text-white", style: { backgroundColor: primaryColor, color: '#fff' }, children: ["Continue to Payment ", _jsx(ChevronRight, { className: "ml-2 w-5 h-5" })] })] })) : (_jsxs("div", { className: "space-y-8 animate-fade-in", children: [deliveryEnabled && (_jsxs("section", { className: "bg-white p-6 rounded-3xl shadow-sm border border-gray-100 flex justify-between items-center group hover:border-gray-300 transition-colors cursor-pointer", onClick: () => setStep('details'), children: [_jsxs("div", { className: "flex gap-4 items-center", children: [_jsx("div", { className: "w-10 h-10 bg-green-50 rounded-full flex items-center justify-center border border-green-100", children: _jsx(CheckCircle, { className: "w-5 h-5 text-green-600" }) }), _jsxs("div", { children: [_jsx("p", { className: "text-xs text-gray-500 font-bold uppercase tracking-wider mb-1", children: "Shipping To" }), _jsxs("p", { className: "font-bold text-gray-900", children: [formData.firstName, " ", formData.lastName] }), _jsxs("p", { className: "text-sm text-gray-500", children: [formData.address, ", ", formData.city] })] })] }), _jsx("span", { className: "text-sm font-bold text-blue-600 px-4 py-2 bg-blue-50 rounded-lg group-hover:bg-blue-100 transition-colors", children: "Edit" })] })), _jsxs("section", { className: "bg-white p-8 rounded-3xl shadow-sm border border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-3 mb-6", children: [_jsx("div", { className: "p-2 bg-blue-50 text-blue-600 rounded-xl", children: _jsx(ShieldCheck, { className: "w-5 h-5" }) }), _jsx("h2", { className: "text-xl font-bold text-gray-900", children: "Payment Security" })] }), _jsx("div", { className: "bg-blue-50/50 p-6 rounded-2xl border border-blue-100 mb-6", children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx(Lock, { className: "w-5 h-5 text-blue-600 mt-1" }), _jsxs("div", { children: [_jsx("h4", { className: "font-bold text-blue-900 mb-1", children: "Encrypted Transaction" }), _jsx("p", { className: "text-sm text-blue-700/80 leading-relaxed", children: "Your payment is processed securely by Payaza. We do not store your card details." })] })] }) }), _jsxs("div", { className: "flex items-center justify-center gap-2 text-xs font-bold text-gray-400 uppercase tracking-widest", children: [_jsx(Lock, { className: "w-3 h-3" }), "256-bit SSL Secure Payment"] })] }), isHoldBlocking && (_jsxs("div", { className: "rounded-2xl border border-red-200 bg-red-50 p-4 flex gap-3", children: [_jsx(AlertCircle, { className: "w-5 h-5 text-red-700 flex-shrink-0 mt-0.5" }), _jsxs("div", { children: [_jsx("p", { className: "font-bold text-red-900 text-sm", children: "Checkout reservation expired" }), _jsx("p", { className: "mt-1 text-sm text-red-800", children: "Your stock hold has expired. Go back to cart and start checkout again to reserve items." })] })] })), hasCheckoutStockIssues && (_jsxs("div", { className: "rounded-2xl border border-amber-200 bg-amber-50 p-4 flex gap-3", children: [_jsx(AlertCircle, { className: "w-5 h-5 text-amber-700 flex-shrink-0 mt-0.5" }), _jsxs("div", { children: [_jsx("p", { className: "font-bold text-amber-900 text-sm", children: "Stock availability changed" }), _jsx("ul", { className: "mt-2 space-y-1 text-sm text-amber-800", children: checkoutStockIssues.map((issue) => (_jsx("li", { children: issue.message }, issue.id))) }), _jsx("p", { className: "mt-2 text-xs text-amber-700", children: "Update your cart before paying. Payment is only available when all items are in stock." })] })] })), _jsx(Button, { onClick: handlePayazaCheckout, size: "lg", className: "w-full h-16 text-lg font-bold rounded-2xl shadow-xl hover:shadow-2xl hover:-translate-y-0.5 transition-all text-white [&_svg]:text-white", style: { backgroundColor: primaryColor, color: '#fff' }, disabled: loading || isPayazaLoading || hasCheckoutStockIssues || isHoldBlocking || checkoutDisabled, children: loading || isPayazaLoading ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" }), _jsx("span", { children: "Processing Securely..." })] })) : checkoutDisabled ? (_jsx("span", { children: "Checkout unavailable" })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Lock, { className: "w-5 h-5" }), _jsx("span", { children: "Pay Now" })] })) }), checkoutDisabled && (_jsx("p", { className: "mt-3 text-sm text-center text-gray-500", children: CHECKOUT_UNAVAILABLE_MESSAGE }))] })) }), _jsxs("div", { className: "w-full lg:w-[400px] flex-shrink-0", children: [_jsxs("div", { className: "bg-white p-8 rounded-3xl shadow-lg border border-gray-100 sticky top-8", children: [_jsx("h2", { className: "text-xl font-black text-gray-900 mb-6", children: "Order Summary" }), _jsx("div", { className: "mb-6", children: _jsx(InventoryHoldCountdown, { holdUntil: inventoryHoldUntil, onExpired: () => {
|
|
1424
|
+
setIsHoldExpired(true);
|
|
1425
|
+
handleInventoryHoldExpired?.();
|
|
1426
|
+
} }) }), _jsx("div", { className: "space-y-6 mb-8 max-h-[400px] overflow-y-auto scrollbar-hide", children: checkoutItems.map((item) => {
|
|
1427
|
+
const stockInfo = getCartLineStockInfo(item.product, item.quantity);
|
|
1428
|
+
return (_jsxs("div", { className: "flex gap-4 group", children: [_jsxs("div", { className: "w-20 h-20 bg-gray-100 rounded-xl overflow-hidden flex-shrink-0 relative border border-gray-200", children: [_jsx(Image, { src: item.product.images[0], alt: item.product.name, fill: true, className: "object-cover group-hover:scale-105 transition-transform duration-500", unoptimized: true }), _jsxs("span", { className: "absolute top-0 right-0 bg-black text-white text-[10px] font-bold px-2 py-1 rounded-bl-lg z-10", children: ["x", item.quantity] })] }), _jsxs("div", { className: "flex-1 py-1", children: [_jsx("p", { className: "font-bold text-gray-900 text-sm line-clamp-2 leading-relaxed", children: item.product.name }), item.variantName && _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: item.variantName }), stockInfo.displayLabel && (_jsx("p", { className: cn('text-xs font-semibold mt-1', stockInfo.stockError ? 'text-red-600' : 'text-amber-700'), children: stockInfo.displayLabel })), _jsx("p", { className: "text-gray-500 text-sm font-medium mt-1", children: formatCurrency(normalizePrice(item.price), item.product?.currency || currency) })] })] }, item.id));
|
|
1429
|
+
}) }), isMarketplaceCheckout && storeBreakdown.length > 1 && (_jsxs("div", { className: "mb-6 rounded-2xl bg-gray-50 border border-gray-100 p-4", children: [_jsxs("p", { className: "text-xs font-bold text-gray-700 mb-3", children: ["Your order will be split into ", storeBreakdown.length, " separate orders \u2014 one per store"] }), _jsx("div", { className: "space-y-2", children: storeBreakdown.map((store) => (_jsxs("div", { className: "flex justify-between text-xs text-gray-600", children: [_jsxs("span", { className: "font-medium truncate pr-2", children: [store.storeName, " (", store.itemCount, " item", store.itemCount === 1 ? '' : 's', ")"] }), _jsx("span", { className: "font-bold text-gray-900 flex-shrink-0", children: formatCurrency(store.subtotal, currency) })] }, store.storeId))) })] })), _jsxs("div", { className: "space-y-4 pt-6 border-t-2 border-gray-50", children: [_jsxs("div", { className: "flex justify-between text-gray-500 font-medium text-sm", children: [_jsx("span", { children: "Subtotal" }), _jsx("span", { className: "text-gray-900 font-bold", children: formatCurrency(subtotal, currency) })] }), deliveryEnabled && (_jsxs("div", { className: "flex justify-between text-gray-500 font-medium text-sm", children: [_jsxs("span", { children: ["Shipping", selectedShippingMethod ? ` (${selectedShippingMethod.name})` : ''] }), _jsx("span", { className: "text-gray-900 font-bold", children: !automatedShippingEnabled ? (_jsx("span", { className: "text-amber-700", children: "Handled by merchant" })) : isCalculatingShipping ? (_jsx("span", { className: "text-gray-400", children: "Calculating..." })) : !selectedShippingMethod ? (_jsx("span", { className: "text-gray-400", children: "Not available" })) : shipping === 0 && freeShippingEligible ? (_jsx("span", { className: "text-green-600", children: "Free" })) : shipping === 0 ? ('Free') : Number.isFinite(shipping) && shipping > 0 ? (formatCurrency(shipping, currency)) : (_jsx("span", { className: "text-gray-400", children: "Not available" })) })] })), feesLoading && (_jsxs("div", { className: "flex justify-between text-gray-500 font-medium text-sm", children: [_jsx("span", { children: "Fees" }), _jsx("span", { className: "text-gray-900 font-bold", children: "Calculating..." })] })), !feesLoading && (_jsx(CheckoutFeeLines, { lines: displayLines, currency: currency, excludeKeys: ['shipping'], className: "flex justify-between text-gray-500 font-medium text-sm", labelClassName: "", amountClassName: "text-gray-900 font-bold" })), _jsxs("div", { className: "flex justify-between items-end pt-4 mt-2 border-t border-gray-100", children: [_jsx("span", { className: "text-base font-bold text-gray-900", children: "Total to pay" }), _jsx("span", { className: "text-3xl font-black text-gray-900 tracking-tight", children: formatCurrency(total, currency) })] })] }), _jsxs("div", { className: "mt-8 pt-6 border-t border-gray-100 grid grid-cols-3 gap-2 opacity-50 grayscale", children: [_jsx("div", { className: "h-8 bg-gray-100 rounded border border-gray-200" }), _jsx("div", { className: "h-8 bg-gray-100 rounded border border-gray-200" }), _jsx("div", { className: "h-8 bg-gray-100 rounded border border-gray-200" })] })] }), PROMO_CODE_ENABLED && (_jsxs("div", { className: "bg-white p-6 rounded-3xl shadow-lg border border-gray-100 mt-6 sticky top-[500px]", children: [_jsxs("h3", { className: "font-bold text-gray-900 mb-4 flex items-center gap-2", children: [_jsx(Tag, { className: "w-4 h-4" }), " Have a promo code?"] }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "text", value: promoCode, onChange: (e) => setPromoCode(e.target.value), placeholder: "Enter code", className: "flex-1 px-4 py-2 bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:border-black transition-all uppercase placeholder:normal-case font-medium" }), _jsx(Button, { onClick: handleApplyPromo, disabled: !promoCode || isPromoApplied, className: "bg-black text-white rounded-xl", style: isPromoApplied ? { backgroundColor: '#22c55e' } : {}, children: isPromoApplied ? 'Applied' : 'Apply' })] }), isPromoApplied && (_jsxs("p", { className: "text-green-600 text-xs font-bold mt-2 flex items-center gap-1", children: [_jsx(CheckCircle, { className: "w-3 h-3" }), " Discount applied to total"] }))] }))] })] })] }) }));
|
|
1430
|
+
}
|