@mohasinac/appkit 4.53.0 → 4.53.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/client/scaffolds/AppShell.js +1 -1
- package/dist/_internal/server/features/auctions/og.d.ts +3 -1
- package/dist/_internal/server/features/auctions/og.js +3 -1
- package/dist/_internal/server/features/bundles/actions.js +1 -1
- package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
- package/dist/_internal/server/features/business-documents/download.js +91 -0
- package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
- package/dist/_internal/server/features/categories/adapters.js +10 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
- package/dist/_internal/server/features/checkout/actions.js +106 -12
- package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
- package/dist/_internal/server/features/checkout/data.d.ts +22 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
- package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
- package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
- package/dist/_internal/server/features/classified/metadata.js +1 -1
- package/dist/_internal/server/features/classified/og.d.ts +3 -1
- package/dist/_internal/server/features/classified/og.js +3 -1
- package/dist/_internal/server/features/digital-code/metadata.js +1 -1
- package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
- package/dist/_internal/server/features/digital-code/og.js +3 -1
- package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
- package/dist/_internal/server/features/digital-code/pool.js +19 -4
- package/dist/_internal/server/features/live/metadata.js +1 -1
- package/dist/_internal/server/features/live/og.d.ts +3 -1
- package/dist/_internal/server/features/live/og.js +3 -1
- package/dist/_internal/server/features/messages/actions.js +1 -1
- package/dist/_internal/server/features/parts/og.js +1 -1
- package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
- package/dist/_internal/server/features/pre-orders/og.js +3 -1
- package/dist/_internal/server/features/price-index/search.d.ts +18 -0
- package/dist/_internal/server/features/price-index/search.js +47 -7
- package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
- package/dist/_internal/server/features/prize-draws/og.js +3 -1
- package/dist/_internal/server/features/products/group-members.d.ts +26 -0
- package/dist/_internal/server/features/products/group-members.js +7 -1
- package/dist/_internal/server/features/products/og.d.ts +3 -1
- package/dist/_internal/server/features/products/og.js +3 -1
- package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
- package/dist/_internal/server/features/search/scoped-sources.js +252 -0
- package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
- package/dist/_internal/server/features/search/search-everything.js +70 -20
- package/dist/_internal/server/features/seo/sitemap.js +6 -0
- package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
- package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +16 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +25 -0
- package/dist/_internal/server/features/stores/tabs.js +122 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
- package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
- package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
- package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
- package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +9 -0
- package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
- package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
- package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
- package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
- package/dist/_internal/shared/config/schema.d.ts +122 -0
- package/dist/_internal/shared/features/cart/schema.js +3 -2
- package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
- package/dist/_internal/shared/features/products/group-rules.js +142 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
- package/dist/_internal/shared/listing-types/_registry.js +39 -1
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +2 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +2 -0
- package/dist/_internal/shared/listing-types/availability.js +48 -0
- package/dist/_internal/shared/listing-types/capabilities.js +19 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +2 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +2 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
- package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
- package/dist/_internal/shared/listing-types/spares/config.js +60 -0
- package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
- package/dist/_internal/shared/listing-types/spares/og.js +1 -0
- package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +2 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
- package/dist/_internal/shared/search/match.d.ts +11 -0
- package/dist/_internal/shared/search/match.js +2 -1
- package/dist/_internal/shared/search/to-groups.d.ts +52 -0
- package/dist/_internal/shared/search/to-groups.js +141 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +39 -15
- package/dist/constants/api-endpoints.js +28 -5
- package/dist/constants/cache-invalidation.js +3 -1
- package/dist/constants/field-names.d.ts +6 -0
- package/dist/constants/field-names.js +6 -0
- package/dist/features/about/components/PolicyPageView.d.ts +22 -2
- package/dist/features/about/components/PolicyPageView.js +14 -2
- package/dist/features/about/components/PublicProfileView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +42 -2
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/hooks/useProfileStats.js +5 -1
- package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
- package/dist/features/addresses/repository/addresses.repository.js +21 -0
- package/dist/features/admin/actions/admin-actions.js +16 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminPageHeader.js +1 -1
- package/dist/features/admin/components/AdminProductEditorView.js +17 -2
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
- package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
- package/dist/features/admin/components/AdminSparesView.js +30 -0
- package/dist/features/admin/components/AdminUsersView.js +9 -7
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/firestore.d.ts +26 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +4 -11
- package/dist/features/auth/repository/user.repository.d.ts +13 -0
- package/dist/features/auth/repository/user.repository.js +28 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
- package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
- package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
- package/dist/features/business-documents/schemas/firestore.js +75 -0
- package/dist/features/cart/actions/cart-actions.js +83 -6
- package/dist/features/cart/repository/cart.repository.js +32 -4
- package/dist/features/cart/schemas/firestore.d.ts +20 -0
- package/dist/features/cart/schemas/index.d.ts +2 -2
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
- package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
- package/dist/features/categories/api/[id]/price-guidance/route.js +113 -0
- package/dist/features/categories/components/BrandDetailPageView.js +19 -3
- package/dist/features/categories/components/BrandDetailTabs.js +10 -0
- package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
- package/dist/features/categories/components/CategoryDetailPageView.js +141 -14
- package/dist/features/categories/components/CategoryDetailTabs.js +12 -0
- package/dist/features/categories/components/CategoryGrid.js +10 -1
- package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
- package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
- package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
- package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
- package/dist/features/categories/constants/category-tabs.d.ts +20 -25
- package/dist/features/categories/constants/category-tabs.js +22 -39
- package/dist/features/categories/repository/categories.repository.d.ts +12 -0
- package/dist/features/categories/repository/categories.repository.js +20 -0
- package/dist/features/categories/schemas/firestore.d.ts +22 -1
- package/dist/features/categories/schemas/firestore.js +10 -0
- package/dist/features/categories/schemas/index.d.ts +6 -0
- package/dist/features/categories/schemas/index.js +2 -0
- package/dist/features/categories/types/index.d.ts +8 -0
- package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
- package/dist/features/categories/utils/taxonomy-visual.js +26 -10
- package/dist/features/classified/components/ClassifiedDetailPageView.js +4 -9
- package/dist/features/contact/components/ContactPageView.d.ts +33 -1
- package/dist/features/contact/components/ContactPageView.js +58 -28
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +4 -9
- package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
- package/dist/features/grouped/schemas/firestore.d.ts +5 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
- package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
- package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
- package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
- package/dist/features/homepage/components/HowItWorksSection.js +4 -4
- package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
- package/dist/features/homepage/components/PromoGrid.js +12 -3
- package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/index.d.ts +0 -20
- package/dist/features/homepage/components/index.js +0 -11
- package/dist/features/homepage/index.d.ts +0 -2
- package/dist/features/homepage/index.js +0 -2
- package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
- package/dist/features/homepage/lib/section-renderer.js +202 -58
- package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
- package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
- package/dist/features/homepage/schemas/firestore.d.ts +106 -3
- package/dist/features/homepage/schemas/firestore.js +32 -2
- package/dist/features/homepage/schemas/index.d.ts +36 -7
- package/dist/features/homepage/schemas/index.js +39 -27
- package/dist/features/homepage/server.d.ts +0 -3
- package/dist/features/homepage/server.js +0 -3
- package/dist/features/homepage/types/index.d.ts +0 -47
- package/dist/features/homepage/types/index.js +49 -0
- package/dist/features/layout/AppLayoutShell.js +1 -1
- package/dist/features/layout/BottomNavItem.js +1 -1
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/live/components/LiveItemDetailPageView.js +4 -9
- package/dist/features/media/hooks/useMedia.js +17 -0
- package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
- package/dist/features/media/repository/media-assets.repository.js +31 -0
- package/dist/features/media/trust-signals.d.ts +85 -0
- package/dist/features/media/trust-signals.js +126 -0
- package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
- package/dist/features/parts/components/PartDetailPageView.js +2 -2
- package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
- package/dist/features/parts/components/PartsIndexPageView.js +2 -2
- package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
- package/dist/features/parts/components/PartsSearchBox.js +57 -0
- package/dist/features/parts/schemas/firestore.d.ts +149 -3
- package/dist/features/parts/schemas/firestore.js +184 -0
- package/dist/features/payments/repository/payout.repository.d.ts +15 -0
- package/dist/features/payments/repository/payout.repository.js +21 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +4 -11
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +3 -1
- package/dist/features/price-index/components/PriceIndexToolView.js +92 -13
- package/dist/features/products/components/CompareOverlay.d.ts +18 -1
- package/dist/features/products/components/CompareOverlay.js +21 -2
- package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
- package/dist/features/products/components/CustomSectionTabContent.js +29 -3
- package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
- package/dist/features/products/components/GroupMemberPicker.js +46 -8
- package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
- package/dist/features/products/components/GroupSettingsPanel.js +91 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
- package/dist/features/products/components/ProductDetailPageView.js +74 -15
- package/dist/features/products/components/ProductForm.d.ts +13 -1
- package/dist/features/products/components/ProductForm.js +16 -2
- package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
- package/dist/features/products/components/ProductsIndexListing.js +3 -3
- package/dist/features/products/components/ShowGroupSection.js +15 -2
- package/dist/features/products/components/SparesListView.d.ts +7 -0
- package/dist/features/products/components/SparesListView.js +39 -0
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/repository/products.repository.d.ts +98 -0
- package/dist/features/products/repository/products.repository.js +235 -17
- package/dist/features/products/schemas/firestore.d.ts +97 -4
- package/dist/features/products/schemas/firestore.js +104 -0
- package/dist/features/products/schemas/index.d.ts +10 -19
- package/dist/features/products/schemas/index.js +23 -6
- package/dist/features/products/types/index.d.ts +45 -1
- package/dist/features/products/utils/group-member-image.d.ts +39 -0
- package/dist/features/products/utils/group-member-image.js +3 -0
- package/dist/features/products/utils/listing-badge-variant.js +4 -0
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/scams/components/ScamProfileView.js +1 -1
- package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
- package/dist/features/search/components/EntityTypeahead.js +92 -0
- package/dist/features/search/components/Search.d.ts +12 -1
- package/dist/features/search/components/Search.js +47 -3
- package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
- package/dist/features/search/components/SearchFacetRail.js +92 -0
- package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
- package/dist/features/search/components/SearchResultsClient.js +103 -0
- package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/search/components/index.d.ts +0 -6
- package/dist/features/search/components/index.js +0 -3
- package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
- package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
- package/dist/features/search/hooks/useScopedSearch.js +114 -0
- package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
- package/dist/features/search/hooks/useSiteSearch.js +149 -0
- package/dist/features/search/index.d.ts +0 -4
- package/dist/features/search/index.js +0 -4
- package/dist/features/search/manifest.d.ts +12 -0
- package/dist/features/search/manifest.js +17 -2
- package/dist/features/search/server.d.ts +0 -3
- package/dist/features/search/server.js +0 -3
- package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +20 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductShell.js +2 -1
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
- package/dist/features/seller/components/SellerSparesView.js +6 -0
- package/dist/features/seller/components/index.d.ts +2 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/shell/CommandPalette.js +1 -1
- package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
- package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
- package/dist/features/stores/components/StoreHeader.js +1 -2
- package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
- package/dist/features/stores/components/StoreSparesPageView.js +48 -0
- package/dist/features/stores/schemas/firestore.d.ts +19 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +280 -45
- package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
- package/dist/features/tester/seed-data/authored/index.js +16 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +372 -18
- package/dist/index.d.ts +17 -57
- package/dist/index.js +35 -96
- package/dist/next/routing/route-map.d.ts +42 -1
- package/dist/next/routing/route-map.js +45 -0
- package/dist/providers/db-firebase/base.repository.d.ts +22 -0
- package/dist/providers/db-firebase/base.repository.js +36 -0
- package/dist/schemas/registry.d.ts +15 -6
- package/dist/security/blind-index-tokens.d.ts +54 -0
- package/dist/security/blind-index-tokens.js +152 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/settings-encryption.d.ts +35 -0
- package/dist/security/settings-encryption.js +91 -0
- package/dist/seed/_helpers/brand-rows.js +38 -14
- package/dist/seed/_helpers/category-forest.js +73 -7
- package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
- package/dist/seed/_helpers/category-images-generated.js +81 -6
- package/dist/seed/_helpers/category-models.d.ts +1 -1
- package/dist/seed/_helpers/category-models.js +7 -1
- package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +50 -2
- package/dist/seed/_helpers/character-features.d.ts +1 -1
- package/dist/seed/_helpers/character-features.js +2 -1
- package/dist/seed/_helpers/franchise-rows.js +10 -2
- package/dist/seed/_helpers/media.d.ts +47 -0
- package/dist/seed/_helpers/media.js +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
- package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
- package/dist/seed/categories-seed-data.js +124 -20
- package/dist/seed/grouped-listings-seed-data.js +16 -0
- package/dist/seed/homepage-sections-seed-data.js +94 -5
- package/dist/seed/index.d.ts +2 -3
- package/dist/seed/index.js +2 -2
- package/dist/seed/manifest.js +3 -0
- package/dist/seed/media-assets-seed-data.d.ts +1 -1
- package/dist/seed/media-assets-seed-data.js +746 -196
- package/dist/seed/model-composition-seed-data.js +122 -6
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +37219 -463
- package/dist/seed/products-art-seed-data.js +7 -18
- package/dist/seed/products-auctions-seed-data.js +56 -47
- package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
- package/dist/seed/products-beyblade-x-seed-data.js +441 -0
- package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +1500 -1240
- package/dist/seed/products-classifieds-seed-data.js +9 -27
- package/dist/seed/products-digital-codes-seed-data.js +9 -18
- package/dist/seed/products-live-items-seed-data.js +5 -13
- package/dist/seed/products-preorders-seed-data.js +67 -33
- package/dist/seed/products-prize-draws-seed-data.js +8 -17
- package/dist/seed/products-spares-seed-data.d.ts +2 -0
- package/dist/seed/products-spares-seed-data.js +368 -0
- package/dist/seed/products-standard-seed-data.js +39 -126
- package/dist/seed/products-stickers-seed-data.js +59 -15
- package/dist/seed/site-settings-seed-data.js +8 -0
- package/dist/seo/json-ld.d.ts +25 -0
- package/dist/seo/json-ld.js +28 -0
- package/dist/server-entry.d.ts +3 -1
- package/dist/server-entry.js +2 -2
- package/dist/server.d.ts +9 -9
- package/dist/server.js +27 -25
- package/dist/styles.css +202 -1
- package/dist/tailwind-input.css +31 -17
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Accordion.js +1 -1
- package/dist/ui/components/Breadcrumb.js +1 -1
- package/dist/ui/components/DetailPageGallery.js +0 -2
- package/dist/ui/components/DetailPageHero.js +0 -1
- package/dist/ui/components/DetailPageTabs.js +1 -1
- package/dist/ui/components/Divider.js +3 -3
- package/dist/ui/components/GatedPrice.js +5 -1
- package/dist/ui/components/HorizontalScroller.js +1 -1
- package/dist/ui/components/ListingLayout.js +3 -3
- package/dist/ui/components/MediaTabs.style.css +81 -0
- package/dist/ui/components/Pagination.js +1 -1
- package/dist/ui/components/PendingValue.d.ts +45 -0
- package/dist/ui/components/PendingValue.js +7 -0
- package/dist/ui/components/Radio.style.css +119 -0
- package/dist/ui/components/RatingDisplay.js +2 -2
- package/dist/ui/components/SettingsSection.js +0 -2
- package/dist/ui/components/SiteLogo.js +3 -0
- package/dist/ui/components/SiteMark.js +3 -0
- package/dist/ui/components/SortDropdown.js +1 -1
- package/dist/ui/components/SpecTable.d.ts +58 -0
- package/dist/ui/components/SpecTable.js +8 -0
- package/dist/ui/components/StarRating.js +1 -3
- package/dist/ui/components/SummaryCard.js +1 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +9 -1
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +2 -0
- package/dist/utils/search-txt-query.d.ts +12 -0
- package/dist/utils/search-txt-query.js +12 -0
- package/package.json +1 -1
- package/scripts/dedupe-peer-deps.mjs +18 -0
- package/scripts/seed-cli.mjs +135 -26
- package/scripts/verify-css-build.mjs +118 -37
- package/dist/_internal/server/features/search/actions.d.ts +0 -7
- package/dist/_internal/server/features/search/actions.js +0 -21
- package/dist/_internal/server/features/search/data.d.ts +0 -15
- package/dist/_internal/server/features/search/data.js +0 -18
- package/dist/_internal/server/features/search/index.d.ts +0 -3
- package/dist/_internal/server/features/search/index.js +0 -2
- package/dist/features/homepage/api/[id]/route.d.ts +0 -23
- package/dist/features/homepage/api/[id]/route.js +0 -103
- package/dist/features/homepage/api/route.d.ts +0 -14
- package/dist/features/homepage/api/route.js +0 -140
- package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
- package/dist/features/homepage/api/sections/[id]/route.js +0 -95
- package/dist/features/homepage/api/sections/route.d.ts +0 -13
- package/dist/features/homepage/api/sections/route.js +0 -82
- package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
- package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
- package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
- package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
- package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
- package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
- package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
- package/dist/features/homepage/components/HeroBanner.js +0 -43
- package/dist/features/homepage/components/HeroSection.d.ts +0 -7
- package/dist/features/homepage/components/HeroSection.js +0 -6
- package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
- package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
- package/dist/features/homepage/components/HomepageView.d.ts +0 -25
- package/dist/features/homepage/components/HomepageView.js +0 -5
- package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
- package/dist/features/homepage/components/NewsletterBanner.js +0 -37
- package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
- package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
- package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
- package/dist/features/homepage/components/TrustBadges.js +0 -46
- package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
- package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
- package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
- package/dist/features/homepage/hooks/useHomepage.js +0 -17
- package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
- package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
- package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
- package/dist/features/homepage/repository/homepage.repository.js +0 -25
- package/dist/features/search/actions/index.d.ts +0 -1
- package/dist/features/search/actions/index.js +0 -1
- package/dist/features/search/actions/search-actions.d.ts +0 -18
- package/dist/features/search/actions/search-actions.js +0 -43
- package/dist/features/search/api/route.d.ts +0 -22
- package/dist/features/search/api/route.js +0 -128
- package/dist/features/search/columns/index.d.ts +0 -17
- package/dist/features/search/columns/index.js +0 -49
- package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
- package/dist/features/search/components/SearchFiltersRow.js +0 -21
- package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
- package/dist/features/search/components/SearchResultsSection.js +0 -35
- package/dist/features/search/components/SearchView.d.ts +0 -27
- package/dist/features/search/components/SearchView.js +0 -8
- package/dist/features/search/hooks/useSearch.d.ts +0 -21
- package/dist/features/search/hooks/useSearch.js +0 -33
- package/dist/features/search/repository/search.repository.d.ts +0 -14
- package/dist/features/search/repository/search.repository.js +0 -59
- package/dist/features/search/schemas/index.d.ts +0 -70
- package/dist/features/search/schemas/index.js +0 -36
- package/dist/features/search/types/index.d.ts +0 -48
- package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
- package/dist/features/stores/components/StoreScopedSearch.js +0 -27
- package/dist/seed/defaults/homepage-sections.d.ts +0 -2
- package/dist/seed/defaults/homepage-sections.js +0 -60
- package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
- package/dist/seed/factories/homepage-section.factory.js +0 -13
- /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
|
@@ -6,10 +6,19 @@ import { resolveMediaUrl } from "../../../utils/media-url.js";
|
|
|
6
6
|
const __P = {
|
|
7
7
|
p4: "p-[var(--appkit-space-4)]",
|
|
8
8
|
};
|
|
9
|
+
/** Hard cap — this layout only has slots for 4 (one hero tile + three). */
|
|
10
|
+
export const PROMO_GRID_MAX_BANNERS = 4;
|
|
9
11
|
export function PromoGrid({ banners, eyebrow = "LIMITED TIME", heading = "HOT DEALS & PROMOS", }) {
|
|
10
12
|
if (banners.length === 0)
|
|
11
13
|
return null;
|
|
12
|
-
return (_jsx(Section, { paddingY: "y-4xl",
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
return (_jsx(Section, { paddingY: "y-4xl",
|
|
15
|
+
// `media-dark` IS the theme-invariant dark surface token (bg-zinc-900)
|
|
16
|
+
// — exactly what this always-dark section needs, so no raw className
|
|
17
|
+
// colour and no suppression marker.
|
|
18
|
+
surface: "media-dark", className: "border-t border-b border-white/[0.06]", children: _jsxs(Div, { className: "mx-auto max-w-7xl", padding: "x-md", children: [_jsx(Row, { wrap: true, align: "end", justify: "between", gap: "sm", className: "mb-7 gap-y-2", children: _jsxs(Div, { 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 text-white", size: "xl", mdSize: "2xl", weight: "bold", children: heading })] }) }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: banners.slice(0, PROMO_GRID_MAX_BANNERS).map((banner, i) => {
|
|
19
|
+
const resolvedSrc = resolveMediaUrl(banner.image);
|
|
20
|
+
return (_jsxs(Link, { href: banner.ctaUrl, className: `group relative block overflow-hidden bg-zinc-900 ${i === 0 ? "sm:row-span-2 min-h-[clamp(220px,32vh,480px)]" : "min-h-[clamp(130px,16vh,240px)]"}`, children: [resolvedSrc ? (_jsx(Image, { src: resolvedSrc, alt: banner.title, fill: true, className: "object-cover transition-transform duration-500 group-hover:scale-105", sizes: i === 0
|
|
21
|
+
? "(max-width: 640px) 100vw, 40vw"
|
|
22
|
+
: "(max-width: 640px) 50vw, 30vw" })) : null, _jsx(Div, { className: `absolute inset-0 ${i === 0 ? "[background:linear-gradient(to_top,rgba(0,0,0,0.9)_0%,rgba(0,0,0,0.3)_50%,transparent_100%)]" : "[background:linear-gradient(to_top,rgba(0,0,0,0.85)_0%,rgba(0,0,0,0.15)_100%)]"}` }), _jsx(Div, { className: "absolute inset-0 pointer-events-none opacity-0 transition-opacity duration-300 group-hover:opacity-100 ring-2 ring-[var(--color-yellow)] ring-inset" }), _jsxs(Div, { className: `absolute bottom-0 left-0 right-0 ${__P.p4}`, children: [_jsx(Text, { family: "display", className: `leading-tight tracking-[0.06em] text-white ${i === 0 ? "text-[1.35rem]" : "text-[1rem]"}`, children: banner.title }), _jsxs(Span, { layout: "inline-flex", gap: "xs", className: "mt-1 font-black uppercase text-[var(--color-yellow)]", size: "xs", children: [banner.ctaLabel, " \u2192"] })] })] }, banner.id));
|
|
23
|
+
}) })] }) }));
|
|
15
24
|
}
|
|
@@ -1,6 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Promoted to a registered `SectionType` ("testimonials") 2026-10-19 — see
|
|
3
|
+
* `TestimonialsSectionConfig` in `schemas/firestore.ts`, which this prop shape
|
|
4
|
+
* mirrors (Firestore config must be a plain serialisable object).
|
|
5
|
+
*
|
|
6
|
+
* Three things fixed in the same pass, all required before this could render
|
|
7
|
+
* correctly on a real page rather than just compile:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Testimonials are now INLINE in config**, not a read from the
|
|
10
|
+
* `testimonials` collection shape (`Testimonial` in `types/index.ts`, with
|
|
11
|
+
* `featured`/`sortOrder`/`active`). Those three fields are collection-row
|
|
12
|
+
* housekeeping with no meaning inside an ordered config array — the config
|
|
13
|
+
* IS the order, and every entry in it is already "featured" by virtue of
|
|
14
|
+
* being configured. `avatarUrl` is dropped too: declared on the old type,
|
|
15
|
+
* never rendered by this component.
|
|
16
|
+
* 2. **It is not a carousel** — no autoplay, no arrows, no dots, just a
|
|
17
|
+
* horizontally-scrolling wrapped row. So the config carries no
|
|
18
|
+
* `autoScroll`/`scrollInterval`/`loop` fields; adding them would be
|
|
19
|
+
* `NO-RENDERER` dead weight from day one.
|
|
20
|
+
* 3. **Every colour/font var below was undefined anywhere in the codebase**
|
|
21
|
+
* (`--section-bg`, `--card-bg`, `--card-border`, `--section-border`,
|
|
22
|
+
* `--section-title-color`, `--text-secondary`, `--color-red`,
|
|
23
|
+
* `--font-bangers`) — this component would have rendered with a
|
|
24
|
+
* transparent background, no borders and the browser's default font had
|
|
25
|
+
* it ever shipped. Migrated to the real `--appkit-*` token set (Root Cause
|
|
26
|
+
* #21); `--color-yellow` was the one survivor (a real token, `tokens.css`).
|
|
27
|
+
*/
|
|
28
|
+
export interface TestimonialConfigItem {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
rating: 1 | 2 | 3 | 4 | 5;
|
|
32
|
+
text: string;
|
|
33
|
+
}
|
|
2
34
|
export interface TestimonialsCarouselProps {
|
|
3
|
-
testimonials:
|
|
35
|
+
testimonials: TestimonialConfigItem[];
|
|
4
36
|
/** Eyebrow label. Default: "COLLECTOR REVIEWS". */
|
|
5
37
|
eyebrow?: string;
|
|
6
38
|
/** Section heading. Default: "WHAT OUR COLLECTORS SAY". */
|
|
@@ -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",
|
|
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 scrollbar-none 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,24 +1,13 @@
|
|
|
1
|
-
export { HeroSection } from "./HeroSection";
|
|
2
1
|
export type { CharacterHotspotProps } from "./CharacterHotspot";
|
|
3
2
|
export { CharacterHotspot } from "./CharacterHotspot";
|
|
4
3
|
export type { CharacterHotspotFormProps } from "./CharacterHotspotForm";
|
|
5
4
|
export { CharacterHotspotForm } from "./CharacterHotspotForm";
|
|
6
|
-
export type { HeroBannerProps } from "./HeroBanner";
|
|
7
|
-
export { HeroBanner } from "./HeroBanner";
|
|
8
5
|
export type { HeroCarouselProps } from "./HeroCarousel";
|
|
9
6
|
export { HeroCarousel } from "./HeroCarousel";
|
|
10
7
|
export type { PromoGridProps } from "./PromoGrid";
|
|
11
8
|
export { PromoGrid } from "./PromoGrid";
|
|
12
|
-
export type { TrustBadgesProps } from "./TrustBadges";
|
|
13
|
-
export { TrustBadges } from "./TrustBadges";
|
|
14
9
|
export type { TestimonialsCarouselProps } from "./TestimonialsCarousel";
|
|
15
10
|
export { TestimonialsCarousel } from "./TestimonialsCarousel";
|
|
16
|
-
export type { BeforeAfterCardProps } from "./BeforeAfterCard";
|
|
17
|
-
export { BeforeAfterCard } from "./BeforeAfterCard";
|
|
18
|
-
export type { NewsletterBannerProps } from "./NewsletterBanner";
|
|
19
|
-
export { NewsletterBanner } from "./NewsletterBanner";
|
|
20
|
-
export { HomepageView } from "./HomepageView";
|
|
21
|
-
export type { HomepageViewProps } from "./HomepageView";
|
|
22
11
|
export { MarketplaceHomepageView } from "./MarketplaceHomepageView";
|
|
23
12
|
export type { MarketplaceHomepageViewProps, MarketplaceHomepageViewAdSlots, } from "./MarketplaceHomepageView";
|
|
24
13
|
export type { SectionCarouselProps } from "./SectionCarousel";
|
|
@@ -37,19 +26,10 @@ export type { FAQItem, FAQTab, FAQSectionProps } from "./FAQSection";
|
|
|
37
26
|
export { FAQSection } from "./FAQSection";
|
|
38
27
|
export type { NewsletterSectionProps } from "./NewsletterSection";
|
|
39
28
|
export { NewsletterSection } from "./NewsletterSection";
|
|
40
|
-
export type { AdvertisementBannerProps } from "./AdvertisementBanner";
|
|
41
|
-
export { AdvertisementBanner } from "./AdvertisementBanner";
|
|
42
29
|
export type { SecurityHighlightItem, SecurityHighlightsSectionProps, } from "./SecurityHighlightsSection";
|
|
43
30
|
export { SecurityHighlightsSection } from "./SecurityHighlightsSection";
|
|
44
|
-
export type { SiteFeatureItem, SiteFeaturesSectionProps, } from "./SiteFeaturesSection";
|
|
45
|
-
export { SiteFeaturesSection } from "./SiteFeaturesSection";
|
|
46
|
-
export type { TrustIndicatorItem, TrustIndicatorsSectionProps, } from "./TrustIndicatorsSection";
|
|
47
|
-
export { TrustIndicatorsSection } from "./TrustIndicatorsSection";
|
|
48
31
|
export type { WhatsAppCommunitySectionProps } from "./WhatsAppCommunitySection";
|
|
49
32
|
export { WhatsAppCommunitySection } from "./WhatsAppCommunitySection";
|
|
50
|
-
export { HomepageSkeleton } from "./HomepageSkeleton";
|
|
51
|
-
export type { FeaturedResultItem, FeaturedResultsSectionProps, } from "./FeaturedResultsSection";
|
|
52
|
-
export { FeaturedResultsSection } from "./FeaturedResultsSection";
|
|
53
33
|
export type { AnnouncementBarProps } from "./AnnouncementBar";
|
|
54
34
|
export { AnnouncementBar, hashBannerMessage } from "./AnnouncementBar";
|
|
55
35
|
export type { ShopByCategorySectionProps } from "./ShopByCategorySection";
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
export { HeroSection } from "./HeroSection.js";
|
|
2
1
|
export { CharacterHotspot } from "./CharacterHotspot.js";
|
|
3
2
|
export { CharacterHotspotForm } from "./CharacterHotspotForm.js";
|
|
4
|
-
export { HeroBanner } from "./HeroBanner.js";
|
|
5
3
|
export { HeroCarousel } from "./HeroCarousel.js";
|
|
6
4
|
export { PromoGrid } from "./PromoGrid.js";
|
|
7
|
-
export { TrustBadges } from "./TrustBadges.js";
|
|
8
5
|
export { TestimonialsCarousel } from "./TestimonialsCarousel.js";
|
|
9
|
-
export { BeforeAfterCard } from "./BeforeAfterCard.js";
|
|
10
|
-
export { NewsletterBanner } from "./NewsletterBanner.js";
|
|
11
|
-
export { HomepageView } from "./HomepageView.js";
|
|
12
6
|
export { MarketplaceHomepageView } from "./MarketplaceHomepageView.js";
|
|
13
7
|
export { SectionCarousel } from "./SectionCarousel.js";
|
|
14
8
|
export { WelcomeSection } from "./WelcomeSection.js";
|
|
@@ -18,13 +12,8 @@ export { HowItWorksSection } from "./HowItWorksSection.js";
|
|
|
18
12
|
export { CustomerReviewsSection } from "./CustomerReviewsSection.js";
|
|
19
13
|
export { FAQSection } from "./FAQSection.js";
|
|
20
14
|
export { NewsletterSection } from "./NewsletterSection.js";
|
|
21
|
-
export { AdvertisementBanner } from "./AdvertisementBanner.js";
|
|
22
15
|
export { SecurityHighlightsSection } from "./SecurityHighlightsSection.js";
|
|
23
|
-
export { SiteFeaturesSection } from "./SiteFeaturesSection.js";
|
|
24
|
-
export { TrustIndicatorsSection } from "./TrustIndicatorsSection.js";
|
|
25
16
|
export { WhatsAppCommunitySection } from "./WhatsAppCommunitySection.js";
|
|
26
|
-
export { HomepageSkeleton } from "./HomepageSkeleton.js";
|
|
27
|
-
export { FeaturedResultsSection } from "./FeaturedResultsSection.js";
|
|
28
17
|
export { AnnouncementBar, hashBannerMessage } from "./AnnouncementBar.js";
|
|
29
18
|
export { ShopByCategorySection } from "./ShopByCategorySection.js";
|
|
30
19
|
export { FeaturedProductsSection } from "./FeaturedProductsSection.js";
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export * from "./types/index.js";
|
|
2
|
-
export * from "./hooks/useHomepage.js";
|
|
3
|
-
export * from "./hooks/useHomepageSections.js";
|
|
4
2
|
export * from "./hooks/useHeroCarousel.js";
|
|
5
3
|
export * from "./hooks/useFeaturedProducts.js";
|
|
6
4
|
export * from "./hooks/useFeaturedAuctions.js";
|
|
@@ -47,5 +47,14 @@ export interface HomepageBrand {
|
|
|
47
47
|
/** Short mark shown in the hero panel, e.g. "LT". */
|
|
48
48
|
shortName?: string;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Every surface a `SectionDef` may be mounted on.
|
|
52
|
+
*
|
|
53
|
+
* `"homepage"` is the only one any renderer currently receives data for — see
|
|
54
|
+
* the note on `SectionDef.surfaces` below. The others are declared now so a
|
|
55
|
+
* reuse decision has somewhere reviewable to live, ahead of the data-loading
|
|
56
|
+
* work that would make them real.
|
|
57
|
+
*/
|
|
58
|
+
export type SectionSurface = "homepage" | "category" | "brand" | "product" | "store";
|
|
50
59
|
export declare function renderSection(section: HomepageSectionDocument, adSlots: MarketplaceHomepageViewAdSlots | undefined, newsletterFormSlot: React.ReactNode, faqItems: FaqItem[], slides: CarouselSlide[], liveStats: LiveStatsMap, sectionData?: SectionData, brand?: HomepageBrand): React.ReactNode;
|
|
51
60
|
export { AnnouncementBar, hashBannerMessage };
|
|
@@ -35,31 +35,55 @@ import { HomepageSectionBoundary } from "../components/HomepageSectionBoundary.j
|
|
|
35
35
|
import { PrizeDrawsSection } from "../../products/components/PrizeDrawsSection.js";
|
|
36
36
|
import { EventRafflesSection } from "../../events/components/EventRafflesSection.js";
|
|
37
37
|
import { CollectionCardsSection } from "../components/CollectionCardsSection.js";
|
|
38
|
+
import { HowItWorksSection } from "../components/HowItWorksSection.js";
|
|
39
|
+
import { TestimonialsCarousel } from "../components/TestimonialsCarousel.js";
|
|
40
|
+
import { PromoGrid } from "../components/PromoGrid.js";
|
|
38
41
|
const AD_SLOT_MAP = {
|
|
39
42
|
carousel: "afterHero",
|
|
40
43
|
products: "afterFeaturedProducts",
|
|
41
44
|
reviews: "afterReviews",
|
|
42
45
|
faq: "afterFAQ",
|
|
43
46
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* One entry per `SectionType`, replacing the 25-arm `switch` this registry is
|
|
49
|
+
* carved from verbatim — every case body below is byte-identical to its
|
|
50
|
+
* switch arm, only re-homed into an object property.
|
|
51
|
+
*
|
|
52
|
+
* `Record<SectionType, SectionDef>` is EXHAUSTIVE: a `SectionType` added to
|
|
53
|
+
* the union without an entry here is a compile error, where the switch's
|
|
54
|
+
* `default: return null` let a listed-but-unhandled type render nothing with
|
|
55
|
+
* no signal anywhere. `audit-homepage-config-coverage` still passes with zero
|
|
56
|
+
* changes — it does a bare name-presence `test()` against this file as a flat
|
|
57
|
+
* string, and every config field name below is exactly where it always was.
|
|
58
|
+
*/
|
|
59
|
+
const SECTION_REGISTRY = {
|
|
60
|
+
carousel: {
|
|
61
|
+
surfaces: ["homepage"],
|
|
62
|
+
render: ({ config, slides }) => {
|
|
48
63
|
const cfg = config;
|
|
49
64
|
return (_jsx(HeroCarousel, { initialSlides: slides, title: cfg?.title, height: cfg?.height, defaultAutoplayDelayMs: cfg?.defaultAutoplayDelayMs, pauseOnHover: cfg?.pauseOnHover, showDots: cfg?.showDots, showArrows: cfg?.showArrows }));
|
|
50
|
-
}
|
|
51
|
-
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
welcome: {
|
|
68
|
+
surfaces: ["homepage"],
|
|
69
|
+
render: ({ config, brand }) => {
|
|
52
70
|
const cfg = config;
|
|
53
71
|
return (_jsx(WelcomeSection, { title: cleanTitle(cfg?.h1) || SECTION_TITLE.welcome,
|
|
54
72
|
// A real `subtitle` wins; `description` is the legacy source and is
|
|
55
73
|
// still parsed for documents that only carry it.
|
|
56
74
|
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 }));
|
|
57
|
-
}
|
|
58
|
-
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
categories: {
|
|
78
|
+
surfaces: ["homepage", "category", "brand"],
|
|
79
|
+
render: ({ config, sectionData }) => {
|
|
59
80
|
const cfg = config;
|
|
60
81
|
return (_jsx(ShopByCategorySection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.categories, viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.categories, initialItems: sectionData.categories, limit: cfg?.maxCategories, cta: cfg?.cta, filters: cfg?.filters, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
61
|
-
}
|
|
62
|
-
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
stats: {
|
|
85
|
+
surfaces: ["homepage"],
|
|
86
|
+
render: ({ config, liveStats }) => {
|
|
63
87
|
const cfg = config;
|
|
64
88
|
const stats = Array.isArray(cfg?.stats)
|
|
65
89
|
? cfg.stats
|
|
@@ -85,44 +109,68 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
|
|
|
85
109
|
if (stats.length === 0)
|
|
86
110
|
return null;
|
|
87
111
|
return _jsx(StatsCounterSection, { stats: stats, title: cleanTitle(cfg?.title) });
|
|
88
|
-
}
|
|
89
|
-
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
products: {
|
|
115
|
+
surfaces: ["homepage", "category", "brand", "product"],
|
|
116
|
+
render: ({ config, sectionData }) => {
|
|
90
117
|
const cfg = config;
|
|
91
118
|
return (_jsx(FeaturedProductsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.products, description: cfg?.subtitle, viewMoreHref: ROUTES.PUBLIC.PRODUCTS, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.products, filterByBrand: cfg?.filterByBrand, initialItems: sectionData.products, rows: cfg?.rows,
|
|
92
119
|
// `maxProducts` is what the admin builder's "Max items" input writes;
|
|
93
120
|
// `maxItems` is the schema's own name. The two never met, so the
|
|
94
121
|
// control had no effect. Read both, newest name first.
|
|
95
122
|
maxItems: cfg?.maxItems ?? cfg?.maxProducts, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
96
|
-
}
|
|
97
|
-
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
auctions: {
|
|
126
|
+
surfaces: ["homepage", "category", "brand"],
|
|
127
|
+
render: ({ config, sectionData }) => {
|
|
98
128
|
const cfg = config;
|
|
99
129
|
return (_jsx(FeaturedAuctionsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.auctions, description: cfg?.subtitle, viewMoreHref: ROUTES.PUBLIC.AUCTIONS, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.auctions, filterByBrand: cfg?.filterByBrand, initialItems: sectionData.auctions, rows: cfg?.rows, maxItems: cfg?.maxAuctions, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
100
|
-
}
|
|
101
|
-
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
"pre-orders": {
|
|
133
|
+
surfaces: ["homepage", "category", "brand"],
|
|
134
|
+
render: ({ config, sectionData }) => {
|
|
102
135
|
const cfg = config;
|
|
103
136
|
return (_jsx(FeaturedPreOrdersSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.preOrders, description: cfg?.subtitle, viewMoreHref: ROUTES.PUBLIC.PRE_ORDERS, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.preOrders, filterByBrand: cfg?.filterByBrand, initialItems: sectionData.preOrders, rows: cfg?.rows, maxItems: cfg?.maxItems, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
104
|
-
}
|
|
105
|
-
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
stores: {
|
|
140
|
+
surfaces: ["homepage", "category", "brand"],
|
|
141
|
+
render: ({ config, sectionData }) => {
|
|
106
142
|
const cfg = config;
|
|
107
143
|
return (_jsx(FeaturedStoresSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.stores, description: cfg?.subtitle, viewMoreHref: ROUTES.PUBLIC.STORES, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.stores, initialItems: sectionData.stores, limit: cfg?.maxStores, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
108
|
-
}
|
|
109
|
-
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
events: {
|
|
147
|
+
surfaces: ["homepage"],
|
|
148
|
+
render: ({ config, sectionData }) => {
|
|
110
149
|
const cfg = config;
|
|
111
150
|
return (_jsx(EventsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.events, description: cfg?.subtitle, viewMoreHref: ROUTES.PUBLIC.EVENTS, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.events, initialItems: sectionData.events, limit: cfg?.maxEvents, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
112
|
-
}
|
|
113
|
-
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
reviews: {
|
|
154
|
+
surfaces: ["homepage", "category", "brand", "product"],
|
|
155
|
+
render: ({ config }) => {
|
|
114
156
|
const cfg = config;
|
|
115
157
|
return (_jsx(HomepageCustomerReviewsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.reviews, viewMoreHref: ROUTES.PUBLIC.REVIEWS, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.reviews, maxReviews: cfg?.maxReviews, itemsPerView: cfg?.itemsPerView, mobileItemsPerView: cfg?.mobileItemsPerView, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
116
|
-
}
|
|
117
|
-
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
banner: {
|
|
161
|
+
surfaces: ["homepage", "category", "brand", "product"],
|
|
162
|
+
render: ({ config }) => {
|
|
118
163
|
const cfg = config;
|
|
119
164
|
// CTAs come from the configured buttons; the component's own neutral
|
|
120
165
|
// defaults fill in when none are set. Previously both labels and both
|
|
121
166
|
// hrefs were hardcoded here and `buttons[]` was ignored entirely.
|
|
122
167
|
const [primaryBtn, secondaryBtn] = cfg?.buttons ?? [];
|
|
123
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 }));
|
|
124
|
-
}
|
|
125
|
-
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
"trust-indicators": {
|
|
172
|
+
surfaces: ["homepage", "category", "brand"],
|
|
173
|
+
render: ({ config, brand }) => {
|
|
126
174
|
const cfg = config;
|
|
127
175
|
const configured = (cfg?.indicators ?? [])
|
|
128
176
|
.filter((ind) => ind?.title?.trim())
|
|
@@ -134,8 +182,11 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
|
|
|
134
182
|
}));
|
|
135
183
|
return (_jsx(TrustFeaturesSection, { title: cleanTitle(cfg?.title) ||
|
|
136
184
|
(brand?.name ? `Why Buyers Trust ${brand.name}` : SECTION_TITLE.trustIndicators), items: configured.length > 0 ? configured : DEFAULT_TRUST_FEATURES }));
|
|
137
|
-
}
|
|
138
|
-
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
features: {
|
|
188
|
+
surfaces: ["homepage"],
|
|
189
|
+
render: ({ config }) => {
|
|
139
190
|
const cfg = config;
|
|
140
191
|
// `items` is the real shape; `features: string[]` is the legacy one and
|
|
141
192
|
// becomes title-only cards. Neither reached the component before — it
|
|
@@ -146,15 +197,21 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
|
|
|
146
197
|
.map((label, index) => ({ key: `feature-${index}`, title: label, description: "" })) ??
|
|
147
198
|
[];
|
|
148
199
|
return (_jsx(SecurityHighlightsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.features, pillLabel: cfg?.pillLabel || SECTION_COPY.featuresPill, items: configured.length > 0 ? configured : DEFAULT_SECURITY_ITEMS, learnMoreHref: cfg?.learnMoreLink || ROUTES.PUBLIC.SECURITY, learnMoreLabel: cfg?.learnMoreLabel || SECTION_COPY.featuresLearnMore }));
|
|
149
|
-
}
|
|
150
|
-
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
"whatsapp-community": {
|
|
203
|
+
surfaces: ["homepage"],
|
|
204
|
+
render: ({ config }) => {
|
|
151
205
|
const cfg = config;
|
|
152
206
|
return (_jsx(WhatsAppCommunitySection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.whatsappCommunity, descriptionHtml: cfg?.description || SECTION_COPY.whatsappDescription,
|
|
153
207
|
// No `|| 5000` fallback: inventing a member count the site cannot
|
|
154
208
|
// verify is a fabricated social-proof number.
|
|
155
209
|
memberCount: cfg?.memberCount, groupLink: cfg?.groupLink || "https://chat.whatsapp.com/", benefits: cfg?.benefits ?? [], testimonial: cfg?.testimonial, buttonText: cfg?.buttonText }));
|
|
156
|
-
}
|
|
157
|
-
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
faq: {
|
|
213
|
+
surfaces: ["homepage", "category", "brand", "product"],
|
|
214
|
+
render: ({ config, faqItems }) => {
|
|
158
215
|
const cfg = config;
|
|
159
216
|
if (!cfg?.showOnHomepage || faqItems.length === 0)
|
|
160
217
|
return null;
|
|
@@ -177,55 +234,142 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
|
|
|
177
234
|
const totalFaqs = faqItems.length;
|
|
178
235
|
const hasMore = totalFaqs > slicedItems.length || readSaturated;
|
|
179
236
|
return (_jsx(FAQSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.faq, subtitle: cfg?.subtitle, tabs: tabs, showCategoryTabs: cfg?.showCategoryTabs ?? false, allowMultipleOpen: cfg?.allowMultipleOpen ?? false, defaultOpenCount: cfg?.defaultOpenCount ?? 0, items: slicedItems, viewMoreHref: cfg?.linkToFullPage ? ROUTES.PUBLIC.FAQS : undefined, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.faq, hasMore: hasMore, moreCount: readSaturated ? 0 : totalFaqs - slicedItems.length }));
|
|
180
|
-
}
|
|
181
|
-
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
"blog-articles": {
|
|
240
|
+
surfaces: ["homepage", "category", "brand"],
|
|
241
|
+
render: ({ config, sectionData }) => {
|
|
182
242
|
const cfg = config;
|
|
183
243
|
return (_jsx(BlogArticlesSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.blogArticles, viewMoreHref: ROUTES.BLOG.LIST, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.blogArticles, initialItems: sectionData.blog, limit: cfg?.maxArticles, showReadTime: cfg?.showReadTime, showAuthor: cfg?.showAuthor, showThumbnails: cfg?.showThumbnails }));
|
|
184
|
-
}
|
|
185
|
-
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
newsletter: {
|
|
247
|
+
surfaces: ["homepage", "category", "brand"],
|
|
248
|
+
render: ({ config, newsletterFormSlot }) => {
|
|
186
249
|
const cfg = config;
|
|
187
250
|
return (_jsx(NewsletterSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.newsletter, subtitle: cfg?.description, privacyLabel: cfg?.privacyText, privacyHref: cfg?.privacyLink, renderForm: () => newsletterFormSlot ?? null }));
|
|
188
|
-
}
|
|
189
|
-
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
brands: {
|
|
254
|
+
// Homepage-only, not category/brand: a rail of OTHER brands reads as
|
|
255
|
+
// intended cross-sell on the homepage, but on a BRAND's own detail page it
|
|
256
|
+
// would compete with that brand's reason for being there. A category page
|
|
257
|
+
// has `BrandsSection` reachable via its own tabs/grid already.
|
|
258
|
+
surfaces: ["homepage"],
|
|
259
|
+
render: ({ config, sectionData }) => {
|
|
190
260
|
const cfg = config;
|
|
191
261
|
return (_jsx(BrandsSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.brands, subtitle: cfg?.subtitle, limit: cfg?.maxBrands || 12, viewMoreHref: ROUTES.PUBLIC.CATEGORIES, viewMoreLabel: cfg?.viewMoreLabel || VIEW_MORE_LABEL.brands, initialItems: sectionData.brands, cta: cfg?.cta, filters: cfg?.filters, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval, loop: cfg?.loop }));
|
|
192
|
-
}
|
|
193
|
-
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
"social-feed": {
|
|
265
|
+
surfaces: ["homepage"],
|
|
266
|
+
render: ({ config }) => {
|
|
194
267
|
const cfg = config;
|
|
195
268
|
const hasStaticPosts = Array.isArray(cfg?.posts) && cfg.posts.length > 0;
|
|
196
269
|
if (!cfg?.platform || (!cfg?.handle && !hasStaticPosts))
|
|
197
270
|
return null;
|
|
198
271
|
return (_jsx(SocialFeedSection, { title: cleanTitle(cfg.title) || "", subtitle: cfg.subtitle, platform: cfg.platform, handle: cfg.handle ?? "", postType: cfg.postType || "all", count: cfg.count || 9, layout: cfg.layout || "grid", showCaption: cfg.showCaption ?? true, showStats: cfg.showStats ?? true, posts: cfg.posts }));
|
|
199
|
-
}
|
|
200
|
-
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
"custom-cards": {
|
|
275
|
+
surfaces: ["homepage", "category", "brand"],
|
|
276
|
+
render: ({ config }) => {
|
|
201
277
|
const cfg = config;
|
|
202
278
|
if (!cfg?.cards?.length)
|
|
203
279
|
return null;
|
|
204
280
|
return (_jsx(CustomCardsSection, { title: cleanTitle(cfg.title), layout: cfg.layout ?? "grid", columns: cfg.columns ?? 3, cards: cfg.cards, autoScroll: cfg.autoScroll, scrollIntervalMs: cfg.scrollIntervalMs, loop: cfg.loop }));
|
|
205
|
-
}
|
|
206
|
-
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
"google-reviews": {
|
|
284
|
+
surfaces: ["homepage"],
|
|
285
|
+
render: ({ config }) => {
|
|
207
286
|
const cfg = config;
|
|
208
287
|
return (_jsx(GoogleReviewsSection, { placeId: cfg?.placeId ?? "", maxReviews: cfg?.maxReviews ?? 6, minRating: cfg?.minRating ?? 0, layout: cfg?.layout ?? "grid", showRating: cfg?.showRating ?? true, showDate: cfg?.showDate ?? true, linkToGoogleMaps: cfg?.linkToGoogleMaps ?? true, googleMapsUrl: cfg?.googleMapsUrl }));
|
|
209
|
-
}
|
|
210
|
-
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
"featured-bundles": {
|
|
291
|
+
surfaces: ["homepage", "category", "brand"],
|
|
292
|
+
render: ({ config, sectionData }) => {
|
|
211
293
|
const cfg = config;
|
|
212
294
|
return (_jsx(FeaturedBundlesSection, { title: cleanTitle(cfg?.title) || SECTION_TITLE.featuredBundles, description: cfg?.subtitle, initialItems: sectionData.bundles, maxItems: cfg?.maxItems, showSavingsBadge: cfg?.showSavingsBadge, viewMoreLabel: cfg?.viewMoreLabel }));
|
|
213
|
-
}
|
|
214
|
-
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
"prize-draws": {
|
|
298
|
+
surfaces: ["homepage", "category", "brand"],
|
|
299
|
+
render: ({ config }) => {
|
|
215
300
|
const cfg = config;
|
|
216
301
|
return _jsx(PrizeDrawsSection, { config: cfg ?? {} });
|
|
217
|
-
}
|
|
218
|
-
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
"event-raffles": {
|
|
305
|
+
surfaces: ["homepage"],
|
|
306
|
+
render: ({ config }) => {
|
|
219
307
|
const cfg = config;
|
|
220
308
|
return _jsx(EventRafflesSection, { config: cfg ?? {} });
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return
|
|
228
|
-
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
"collection-cards": {
|
|
312
|
+
surfaces: ["homepage", "category", "brand"],
|
|
313
|
+
render: ({ config, sectionData }) => {
|
|
314
|
+
const cfg = config;
|
|
315
|
+
return (_jsx(CollectionCardsSection, { config: cfg ?? { collections: [] },
|
|
316
|
+
// The `categories`/`brands`/`stores` arrays homepage already fetches
|
|
317
|
+
// for ITS OWN same-named sections — zero extra round-trips. See the
|
|
318
|
+
// component's own docstring for why only these three are wired.
|
|
319
|
+
sectionData: {
|
|
320
|
+
categories: sectionData.categories,
|
|
321
|
+
brands: sectionData.brands,
|
|
322
|
+
stores: sectionData.stores,
|
|
323
|
+
} }));
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
// Promoted out of the orphan-component set 2026-10-19 (see each component's
|
|
327
|
+
// own docstring for the config-serialisability fixes this required).
|
|
328
|
+
"how-it-works": {
|
|
329
|
+
surfaces: ["homepage"],
|
|
330
|
+
render: ({ config }) => {
|
|
331
|
+
const cfg = config;
|
|
332
|
+
if (!cfg?.title || !Array.isArray(cfg.steps) || cfg.steps.length === 0)
|
|
333
|
+
return null;
|
|
334
|
+
return (_jsx(HowItWorksSection, { title: cfg.title, subtitle: cfg.subtitle, pillLabel: cfg.pillLabel, ctaLabel: cfg.ctaLabel, ctaLink: cfg.ctaLink, steps: cfg.steps }));
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
testimonials: {
|
|
338
|
+
surfaces: ["homepage"],
|
|
339
|
+
render: ({ config }) => {
|
|
340
|
+
const cfg = config;
|
|
341
|
+
if (!Array.isArray(cfg?.testimonials) || cfg.testimonials.length === 0)
|
|
342
|
+
return null;
|
|
343
|
+
return (_jsx(TestimonialsCarousel, { eyebrow: cfg.eyebrow, heading: cfg.heading, testimonials: cfg.testimonials }));
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
"promo-grid": {
|
|
347
|
+
surfaces: ["homepage"],
|
|
348
|
+
render: ({ config }) => {
|
|
349
|
+
const cfg = config;
|
|
350
|
+
if (!Array.isArray(cfg?.banners) || cfg.banners.length === 0)
|
|
351
|
+
return null;
|
|
352
|
+
return (_jsx(PromoGrid, { eyebrow: cfg.eyebrow, heading: cfg.heading, banners: cfg.banners }));
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liveStats, sectionData, brand) {
|
|
357
|
+
const def = SECTION_REGISTRY[section.type];
|
|
358
|
+
// No `default` arm left to fall through to — an unmapped `SectionType` is a
|
|
359
|
+
// compile error on the registry object above, not a runtime `null`. This
|
|
360
|
+
// branch only guards a value that bypassed the type system (a raw Firestore
|
|
361
|
+
// read of a document whose `type` predates the current union).
|
|
362
|
+
if (!def)
|
|
363
|
+
return null;
|
|
364
|
+
return def.render({
|
|
365
|
+
config: section.config,
|
|
366
|
+
newsletterFormSlot,
|
|
367
|
+
faqItems,
|
|
368
|
+
slides,
|
|
369
|
+
liveStats,
|
|
370
|
+
sectionData,
|
|
371
|
+
brand,
|
|
372
|
+
});
|
|
229
373
|
}
|
|
230
374
|
export function renderSection(section, adSlots, newsletterFormSlot, faqItems, slides, liveStats, sectionData = {}, brand) {
|
|
231
375
|
const sectionElement = renderSectionElement(section, newsletterFormSlot, faqItems, slides, liveStats, sectionData, brand);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { JsonValue } from "@mohasinac/appkit";
|
|
7
7
|
import { BaseRepository, type FirebaseSieveFields, type FirebaseSieveResult, type SieveModel } from "../../../providers/db-firebase";
|
|
8
|
-
import { type HomepageSectionCreateInput, type HomepageSectionDocument, type SectionType } from "../schemas";
|
|
8
|
+
import { type HomepageSectionCreateInput, type HomepageSectionDocument, type SectionSurface, type SectionType } from "../schemas";
|
|
9
9
|
export declare class HomepageSectionsRepository extends BaseRepository<HomepageSectionDocument> {
|
|
10
10
|
constructor();
|
|
11
11
|
static readonly SIEVE_FIELDS: FirebaseSieveFields;
|
|
@@ -34,9 +34,41 @@ export declare class HomepageSectionsRepository extends BaseRepository<HomepageS
|
|
|
34
34
|
* below deliberately keeps replace semantics — that is its whole purpose.
|
|
35
35
|
*/
|
|
36
36
|
update(id: string, data: Partial<HomepageSectionDocument>): Promise<HomepageSectionDocument>;
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Enabled sections for one surface, in `order`.
|
|
39
|
+
*
|
|
40
|
+
* 🛑 The parameter DEFAULTS to `"homepage"`, and that default is the safety
|
|
41
|
+
* property, not a convenience. This method previously returned every enabled
|
|
42
|
+
* row regardless of surface — so the moment a category-surface row exists,
|
|
43
|
+
* an unfiltered homepage would render it. Defaulting here means the existing
|
|
44
|
+
* homepage call site is correct with no change at all, and a caller that
|
|
45
|
+
* wants another surface has to say so.
|
|
46
|
+
*
|
|
47
|
+
* 🛑 The surface is matched IN MEMORY, deliberately. The only composite index
|
|
48
|
+
* on this collection is `(enabled, order)`;
|
|
49
|
+
* `where(enabled).where(surface).orderBy(order)` is a three-field composite it
|
|
50
|
+
* does not cover, and Firestore throws FAILED_PRECONDITION at RUNTIME rather
|
|
51
|
+
* than at build time. `MarketplaceHomepageView` already filters sections in
|
|
52
|
+
* memory for the listing-type gate — this follows that precedent. Section
|
|
53
|
+
* counts are tens, so the read is unchanged in cost.
|
|
54
|
+
*/
|
|
55
|
+
getEnabledSections(surface?: SectionSurface): Promise<HomepageSectionDocument[]>;
|
|
38
56
|
getDisabledSections(): Promise<HomepageSectionDocument[]>;
|
|
39
|
-
|
|
57
|
+
/**
|
|
58
|
+
* 🛑 `surface` is NOT optional in spirit, even though it defaults.
|
|
59
|
+
*
|
|
60
|
+
* This was `where(type == X).limit(1)`, which assumed ONE document per type.
|
|
61
|
+
* With surfaces that assumption is false — a `products` section can exist on
|
|
62
|
+
* the homepage AND on a category page — and `limit(1)` would return whichever
|
|
63
|
+
* Firestore happened to order first. An arbitrary-but-plausible answer is the
|
|
64
|
+
* worst failure shape available here, because nothing errors.
|
|
65
|
+
*
|
|
66
|
+
* The surface is matched IN MEMORY rather than added as a second `where`: the
|
|
67
|
+
* only composite index on this collection is `(enabled, order)`, and
|
|
68
|
+
* `where(type).where(surface)` needs one that does not exist. Fetching the few
|
|
69
|
+
* rows of a type and picking by surface costs nothing at these counts.
|
|
70
|
+
*/
|
|
71
|
+
getSectionByType(type: SectionType, surface?: SectionSurface): Promise<HomepageSectionDocument | null>;
|
|
40
72
|
enableSection(sectionId: string): Promise<HomepageSectionDocument>;
|
|
41
73
|
disableSection(sectionId: string): Promise<HomepageSectionDocument>;
|
|
42
74
|
toggleSection(sectionId: string): Promise<HomepageSectionDocument>;
|