@mohasinac/appkit 4.53.1 → 4.54.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/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/theme/ThemeProvider.js +15 -1
- package/dist/_internal/server/features/auth/capabilities.js +7 -5
- package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
- package/dist/_internal/server/features/checkout/actions.js +96 -51
- package/dist/_internal/server/features/checkout/index.d.ts +1 -1
- package/dist/_internal/server/features/checkout/index.js +1 -1
- package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
- package/dist/_internal/server/features/orders/adapters.js +1 -3
- package/dist/_internal/server/features/price-index/market.d.ts +57 -0
- package/dist/_internal/server/features/price-index/market.js +120 -0
- package/dist/_internal/server/features/products/list-public.d.ts +12 -0
- package/dist/_internal/server/features/products/list-public.js +10 -1
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
- package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
- package/dist/_internal/server/features/search/index-build/sources.js +43 -2
- package/dist/_internal/server/features/site-settings/adapters.js +1 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +0 -1
- package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
- package/dist/_internal/server/features/stores/tabs.js +5 -3
- package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
- package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
- package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
- package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
- package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
- package/dist/_internal/server/notifications/channel-health.js +2 -2
- package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
- package/dist/_internal/server/notifications/send-guard.js +2 -4
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +128 -28
- package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
- package/dist/_internal/shared/checkout/order-math.js +1 -1
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
- package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
- package/dist/_internal/shared/features/checkout/config.js +0 -2
- package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
- package/dist/_internal/shared/features/messaging/config.js +1 -4
- package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
- package/dist/_internal/shared/features/site-settings/fees.js +0 -2
- package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
- package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
- package/dist/_internal/shared/fees/calculator.d.ts +0 -8
- package/dist/_internal/shared/fees/calculator.js +0 -7
- package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
- package/dist/_internal/shared/listing-types/tiers.js +150 -0
- package/dist/_internal/shared/search/match.js +28 -2
- package/dist/cli/index.js +0 -2
- package/dist/client.d.ts +25 -4
- package/dist/client.js +36 -5
- package/dist/constants/api-endpoints.d.ts +28 -15
- package/dist/constants/api-endpoints.js +14 -8
- package/dist/constants/field-names.d.ts +1 -0
- package/dist/constants/field-names.js +1 -0
- package/dist/constants/notification-types.d.ts +1 -1
- package/dist/constants/notification-types.js +1 -1
- package/dist/core/integration-keys.d.ts +5 -5
- package/dist/core/integration-keys.js +21 -10
- package/dist/features/about/components/FeesView.js +0 -6
- package/dist/features/about/components/GuidesHubView.js +15 -2
- package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
- package/dist/features/account/components/UserOrdersView.js +26 -7
- package/dist/features/account/types/index.d.ts +0 -2
- package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
- package/dist/features/addresses/utils/postal-autofill.js +54 -0
- package/dist/features/admin/actions/notification-actions.d.ts +2 -8
- package/dist/features/admin/actions/notification-actions.js +9 -104
- package/dist/features/admin/components/AdminGuideHubView.js +1 -8
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +0 -2
- package/dist/features/admin/components/AdminSectionsView.js +3 -2
- package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
- package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
- package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
- package/dist/features/admin/components/OwnerQuickActions.js +142 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
- package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
- package/dist/features/admin/components/sections/icon-options.js +23 -0
- package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
- package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
- package/dist/features/admin/constants/site-settings-tabs.js +6 -12
- package/dist/features/admin/repository/site-settings.repository.js +1 -1
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
- package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
- package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
- package/dist/features/admin/schemas/admin-user-form.js +3 -44
- package/dist/features/admin/schemas/firestore.d.ts +28 -54
- package/dist/features/admin/schemas/firestore.js +40 -18
- package/dist/features/auctions/components/AuctionDetailPageView.js +12 -10
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
- package/dist/features/auth/checkout-value-otp.d.ts +1 -1
- package/dist/features/auth/checkout-value-otp.js +1 -1
- package/dist/features/auth/permissions/constants.d.ts +29 -2
- package/dist/features/auth/permissions/constants.js +67 -1
- package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
- package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
- package/dist/features/cart/components/CartDrawer.js +3 -2
- package/dist/features/cart/components/CartGroupLineRow.js +2 -1
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
- package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
- package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
- package/dist/features/cart/hooks/useAddToCart.js +10 -5
- package/dist/features/cart/repository/cart.repository.js +1 -2
- package/dist/features/cart/schemas/firestore.d.ts +1 -2
- package/dist/features/cart/utils/pending-ops.d.ts +11 -1
- package/dist/features/cart/utils/pending-ops.js +14 -2
- package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
- package/dist/features/categories/components/BrandDetailPageView.js +15 -6
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/BrandDetailTabs.js +18 -3
- package/dist/features/categories/components/BundleCollage.js +3 -2
- package/dist/features/categories/components/BundleDetailView.js +2 -1
- package/dist/features/categories/components/BundleItemsPicker.js +3 -4
- package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
- package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
- package/dist/features/categories/components/CategoryGrid.js +9 -2
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
- package/dist/features/classified/components/ClassifiedDetailPageView.js +12 -2
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +12 -2
- package/dist/features/events/components/EventCard.d.ts +11 -1
- package/dist/features/events/components/EventCard.js +9 -2
- package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
- package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
- package/dist/features/homepage/components/CTABannerSection.js +6 -3
- package/dist/features/homepage/components/HeroCarousel.js +8 -6
- package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
- package/dist/features/homepage/components/SectionCarousel.js +13 -5
- package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
- package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
- package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
- package/dist/features/homepage/components/StatsCounterSection.js +2 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
- package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
- package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
- package/dist/features/homepage/components/WelcomeSection.js +3 -3
- package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
- package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
- package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
- package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
- package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
- package/dist/features/homepage/constants/section-copy.d.ts +12 -10
- package/dist/features/homepage/constants/section-copy.js +28 -6
- package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
- package/dist/features/homepage/constants/stat-icons.js +17 -0
- package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
- package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
- package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
- package/dist/features/homepage/lib/section-defaults.js +24 -4
- package/dist/features/homepage/lib/section-renderer.js +48 -8
- package/dist/features/homepage/schemas/firestore.d.ts +18 -1
- package/dist/features/layout/AppLayoutShell.js +2 -1
- package/dist/features/layout/BottomActions.d.ts +1 -0
- package/dist/features/layout/BottomActions.js +330 -0
- package/dist/features/layout/BottomChrome.d.ts +45 -0
- package/dist/features/layout/BottomChrome.js +5 -17
- package/dist/features/layout/SideActionDock.js +36 -13
- package/dist/features/layout/index.d.ts +2 -7
- package/dist/features/layout/index.js +7 -7
- package/dist/features/layout/useIsDesktop.d.ts +36 -0
- package/dist/features/layout/useIsDesktop.js +48 -0
- package/dist/features/live/components/LiveItemDetailPageView.js +12 -2
- package/dist/features/orders/actions/refund-actions.js +0 -1
- package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
- package/dist/features/orders/components/OrderAddonBadges.js +3 -4
- package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
- package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
- package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
- package/dist/features/orders/components/index.d.ts +2 -1
- package/dist/features/orders/components/index.js +1 -1
- package/dist/features/orders/repository/orders.repository.d.ts +0 -8
- package/dist/features/orders/repository/orders.repository.js +0 -2
- package/dist/features/orders/schemas/firestore.d.ts +17 -9
- package/dist/features/orders/types/index.d.ts +2 -5
- package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
- package/dist/features/orders/utils/order-announcement-message.js +16 -0
- package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
- package/dist/features/orders/utils/payment-proof-message.js +17 -0
- package/dist/features/parts/components/PartDetailPageView.js +96 -1
- package/dist/features/parts/schemas/firestore.d.ts +247 -0
- package/dist/features/parts/schemas/firestore.js +6 -6
- package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -10
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
- package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
- package/dist/features/price-index/lookup-target.d.ts +48 -0
- package/dist/features/price-index/lookup-target.js +107 -0
- package/dist/features/products/api/[id]/route.js +8 -1
- package/dist/features/products/api/route.js +16 -4
- package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
- package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
- package/dist/features/products/components/CompareOverlay.d.ts +2 -1
- package/dist/features/products/components/CompareOverlay.js +2 -1
- package/dist/features/products/components/GroupSettingsPanel.js +2 -1
- package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
- package/dist/features/products/components/InteractiveProductCard.js +16 -4
- package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.js +34 -4
- package/dist/features/products/components/ProductGrid.d.ts +14 -1
- package/dist/features/products/components/ProductGrid.js +22 -5
- package/dist/features/products/components/ProductsIndexListing.js +2 -2
- package/dist/features/products/components/SublistingCarouselSection.js +2 -1
- package/dist/features/products/repository/products.repository.d.ts +1 -0
- package/dist/features/products/repository/products.repository.js +5 -1
- package/dist/features/products/utils/group-member-image.d.ts +9 -2
- package/dist/features/products/utils/group-member-image.js +2 -1
- package/dist/features/reviews/api/[id]/route.js +83 -23
- package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
- package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
- package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
- package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
- package/dist/features/reviews/components/index.d.ts +4 -0
- package/dist/features/reviews/components/index.js +2 -0
- package/dist/features/scams/schemas/index.d.ts +10 -10
- package/dist/features/search/action-index/settings-entries.js +0 -9
- package/dist/features/seller/actions/seller-actions.d.ts +1 -1
- package/dist/features/seller/actions/seller-actions.js +49 -3
- package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
- package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
- package/dist/features/seller/components/SellerProductsView.js +3 -2
- package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
- package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
- package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
- package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
- package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
- package/dist/features/store-extensions/schemas/firestore.js +0 -10
- package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
- package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
- package/dist/features/stores/components/StoreGuideHubView.js +2 -8
- package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
- package/dist/features/stores/components/index.d.ts +0 -2
- package/dist/features/stores/components/index.js +0 -1
- package/dist/features/stores/repository/store.repository.d.ts +1 -26
- package/dist/features/stores/repository/store.repository.js +5 -60
- package/dist/features/stores/schemas/firestore.d.ts +6 -25
- package/dist/features/stores/schemas/firestore.js +6 -3
- package/dist/features/stores/schemas/index.d.ts +1 -87
- package/dist/features/stores/schemas/index.js +10 -15
- package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
- package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
- package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
- package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +427 -69
- package/dist/index.d.ts +20 -32
- package/dist/index.js +34 -43
- package/dist/next/routing/route-map.d.ts +2 -8
- package/dist/next/routing/route-map.js +21 -4
- package/dist/providers/db-firebase/base.repository.d.ts +1 -1
- package/dist/providers/db-firebase/base.repository.js +1 -1
- package/dist/providers/payment-razorpay/index.d.ts +125 -0
- package/dist/providers/payment-razorpay/index.js +232 -0
- package/dist/providers/payment-razorpay/signature.d.ts +53 -0
- package/dist/providers/payment-razorpay/signature.js +71 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
- package/dist/providers/shipping-shiprocket/index.js +356 -0
- package/dist/providers.d.ts +3 -0
- package/dist/providers.js +3 -0
- package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
- package/dist/react/hooks/useCanSeePrices.js +25 -0
- package/dist/repositories/index.d.ts +1 -1
- package/dist/repositories/index.js +1 -1
- package/dist/schemas/registry.d.ts +10 -115
- package/dist/schemas/registry.js +1 -2
- package/dist/security/pii-encrypt.js +1 -1
- package/dist/seed/_helpers/category-forest.js +27 -0
- package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +13412 -3020
- package/dist/seed/carousel-slides-seed-data.js +47 -10
- package/dist/seed/categories-seed-data.js +48 -6
- package/dist/seed/faq-seed-data.js +2 -2
- package/dist/seed/homepage-sections-seed-data.js +286 -54
- package/dist/seed/index.d.ts +1 -1
- package/dist/seed/index.js +1 -1
- package/dist/seed/manifest.d.ts +1 -1
- package/dist/seed/manifest.js +1 -2
- package/dist/seed/model-composition-seed-data.js +6 -8
- package/dist/seed/part-glossary/chunk0.d.ts +9 -0
- package/dist/seed/part-glossary/chunk0.js +35448 -0
- package/dist/seed/part-glossary/chunk1.d.ts +9 -0
- package/dist/seed/part-glossary/chunk1.js +40494 -0
- package/dist/seed/part-glossary/chunk2.d.ts +9 -0
- package/dist/seed/part-glossary/chunk2.js +51242 -0
- package/dist/seed/part-glossary/chunk3.d.ts +9 -0
- package/dist/seed/part-glossary/chunk3.js +53337 -0
- package/dist/seed/part-glossary/chunk4.d.ts +9 -0
- package/dist/seed/part-glossary/chunk4.js +51454 -0
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +23 -47483
- package/dist/seed/products-beyblade-x-seed-data.js +36 -1
- package/dist/seed/site-settings-seed-data.js +34 -35
- package/dist/seed/store-extensions-seed-data.d.ts +1 -2
- package/dist/seed/store-extensions-seed-data.js +1 -23
- package/dist/seed/stores-seed-data.js +0 -1
- package/dist/server-entry.d.ts +1 -1
- package/dist/server-entry.js +1 -1
- package/dist/server.d.ts +10 -10
- package/dist/server.js +24 -22
- package/dist/styles.css +392 -43
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -1
- package/dist/tokens/themes/default-light.js +2 -1
- package/dist/tokens/tokens.css +6 -2
- package/dist/ui/components/Button.d.ts +11 -0
- package/dist/ui/components/Button.js +11 -0
- package/dist/ui/components/Button.style.css +29 -0
- package/dist/ui/components/CarouselNav.d.ts +57 -0
- package/dist/ui/components/CarouselNav.js +25 -0
- package/dist/ui/components/CarouselNav.style.css +265 -0
- package/dist/ui/components/GatedPrice.js +30 -3
- package/dist/ui/components/GatedPrice.style.css +43 -40
- package/dist/ui/components/HorizontalScroller.d.ts +12 -1
- package/dist/ui/components/HorizontalScroller.js +43 -3
- package/dist/ui/components/ImageMosaic.d.ts +8 -1
- package/dist/ui/components/ImageMosaic.js +3 -2
- package/dist/ui/components/ImageMosaic.style.css +22 -0
- package/dist/ui/components/Layout.style.css +6 -0
- package/dist/ui/components/Semantic.d.ts +3 -2
- package/dist/ui/components/Semantic.js +1 -0
- package/dist/ui/components/Typography.d.ts +2 -0
- package/dist/ui/components/Typography.js +2 -0
- package/dist/ui/components/Typography.style.css +19 -0
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +4 -0
- package/package.json +3 -2
- package/scripts/seed-cli.mjs +133 -27
- package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
- package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
- package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
- package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
- package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
- package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
- package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
- package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
- package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
- package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
- package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
- package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
- package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
- package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
- package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
- package/dist/features/whatsapp-bot/components/index.js +0 -2
- package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
- package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
- package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
- package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
- package/dist/features/whatsapp-bot/index.d.ts +0 -3
- package/dist/features/whatsapp-bot/index.js +0 -3
- package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
- package/dist/features/whatsapp-bot/manifest.js +0 -13
- package/dist/features/whatsapp-bot/messages/en.json +0 -7
- package/dist/features/whatsapp-bot/server.d.ts +0 -7
- package/dist/features/whatsapp-bot/server.js +0 -7
- package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
- package/dist/features/whatsapp-bot/types/index.js +0 -1
|
@@ -2,6 +2,8 @@ import React from "react";
|
|
|
2
2
|
export type CTABannerHeight = "sm" | "md" | "lg" | "xl";
|
|
3
3
|
export interface CTABannerSectionProps {
|
|
4
4
|
title?: string;
|
|
5
|
+
/** Small uppercase label above the headline. Defaults to a generic one. */
|
|
6
|
+
eyebrow?: string;
|
|
5
7
|
subtitle?: string;
|
|
6
8
|
/** Longer supporting paragraph below the subtitle. */
|
|
7
9
|
description?: string;
|
|
@@ -25,4 +27,4 @@ export interface CTABannerSectionProps {
|
|
|
25
27
|
backgroundImage?: string;
|
|
26
28
|
className?: string;
|
|
27
29
|
}
|
|
28
|
-
export declare function CTABannerSection({ title, subtitle, description, primaryLabel, primaryHref, secondaryLabel, secondaryHref, height, backgroundImage, className, }: CTABannerSectionProps): React.JSX.Element;
|
|
30
|
+
export declare function CTABannerSection({ title, eyebrow, subtitle, description, primaryLabel, primaryHref, secondaryLabel, secondaryHref, height, backgroundImage, className, }: CTABannerSectionProps): React.JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Link from "next/link.js";
|
|
3
|
-
import { Div, Heading, Row, Scrim, Section, Span, Text } from "../../../ui/index.js";
|
|
3
|
+
import { Div, Heading, Icon, Row, Scrim, Section, Span, Text } from "../../../ui/index.js";
|
|
4
4
|
import { MediaImage } from "../../media/MediaImage.js";
|
|
5
5
|
import { ROUTES } from "../../../next/routing/route-map.js";
|
|
6
6
|
import { SECTION_TITLE, SECTION_COPY } from "../constants/section-copy.js";
|
|
@@ -20,6 +20,9 @@ const HEIGHT_PADDING_Y = {
|
|
|
20
20
|
lg: "y-5xl",
|
|
21
21
|
xl: "y-6xl",
|
|
22
22
|
};
|
|
23
|
-
export function CTABannerSection({ title = SECTION_TITLE.banner, subtitle, description, primaryLabel = SECTION_COPY.bannerPrimaryCta, primaryHref = String(ROUTES.PUBLIC.PRODUCTS), secondaryLabel = SECTION_COPY.bannerSecondaryCta,
|
|
24
|
-
|
|
23
|
+
export function CTABannerSection({ title = SECTION_TITLE.banner, eyebrow = SECTION_COPY.bannerEyebrow, subtitle, description, primaryLabel = SECTION_COPY.bannerPrimaryCta, primaryHref = String(ROUTES.PUBLIC.PRODUCTS), secondaryLabel = SECTION_COPY.bannerSecondaryCta,
|
|
24
|
+
// Pairs with SECTION_COPY.bannerSecondaryCta — see the note there for why
|
|
25
|
+
// this banner must not default to /auctions.
|
|
26
|
+
secondaryHref = String(ROUTES.PUBLIC.CATEGORIES), height = "md", backgroundImage, className = "", }) {
|
|
27
|
+
return (_jsxs(Section, { tone: "accent-banner", className: `relative ${className}`, overflow: "hidden", paddingY: HEIGHT_PADDING_Y[height], paddingX: "x-md", children: [backgroundImage && (_jsxs(_Fragment, { children: [_jsx(Div, { className: "absolute inset-0", children: _jsx(MediaImage, { src: backgroundImage, alt: "", size: "banner", objectFit: "cover" }) }), _jsx(Scrim, { direction: "left-to-right", intensity: "strong", className: "absolute inset-0" })] })), _jsxs(Div, { className: "relative mx-auto max-w-3xl text-left", children: [_jsxs(Div, { layout: "inline-flex", align: "center", gap: "2", surface: "frost", rounded: "full", padding: "x-sm", className: "mb-4 py-[var(--appkit-space-1-5)] backdrop-blur-sm", children: [_jsx(Icon, { name: "deals", size: "sm", tone: "on-solid" }), _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", transform: "uppercase", className: "tracking-[0.18em]", children: eyebrow })] }), _jsx(Heading, { color: "inverse", level: 2, mdSize: "3xl", lgSize: "4xl", size: "2xl", weight: "bold", children: title }), subtitle && (_jsx(Text, { color: "inverse-muted", className: "mt-3", size: "base", children: subtitle })), description && (_jsx(Text, { color: "inverse-muted", className: "mt-2 max-w-2xl", size: "sm", children: description })), _jsxs(Row, { className: "mt-8", align: "center", justify: "start", gap: "md", wrap: true, children: [_jsx(Link, { href: primaryHref, className: "inline-flex items-center rounded-full bg-white px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-primary-700 shadow-sm transition-all hover:bg-surface-hover hover:shadow-md focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: primaryLabel }), secondaryHref && (_jsx(Link, { href: secondaryHref, className: "inline-flex items-center rounded-full border-2 border-white/80 px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-white transition-all hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: secondaryLabel }))] })] })] }));
|
|
25
28
|
}
|
|
@@ -6,8 +6,10 @@ import { Button, Div, Heading, Row, Scrim, Section, Span, Stack, Text } from "..
|
|
|
6
6
|
import { MediaImage } from "../../media/MediaImage.js";
|
|
7
7
|
import { MediaVideo } from "../../media/MediaVideo.js";
|
|
8
8
|
import { useHeroCarousel } from "../hooks/useHeroCarousel.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import { POSITION_FILL, FLEX_CENTER, HERO_PLACEHOLDER_BG } from "../constants/hero-carousel-styles.js";
|
|
10
|
+
/* The one carousel position/navigation control. The dot and arrow class
|
|
11
|
+
strings this file used to import are deleted — see CarouselNav.style.css. */
|
|
12
|
+
import { CarouselNav } from "../../../ui/components/CarouselNav.js";
|
|
11
13
|
function makeButtonClickHandler(href, openInNewTab, push) {
|
|
12
14
|
return () => {
|
|
13
15
|
if (openInNewTab) {
|
|
@@ -128,7 +130,9 @@ function CarouselCardRenderer({ card, isMobile, push, }) {
|
|
|
128
130
|
}) }))] })] })), card.isButtonOnly && card.buttons?.[0] && (_jsx(Button, { variant: "ghost", rounded: "none", className: `${POSITION_FILL} ${FLEX_CENTER} font-[600] text-white hover:bg-[rgba(0,0,0,0.2)] transition-colors p-[0]`, onClick: makeButtonClickHandler(card.buttons[0].href, card.buttons[0].openInNewTab, push), children: _jsx(Span, { size: "lg", mdSize: "2xl", children: card.buttons[0].text }) }))] }));
|
|
129
131
|
}
|
|
130
132
|
export function HeroCarousel({ initialSlides, push, height, defaultAutoplayDelayMs, pauseOnHover = true, showDots = true, showArrows = true, title, } = {}) {
|
|
131
|
-
|
|
133
|
+
/* `useHandMode()` was read only to pick which bottom corner the arrow pair
|
|
134
|
+
sat in. The nav is centred and symmetrical now, so there is no corner to
|
|
135
|
+
choose and no reason for this surface to know about handedness. */
|
|
132
136
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
133
137
|
const [isPaused, setIsPaused] = useState(false);
|
|
134
138
|
const sectionRef = useRef(null);
|
|
@@ -206,7 +210,5 @@ export function HeroCarousel({ initialSlides, push, height, defaultAutoplayDelay
|
|
|
206
210
|
alignContent: "center",
|
|
207
211
|
alignItems: "stretch",
|
|
208
212
|
}, children: slide.cards.slice(0, 6).map((card) => (_jsx(CarouselCardRenderer, { card: card, isMobile: isMobile, push: push }, card.id))) }))] }, slide.id));
|
|
209
|
-
}) }) }), showDots && slides.length > 1 && (_jsx(Row, {
|
|
210
|
-
? HERO_CAROUSEL_DOT_ACTIVE
|
|
211
|
-
: `${HERO_CAROUSEL_DOT_INACTIVE} hover:bg-white/75`}`, onClick: () => goToSlide(index), "aria-label": `Go to slide ${index + 1}`, children: index === currentSlide && (_jsx(Span, { className: "absolute inset-y-0 left-0 bg-[rgba(0,0,0,0.2)] animate-[progress-fill_4s_linear_forwards]", rounded: "full", "aria-hidden": "true" })) }, index))) })), showArrows && slides.length > 1 && (_jsxs(Row, { gap: "sm", className: `absolute bottom-4 ${hand === "left" ? "left-4" : "right-4"} z-20`, children: [_jsx(Button, { variant: "ghost", className: `p-[0] ${HERO_CAROUSEL_ARROW}`, onClick: goPrev, "aria-label": "Previous slide", children: _jsx("svg", { className: "w-7 h-7 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M15 19l-7-7 7-7" }) }) }), _jsx(Button, { variant: "ghost", className: `p-[0] ${HERO_CAROUSEL_ARROW}`, onClick: goNext, "aria-label": "Next slide", children: _jsx("svg", { className: "w-7 h-7 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M9 5l7 7-7 7" }) }) })] }))] }));
|
|
213
|
+
}) }) }), (showDots || showArrows) && slides.length > 1 && (_jsx(Row, { justify: "center", className: "absolute bottom-4 inset-x-0 z-20 px-[var(--appkit-space-4)]", children: _jsx(CarouselNav, { count: slides.length, index: currentSlide, onSelect: showDots ? goToSlide : undefined, onPrev: showArrows ? goPrev : undefined, onNext: showArrows ? goNext : undefined, tone: "on-media", progressMs: prefersReducedMotion ? 0 : autoplayDelay, paused: isPaused, loop: true, ariaLabel: "Featured promotions" }) }))] }));
|
|
212
214
|
}
|
|
@@ -19,7 +19,7 @@ import { fetchLiveStats } from "../lib/live-stats.js";
|
|
|
19
19
|
import { renderSection, AnnouncementBar } from "../lib/section-renderer.js";
|
|
20
20
|
import { SECTION_COPY } from "../constants/section-copy.js";
|
|
21
21
|
import { homepageSectionsRepository } from "../repository/homepage-sections.repository.js";
|
|
22
|
-
import { isListingTypeEnabled } from "../../../_internal/shared/listing-types/feature-flags.js";
|
|
22
|
+
import { isListingTypeEnabled, isCategoryTypeEnabled, } from "../../../_internal/shared/listing-types/feature-flags.js";
|
|
23
23
|
/**
|
|
24
24
|
* Homepage sections that advertise a specific listing type, and must therefore
|
|
25
25
|
* disappear when the site stops offering it. A section type absent from this
|
|
@@ -30,6 +30,18 @@ const HOMEPAGE_SECTION_LISTING_TYPE = {
|
|
|
30
30
|
"pre-orders": "pre-order",
|
|
31
31
|
"prize-draws": "prize-draw",
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The same idea for the CATEGORY types, added 2026-10-20.
|
|
35
|
+
*
|
|
36
|
+
* 🛑 Bundles are not a `ListingType`, so `featured-bundles` sat outside the
|
|
37
|
+
* map above and rendered unconditionally — the one merchandise rail on the
|
|
38
|
+
* homepage with no off switch at all, while every neighbouring rail had one.
|
|
39
|
+
* `listings.categoryTypes.bundle` is the control that already exists for
|
|
40
|
+
* exactly this, and the admin Site Settings screen already shows it.
|
|
41
|
+
*/
|
|
42
|
+
const HOMEPAGE_SECTION_CATEGORY_TYPE = {
|
|
43
|
+
"featured-bundles": "bundle",
|
|
44
|
+
};
|
|
33
45
|
import { getFeaturedProducts, getFeaturedAuctions, getFeaturedPreOrders } from "../../products/actions/product-actions.js";
|
|
34
46
|
import { listTopLevelCategories, listBrandCategories } from "../../categories/actions/category-actions.js";
|
|
35
47
|
import { listFeaturedBundles } from "../../../_internal/server/features/bundles/data.js";
|
|
@@ -83,12 +95,21 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
|
|
|
83
95
|
// half of it had a real successor (`settings.listings.listingTypes`).
|
|
84
96
|
//
|
|
85
97
|
// So auctions / pre-orders / prize-draws are gated by the same control that
|
|
86
|
-
// hides them on every other surface,
|
|
87
|
-
//
|
|
88
|
-
//
|
|
98
|
+
// hides them on every other surface, `featured-bundles` joined them on
|
|
99
|
+
// 2026-10-20 via the category-type half of the same setting, and the
|
|
100
|
+
// `events` / `blog` / `event-raffles` sections stay unconditional — there is
|
|
101
|
+
// no product control for "we don't run events", and there never was one that
|
|
102
|
+
// anything but this line read. Those are switched off per-document instead
|
|
103
|
+
// (`enabled: false`), which is the only lever they have.
|
|
89
104
|
const enabledSections = allSections.filter((section) => {
|
|
90
|
-
const
|
|
91
|
-
|
|
105
|
+
const type = section.type;
|
|
106
|
+
const gatedListing = HOMEPAGE_SECTION_LISTING_TYPE[type];
|
|
107
|
+
if (gatedListing && !isListingTypeEnabled(gatedListing, siteSettings))
|
|
108
|
+
return false;
|
|
109
|
+
const gatedCategory = HOMEPAGE_SECTION_CATEGORY_TYPE[type];
|
|
110
|
+
if (gatedCategory && !isCategoryTypeEnabled(gatedCategory, siteSettings))
|
|
111
|
+
return false;
|
|
112
|
+
return true;
|
|
92
113
|
});
|
|
93
114
|
// Collect live metric requests from all enabled stats sections
|
|
94
115
|
const liveStatRequests = [];
|
|
@@ -136,7 +157,12 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
|
|
|
136
157
|
activeTypes.has("products") ? getFeaturedProducts(12) : null,
|
|
137
158
|
activeTypes.has("auctions") ? getFeaturedAuctions(12) : null,
|
|
138
159
|
activeTypes.has("pre-orders") ? getFeaturedPreOrders(12) : null,
|
|
139
|
-
|
|
160
|
+
// `welcome` is a second trigger, not a typo: its hero mosaic is built from
|
|
161
|
+
// these categories' cover images. Gating the fetch on `categories` alone
|
|
162
|
+
// meant a homepage without a categories section rendered the hero's
|
|
163
|
+
// brand-mark fallback with nothing anywhere saying the imagery had simply
|
|
164
|
+
// not been fetched.
|
|
165
|
+
activeTypes.has("categories") || activeTypes.has("welcome")
|
|
140
166
|
? safeRead(() => listTopLevelCategories(12), { route: "/", key: "homepage.categories", fallback: null })
|
|
141
167
|
: null,
|
|
142
168
|
activeTypes.has("brands")
|
|
@@ -44,9 +44,17 @@ export function SectionCarousel({ title, description, headingVariant = "editoria
|
|
|
44
44
|
headingClass,
|
|
45
45
|
]
|
|
46
46
|
.filter(Boolean)
|
|
47
|
-
.join(" "), children: title }), headingVariant === "editorial" && (_jsxs(Row, { align: "center", justify: "center", gap: "sm", textSize: "xs", color: "faint", className: "mt-1 select-none", "aria-hidden": "true", children: [_jsx(Span, { className: "h-px w-6 bg-current" }), _jsx(Span, { size: "xs", children: "\u2736" }), _jsx(Span, { className: "h-px w-6 bg-current" })] })), description && (_jsx(Text, { className: `${descVariant} mt-2`, size: "base", children: description }))] }), isLoading ? (_jsx(CarouselSkeleton, { count: skeletonCount })) : (_jsx(HorizontalScroller, { items: items, renderItem: renderItem, perView: perView, gap: gap, autoScroll: autoScroll, autoScrollInterval: autoScrollInterval, loop: loop, keyExtractor: keyExtractor, rows: rows, minItemWidth: minItemWidth,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
.join(" "), children: title }), headingVariant === "editorial" && (_jsxs(Row, { align: "center", justify: "center", gap: "sm", textSize: "xs", color: "faint", className: "mt-1 select-none", "aria-hidden": "true", children: [_jsx(Span, { className: "h-px w-6 bg-current" }), _jsx(Span, { size: "xs", children: "\u2736" }), _jsx(Span, { className: "h-px w-6 bg-current" })] })), description && (_jsx(Text, { className: `${descVariant} mt-2`, size: "base", children: description }))] }), isLoading ? (_jsx(CarouselSkeleton, { count: skeletonCount })) : (_jsx(HorizontalScroller, { items: items, renderItem: renderItem, perView: perView, gap: gap, autoScroll: autoScroll, autoScrollInterval: autoScrollInterval, loop: loop, keyExtractor: keyExtractor, rows: rows, minItemWidth: minItemWidth,
|
|
48
|
+
/*
|
|
49
|
+
* One in-flow control instead of two absolute arrows.
|
|
50
|
+
*
|
|
51
|
+
* The arrows were `display:none` below 640px, so on a phone every
|
|
52
|
+
* rail on the homepage had no affordance at all — only a hidden
|
|
53
|
+
* scrollbar and the hope that a visitor would try swiping. They
|
|
54
|
+
* also cost the rail 2 × 44px of wrapper gutter at EVERY width to
|
|
55
|
+
* reserve space for themselves. `showNav` carries arrows AND a
|
|
56
|
+
* position indicator in flow, so the control exists on a phone and
|
|
57
|
+
* the gutter goes back to the cards.
|
|
58
|
+
*/
|
|
59
|
+
showArrows: false, showNav: true, navAriaLabel: title, snapToItems: true, showScrollbar: false, pauseOnHover: true })), viewMoreHref && !isLoading && (_jsx(Row, { className: "mt-6", justify: hand === "left" ? "end" : "start", children: _jsx(TextLink, { rounded: "lg", paddingX: "xl", paddingY: "sm", href: viewMoreHref, shadow: useLightText ? "lg" : "none", layout: "inline-flex", align: "center", className: "gap-[0.375rem] transition-colors bg-primary text-white hover:bg-primary-600", size: "sm", weight: "semibold", children: viewMoreLabel }) }))] })] }));
|
|
52
60
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
2
3
|
export interface SecurityHighlightItem {
|
|
3
4
|
key: string;
|
|
4
5
|
title: string;
|
|
5
6
|
description: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* 🛑 Replaces `renderIcon?: (props) => ReactNode`, which was unreachable: the
|
|
9
|
+
* items come from a Firestore section config and a function cannot round-trip
|
|
10
|
+
* through a document, so the renderer never passed one and the icon row below
|
|
11
|
+
* never rendered at all. See constants/trust-icon-aliases.ts.
|
|
12
|
+
*/
|
|
13
|
+
iconName?: IconKey;
|
|
9
14
|
colorClass?: string;
|
|
10
15
|
iconColorClass?: string;
|
|
11
16
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { THEMED_TEXT_PRIMARY } from "../../../_internal/shared/styles/themed.js";
|
|
5
|
-
import { Div, Grid, Heading, Row, Section, Span, Text, TextLink } from "../../../ui/index.js";
|
|
5
|
+
import { Div, Grid, Heading, Icon, Row, Section, Span, Text, TextLink } from "../../../ui/index.js";
|
|
6
6
|
// --- Constants ---------------------------------------------------------------
|
|
7
7
|
const CARD_DELAYS = ["delay-0", "delay-100", "delay-200", "delay-300", "delay-[400ms]", "delay-500"];
|
|
8
8
|
// --- Single card -------------------------------------------------------------
|
|
@@ -15,7 +15,7 @@ function SecurityCard({ item, visible, delayClass, }) {
|
|
|
15
15
|
colorClass,
|
|
16
16
|
delayClass,
|
|
17
17
|
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4",
|
|
18
|
-
].join(" "), "data-section": "securityhighlightssection-div-357", children: [item.
|
|
18
|
+
].join(" "), "data-section": "securityhighlightssection-div-357", children: [item.iconName && (_jsx(Row, { className: "w-10 h-10 mb-3", surface: "default", align: "center", justify: "center", rounded: "lg", children: _jsx(Icon, { name: item.iconName, size: "xl", className: iconColorClass }) })), _jsx(Text, { className: "mb-1", weight: "semibold", children: item.title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "sm", children: item.description })] }));
|
|
19
19
|
}
|
|
20
20
|
// --- Section -----------------------------------------------------------------
|
|
21
21
|
export function SecurityHighlightsSection({ title, subtitle, pillLabel, items, learnMoreHref, learnMoreLabel = "Learn more →", className = "", }) {
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
2
2
|
export interface StatItem {
|
|
3
3
|
key: string;
|
|
4
4
|
value: string;
|
|
5
5
|
label: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* 🛑 Replaces `renderIcon?: (props) => ReactNode`, which was unreachable — a
|
|
8
|
+
* function has no representation in the Firestore section config these stats
|
|
9
|
+
* come from, so the icon box below never rendered once. For a LIVE stat the
|
|
10
|
+
* renderer derives this from `metric` via STAT_PRESET_ICON, so a correct icon
|
|
11
|
+
* needs no extra config at all.
|
|
12
|
+
*/
|
|
13
|
+
iconName?: IconKey;
|
|
9
14
|
}
|
|
10
15
|
export interface StatsCounterSectionProps {
|
|
11
16
|
stats: StatItem[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
|
-
import { Div, Grid, Heading, Row, Section, Text } from "../../../ui/index.js";
|
|
4
|
+
import { Div, Grid, Heading, Icon, Row, Section, Text } from "../../../ui/index.js";
|
|
5
5
|
// --- Constants ---------------------------------------------------------------
|
|
6
6
|
const STAT_DELAYS = ["delay-0", "delay-[120ms]", "delay-[240ms]", "delay-[360ms]"];
|
|
7
7
|
// --- Smngle stat mtem ---------------------------------------------------------
|
|
@@ -12,7 +12,7 @@ function StatCard({ stat, visible, delayClass, isLast, }) {
|
|
|
12
12
|
delayClass,
|
|
13
13
|
visible ? "translate-y-0 opacity-100" : "translate-y-6 opacity-0",
|
|
14
14
|
!isLast ? "border-r border-[var(--appkit-color-border)]" : "",
|
|
15
|
-
].join(" "), children: [stat.
|
|
15
|
+
].join(" "), children: [stat.iconName && (_jsx(Row, { className: "mb-4 h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30", align: "center", justify: "center", rounded: "2xl", children: _jsx(Icon, { name: stat.iconName, size: "xl", tone: "primary" }) })), _jsx(Heading, { level: 3, variant: "none", gradient: "brand", className: "mb-1 font-display font-black", mdSize: "5xl", size: "4xl", children: stat.value }), _jsx(Text, { variant: "none", className: "uppercase tracking-widest", color: "muted", size: "xs", weight: "medium", children: stat.label })] }));
|
|
16
16
|
}
|
|
17
17
|
// --- Sectmon -----------------------------------------------------------------
|
|
18
18
|
export function StatsCounterSection({ stats, title, className = "", }) {
|
|
@@ -3,5 +3,5 @@ import { Div, Heading, Stack, StarRating, Text } from "../../../ui/index.js";
|
|
|
3
3
|
export function TestimonialsCarousel({ testimonials, eyebrow = "COLLECTOR REVIEWS", heading = "WHAT OUR COLLECTORS SAY", }) {
|
|
4
4
|
if (testimonials.length === 0)
|
|
5
5
|
return null;
|
|
6
|
-
return (_jsx(Stack, { as: "section", justify: "center", surface: "muted", border: "subtle", className: "min-h-[calc(100svh-var(--header-height,4rem))] [padding-block:clamp(3rem,6vh,5rem)]", children: _jsxs(Stack, { className: "mx-auto w-full max-w-7xl sm:px-[2rem] min-h-0", padding: "x-lg", children: [_jsxs(Div, { className: "mb-6 text-left shrink-0", children: [_jsx(Text, { className: "mb-1 font-black uppercase tracking-widest text-error tracking-[0.18em]", size: "xs", children: eyebrow }), _jsx(Heading, { level: 2, family: "display", className: "tracking-[0.08em] leading-none", size: "2xl", mdSize: "3xl", weight: "bold", color: "primary", children: heading })] }), _jsx(Stack, { wrap: true, className: "overflow-x-auto
|
|
6
|
+
return (_jsx(Stack, { as: "section", justify: "center", surface: "muted", border: "subtle", className: "min-h-[calc(100svh-var(--header-height,4rem))] [padding-block:clamp(3rem,6vh,5rem)]", children: _jsxs(Stack, { className: "mx-auto w-full max-w-7xl sm:px-[2rem] min-h-0", padding: "x-lg", children: [_jsxs(Div, { className: "mb-6 text-left shrink-0", children: [_jsx(Text, { className: "mb-1 font-black uppercase tracking-widest text-error tracking-[0.18em]", size: "xs", children: eyebrow }), _jsx(Heading, { level: 2, family: "display", className: "tracking-[0.08em] leading-none", size: "2xl", mdSize: "3xl", weight: "bold", color: "primary", children: heading })] }), _jsx(Stack, { wrap: true, className: "overflow-x-auto max-h-[50svh] content-start", gap: "md", children: testimonials.map((t) => (_jsxs(Stack, { padding: "5", surface: "card", border: "subtle", className: "shrink-0 w-[clamp(260px,28vw,360px)]", shadow: "card", gap: "3", children: [_jsx(StarRating, { value: t.rating, readOnly: true, size: "sm" }), _jsxs(Text, { className: "flex-1 leading-relaxed", size: "sm", color: "muted", children: ["\u201C", t.text, "\u201D"] }), _jsxs(Text, { className: "font-black uppercase text-[var(--color-yellow)] tracking-[0.06em]", size: "xs", children: ["\u2014 ", t.name] })] }, t.id))) })] }) }));
|
|
7
7
|
}
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
3
|
+
/**
|
|
4
|
+
* 🛑 `renderIcon?: (props) => ReactNode` was removed, not renamed.
|
|
5
|
+
*
|
|
6
|
+
* It was unreachable by construction: every item here comes from a Firestore
|
|
7
|
+
* section config, and a function has no representation in a document — so the
|
|
8
|
+
* section renderer never passed one, and all four tiles fell through to a
|
|
9
|
+
* hardcoded `✓`. Four different promises ("Authenticity checked", "Escrow-backed
|
|
10
|
+
* payments", "Straightforward returns", "Real human support") rendered the same
|
|
11
|
+
* glyph. `iconName` is data, so it survives the document round-trip.
|
|
12
|
+
*
|
|
13
|
+
* `id` is now a separate field because `iconName` used to serve as BOTH the
|
|
14
|
+
* icon and the React key — two indicators sharing an icon produced duplicate
|
|
15
|
+
* keys, and giving the icon a correct default would have made that collision
|
|
16
|
+
* likely rather than rare.
|
|
17
|
+
*/
|
|
2
18
|
export interface TrustFeatureItem {
|
|
3
|
-
|
|
19
|
+
id: string;
|
|
4
20
|
title: string;
|
|
5
21
|
description: string;
|
|
6
|
-
|
|
7
|
-
className?: string;
|
|
8
|
-
}) => React.ReactNode;
|
|
22
|
+
iconName?: IconKey;
|
|
9
23
|
}
|
|
10
24
|
export interface TrustFeaturesSectionProps {
|
|
11
25
|
items: TrustFeatureItem[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
|
-
import { Div, Grid, Heading, Row, Section,
|
|
4
|
+
import { Div, Grid, Heading, Icon, Row, Section, Text } from "../../../ui/index.js";
|
|
5
5
|
// --- Constants ---------------------------------------------------------------
|
|
6
6
|
const CARD_DELAYS = ["delay-0", "delay-100", "delay-200", "delay-300", "delay-[400ms]", "delay-500"];
|
|
7
7
|
// --- Single cards-variant card -----------------------------------------------
|
|
@@ -11,11 +11,11 @@ function TrustFeatureCard({ item, visible, delayClass, }) {
|
|
|
11
11
|
"transition-all duration-500",
|
|
12
12
|
delayClass,
|
|
13
13
|
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4",
|
|
14
|
-
].join(" "), "data-section": "trustfeaturessection-div-373", children: [_jsx(Row, { className: "h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30 flex-shrink-0", align: "center", justify: "center", rounded: "2xl", children:
|
|
14
|
+
].join(" "), "data-section": "trustfeaturessection-div-373", children: [item.iconName && (_jsx(Row, { className: "h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30 flex-shrink-0", align: "center", justify: "center", rounded: "2xl", children: _jsx(Icon, { name: item.iconName, size: "xl", tone: "primary" }) })), _jsx(Heading, { level: 3, className: "mt-3 mb-1 tracking-wide uppercase", color: "primary", size: "sm", weight: "bold", children: item.title }), _jsx(Text, { className: "leading-relaxed", color: "muted", size: "xs", children: item.description })] }));
|
|
15
15
|
}
|
|
16
16
|
// --- Single strip-variant item -----------------------------------------------
|
|
17
17
|
function TrustStripItem({ item }) {
|
|
18
|
-
return (_jsxs(Div, { layout: "inline-flex", gap: "2", align: "center", className: "flex-shrink-0", padding: "x-lg", children: [item.
|
|
18
|
+
return (_jsxs(Div, { layout: "inline-flex", gap: "2", align: "center", className: "flex-shrink-0", padding: "x-lg", children: [item.iconName && _jsx(Icon, { name: item.iconName, size: "lg", tone: "primary" }), _jsx(Text, { className: "whitespace-nowrap", color: "muted", size: "sm", weight: "medium", children: item.title })] }));
|
|
19
19
|
}
|
|
20
20
|
// --- Section -----------------------------------------------------------------
|
|
21
21
|
export function TrustFeaturesSection({ items, title, variant = "cards", className = "", }) {
|
|
@@ -36,7 +36,7 @@ export function TrustFeaturesSection({ items, title, variant = "cards", classNam
|
|
|
36
36
|
}, []);
|
|
37
37
|
if (variant === "strip") {
|
|
38
38
|
const doubled = [...items, ...items];
|
|
39
|
-
return (_jsx(Section, { border: "subtle", ref: sectionRef, className: `overflow-hidden border-y ${className}`, padding: "y-md", children: _jsx(Div, { layout: "flex", className: "animate-marquee", children: doubled.map((item, i) => (_jsx(TrustStripItem, { item: item }, `${item.
|
|
39
|
+
return (_jsx(Section, { border: "subtle", ref: sectionRef, className: `overflow-hidden border-y ${className}`, padding: "y-md", children: _jsx(Div, { layout: "flex", className: "animate-marquee", children: doubled.map((item, i) => (_jsx(TrustStripItem, { item: item }, `${item.id}-${i}`))) }) }));
|
|
40
40
|
}
|
|
41
|
-
return (_jsx(Section, { ref: sectionRef, paddingY: "y-2-5xl", className: className, paddingX: "x-md", surface: "muted", children: _jsxs(Div, { className: "max-w-6xl mx-auto", children: [title && (_jsx(Div, { className: "text-left mb-8", children: _jsx(Heading, { level: 2, color: "primary", size: "3xl", weight: "bold", mdSize: "4xl", children: title }) })), _jsx(Grid, { cols: "statTiles", gap: "lg", children: items.map((item, index) => (_jsx(TrustFeatureCard, { item: item, visible: visible, delayClass: CARD_DELAYS[Math.min(index, CARD_DELAYS.length - 1)] }, item.
|
|
41
|
+
return (_jsx(Section, { ref: sectionRef, paddingY: "y-2-5xl", className: className, paddingX: "x-md", surface: "muted", children: _jsxs(Div, { className: "max-w-6xl mx-auto", children: [title && (_jsx(Div, { className: "text-left mb-8", children: _jsx(Heading, { level: 2, color: "primary", size: "3xl", weight: "bold", mdSize: "4xl", children: title }) })), _jsx(Grid, { cols: "statTiles", gap: "lg", children: items.map((item, index) => (_jsx(TrustFeatureCard, { item: item, visible: visible, delayClass: CARD_DELAYS[Math.min(index, CARD_DELAYS.length - 1)] }, item.id))) })] }) }));
|
|
42
42
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
2
3
|
export interface WelcomeSectionChip {
|
|
3
4
|
key: string;
|
|
4
|
-
emoji
|
|
5
|
+
/** Registry icon key. Replaces `emoji`, which no utility could size. */
|
|
6
|
+
iconName: IconKey;
|
|
5
7
|
label: string;
|
|
6
8
|
}
|
|
7
9
|
export interface WelcomeSectionProps {
|
|
@@ -16,8 +18,17 @@ export interface WelcomeSectionProps {
|
|
|
16
18
|
secondaryCtaHref?: string;
|
|
17
19
|
onSecondaryCtaClick?: () => void;
|
|
18
20
|
trustChips?: WelcomeSectionChip[];
|
|
21
|
+
/**
|
|
22
|
+
* Decorative hero imagery, MOST IMPORTANT FIRST — the first takes the large
|
|
23
|
+
* mosaic cell. Below `MOSAIC_MIN` (3) the brand-mark panel is used instead.
|
|
24
|
+
*
|
|
25
|
+
* Must be deterministic: `ImageMosaic` is explicit that `Math.random()` here
|
|
26
|
+
* would break SSR/hydration agreement, so the caller passes a stable
|
|
27
|
+
* configured order rather than a shuffle.
|
|
28
|
+
*/
|
|
29
|
+
heroImages?: readonly string[];
|
|
19
30
|
isLoading?: boolean;
|
|
20
31
|
brandLogoText?: string;
|
|
21
32
|
className?: string;
|
|
22
33
|
}
|
|
23
|
-
export declare function WelcomeSection({ title, subtitle, pillLabel, showCTA, ctaLabel, ctaHref, onCtaClick, secondaryCtaLabel, secondaryCtaHref, onSecondaryCtaClick, trustChips, isLoading, brandLogoText, className, }: WelcomeSectionProps): React.JSX.Element;
|
|
34
|
+
export declare function WelcomeSection({ title, subtitle, pillLabel, showCTA, ctaLabel, ctaHref, onCtaClick, secondaryCtaLabel, secondaryCtaHref, onSecondaryCtaClick, trustChips, heroImages, isLoading, brandLogoText, className, }: WelcomeSectionProps): React.JSX.Element;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { THEMED_TEXT_SECONDARY, FLEX_CENTER } from "../../../_internal/shared/styles/themed.js";
|
|
4
|
-
import { Button, Div, Grid, Heading, Row, Section, SiteLogo, SiteMark, Span, Stack, Text, TextLink } from "../../../ui/index.js";
|
|
4
|
+
import { Button, Div, Grid, Heading, Icon, ImageMosaic, MOSAIC_MIN, Row, Section, SiteLogo, SiteMark, Span, Stack, Text, TextLink } from "../../../ui/index.js";
|
|
5
5
|
// --- Component ---------------------------------------------------------------
|
|
6
|
-
export function WelcomeSection({ title, subtitle, pillLabel, showCTA = true, ctaLabel = "Shop now", ctaHref, onCtaClick, secondaryCtaLabel = "Browse products", secondaryCtaHref, onSecondaryCtaClick, trustChips = [], isLoading = false, brandLogoText = "", className = "", }) {
|
|
6
|
+
export function WelcomeSection({ title, subtitle, pillLabel, showCTA = true, ctaLabel = "Shop now", ctaHref, onCtaClick, secondaryCtaLabel = "Browse products", secondaryCtaHref, onSecondaryCtaClick, trustChips = [], heroImages, isLoading = false, brandLogoText = "", className = "", }) {
|
|
7
7
|
const themed = { textSecondary: THEMED_TEXT_SECONDARY };
|
|
8
8
|
const flex = { center: FLEX_CENTER };
|
|
9
9
|
if (isLoading) {
|
|
10
10
|
return (_jsx(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-16)] md:pt-[0px] md:pb-[6rem] ${className}`, paddingX: "x-md", children: _jsxs(Div, { className: "animate-pulse max-w-4xl mx-auto text-left", children: [_jsx(Div, { className: "h-6 w-52 mb-6", surface: "subtle", rounded: "full" }), _jsx(Div, { className: "h-20 mb-4 max-w-2xl", surface: "subtle", rounded: "lg" }), _jsx(Div, { className: "h-6 mb-8 max-w-lg", surface: "subtle", rounded: "lg" }), _jsxs(Row, { justify: "start", gap: "md", children: [_jsx(Div, { className: "h-12 w-36", surface: "subtle", rounded: "xl" }), _jsx(Div, { className: "h-12 w-36", surface: "subtle", rounded: "xl" })] })] }) }));
|
|
11
11
|
}
|
|
12
|
-
return (_jsxs(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-20)] md:pt-[0px] md:pb-[7rem] ${className}`, paddingX: "x-md", children: [_jsx(Div, { className: "pointer-events-none absolute -top-32 -left-32 w-[28rem] h-[28rem] bg-primary/10 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "pointer-events-none absolute -bottom-40 -right-40 w-[36rem] h-[36rem] bg-secondary/10 dark:bg-secondary/15 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "relative z-10 max-w-7xl mx-auto", children: _jsxs(Grid, { align: "center", gap: "2xl", className: "grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2", children: [_jsxs(Div, { className: "text-left", children: [pillLabel && (_jsx(Div, { children: _jsxs(Span, { layout: "inline-flex", gap: "md", size: "xs", weight: "medium", className: /* audit-variant-ok: colour+alpha border (primary-500/30); the `border` variant takes a token name, not an rgba step */ "border border-primary-500/30 bg-primary-500/10 px-[1.25rem] py-[0.375rem] tracking-[0.2em] text-primary-700 dark:text-primary-400 backdrop-blur-sm", rounded: "full", transform: "uppercase", children: [_jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" }), pillLabel, _jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" })] }) })), _jsx(Heading, { level: 1, variant: "none", gradient: "brand-tri", className: "mt-4 font-display leading-[1.1] tracking-tight break-words", size: "5xl", mdSize: "6xl", lgSize: "7xl", xlSize: "7xl", children: title }), subtitle && (_jsx(Text, { className: `mt-4 ${themed.textSecondary} max-w-xl leading-relaxed`, size: "xl", children: subtitle })), showCTA && (_jsxs(Row, { wrap: true, gap: "md", className: "mt-8", justify: "start", children: [ctaHref ? (_jsx(TextLink, { rounded: "xl", href: ctaHref, layout: "inline-flex", align: "center", justify: "center", className: "px-[2rem] py-[0.875rem] !bg-primary hover:!bg-primary-600 text-white dark:!bg-primary dark:hover:!bg-primary-600 dark:text-white btn-glow transition-all hover:scale-[1.02]", size: "base", weight: "bold", children: ctaLabel })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: onCtaClick, children: ctaLabel })), secondaryCtaHref ? (_jsx(TextLink, { rounded: "xl", href: secondaryCtaHref, layout: "inline-flex", align: "center", justify: "center", className: "border-2 border-cobalt/40 dark:border-cobalt-400/40 px-[2rem] py-[0.875rem] text-cobalt-700 dark:text-cobalt-300 hover:bg-primary-surface transition-all hover:scale-[1.02]", size: "base", weight: "semibold", children: secondaryCtaLabel })) : (_jsx(Button, { variant: "outline", size: "lg", onClick: onSecondaryCtaClick, children: secondaryCtaLabel }))] })), trustChips.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-6", justify: "start", children: trustChips.map((chip) => (_jsxs(
|
|
12
|
+
return (_jsxs(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-20)] md:pt-[0px] md:pb-[7rem] ${className}`, paddingX: "x-md", children: [_jsx(Div, { className: "pointer-events-none absolute -top-32 -left-32 w-[28rem] h-[28rem] bg-primary/10 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "pointer-events-none absolute -bottom-40 -right-40 w-[36rem] h-[36rem] bg-secondary/10 dark:bg-secondary/15 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "relative z-10 max-w-7xl mx-auto", children: _jsxs(Grid, { align: "center", gap: "2xl", className: "grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2", children: [_jsxs(Div, { className: "text-left", children: [pillLabel && (_jsx(Div, { children: _jsxs(Span, { layout: "inline-flex", gap: "md", size: "xs", weight: "medium", className: /* audit-variant-ok: colour+alpha border (primary-500/30); the `border` variant takes a token name, not an rgba step */ "border border-primary-500/30 bg-primary-500/10 px-[1.25rem] py-[0.375rem] tracking-[0.2em] text-primary-700 dark:text-primary-400 backdrop-blur-sm", rounded: "full", transform: "uppercase", children: [_jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" }), pillLabel, _jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" })] }) })), _jsx(Heading, { level: 1, variant: "none", gradient: "brand-tri", className: "mt-4 font-display leading-[1.1] tracking-tight break-words", size: "5xl", mdSize: "6xl", lgSize: "7xl", xlSize: "7xl", children: title }), subtitle && (_jsx(Text, { className: `mt-4 ${themed.textSecondary} max-w-xl leading-relaxed`, size: "xl", children: subtitle })), showCTA && (_jsxs(Row, { wrap: true, gap: "md", className: "mt-8", justify: "start", children: [ctaHref ? (_jsx(TextLink, { rounded: "xl", href: ctaHref, layout: "inline-flex", align: "center", justify: "center", className: "px-[2rem] py-[0.875rem] !bg-primary hover:!bg-primary-600 text-white dark:!bg-primary dark:hover:!bg-primary-600 dark:text-white btn-glow transition-all hover:scale-[1.02]", size: "base", weight: "bold", children: ctaLabel })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: onCtaClick, children: ctaLabel })), secondaryCtaHref ? (_jsx(TextLink, { rounded: "xl", href: secondaryCtaHref, layout: "inline-flex", align: "center", justify: "center", className: "border-2 border-cobalt/40 dark:border-cobalt-400/40 px-[2rem] py-[0.875rem] text-cobalt-700 dark:text-cobalt-300 hover:bg-primary-surface transition-all hover:scale-[1.02]", size: "base", weight: "semibold", children: secondaryCtaLabel })) : (_jsx(Button, { variant: "outline", size: "lg", onClick: onSecondaryCtaClick, children: secondaryCtaLabel }))] })), trustChips.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-6", justify: "start", children: trustChips.map((chip) => (_jsxs(Row, { align: "center", gap: "xs", surface: "default", border: "subtle", rounded: "full", shadow: "sm", className: "px-[0.875rem] py-[0.375rem]", children: [_jsx(Icon, { name: chip.iconName, size: "sm", tone: "success" }), _jsx(Span, { size: "xs", weight: "medium", color: "muted", children: chip.label })] }, chip.key))) }))] }), _jsx(Div, { className: "hidden lg:block", children: heroImages && heroImages.length >= MOSAIC_MIN ? (_jsx(ImageMosaic, { size: "hero", images: heroImages, alt: `${brandLogoText || "Marketplace"} collection highlights` })) : (_jsxs(Div, { className: `relative overflow-hidden aspect-[4/3] bg-[image:var(--appkit-gradient-section-mesh)]`, shadow: "2xl", border: "default", rounded: "3xl", children: [_jsx(Div, { className: "absolute inset-0 bg-[image:var(--appkit-gradient-glass)]" }), _jsxs(Stack, { centered: true, gap: "sm", className: `absolute inset-0 ${flex.center} p-[2.5rem]`, children: [_jsx(SiteMark, { title: brandLogoText || "LetItRip.in", size: "xl" }), _jsx(SiteLogo, { title: brandLogoText || "LetItRip.in", size: "xl" })] })] })) })] }) })] }));
|
|
13
13
|
}
|
|
@@ -11,4 +11,32 @@ export interface WhatsAppCommunitySectionProps {
|
|
|
11
11
|
isLoading?: boolean;
|
|
12
12
|
className?: string;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* The community invite.
|
|
16
|
+
*
|
|
17
|
+
* ## 🛑 It looks like a chat because it IS a chat invite
|
|
18
|
+
*
|
|
19
|
+
* This was a single flat card: icon row → heading → description → a 2-column
|
|
20
|
+
* grid of four identical `✓` circles → an italic blockquote → a button, all
|
|
21
|
+
* left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
|
|
22
|
+
* blockquote) spent a lot of vertical space *telling* you the group is useful.
|
|
23
|
+
* As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
|
|
24
|
+
*
|
|
25
|
+
* Everything needed already existed and had no consumer: `Card`'s
|
|
26
|
+
* `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
|
|
27
|
+
* notches and an auto-margin for right alignment) and the
|
|
28
|
+
* `--appkit-color-whatsapp-bg` beige token.
|
|
29
|
+
*
|
|
30
|
+
* ## 🛑 Three things that are deliberate
|
|
31
|
+
*
|
|
32
|
+
* 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
|
|
33
|
+
* same category of claim as a made-up member count — which this feature
|
|
34
|
+
* already refuses to invent. The bubble shape carries the motif on its own.
|
|
35
|
+
* 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
|
|
36
|
+
* `display:inline-block; max-width:80%`, and a stretched flex item defeats
|
|
37
|
+
* both, so the bubbles would become full-width boxes.
|
|
38
|
+
* 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
|
|
39
|
+
* primary→secondary — the SAME gradient as `CTABannerSection` a couple of
|
|
40
|
+
* sections below, which is a real part of why the page read monotonous.
|
|
41
|
+
*/
|
|
14
42
|
export declare function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel, testimonial, benefits, buttonText, groupLink, isLoading, className, }: WhatsAppCommunitySectionProps): React.JSX.Element | null;
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import { Users } from "lucide-react";
|
|
3
|
+
import { Button, Card, Div, Grid, Heading, Icon, RichText, Row, Section, Span, Stack, Text } from "../../../ui/index.js";
|
|
5
4
|
import { getDefaultLocale } from "../../../core/baseline-resolver.js";
|
|
6
|
-
import {
|
|
5
|
+
import { WhatsAppGlyph } from "./WhatsAppGlyph.js";
|
|
7
6
|
// --- Section -----------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* The community invite.
|
|
9
|
+
*
|
|
10
|
+
* ## 🛑 It looks like a chat because it IS a chat invite
|
|
11
|
+
*
|
|
12
|
+
* This was a single flat card: icon row → heading → description → a 2-column
|
|
13
|
+
* grid of four identical `✓` circles → an italic blockquote → a button, all
|
|
14
|
+
* left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
|
|
15
|
+
* blockquote) spent a lot of vertical space *telling* you the group is useful.
|
|
16
|
+
* As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
|
|
17
|
+
*
|
|
18
|
+
* Everything needed already existed and had no consumer: `Card`'s
|
|
19
|
+
* `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
|
|
20
|
+
* notches and an auto-margin for right alignment) and the
|
|
21
|
+
* `--appkit-color-whatsapp-bg` beige token.
|
|
22
|
+
*
|
|
23
|
+
* ## 🛑 Three things that are deliberate
|
|
24
|
+
*
|
|
25
|
+
* 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
|
|
26
|
+
* same category of claim as a made-up member count — which this feature
|
|
27
|
+
* already refuses to invent. The bubble shape carries the motif on its own.
|
|
28
|
+
* 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
|
|
29
|
+
* `display:inline-block; max-width:80%`, and a stretched flex item defeats
|
|
30
|
+
* both, so the bubbles would become full-width boxes.
|
|
31
|
+
* 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
|
|
32
|
+
* primary→secondary — the SAME gradient as `CTABannerSection` a couple of
|
|
33
|
+
* sections below, which is a real part of why the page read monotonous.
|
|
34
|
+
*/
|
|
8
35
|
export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel = "members", testimonial, benefits = [], buttonText = "Join our WhatsApp community", groupLink, isLoading = false, className = "", }) {
|
|
9
|
-
const { hand } = useHandMode();
|
|
10
36
|
if (isLoading) {
|
|
11
37
|
return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsx(Div, { className: "h-72 animate-pulse", surface: "subtle", rounded: "2xl" }) }) }));
|
|
12
38
|
}
|
|
@@ -14,7 +40,17 @@ export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount,
|
|
|
14
40
|
return null;
|
|
15
41
|
const handleJoin = () => {
|
|
16
42
|
if (groupLink)
|
|
17
|
-
window.open(groupLink, "_blank");
|
|
43
|
+
window.open(groupLink, "_blank", "noopener,noreferrer");
|
|
18
44
|
};
|
|
19
|
-
|
|
45
|
+
/* The thread. Benefits read as incoming messages; the testimonial closes it.
|
|
46
|
+
Below two there is no conversation to show, so the panel stands down and
|
|
47
|
+
the pitch column takes the full width rather than sitting beside an
|
|
48
|
+
almost-empty box. */
|
|
49
|
+
const thread = [...benefits.slice(0, 4), ...(testimonial ? [`“${testimonial}”`] : [])];
|
|
50
|
+
const showThread = thread.length >= 2;
|
|
51
|
+
return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsxs(Section, { color: "inverse", tone: "whatsapp", rounded: "3xl", shadow: "xl", className: "relative overflow-hidden", children: [_jsx(Div, { className: "absolute inset-0 opacity-[0.10] pointer-events-none bg-[radial-gradient(circle_at_1px_1px,white_1px,transparent_0)] bg-[size:18px_18px]", "aria-hidden": true }), _jsxs(Grid, { cols: showThread ? "halves" : "autoLg", gap: "hero", align: "center", className: "relative z-10 px-[1.5rem] py-[2.5rem] sm:px-[2.5rem] sm:py-[3rem]", children: [_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { align: "center", gap: "md", wrap: true, children: [_jsxs(Row, { surface: "frost", rounded: "full", padding: "x-sm", paddingY: "y-2xs-tall", align: "center", gap: "xs", className: "backdrop-blur-sm", children: [_jsx(WhatsAppGlyph, { className: "h-4 w-4" }), _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", transform: "uppercase", className: "tracking-[0.18em]", children: "WhatsApp Community" })] }), memberCount && (_jsxs(Row, { align: "center", gap: "xs", children: [_jsxs(Span, { layout: "flex", className: "relative h-2 w-2", "aria-hidden": true, children: [_jsx(Span, { rounded: "full", className: "absolute inline-flex h-full w-full animate-ping bg-[var(--appkit-color-surface)] opacity-75" }), _jsx(Span, { rounded: "full", className: "relative inline-flex h-2 w-2 bg-[var(--appkit-color-surface)]" })] }), _jsxs(Span, { color: "inverse-muted", size: "xs", weight: "medium", numeric: true, children: [memberCount.toLocaleString(getDefaultLocale()), "+ ", memberCountLabel] })] }))] }), _jsx(Heading, { color: "inverse", level: 2, size: "3xl", mdSize: "4xl", weight: "bold", className: "leading-[1.1] tracking-tight", children: title }), descriptionHtml && (
|
|
52
|
+
/* No colour class here. `prose-invert` sets `--tw-prose-body`
|
|
53
|
+
itself, so ANY wrapper colour loses to it — the previous
|
|
54
|
+
`text-white/80` on this element did nothing. */
|
|
55
|
+
_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm prose-invert max-w-none", className: "max-w-md text-[length:var(--appkit-text-base)] leading-relaxed" })), groupLink && (_jsx(Row, { children: _jsxs(Button, { variant: "inverse", size: "lg", shadow: "lg", gap: "md", onClick: handleJoin, "aria-label": buttonText, children: [_jsx(WhatsAppGlyph, { className: "h-5 w-5" }), buttonText] }) }))] }), showThread && (_jsxs(Stack, { gap: "sm", align: "start", rounded: "2xl", padding: "md", shadow: "2xl", className: "bg-[var(--appkit-color-whatsapp-bg)]", role: "img", "aria-label": "Example messages from the community group", children: [thread.map((line, i) => (_jsx(Card, { padding: "none", variant: i % 2 === 1 ? "chat-bubble-mine" : "chat-bubble-theirs", children: _jsx(Text, { size: "sm", className: "leading-snug", children: line }) }, i))), _jsxs(Row, { align: "center", gap: "xs", className: "self-end pt-[var(--appkit-space-1)]", children: [_jsx(Icon, { name: "lock", size: "xs", tone: "muted" }), _jsx(Span, { size: "xs", color: "muted", children: "End-to-end encrypted by WhatsApp" })] })] }))] })] }) }) }));
|
|
20
56
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The WhatsApp brand mark.
|
|
4
|
+
*
|
|
5
|
+
* ## 🛑 Why this is NOT in `icon-registry.ts`
|
|
6
|
+
*
|
|
7
|
+
* That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
|
|
8
|
+
* to lucide glyphs, and its header is explicit that it is deliberately small
|
|
9
|
+
* and not a re-export of an icon set. A third-party brand mark is neither an
|
|
10
|
+
* intent nor a lucide glyph — registering it would make "which icon set is this
|
|
11
|
+
* key from?" a question with two answers.
|
|
12
|
+
*
|
|
13
|
+
* It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
|
|
14
|
+
* (~1.2KB of identical path data in one file), and the second copy had no
|
|
15
|
+
* `shrink-0`, so inside a padded flex control it could shrink below its stated
|
|
16
|
+
* size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function WhatsAppGlyph({ className }: {
|
|
19
|
+
className?: string;
|
|
20
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The WhatsApp brand mark.
|
|
4
|
+
*
|
|
5
|
+
* ## 🛑 Why this is NOT in `icon-registry.ts`
|
|
6
|
+
*
|
|
7
|
+
* That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
|
|
8
|
+
* to lucide glyphs, and its header is explicit that it is deliberately small
|
|
9
|
+
* and not a re-export of an icon set. A third-party brand mark is neither an
|
|
10
|
+
* intent nor a lucide glyph — registering it would make "which icon set is this
|
|
11
|
+
* key from?" a question with two answers.
|
|
12
|
+
*
|
|
13
|
+
* It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
|
|
14
|
+
* (~1.2KB of identical path data in one file), and the second copy had no
|
|
15
|
+
* `shrink-0`, so inside a padded flex control it could shrink below its stated
|
|
16
|
+
* size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
|
|
17
|
+
*/
|
|
18
|
+
export function WhatsAppGlyph({ className = "" }) {
|
|
19
|
+
return (_jsx("svg", { className: `shrink-0 ${className}`, fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }));
|
|
20
|
+
}
|