@mohasinac/appkit 4.53.2 → 4.54.1
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/server/features/auth/capabilities.js +7 -5
- 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/products/listing-tab-counts.js +81 -25
- 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/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/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 +21 -15
- package/dist/constants/api-endpoints.js +7 -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 +4 -3
- 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/components/BrandDetailPageView.js +2 -1
- package/dist/features/categories/components/BundleDetailView.js +2 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -1
- 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 +2 -1
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +2 -1
- 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 +2 -1
- 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 +4 -3
- 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.js +1 -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 +27 -2
- 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/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/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/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/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 +415 -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 -88
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +13399 -3019
- 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-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +63936 -13803
- 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 +8 -10
- package/dist/server.js +16 -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/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
|
@@ -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
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HeroCarousel-specific class strings
|
|
2
|
+
* HeroCarousel-specific class strings.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 🛑 `HERO_CAROUSEL_ARROW`, `HERO_CAROUSEL_DOT_ACTIVE` and
|
|
5
|
+
* `HERO_CAROUSEL_DOT_INACTIVE` were DELETED 2026-10-20 along with the markup
|
|
6
|
+
* that consumed them. They were one of three unrelated carousel-indicator
|
|
7
|
+
* implementations on the homepage; all three are now
|
|
8
|
+
* `ui/components/CarouselNav`, whose docstring records what each of them got
|
|
9
|
+
* wrong. Do not reintroduce a per-surface dot or arrow style here — a second
|
|
10
|
+
* appearance is how the three diverged in the first place.
|
|
6
11
|
*/
|
|
7
|
-
export declare const HERO_CAROUSEL_ARROW = "w-10 h-10 rounded-2xl bg-[color-mix(in_srgb,var(--appkit-color-surface)_85%,transparent)] backdrop-blur-sm shadow-lg border border-[var(--appkit-color-border)] text-[var(--appkit-color-text)] hover:-translate-y-0.5 hover:bg-[var(--appkit-color-surface)] hover:shadow-xl active:scale-95 transition-all duration-200 flex items-center justify-center";
|
|
8
|
-
export declare const HERO_CAROUSEL_DOT_ACTIVE = "w-8 h-2 !min-h-0 rounded-full bg-[var(--appkit-color-surface)] shadow-sm transition-all duration-500";
|
|
9
|
-
export declare const HERO_CAROUSEL_DOT_INACTIVE = "w-2 h-2 !min-h-0 rounded-full bg-white/55 shadow-sm transition-all duration-500";
|
|
10
12
|
/** Absolute fill helper — `position: absolute; inset: 0`. */
|
|
11
13
|
export declare const POSITION_FILL = "absolute inset-0";
|
|
12
14
|
/** Flex centering helper — `flex items-center justify-center`. */
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HeroCarousel-specific class strings
|
|
2
|
+
* HeroCarousel-specific class strings.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 🛑 `HERO_CAROUSEL_ARROW`, `HERO_CAROUSEL_DOT_ACTIVE` and
|
|
5
|
+
* `HERO_CAROUSEL_DOT_INACTIVE` were DELETED 2026-10-20 along with the markup
|
|
6
|
+
* that consumed them. They were one of three unrelated carousel-indicator
|
|
7
|
+
* implementations on the homepage; all three are now
|
|
8
|
+
* `ui/components/CarouselNav`, whose docstring records what each of them got
|
|
9
|
+
* wrong. Do not reintroduce a per-surface dot or arrow style here — a second
|
|
10
|
+
* appearance is how the three diverged in the first place.
|
|
6
11
|
*/
|
|
7
|
-
export const HERO_CAROUSEL_ARROW = "w-10 h-10 rounded-2xl bg-[color-mix(in_srgb,var(--appkit-color-surface)_85%,transparent)] backdrop-blur-sm shadow-lg border border-[var(--appkit-color-border)] text-[var(--appkit-color-text)] hover:-translate-y-0.5 hover:bg-[var(--appkit-color-surface)] hover:shadow-xl active:scale-95 transition-all duration-200 flex items-center justify-center";
|
|
8
|
-
export const HERO_CAROUSEL_DOT_ACTIVE = "w-8 h-2 !min-h-0 rounded-full bg-[var(--appkit-color-surface)] shadow-sm transition-all duration-500";
|
|
9
|
-
export const HERO_CAROUSEL_DOT_INACTIVE = "w-2 h-2 !min-h-0 rounded-full bg-white/55 shadow-sm transition-all duration-500";
|
|
10
12
|
/** Absolute fill helper — `position: absolute; inset: 0`. */
|
|
11
13
|
export const POSITION_FILL = "absolute inset-0";
|
|
12
14
|
/** Flex centering helper — `flex items-center justify-center`. */
|
|
@@ -71,8 +71,10 @@ export declare const SECTION_COPY: {
|
|
|
71
71
|
readonly featuresPill: "Built for trust";
|
|
72
72
|
readonly featuresLearnMore: "Learn about our security →";
|
|
73
73
|
readonly bannerPrimaryCta: "Shop All Products →";
|
|
74
|
-
readonly bannerSecondaryCta: "Browse
|
|
75
|
-
|
|
74
|
+
readonly bannerSecondaryCta: "Browse Categories →";
|
|
75
|
+
/** Eyebrow above the CTA banner headline — replaces a decorative ✨. */
|
|
76
|
+
readonly bannerEyebrow: "Start here";
|
|
77
|
+
readonly whatsappDescription: "Get deal alerts, new arrivals, and exclusive drops before anyone else.";
|
|
76
78
|
/**
|
|
77
79
|
* Shown only when `siteSettings.announcementBar` has no message. Was a
|
|
78
80
|
* hardcoded seasonal Pokémon TCG discount, which would have gone out as
|
|
@@ -90,18 +92,18 @@ export declare const SECTION_COPY: {
|
|
|
90
92
|
*/
|
|
91
93
|
export declare const WELCOME_TRUST_CHIPS: readonly [{
|
|
92
94
|
readonly key: "delivery";
|
|
93
|
-
readonly
|
|
94
|
-
readonly label: "Fast
|
|
95
|
+
readonly iconName: "ship";
|
|
96
|
+
readonly label: "Fast delivery";
|
|
95
97
|
}, {
|
|
96
98
|
readonly key: "secure";
|
|
97
|
-
readonly
|
|
98
|
-
readonly label: "Secure
|
|
99
|
+
readonly iconName: "lock";
|
|
100
|
+
readonly label: "Secure payments";
|
|
99
101
|
}, {
|
|
100
102
|
readonly key: "rating";
|
|
101
|
-
readonly
|
|
102
|
-
readonly label: "Buyer
|
|
103
|
+
readonly iconName: "review";
|
|
104
|
+
readonly label: "Buyer rated";
|
|
103
105
|
}, {
|
|
104
106
|
readonly key: "returns";
|
|
105
|
-
readonly
|
|
106
|
-
readonly label: "Easy
|
|
107
|
+
readonly iconName: "restore";
|
|
108
|
+
readonly label: "Easy returns";
|
|
107
109
|
}];
|
|
@@ -71,8 +71,18 @@ export const SECTION_COPY = {
|
|
|
71
71
|
featuresPill: "Built for trust",
|
|
72
72
|
featuresLearnMore: "Learn about our security →",
|
|
73
73
|
bannerPrimaryCta: "Shop All Products →",
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
/*
|
|
75
|
+
* 🛑 Not "Browse Auctions →". The CTA banner is NOT in
|
|
76
|
+
* `HOMEPAGE_SECTION_LISTING_TYPE`, so unlike the auctions rail it is never
|
|
77
|
+
* gated — it renders whatever this says on a site running
|
|
78
|
+
* `listings.listingTypes.auction: false`, which is a button on the homepage
|
|
79
|
+
* leading to a browse page with nothing in it. The `secondaryHref` default in
|
|
80
|
+
* CTABannerSection.tsx moved with it; they are one control in two files.
|
|
81
|
+
*/
|
|
82
|
+
bannerSecondaryCta: "Browse Categories →",
|
|
83
|
+
/** Eyebrow above the CTA banner headline — replaces a decorative ✨. */
|
|
84
|
+
bannerEyebrow: "Start here",
|
|
85
|
+
whatsappDescription: "Get deal alerts, new arrivals, and exclusive drops before anyone else.",
|
|
76
86
|
/**
|
|
77
87
|
* Shown only when `siteSettings.announcementBar` has no message. Was a
|
|
78
88
|
* hardcoded seasonal Pokémon TCG discount, which would have gone out as
|
|
@@ -89,8 +99,20 @@ export const SECTION_COPY = {
|
|
|
89
99
|
* Revisit if a consumer needs different ones.
|
|
90
100
|
*/
|
|
91
101
|
export const WELCOME_TRUST_CHIPS = [
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
/*
|
|
103
|
+
* 🛑 Registry icon keys, not emoji.
|
|
104
|
+
*
|
|
105
|
+
* An emoji cannot be sized — no width or height utility reaches a text
|
|
106
|
+
* character, so it renders at whatever the platform font fallback is, next to
|
|
107
|
+
* a label that IS sized (Root Cause #80). It is also a different glyph on
|
|
108
|
+
* every OS, which is the opposite of a design system.
|
|
109
|
+
*
|
|
110
|
+
* `🚀` was additionally just wrong: a rocket is not delivery. `ship` is a
|
|
111
|
+
* truck. Labels are sentence case — Title Case On Four Short Chips reads
|
|
112
|
+
* dated on its own.
|
|
113
|
+
*/
|
|
114
|
+
{ key: "delivery", iconName: "ship", label: "Fast delivery" },
|
|
115
|
+
{ key: "secure", iconName: "lock", label: "Secure payments" },
|
|
116
|
+
{ key: "rating", iconName: "review", label: "Buyer rated" },
|
|
117
|
+
{ key: "returns", iconName: "restore", label: "Easy returns" },
|
|
96
118
|
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LiveStatPreset } from "../schemas/firestore";
|
|
2
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
3
|
+
/**
|
|
4
|
+
* `LiveStatPreset` → the glyph that means it.
|
|
5
|
+
*
|
|
6
|
+
* A live stat therefore gets a correct icon with ZERO config: the preset is
|
|
7
|
+
* already a closed 6-member union, so the icon is derivable from what the stat
|
|
8
|
+
* measures rather than being a second thing an admin has to fill in and keep
|
|
9
|
+
* consistent. Declared `Record<LiveStatPreset, IconKey>` so a seventh preset
|
|
10
|
+
* is a compile error here rather than a silently iconless tile.
|
|
11
|
+
*/
|
|
12
|
+
export declare const STAT_PRESET_ICON: Record<LiveStatPreset, IconKey>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LiveStatPreset` → the glyph that means it.
|
|
3
|
+
*
|
|
4
|
+
* A live stat therefore gets a correct icon with ZERO config: the preset is
|
|
5
|
+
* already a closed 6-member union, so the icon is derivable from what the stat
|
|
6
|
+
* measures rather than being a second thing an admin has to fill in and keep
|
|
7
|
+
* consistent. Declared `Record<LiveStatPreset, IconKey>` so a seventh preset
|
|
8
|
+
* is a compile error here rather than a silently iconless tile.
|
|
9
|
+
*/
|
|
10
|
+
export const STAT_PRESET_ICON = {
|
|
11
|
+
total_listings: "order",
|
|
12
|
+
verified_sellers: "verify",
|
|
13
|
+
total_buyers: "user",
|
|
14
|
+
platform_rating: "review",
|
|
15
|
+
total_orders: "cart",
|
|
16
|
+
total_reviews: "message",
|
|
17
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IconKey } from "../../../ui/icons/icon-registry";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a stored icon string to a registry key.
|
|
4
|
+
*
|
|
5
|
+
* Accepts an already-valid `IconKey` unchanged, so a value authored after the
|
|
6
|
+
* admin editor moved to a key picker needs no alias entry.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveTrustIcon(stored: string | undefined | null): IconKey | undefined;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isIconKey } from "../../../ui/icons/icon-registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stored icon strings → `IconKey`s, for the trust / security / stats tiles.
|
|
4
|
+
*
|
|
5
|
+
* ## 🛑 Why an alias map and not a retype
|
|
6
|
+
*
|
|
7
|
+
* `TrustIndicator.icon` is a `string` and live documents hold TWO unrelated
|
|
8
|
+
* spellings of it:
|
|
9
|
+
*
|
|
10
|
+
* - kebab lucide names, from the seed — `"shield-check"`, `"rotate-ccw"`,
|
|
11
|
+
* `"message-circle"`;
|
|
12
|
+
* - intent slugs, from `section-defaults.ts` — `"secure-payments"`,
|
|
13
|
+
* `"fast-delivery"`, `"easy-returns"`, `"support"`.
|
|
14
|
+
*
|
|
15
|
+
* Neither set is a valid `IconKey` (the registry is intent-named: `verify`,
|
|
16
|
+
* `restore`, `message`…), so retyping the field would invalidate every stored
|
|
17
|
+
* document at once. Mapping instead means existing admin-authored values keep
|
|
18
|
+
* working and the field stays editable.
|
|
19
|
+
*
|
|
20
|
+
* ## 🛑 Why the icon was invisible before this existed
|
|
21
|
+
*
|
|
22
|
+
* All three components declared `renderIcon?: (props) => ReactNode` and the
|
|
23
|
+
* section renderer never passed it — a function prop has no representation in a
|
|
24
|
+
* Firestore document, so it was unreachable by construction. The result was
|
|
25
|
+
* four trust tiles rendering the same hardcoded `✓` while four *different*
|
|
26
|
+
* promises sat beside them, and no icon at all on the stats and security
|
|
27
|
+
* tiles. The admin editor round-tripped `icon` the whole time and the component
|
|
28
|
+
* used it only as a React key. Root Cause #51.
|
|
29
|
+
*
|
|
30
|
+
* An unmapped value resolves to `undefined` and the tile renders text-only,
|
|
31
|
+
* which is strictly better than one glyph standing in for everything.
|
|
32
|
+
*/
|
|
33
|
+
const TRUST_ICON_ALIASES = {
|
|
34
|
+
// Lucide kebab names, as written by the seed and the admin editor.
|
|
35
|
+
"shield-check": "verify",
|
|
36
|
+
lock: "lock",
|
|
37
|
+
"rotate-ccw": "restore",
|
|
38
|
+
"message-circle": "message",
|
|
39
|
+
truck: "ship",
|
|
40
|
+
star: "review",
|
|
41
|
+
package: "order",
|
|
42
|
+
"trending-up": "analytics",
|
|
43
|
+
"help-circle": "help",
|
|
44
|
+
tag: "deals",
|
|
45
|
+
flag: "report",
|
|
46
|
+
// Intent slugs, as written by DEFAULT_TRUST_FEATURES.
|
|
47
|
+
"secure-payments": "lock",
|
|
48
|
+
"fast-delivery": "ship",
|
|
49
|
+
"easy-returns": "restore",
|
|
50
|
+
support: "help",
|
|
51
|
+
authenticity: "verify",
|
|
52
|
+
// Intent slugs, as written by the `features` seed config.
|
|
53
|
+
escrow: "lock",
|
|
54
|
+
"verified-sellers": "verify",
|
|
55
|
+
"scam-registry": "report",
|
|
56
|
+
"encrypted-data": "lock",
|
|
57
|
+
encryption: "lock",
|
|
58
|
+
tls: "lock",
|
|
59
|
+
rbac: "user",
|
|
60
|
+
"min-priv": "settings",
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Resolve a stored icon string to a registry key.
|
|
64
|
+
*
|
|
65
|
+
* Accepts an already-valid `IconKey` unchanged, so a value authored after the
|
|
66
|
+
* admin editor moved to a key picker needs no alias entry.
|
|
67
|
+
*/
|
|
68
|
+
export function resolveTrustIcon(stored) {
|
|
69
|
+
if (!stored)
|
|
70
|
+
return undefined;
|
|
71
|
+
const aliased = TRUST_ICON_ALIASES[stored];
|
|
72
|
+
if (aliased)
|
|
73
|
+
return aliased;
|
|
74
|
+
return isIconKey(stored) ? stored : undefined;
|
|
75
|
+
}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
/** Static default content used when Firestore section config has no override. */
|
|
2
|
+
import type { IconKey } from "../../../ui/icons/icon-registry";
|
|
3
|
+
/**
|
|
4
|
+
* 🛑 `iconName` holds a real `IconKey`, not a slug.
|
|
5
|
+
*
|
|
6
|
+
* These used to carry intent slugs (`"secure-payments"`, `"fast-delivery"`…)
|
|
7
|
+
* that nothing resolved, because the component's only icon channel was a
|
|
8
|
+
* `renderIcon` function prop the section renderer never passed. The slugs are
|
|
9
|
+
* still accepted from STORED documents via `resolveTrustIcon`, but a default
|
|
10
|
+
* authored here has no reason to go through an alias — so these are typed.
|
|
11
|
+
*
|
|
12
|
+
* `id` is separate from `iconName` because the old shape used the icon string
|
|
13
|
+
* as the React key, which collides as soon as two tiles share a glyph.
|
|
14
|
+
*/
|
|
2
15
|
export declare const DEFAULT_TRUST_FEATURES: {
|
|
3
|
-
|
|
16
|
+
id: string;
|
|
4
17
|
title: string;
|
|
5
18
|
description: string;
|
|
19
|
+
iconName?: IconKey;
|
|
6
20
|
}[];
|
|
7
21
|
export declare const DEFAULT_SECURITY_ITEMS: {
|
|
8
22
|
key: string;
|
|
9
23
|
title: string;
|
|
10
24
|
description: string;
|
|
25
|
+
iconName?: IconKey;
|
|
11
26
|
}[];
|
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
/** Static default content used when Firestore section config has no override. */
|
|
2
|
+
/**
|
|
3
|
+
* 🛑 `iconName` holds a real `IconKey`, not a slug.
|
|
4
|
+
*
|
|
5
|
+
* These used to carry intent slugs (`"secure-payments"`, `"fast-delivery"`…)
|
|
6
|
+
* that nothing resolved, because the component's only icon channel was a
|
|
7
|
+
* `renderIcon` function prop the section renderer never passed. The slugs are
|
|
8
|
+
* still accepted from STORED documents via `resolveTrustIcon`, but a default
|
|
9
|
+
* authored here has no reason to go through an alias — so these are typed.
|
|
10
|
+
*
|
|
11
|
+
* `id` is separate from `iconName` because the old shape used the icon string
|
|
12
|
+
* as the React key, which collides as soon as two tiles share a glyph.
|
|
13
|
+
*/
|
|
2
14
|
export const DEFAULT_TRUST_FEATURES = [
|
|
3
15
|
{
|
|
4
|
-
|
|
16
|
+
id: "secure-payments",
|
|
17
|
+
iconName: "lock",
|
|
5
18
|
title: "Secure Payments",
|
|
6
19
|
description: "Protected payments with transparent order tracking.",
|
|
7
20
|
},
|
|
8
21
|
{
|
|
9
|
-
|
|
22
|
+
id: "fast-delivery",
|
|
23
|
+
iconName: "ship",
|
|
10
24
|
title: "Fast Delivery",
|
|
11
25
|
description: "Fast shipping with reliable nationwide logistics partners.",
|
|
12
26
|
},
|
|
13
27
|
{
|
|
14
|
-
|
|
28
|
+
id: "easy-returns",
|
|
29
|
+
iconName: "restore",
|
|
15
30
|
title: "Easy Returns",
|
|
16
31
|
description: "Hassle-free returns within the policy window.",
|
|
17
32
|
},
|
|
18
33
|
{
|
|
19
|
-
|
|
34
|
+
id: "support",
|
|
35
|
+
iconName: "help",
|
|
20
36
|
title: "24/7 Support",
|
|
21
37
|
description: "Real help from our team across pre and post purchase.",
|
|
22
38
|
},
|
|
@@ -24,21 +40,25 @@ export const DEFAULT_TRUST_FEATURES = [
|
|
|
24
40
|
export const DEFAULT_SECURITY_ITEMS = [
|
|
25
41
|
{
|
|
26
42
|
key: "encryption",
|
|
43
|
+
iconName: "lock",
|
|
27
44
|
title: "End-to-End Encryption",
|
|
28
45
|
description: "All sensitive data is encrypted in transit and at rest.",
|
|
29
46
|
},
|
|
30
47
|
{
|
|
31
48
|
key: "tls",
|
|
49
|
+
iconName: "verify",
|
|
32
50
|
title: "TLS 1.3 in Transit",
|
|
33
51
|
description: "Every API call and page load is secured with modern TLS.",
|
|
34
52
|
},
|
|
35
53
|
{
|
|
36
54
|
key: "rbac",
|
|
55
|
+
iconName: "user",
|
|
37
56
|
title: "Role-Based Access",
|
|
38
57
|
description: "Strict role boundaries keep buyer, seller, and admin data separate.",
|
|
39
58
|
},
|
|
40
59
|
{
|
|
41
60
|
key: "min-priv",
|
|
61
|
+
iconName: "settings",
|
|
42
62
|
title: "Minimum-Privilege Tokens",
|
|
43
63
|
description: "Short-lived, scoped tokens minimise exposure on every request.",
|
|
44
64
|
},
|
|
@@ -5,6 +5,11 @@ import { cleanTitle, parseWelcomeDescription } from "./section-helpers.js";
|
|
|
5
5
|
import { DEFAULT_TRUST_FEATURES, DEFAULT_SECURITY_ITEMS } from "./section-defaults.js";
|
|
6
6
|
import { SECTION_TITLE, SECTION_COPY, VIEW_MORE_LABEL, WELCOME_TRUST_CHIPS, } from "../constants/section-copy.js";
|
|
7
7
|
import { FAQ_CATEGORY_LABELS } from "../constants/faq-category-labels.js";
|
|
8
|
+
/* Root Cause #51 — the stored `icon` string had no reader. These resolve it to
|
|
9
|
+
a registry key so the trust / security / stats tiles render a real glyph
|
|
10
|
+
instead of one hardcoded ✓ (or nothing at all). */
|
|
11
|
+
import { resolveTrustIcon } from "../constants/trust-icon-aliases.js";
|
|
12
|
+
import { STAT_PRESET_ICON } from "../constants/stat-icons.js";
|
|
8
13
|
import { FAQ_HOMEPAGE_READ_CAP } from "../../faq/constants/read-caps.js";
|
|
9
14
|
import { AnnouncementBar, hashBannerMessage } from "../components/AnnouncementBar.js";
|
|
10
15
|
import { HeroCarousel } from "../components/HeroCarousel.js";
|
|
@@ -66,9 +71,26 @@ const SECTION_REGISTRY = {
|
|
|
66
71
|
},
|
|
67
72
|
welcome: {
|
|
68
73
|
surfaces: ["homepage"],
|
|
69
|
-
render: ({ config, brand }) => {
|
|
74
|
+
render: ({ config, brand, sectionData }) => {
|
|
70
75
|
const cfg = config;
|
|
71
|
-
|
|
76
|
+
/*
|
|
77
|
+
* Hero imagery, taken from the featured categories' own covers.
|
|
78
|
+
*
|
|
79
|
+
* Deterministic — the first five in CONFIGURED order, never shuffled, so
|
|
80
|
+
* the server and client render the same mosaic (ImageMosaic's header is
|
|
81
|
+
* explicit about why `Math.random()` is wrong here).
|
|
82
|
+
*
|
|
83
|
+
* 🛑 `sectionData.categories` is only populated when the page also has a
|
|
84
|
+
* `categories` section enabled, because MarketplaceHomepageView gates
|
|
85
|
+
* each fetch on `activeTypes`. `welcome` is registered as a trigger for
|
|
86
|
+
* that fetch for exactly this reason; without it the mosaic silently
|
|
87
|
+
* falls back to the brand panel and nothing says why.
|
|
88
|
+
*/
|
|
89
|
+
const heroImages = (sectionData.categories ?? [])
|
|
90
|
+
.map((c) => c.display?.coverImage)
|
|
91
|
+
.filter((src) => Boolean(src))
|
|
92
|
+
.slice(0, 5);
|
|
93
|
+
return (_jsx(WelcomeSection, { heroImages: heroImages, title: cleanTitle(cfg?.h1) || SECTION_TITLE.welcome,
|
|
72
94
|
// A real `subtitle` wins; `description` is the legacy source and is
|
|
73
95
|
// still parsed for documents that only carry it.
|
|
74
96
|
subtitle: cfg?.subtitle?.trim() || parseWelcomeDescription(cfg?.description), pillLabel: cfg?.pillLabel || SECTION_COPY.welcomePill, showCTA: cfg?.showCTA ?? true, ctaLabel: cfg?.ctaText || SECTION_COPY.welcomePrimaryCta, ctaHref: cfg?.ctaLink || ROUTES.PUBLIC.PRODUCTS, secondaryCtaLabel: cfg?.secondaryCtaText || SECTION_COPY.welcomeSecondaryCta, secondaryCtaHref: cfg?.secondaryCtaLink || ROUTES.PUBLIC.PRODUCTS, trustChips: [...WELCOME_TRUST_CHIPS], brandLogoText: brand?.shortName }));
|
|
@@ -103,6 +125,11 @@ const SECTION_REGISTRY = {
|
|
|
103
125
|
: `stat-${index}`,
|
|
104
126
|
label: item.label,
|
|
105
127
|
value: displayValue,
|
|
128
|
+
// Derived from the preset, so a live stat gets a correct icon
|
|
129
|
+
// with no extra config — the preset already says what the
|
|
130
|
+
// number measures. `iconName` on the config entry wins for a
|
|
131
|
+
// static stat, which has no metric to derive from.
|
|
132
|
+
iconName: resolveTrustIcon(item.iconName) ?? (item.metric ? STAT_PRESET_ICON[item.metric] : undefined),
|
|
106
133
|
};
|
|
107
134
|
})
|
|
108
135
|
: [];
|
|
@@ -165,7 +192,7 @@ const SECTION_REGISTRY = {
|
|
|
165
192
|
// defaults fill in when none are set. Previously both labels and both
|
|
166
193
|
// hrefs were hardcoded here and `buttons[]` was ignored entirely.
|
|
167
194
|
const [primaryBtn, secondaryBtn] = cfg?.buttons ?? [];
|
|
168
|
-
return (_jsx(CTABannerSection, { title: cfg?.content?.title || SECTION_TITLE.banner, subtitle: cfg?.content?.subtitle, description: cfg?.content?.description, height: cfg?.height, backgroundImage: cfg?.backgroundImage, primaryLabel: primaryBtn?.text, primaryHref: primaryBtn?.link, secondaryLabel: secondaryBtn?.text, secondaryHref: secondaryBtn?.link }));
|
|
195
|
+
return (_jsx(CTABannerSection, { title: cfg?.content?.title || SECTION_TITLE.banner, eyebrow: cfg?.content?.eyebrow || SECTION_COPY.bannerEyebrow, subtitle: cfg?.content?.subtitle, description: cfg?.content?.description, height: cfg?.height, backgroundImage: cfg?.backgroundImage, primaryLabel: primaryBtn?.text, primaryHref: primaryBtn?.link, secondaryLabel: secondaryBtn?.text, secondaryHref: secondaryBtn?.link }));
|
|
169
196
|
},
|
|
170
197
|
},
|
|
171
198
|
"trust-indicators": {
|
|
@@ -175,8 +202,10 @@ const SECTION_REGISTRY = {
|
|
|
175
202
|
const configured = (cfg?.indicators ?? [])
|
|
176
203
|
.filter((ind) => ind?.title?.trim())
|
|
177
204
|
.map((ind) => ({
|
|
178
|
-
key
|
|
179
|
-
|
|
205
|
+
// `id` is the React key; `iconName` is the glyph. These were one
|
|
206
|
+
// field before, so two indicators sharing an icon collided.
|
|
207
|
+
id: ind.id,
|
|
208
|
+
iconName: resolveTrustIcon(ind.icon),
|
|
180
209
|
title: ind.title,
|
|
181
210
|
description: ind.description,
|
|
182
211
|
}));
|
|
@@ -191,7 +220,13 @@ const SECTION_REGISTRY = {
|
|
|
191
220
|
// `items` is the real shape; `features: string[]` is the legacy one and
|
|
192
221
|
// becomes title-only cards. Neither reached the component before — it
|
|
193
222
|
// always rendered DEFAULT_SECURITY_ITEMS regardless of config.
|
|
194
|
-
const configured = cfg?.items
|
|
223
|
+
const configured = cfg?.items
|
|
224
|
+
?.filter((item) => item?.title?.trim())
|
|
225
|
+
// The stored `key` doubles as the icon hint — the seeded items carry
|
|
226
|
+
// intent slugs (`escrow`, `scam-registry`, `encrypted-data`) that the
|
|
227
|
+
// alias map resolves, so these tiles get real glyphs with no new
|
|
228
|
+
// config field. An explicit `iconName` wins when present.
|
|
229
|
+
.map((item) => ({ ...item, iconName: resolveTrustIcon(item.iconName ?? item.key) })) ??
|
|
195
230
|
cfg?.features
|
|
196
231
|
?.filter((label) => label?.trim())
|
|
197
232
|
.map((label, index) => ({ key: `feature-${index}`, title: label, description: "" })) ??
|
|
@@ -206,7 +241,7 @@ const SECTION_REGISTRY = {
|
|
|
206
241
|
return (_jsx(WhatsAppCommunitySection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.whatsappCommunity, descriptionHtml: cfg?.description || SECTION_COPY.whatsappDescription,
|
|
207
242
|
// No `|| 5000` fallback: inventing a member count the site cannot
|
|
208
243
|
// verify is a fabricated social-proof number.
|
|
209
|
-
memberCount: cfg?.memberCount, groupLink: cfg?.groupLink ||
|
|
244
|
+
memberCount: cfg?.memberCount, groupLink: cfg?.groupLink || undefined, benefits: cfg?.benefits ?? [], testimonial: cfg?.testimonial, buttonText: cfg?.buttonText }));
|
|
210
245
|
},
|
|
211
246
|
},
|
|
212
247
|
faq: {
|
|
@@ -331,7 +366,12 @@ const SECTION_REGISTRY = {
|
|
|
331
366
|
const cfg = config;
|
|
332
367
|
if (!cfg?.title || !Array.isArray(cfg.steps) || cfg.steps.length === 0)
|
|
333
368
|
return null;
|
|
334
|
-
return (_jsx(HowItWorksSection, { title: cfg.title, subtitle: cfg.subtitle, pillLabel: cfg.pillLabel, ctaLabel: cfg.ctaLabel, ctaLink: cfg.ctaLink,
|
|
369
|
+
return (_jsx(HowItWorksSection, { title: cfg.title, subtitle: cfg.subtitle, pillLabel: cfg.pillLabel, ctaLabel: cfg.ctaLabel, ctaLink: cfg.ctaLink,
|
|
370
|
+
/* `cfg.steps[].iconKey` is a loose `string` (it is admin data) while
|
|
371
|
+
the component's is an `IconKey`. Resolving rather than casting
|
|
372
|
+
means an unrecognised stored value renders a step with no icon
|
|
373
|
+
instead of handing `<Icon>` a key it will silently drop. */
|
|
374
|
+
steps: cfg.steps.map((s) => ({ ...s, iconKey: resolveTrustIcon(s.iconKey) })) }));
|
|
335
375
|
},
|
|
336
376
|
},
|
|
337
377
|
testimonials: {
|